/** @brief Blends two images based on alpha channel present in foreground image. @param foreground Foreground image, must have an alpha channel @param background Background image, may have an alpha channel @param blend_alpha Whether the returned image will have an alpha channel. @return A copy of the background image with the foreground image blended on top of it. The returned image will have an alpha channel iff the background image has an alpha channel. In that case the alpha channel is blended identical to the red/green/blue channels. */ wxImage BlendImage( const wxImage& foreground, const wxImage& background, bool blend_alpha ) { if ( ( foreground.GetWidth() != background.GetWidth() ) || ( background.GetHeight() != foreground.GetHeight() ) ) { wxLogDebugFunc(_T("size mismatch while blending")); return background; } bool zhu = blend_alpha && background.HasAlpha(); if ( foreground.HasAlpha() ) { wxImage ret( background.GetWidth(), foreground.GetHeight() ); const unsigned char* background_data = background.GetData(); const unsigned char* foreground_data = foreground.GetData(); const unsigned char* background_alpha = NULL; const unsigned char* foreground_alpha = foreground.GetAlpha(); unsigned char* result_data = ret.GetData(); unsigned char* result_alpha = NULL; unsigned int pixel_count = background.GetWidth() * background.GetHeight(); if ( zhu ) { background_alpha = background.GetAlpha(); ret.InitAlpha(); result_alpha = ret.GetAlpha(); } for ( unsigned int i = 0, i_a = 0; i < pixel_count * 3; i+=3, i_a++ ) { unsigned char fore_alpha = foreground_alpha[i_a] ; float back_blend_fac = ( 255 - fore_alpha)/255.0; float fore_blend_fac = fore_alpha/255.0 ; result_data[i] = foreground_data[i] * fore_blend_fac + background_data[i] * back_blend_fac ; result_data[i+1] = foreground_data[i+1] * fore_blend_fac + background_data[i+1] * back_blend_fac ; result_data[i+2] = foreground_data[i+2] * fore_blend_fac + background_data[i+2] * back_blend_fac ; if ( zhu ) { unsigned char back_alpha = background_alpha[i_a] ; result_alpha[i_a] = fore_alpha * fore_blend_fac + back_alpha * back_blend_fac ; } } return ret; } wxLogDebugFunc(_T("cannot blend without alpha")); return background; }
bool wxBitmap::CreateFromImage(const wxImage& image, int depth) { UnRef(); wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) wxCHECK_MSG( depth == -1 || depth == 1, FALSE, wxT("invalid bitmap depth") ) if (image.GetWidth() <= 0 || image.GetHeight() <= 0) return false; m_refData = new wxBitmapRefData(); if (depth == 1) { return CreateFromImageAsBitmap(image); } else { #ifdef __WXGTK20__ if (image.HasAlpha()) return CreateFromImageAsPixbuf(image); #endif return CreateFromImageAsPixmap(image); } }
wxImage tintImage( wxImage to_colorize, wxColour col) { wxImage highlightIcon(to_colorize.GetWidth(),to_colorize.GetHeight()); bool do_alpha = false; if(to_colorize.HasAlpha()) { highlightIcon.InitAlpha(); do_alpha = true; } else if(to_colorize.HasMask()) { highlightIcon.SetMaskFromImage(to_colorize,to_colorize.GetMaskRed(),to_colorize.GetMaskGreen(),to_colorize.GetMaskBlue()); } for(int x = 0; x < highlightIcon.GetWidth(); x++) { for(int y = 0; y < highlightIcon.GetHeight(); y++) { to_colorize.GetData(); unsigned char srcR = to_colorize.GetRed(x,y); unsigned char srcG = to_colorize.GetGreen(x,y); unsigned char srcB = to_colorize.GetBlue(x,y); highlightIcon.SetRGB(x,y,(srcR + col.Red())/2,(srcG + col.Green())/2, (srcB + col.Blue())/2); if(do_alpha) highlightIcon.SetAlpha(x,y,to_colorize.GetAlpha(x,y)); } } return highlightIcon; }
/** * Predicate to check an image pixel matches color and alpha * * @param aImage the image to check * @param aX pixel x-coordinate * @param aY pixel y-coordinate * @param aColor expected color (alpha is 1.0 if image doesn't support alpha) * @return true if colour match */ bool IsImagePixelOfColor( const wxImage& aImage, int aX, int aY, const KIGFX::COLOR4D& aColor ) { const wxSize imageSize = aImage.GetSize(); if( imageSize.x < aX || imageSize.y < aY ) { BOOST_TEST_INFO( "Pixel (" << aX << ", " << aY << "is not in image of size (" << imageSize.x << ", " << imageSize.y << ")" ); return false; } const int r = aImage.GetRed( aX, aY ); const int g = aImage.GetGreen( aX, aY ); const int b = aImage.GetBlue( aX, aY ); const int a = aImage.HasAlpha() ? aImage.GetAlpha( aX, aY ) : 255; if( !KI_TEST::IsColorNearHex( aColor, r, g, b, a ) ) { BOOST_TEST_INFO( "Colour doesn't match: got rgba(" << r << ", " << g << ", " << b << ", " << a << "), expected " << aColor ); return false; } return true; }
/// Gets a rectangle from within another image, INCLUDING the alpha channel /// \bug in wxWidgets, wxImage::GetSubImage should do this itself. wxImage GetSubImageWithAlpha( const wxImage & Src, const wxRect &rect ) { //First part of this code is lifted from wxImage::GetSubImage() source code. wxImage image; wxCHECK_MSG( Src.Ok(), image, wxT("invalid image") ); wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && ( rect.GetRight()<=Src.GetWidth()) && (rect.GetBottom()<=Src.GetHeight()), image, wxT("invalid subimage size") ); int subwidth=rect.GetWidth(); const int subheight=rect.GetHeight(); image.Create( subwidth, subheight, false ); unsigned char *subdata = image.GetData(), *data=Src.GetData(); wxCHECK_MSG( subdata, image, wxT("unable to create image") ); // JKC: Quick hack - don't deal with masks - need to understand macro M_IMGDATA first. // if (Src.M_IMGDATA->m_hasMask) // image.SetMaskColour( Src.M_IMGDATA->m_maskRed, Src.M_IMGDATA->m_maskGreen, Src.M_IMGDATA->m_maskBlue ); int subleft=3*rect.GetLeft(); int width=3*Src.GetWidth(); subwidth*=3; data+=rect.GetTop()*width+subleft; for (long j = 0; j < subheight; ++j) { memcpy( subdata, data, subwidth); subdata+=subwidth; data+=width; } // OK, so we've copied the RGB data. // Now do the Alpha channel. wxASSERT( Src.HasAlpha() ); image.InitAlpha(); subleft/=3; width/=3; subwidth/=3; data =Src.GetAlpha(); subdata =image.GetAlpha(); data+=rect.GetTop()*width+subleft; for (long j = 0; j < subheight; ++j) { memcpy( subdata, data, subwidth); subdata+=subwidth; data+=width; } return image; }
ImageDetailsDocument::ImageDetailsDocument(ImageDocument *parent) : wxDocument(parent) { const wxImage image = parent->GetImage(); m_size.x = image.GetWidth(); m_size.y = image.GetHeight(); m_numColours = image.CountColours(); m_type = image.GetType(); m_hasAlpha = image.HasAlpha(); }
bool check_equal(const wxImage &self, const wxImage &cother) { if(self.GetHeight() != cother.GetHeight()){ return false; } if(self.GetWidth() != cother.GetWidth()) { return false; } if(strcmp((char*)self.GetData(), (char*)cother.GetData()) != 0){ return false; } if(self.HasAlpha()) { if(!cother.HasAlpha()) return false; if(strcmp((char*)self.GetAlpha(), (char*)cother.GetAlpha()) != 0){ return false; } } else { return !cother.HasAlpha(); } return true; }
wxImage BorderInvariantResizeImage(const wxImage& image, int width, int height) { if (!image.IsOk() || (width == image.GetWidth() && height == image.GetHeight())) return image; wxImage ret(width, height); Resizer data_resize(ret, image, false); data_resize(); if (image.HasAlpha()) { ret.InitAlpha(); Resizer alpha_resize(ret, image, true); alpha_resize(); } return ret; }
void zen::convertToVanillaImage(wxImage& img) { if (!img.HasAlpha()) { const int width = img.GetWidth (); const int height = img.GetHeight(); if (width <= 0 || height <= 0) return; unsigned char mask_r = 0; unsigned char mask_g = 0; unsigned char mask_b = 0; const bool haveMask = img.HasMask() && img.GetOrFindMaskColour(&mask_r, &mask_g, &mask_b); //check for mask before calling wxImage::GetOrFindMaskColour() to skip needlessly searching for new mask color img.SetAlpha(); ::memset(img.GetAlpha(), wxIMAGE_ALPHA_OPAQUE, width * height); //wxWidgets, as always, tries to be more clever than it really is and f***s up wxStaticBitmap if wxBitmap is fully opaque: img.GetAlpha()[width * height - 1] = 254; if (haveMask) { img.SetMask(false); unsigned char* alphaPtr = img.GetAlpha(); const unsigned char* dataPtr = img.GetData(); const int pixelCount = width * height; for (int i = 0; i < pixelCount; ++ i) { const unsigned char r = *dataPtr++; const unsigned char g = *dataPtr++; const unsigned char b = *dataPtr++; if (r == mask_r && g == mask_g && b == mask_b) alphaPtr[i] = wxIMAGE_ALPHA_TRANSPARENT; } } } else { assert(!img.HasMask()); } }
wxSVGCanvasImageCairoData::wxSVGCanvasImageCairoData(wxImage image) { m_count = 1; int bw = image.GetWidth(); int bh = image.GetHeight(); m_buffer = new unsigned char[bw*bh*4]; wxUint32* data = (wxUint32*) m_buffer; // Create a surface object and copy the bitmap pixel data to it unsigned char* srcPix = image.GetData(); if (image.HasAlpha()) { // alpha m_surface = cairo_image_surface_create_for_data(m_buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); unsigned char* srcAlpha = image.GetAlpha(); for (int y = 0; y < bh; y++) { for (int x = 0; x < bw; x++) { // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity, with alpha in the upper 8 bits, // then red, then green, then blue. The 32-bit quantities are stored native-endian. // Pre-multiplied alpha is used. unsigned char alpha = srcAlpha != NULL ? (*srcAlpha) : 255; if (alpha == 0) *data = 0; else *data = (alpha << 24 | (srcPix[0] * alpha / 255) << 16 | (srcPix[1] * alpha / 255) << 8 | (srcPix[2] * alpha / 255)); data++; srcPix += 3; if (srcAlpha) srcAlpha++; } } } else { // no alpha m_surface = cairo_image_surface_create_for_data(m_buffer, CAIRO_FORMAT_RGB24, bw, bh, bw * 4); for (int y = 0; y < bh; y++) { for (int x = 0; x < bw; x++) { // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with the upper 8 bits unused. // Red, Green, and Blue are stored in the remaining 24 bits in that order. // The 32-bit quantities are stored native-endian. *data = (srcPix[0] << 16 | srcPix[1] << 8 | srcPix[2]); data++; srcPix += 3; } } } }
QImage wxQtConvertImage( const wxImage &image ) { bool hasAlpha = image.HasAlpha(); bool hasMask = image.HasMask(); wxSize size ( image.GetWidth(), image.GetHeight() ); QImage qtImage( wxQtConvertSize( size ), ( (hasAlpha || hasMask ) ? QImage::Format_ARGB32 : QImage::Format_RGB32 ) ); unsigned char *data = image.GetData(); unsigned char *alpha = hasAlpha ? image.GetAlpha() : NULL; QRgb colour; QRgb maskedColour; if ( hasMask ) { unsigned char r, g, b; image.GetOrFindMaskColour( &r, &g, &b ); maskedColour = ( r << 16 ) + ( g << 8 ) + b; } for (int y = 0; y < image.GetHeight(); y++) { for (int x = 0; x < image.GetWidth(); x++) { if (hasAlpha) { colour = alpha[0] << 24; alpha++; } else colour = 0; colour += (data[0] << 16) + (data[1] << 8) + data[2]; if ( hasMask && colour != maskedColour ) colour += 0xFF000000; // 255 << 24 qtImage.setPixel(x, y, colour); data += 3; } } return qtImage; }
// Creates a surface that will use wxImage's pixel data (RGB only) static wxIDirectFBSurfacePtr CreateSurfaceForImage(const wxImage& image) { wxCHECK_MSG( image.Ok(), NULL, _T("invalid image") ); // FIXME_DFB: implement alpha handling by merging alpha buffer with RGB // into a temporary RGBA surface wxCHECK_MSG( !image.HasAlpha(), NULL, _T("alpha channel not supported") ); DFBSurfaceDescription desc; desc.flags = (DFBSurfaceDescriptionFlags) (DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_PREALLOCATED); desc.caps = DSCAPS_NONE; desc.width = image.GetWidth(); desc.height = image.GetHeight(); desc.pixelformat = DSPF_RGB24; desc.preallocated[0].data = image.GetData(); desc.preallocated[0].pitch = 3 * desc.width; return wxIDirectFB::Get()->CreateSurface(&desc); }
void GOrgueBitmap::ScaleBMP(wxImage& img, double scale, const wxRect& rect, GOrgueBitmap* background) { if (background && img.HasAlpha()) { wxBitmap bmp(img.GetWidth(), img.GetHeight()); wxBitmap orig(img); wxMemoryDC dc; dc.SelectObject(bmp); dc.DrawBitmap(background->GetBitmap(), -rect.GetX(), -rect.GetY(), false); dc.DrawBitmap(orig, 0, 0, true); bmp.SetMask(orig.GetMask()); wxImage img_result = bmp.ConvertToImage(); img_result.InitAlpha(); memcpy(img_result.GetAlpha(), img.GetAlpha(), img.GetWidth() * img.GetHeight()); m_bmp = (wxBitmap)img_result.Scale(img.GetWidth() * scale, img.GetHeight() * scale, wxIMAGE_QUALITY_BICUBIC); } else m_bmp = (wxBitmap)img.Scale(img.GetWidth() * scale, img.GetHeight() * scale, wxIMAGE_QUALITY_BICUBIC); m_Scale = scale; }
void Map::AssignImgData(ImgData *imgdata, wxImage &img) { if(imgdata == NULL) return; if(img.IsOk()) { unsigned char *pixdata, *alphadata; int width, height; long datasize; if(!img.HasAlpha()) img.SetAlpha(); width = img.GetWidth(); height = img.GetHeight(); pixdata = img.GetData(); alphadata = img.GetAlpha(); datasize = (long) 4 * width * height; (*imgdata).width = (long)width; (*imgdata).height = (long)height; (*imgdata).data = (unsigned char*)malloc(datasize); if((*imgdata).data == NULL) return; int pi = 0, ai = 0; for(int di = 0; di < datasize;) { (*imgdata).data[di++] = pixdata[pi++]; (*imgdata).data[di++] = pixdata[pi++]; (*imgdata).data[di++] = pixdata[pi++]; (*imgdata).data[di++] = alphadata[ai++]; } } else { (*imgdata).width = 0; (*imgdata).height = 0; (*imgdata).data = NULL; } }
bool wxDIB::Create(const wxImage& image) { wxCHECK_MSG( image.Ok(), false, wxT("invalid wxImage in wxDIB ctor") ); const int h = image.GetHeight(); const int w = image.GetWidth(); // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise // a 24bpp RGB is sufficient m_hasAlpha = image.HasAlpha(); const int bpp = m_hasAlpha ? 32 : 24; if ( !Create(w, h, bpp) ) return false; // DIBs are stored in bottom to top order (see also the comment above in // Create()) so we need to copy bits line by line and starting from the end const int srcBytesPerLine = w * 3; const int dstBytesPerLine = GetLineSize(w, bpp); const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine); const unsigned char *alpha = m_hasAlpha ? image.GetAlpha() + (h - 1)*w : NULL; unsigned char *dstLineStart = (unsigned char *)m_data; for ( int y = 0; y < h; y++ ) { // copy one DIB line unsigned char *dst = dstLineStart; if ( alpha ) { for ( int x = 0; x < w; x++ ) { // RGB order is reversed, and we need to premultiply // all channels by alpha value for use with ::AlphaBlend. const unsigned char a = *alpha++; *dst++ = (unsigned char)((src[2] * a + 127) / 255); *dst++ = (unsigned char)((src[1] * a + 127) / 255); *dst++ = (unsigned char)((src[0] * a + 127) / 255); *dst++ = a; src += 3; } } else // no alpha channel { for ( int x = 0; x < w; x++ ) { // RGB order is reversed. *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; src += 3; } } // pass to the previous line in the image src -= 2*srcBytesPerLine; if ( alpha ) alpha -= 2*w; // and to the next one in the DIB dstLineStart += dstBytesPerLine; } return true; }
bool wxDIB::Create(const wxImage& image, PixelFormat pf) { wxCHECK_MSG( image.IsOk(), false, wxT("invalid wxImage in wxDIB ctor") ); const int h = image.GetHeight(); const int w = image.GetWidth(); // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise // a 24bpp RGB is sufficient const bool hasAlpha = image.HasAlpha(); const int bpp = hasAlpha ? 32 : 24; if ( !Create(w, h, bpp) ) return false; // DIBs are stored in bottom to top order (see also the comment above in // Create()) so we need to copy bits line by line and starting from the end const int srcBytesPerLine = w * 3; const int dstBytesPerLine = GetLineSize(w, bpp); const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine); const unsigned char *alpha = hasAlpha ? image.GetAlpha() + (h - 1)*w : NULL; unsigned char *dstLineStart = (unsigned char *)m_data; for ( int y = 0; y < h; y++ ) { // Copy one DIB line. Note that RGB components order is reversed in // Windows bitmaps compared to wxImage and is actually BGR. unsigned char *dst = dstLineStart; if ( alpha ) { int x; switch ( pf ) { case PixelFormat_PreMultiplied: // Pre-multiply pixel values so that the DIB could be used // with ::AlphaBlend(). for ( x = 0; x < w; x++ ) { const unsigned char a = *alpha++; *dst++ = (unsigned char)((src[2] * a + 127) / 255); *dst++ = (unsigned char)((src[1] * a + 127) / 255); *dst++ = (unsigned char)((src[0] * a + 127) / 255); *dst++ = a; src += 3; } break; case PixelFormat_NotPreMultiplied: // Just copy pixel data without changing it. for ( x = 0; x < w; x++ ) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; *dst++ = *alpha++; src += 3; } break; } } else // no alpha channel { for ( int x = 0; x < w; x++ ) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; src += 3; } } // pass to the previous line in the image src -= 2*srcBytesPerLine; if ( alpha ) alpha -= 2*w; // and to the next one in the DIB dstLineStart += dstBytesPerLine; } return true; }