Setting the alpha bit on a per pixel basis

I am using ShivaVG and am developing an application that loads a JPEG via the IJG JPEG Library. The user has the option of setting a “transparency color” from the image as the transparency color. I have a routine that computes a euclidean mean distance from the color based upon Red, Green and Blue distance and determines if the color is within a threshold of similarity [due to compression algorithm]. If it is similar, then set the alpha channel to 100% transparent.

My question is how do I access the individual pixel information after it has been loaded from the JPEG and into a VGImage? And set the pixel’s Alpha channel?

Here is how I am loading the image [taken from ShivaVG examples]:


VGImage cLoader::createImageFromJpeg(const char *filename)
{
	FILE *infile;
  	struct jpeg_decompress_struct jdc;
  	struct jpeg_error_mgr jerr;
  	JSAMPARRAY buffer;  
  	unsigned int bstride;
  	unsigned int bbpp;

  	VGImage img;
  	VGubyte *data;
  	unsigned int width;
  	unsigned int height;
  	unsigned int dstride;
  	unsigned int dbpp;
  
  	VGubyte *brow;
  	VGubyte *drow;
  	unsigned int x;
  	unsigned int lilEndianTest = 1;
  	VGImageFormat rgbaFormat;

  	/* Check for endianness */
  	if (((unsigned char*)&lilEndianTest)[0] == 1)
    	rgbaFormat = VG_lABGR_8888;
  	else rgbaFormat = VG_lRGBA_8888;
  
  	/* Try to open image file */
  	infile = fopen(filename, "rb");
  	if (infile == NULL) 
  	{
    	printf("Failed opening '%s' for reading!
", filename);
    	return VG_INVALID_HANDLE; 
    }
  
  	/* Setup default error handling */
  	jdc.err = jpeg_std_error(&jerr);
  	jpeg_create_decompress(&jdc);
  
  	/* Set input file */
  	jpeg_stdio_src(&jdc, infile);
  
  	/* Read header and start */
  	jpeg_read_header(&jdc, TRUE);
  	jpeg_start_decompress(&jdc);
  	width = jdc.output_width;
  	height = jdc.output_height;
  
  	/* Allocate buffer using jpeg allocator */
  	bbpp = jdc.output_components;
  	bstride = width * bbpp;
  	buffer = (*jdc.mem->alloc_sarray)((j_common_ptr) &jdc, JPOOL_IMAGE, bstride, 1);
  
  	/* Allocate image data buffer */
  	dbpp = 4;
  	dstride = width * dbpp;
  	data = (VGubyte*)malloc(dstride * height);
  
  	/* Iterate until all scanlines processed */
  	while (jdc.output_scanline < height) 
  	{
    	/* Read scanline into buffer */
    	jpeg_read_scanlines(&jdc, buffer, 1);    
    	drow = data + (height-jdc.output_scanline) * dstride;
    	brow = buffer[0];
    
    	/* Expand to RGBA */
    	for (x=0; x<width; ++x, drow+=dbpp, brow+=bbpp) 
    	{
      		switch (bbpp) 
      		{
      			case 4:
        				drow[0] = brow[0];
        				drow[1] = brow[1];
        				drow[2] = brow[2];
        				drow[3] = brow[3];
        				break;
      			case 3:
        				drow[0] = brow[0];
        				drow[1] = brow[1];
        				drow[2] = brow[2];
        				drow[3] = 255;
        				break; 
        	}
    	}
  	}
  
  	/* Create VG image */
  	img = vgCreateImage(rgbaFormat, width, height, VG_IMAGE_QUALITY_BETTER);
  	
  	if (img != VG_INVALID_HANDLE)
  	{
  		vgImageSubData(img, data, dstride, rgbaFormat, 0, 0, width, height);
  	}  
  	/* Cleanup */
  	jpeg_destroy_decompress(&jdc);
  	fclose(infile);
  	free(data);
  
  	return img;
};

Why not just do the calculation after you decompress the jpg, and before you upload it with the vgImageSubData() call?

I suppose if you NEED to do it afterward, you could use vgGetImageSubData(), modify the data and then call vgImageSubData() again. Seems like a waste though. Alternatively, you could try if there is an Image Filter function what suits your needs (like vgColorMatrix()/vgLookupSingle). You may need to massage the function input a bit though to get those to work as you like.

Thanks Ivo, I didn’t even think to check while I was loading the image. I made it a little easier for me by implementing a pixel color based upon byte aligned struct


#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */

typedef union
{
	VGubyte red;
	VGubyte green;
	VGubyte blue;
	VGubyte alpha;
} pixelcolor;  //32 bit RGBA color

#pragma pack(pop)   /* restore original alignment from stack */

Then changed the code to:


        VGubyte *brow;
  	pixelcolor *drow;
.....
.....
        /* Allocate buffer using jpeg allocator */
  	bbpp = jdc.output_components;
  	bstride = width * bbpp;
  	buffer = (*jdc.mem->alloc_sarray)((j_common_ptr) &jdc, JPOOL_IMAGE, bstride, 1);
  
  	/* Allocate image data buffer */
  	dbpp = 4;
  	dstride = width * dbpp;
  	data = (pixelcolor*)malloc(width * height);
  
  	/* Iterate until all scanlines processed */
  	while (jdc.output_scanline < height) 
  	{
    	/* Read scanline into buffer */
    	jpeg_read_scanlines(&jdc, buffer, 1);    
    	drow = data + (height-jdc.output_scanline) * width;
    	brow = buffer[0];
    
    	/* Expand to RGBA */
    	for (x=0; x<width; ++x, drow++, brow+=bbpp) 
    	{
      		switch (bbpp) 
      		{
      			case 4:
        				drow->red = brow[0];
        				drow->green = brow[1];
        				drow->blue = brow[2];
        				drow->alpha = brow[3];
        				break;
      			case 3:
        				drow->red = brow[0];
        				drow->green = brow[1];
        				drow->blue = brow[2];
        				drow->alpha = 255;
        				break; 
        	}
        	if (in_hastransparency)
        	{
        		if (isInTolerance(*drow, in_transcolor))
        		{
        			drow->alpha = 0;
        		}
        	}
    	}
  }

I’m still learning the VG and vector graphics implementations…