diff --git a/src/common/imagpng.cpp b/src/common/imagpng.cpp index 41d032ee32..b33539bb3a 100644 --- a/src/common/imagpng.cpp +++ b/src/common/imagpng.cpp @@ -38,40 +38,13 @@ // For memcpy #include -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// image cannot have any transparent pixels at all, have only 100% opaque -// and/or 100% transparent pixels in which case a simple mask is enough to -// store this information in wxImage or have a real alpha channel in which case -// we need to have it in wxImage as well -enum Transparency -{ - Transparency_None, - Transparency_Mask, - Transparency_Alpha -}; - // ---------------------------------------------------------------------------- // local functions // ---------------------------------------------------------------------------- -// return the kind of transparency needed for this image assuming that it does -// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask -static Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes); - // init the alpha channel for the image and fill it with 1s up to (x, y) static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y); -// find a free colour for the mask in the PNG data array -static void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask); - // is the pixel with this value of alpha a fully opaque one? static inline bool IsOpaque(unsigned char a) @@ -179,52 +152,6 @@ PNGLINKAGEMODE wx_PNG_error(png_structp png_ptr, png_const_charp message) // LoadFile() helpers // ---------------------------------------------------------------------------- -// determine the kind of transparency we need for this image: if the only alpha -// values it has are 0 (transparent) and 0xff (opaque) then we can simply -// create a mask for it, we should be ok with a simple mask but otherwise we -// need a full blown alpha channel in wxImage -// -// parameters: -// lines raw PNG data -// x, y starting position -// w, h size of the image -// numColBytes number of colour bytes (1 for grey scale, 3 for RGB) -// (NB: alpha always follows the colour bytes) -Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes) -{ - // suppose that a mask will suffice and check all the remaining alpha - // values to see if it does - for ( ; y < h; y++ ) - { - // each pixel is numColBytes+1 bytes, offset into the current line by - // the current x position - unsigned const char *ptr = lines[y] + (x * (numColBytes + 1)); - - for ( png_uint_32 x2 = x; x2 < w; x2++ ) - { - // skip the grey or colour byte(s) - ptr += numColBytes; - - unsigned char a2 = *ptr++; - - if ( !IsTransparent(a2) && !IsOpaque(a2) ) - { - // not fully opaque nor fully transparent, hence need alpha - return Transparency_Alpha; - } - } - - // during the next loop iteration check all the pixels in the row - x = 0; - } - - // mask will be enough - return Transparency_Mask; -} - unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) { // create alpha channel @@ -243,49 +170,6 @@ unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) return alpha; } -void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask) -{ - // choosing the colour for the mask is more - // difficult: we need to iterate over the entire - // image for this in order to choose an unused - // colour (this is not very efficient but what else - // can we do?) - wxImageHistogram h; - unsigned nentries = 0; - unsigned char r2, g2, b2; - for ( png_uint_32 y2 = 0; y2 < height; y2++ ) - { - const unsigned char *p = lines[y2]; - for ( png_uint_32 x2 = 0; x2 < width; x2++ ) - { - r2 = *p++; - g2 = *p++; - b2 = *p++; - ++p; // jump over alpha - - wxImageHistogramEntry& - entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)]; - - if ( entry.value++ == 0 ) - entry.index = nentries++; - } - } - - if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) ) - { - wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred.")); - - // use a fixed mask colour and we'll fudge - // the real pixels with this colour (see - // below) - rMask = 0xfe; - gMask = 0; - bMask = 0xff; - } -} - // ---------------------------------------------------------------------------- // reading PNGs // ---------------------------------------------------------------------------- @@ -308,17 +192,9 @@ void CopyDataFromPNG(wxImage *image, png_uint_32 height, int color_type) { - Transparency transparency = Transparency_None; - - // only non NULL if transparency == Transparency_Alpha + // allocated on demand if we have any non-opaque pixels unsigned char *alpha = NULL; - // RGB of the mask colour if transparency == Transparency_Mask - // (but init them anyhow to avoid compiler warnings) - unsigned char rMask = 0, - gMask = 0, - bMask = 0; - unsigned char *ptrDst = image->GetData(); if ( !(color_type & PNG_COLOR_MASK_COLOR) ) { @@ -332,66 +208,16 @@ void CopyDataFromPNG(wxImage *image, unsigned char a = *ptrSrc++; // the first time we encounter a transparent pixel we must - // decide about what to do about them - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - // we'll need at least the mask for this image and - // maybe even full alpha channel info: the former is - // only enough if we have alpha values of 0 and 0xff - // only, otherwisewe need the latter - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 1 - ); + // allocate alpha channel for the image + if ( !IsOpaque(a) && !alpha ) + alpha = InitAlpha(image, x, y); - if ( transparency == Transparency_Mask ) - { - // let's choose this colour for the mask: this is - // not a problem here as all the other pixels are - // grey, i.e. R == G == B which is not the case for - // this one so no confusion is possible - rMask = 0xff; - gMask = 0; - bMask = 0xff; - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } - } + if ( alpha ) + *alpha++ = a; - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - // else: !transparent - - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), wxT("logic error") ); - - wxFALLTHROUGH; - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - wxFALLTHROUGH; - - case Transparency_None: - *ptrDst++ = g; - *ptrDst++ = g; - *ptrDst++ = g; - break; - } + *ptrDst++ = g; + *ptrDst++ = g; + *ptrDst++ = g; } } } @@ -407,78 +233,19 @@ void CopyDataFromPNG(wxImage *image, unsigned char b = *ptrSrc++; unsigned char a = *ptrSrc++; - // the logic here is the same as for the grey case except - // where noted - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 3 - ); + // the logic here is the same as for the grey case + if ( !IsOpaque(a) && !alpha ) + alpha = InitAlpha(image, x, y); - if ( transparency == Transparency_Mask ) - { - FindMaskColour(lines, width, height, - rMask, gMask, bMask); - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } + if ( alpha ) + *alpha++ = a; - } - - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - else // !transparent - { - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), wxT("logic error") ); - - // if we couldn't find a unique colour for the - // mask, we can have real pixels with the same - // value as the mask and it's better to slightly - // change their colour than to make them - // transparent - if ( r == rMask && g == gMask && b == bMask ) - { - r++; - } - } - - wxFALLTHROUGH; - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - wxFALLTHROUGH; - - case Transparency_None: - *ptrDst++ = r; - *ptrDst++ = g; - *ptrDst++ = b; - break; - } + *ptrDst++ = r; + *ptrDst++ = g; + *ptrDst++ = b; } } } - - if ( transparency == Transparency_Mask ) - { - image->SetMaskColour(rMask, gMask, bMask); - } } // temporarily disable the warning C4611 (interaction between '_setjmp' and