/// Takes a background image, foreground image, and mask /// (i.e. the alpha channel for the foreground), and /// returns an new image where the foreground has been /// overlaid onto the background using alpha-blending, /// at location (xoff, yoff). wxImage *OverlayImage(teBmps eBack, teBmps eForeground, int xoff, int yoff) { wxImage imgBack(theTheme.Image( eBack )); wxImage imgFore(theTheme.Image( eForeground )); // TMP: dmazzoni - just so the code runs even though not all of // our images have transparency... if (!imgFore.HasAlpha()) return new wxImage(imgBack); wxASSERT( imgFore.HasAlpha() ); unsigned char *bg = imgBack.GetData(); unsigned char *fg = imgFore.GetData(); unsigned char *mk = imgFore.GetAlpha(); int bgWidth = imgBack.GetWidth(); int bgHeight = imgBack.GetHeight(); int fgWidth = imgFore.GetWidth(); int fgHeight = imgFore.GetHeight(); //Now, determine the dimensions of the images to be masked together //on top of the background. This should be equal to the area of the //smaller of the foreground and the mask, as long as it is //within the area of the background, given the offset. //Make sure the foreground size is no bigger than the mask int wCutoff = fgWidth; int hCutoff = fgHeight; // If the masked foreground + offset is bigger than the background, masking // should only occur within these bounds of the foreground image wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff; hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff; //Make a new image the size of the background wxImage * dstImage = new wxImage(bgWidth, bgHeight); unsigned char *dst = dstImage->GetData(); memcpy(dst, bg, bgWidth * bgHeight * 3); // Go through the foreground image bit by bit and mask it on to the // background, at an offset of xoff,yoff. // BUT...Don't go beyond the size of the background image, // the foreground image, or the mask int x, y; for (y = 0; y < hCutoff; y++) { unsigned char *bkp = bg + 3 * ((y + yoff) * bgWidth + xoff); unsigned char *dstp = dst + 3 * ((y + yoff) * bgWidth + xoff); for (x = 0; x < wCutoff; x++) { int value = mk[(y * fgWidth + x)];// Don't multiply by 3... int opp = 255 - value; for (int c = 0; c < 3; c++) dstp[x * 3 + c] = ((bkp[x * 3 + c] * opp) + (fg[3 * (y * fgWidth + x) + c] * value)) / 255; } } return dstImage; }
/// Takes a background image, foreground image, and mask /// (i.e. the alpha channel for the foreground), and /// returns an NEW image where the foreground has been /// overlaid onto the background using alpha-blending, /// at location (xoff, yoff). std::unique_ptr<wxImage> OverlayImage(teBmps eBack, teBmps eForeground, int xoff, int yoff) { wxImage imgBack(theTheme.Image( eBack )); wxImage imgFore(theTheme.Image( eForeground )); // TMP: dmazzoni - just so the code runs even though not all of // our images have transparency... if (!imgFore.HasAlpha()) return std::make_unique<wxImage>(imgBack); wxASSERT( imgFore.HasAlpha() ); unsigned char *bg = imgBack.GetData(); unsigned char *fg = imgFore.GetData(); unsigned char *mk = imgFore.GetAlpha(); int bgWidth = imgBack.GetWidth(); int bgHeight = imgBack.GetHeight(); int fgWidth = imgFore.GetWidth(); int fgHeight = imgFore.GetHeight(); //Now, determine the dimensions of the images to be masked together //on top of the background. This should be equal to the area of the //smaller of the foreground and the mask, as long as it is //within the area of the background, given the offset. //Make sure the foreground size is no bigger than the mask int wCutoff = fgWidth; int hCutoff = fgHeight; // If the masked foreground + offset is bigger than the background, masking // should only occur within these bounds of the foreground image wCutoff = (bgWidth - xoff > wCutoff) ? wCutoff : bgWidth - xoff; hCutoff = (bgHeight - yoff > hCutoff) ? hCutoff : bgHeight - yoff; //Make a NEW image the size of the background auto dstImage = std::make_unique<wxImage>(bgWidth, bgHeight); unsigned char *dst = dstImage->GetData(); memcpy(dst, bg, bgWidth * bgHeight * 3); // If background image has tranparency, then we want to blend with the // current backgorund colour. if( imgBack.HasAlpha() ){ unsigned char *pAlpha = imgBack.GetAlpha(); wxColour c = theTheme.Colour( clrMedium ); unsigned char onePixImage[3]; // GetData() guarantees RGB order [wxWidgets does the ocnversion] onePixImage[ 0 ] = c.Red(); onePixImage[ 1 ] = c.Green(); onePixImage[ 2 ] = c.Blue(); for( int i=0;i< bgWidth*bgHeight;i++){ unsigned char * pPix = &dst[ 3*i]; float alpha = 1.0 - (pAlpha[i]/255.0); pPix[0] = pPix[0] + alpha *( (int)onePixImage[0]-(int)pPix[0]); pPix[1] = pPix[1] + alpha *( (int)onePixImage[1]-(int)pPix[1]); pPix[2] = pPix[2] + alpha *( (int)onePixImage[2]-(int)pPix[2]); } } // Go through the foreground image bit by bit and mask it on to the // background, at an offset of xoff,yoff. // BUT...Don't go beyond the size of the background image, // the foreground image, or the mask int x, y; for (y = 0; y < hCutoff; y++) { unsigned char *bkp = bg + 3 * ((y + yoff) * bgWidth + xoff); unsigned char *dstp = dst + 3 * ((y + yoff) * bgWidth + xoff); for (x = 0; x < wCutoff; x++) { int value = mk[(y * fgWidth + x)];// Don't multiply by 3... int opp = 255 - value; for (int c = 0; c < 3; c++) dstp[x * 3 + c] = ((bkp[x * 3 + c] * opp) + (fg[3 * (y * fgWidth + x) + c] * value)) / 255; } } return dstImage; }