PDA

View Full Version : Setting the alpha bit on a per pixel basis



iharrold
09-22-2008, 06:34 AM
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!\n", 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;
};

Ivo Moravec
09-22-2008, 08:12 AM
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()/vgLookup[Single]()). You may need to massage the function input a bit though to get those to work as you like.

iharrold
09-22-2008, 01:01 PM
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()/vgLookup[Single]()). 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....