X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f60e313437547e11326e34f93c549356e7291f9f..ad653fa23069c5d9378247084f03c9a718c3ad62:/src/common/imagtiff.cpp diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index 1083157434..1c3e22632d 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -48,11 +48,7 @@ extern "C" #include "wx/wfstream.h" #ifndef TIFFLINKAGEMODE - #if defined(__WATCOMC__) && defined(__WXMGL__) - #define TIFFLINKAGEMODE cdecl - #else - #define TIFFLINKAGEMODE LINKAGEMODE - #endif + #define TIFFLINKAGEMODE LINKAGEMODE #endif // ============================================================================ @@ -330,19 +326,24 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); - uint16 photometric; - uint16 samplesPerPixel; + uint16 samplesPerPixel = 0; + (void) TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); + + uint16 bitsPerSample = 0; + (void) TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); + uint16 extraSamples; uint16* samplesInfo; - TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extraSamples, &samplesInfo); + + uint16 photometric; if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { photometric = PHOTOMETRIC_MINISWHITE; } const bool hasAlpha = (extraSamples >= 1 - && ((samplesInfo[0] == EXTRASAMPLE_UNSPECIFIED && samplesPerPixel > 3) + && ((samplesInfo[0] == EXTRASAMPLE_UNSPECIFIED) || samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)) || (extraSamples == 0 && samplesPerPixel == 4 @@ -399,13 +400,22 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos bool ok = true; char msg[1024] = ""; - if ( !TIFFRGBAImageOK(tif, msg) - && planarConfig == PLANARCONFIG_CONTIG - && samplesPerPixel == 2 && extraSamples == 1) - { + if + ( + (planarConfig == PLANARCONFIG_CONTIG && samplesPerPixel == 2 + && extraSamples == 1) + && + ( + ( !TIFFRGBAImageOK(tif, msg) ) + || (bitsPerSample == 8) + ) + ) + { + const bool isGreyScale = (bitsPerSample == 8); unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); uint32 pos = 0; - const int minValue = (photometric == PHOTOMETRIC_MINISWHITE) ? 255 : 0; + const bool minIsWhite = (photometric == PHOTOMETRIC_MINISWHITE); + const int minValue = minIsWhite ? 255 : 0; const int maxValue = 255 - minValue; /* @@ -421,14 +431,28 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos break; } - for (uint32 x = 0; x < w; ++x) + if (isGreyScale) { - int mask = buf[x*2/8] << ((x*2)%8); + for (uint32 x = 0; x < w; ++x) + { + uint8 val = minIsWhite ? 255 - buf[x*2] : buf[x*2]; + uint8 alpha = minIsWhite ? 255 - buf[x*2+1] : buf[x*2+1]; + raster[pos] = val + (val << 8) + (val << 16) + + (alpha << 24); + pos++; + } + } + else + { + for (uint32 x = 0; x < w; ++x) + { + int mask = buf[x*2/8] << ((x*2)%8); - uint8 val = mask & 128 ? maxValue : minValue; - raster[pos] = val + (val << 8) + (val << 16) - + ((mask & 64 ? maxValue : minValue) << 24); - pos++; + uint8 val = mask & 128 ? maxValue : minValue; + raster[pos] = val + (val << 8) + (val << 16) + + ((mask & 64 ? maxValue : minValue) << 24); + pos++; + } } } @@ -478,19 +502,19 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos image->SetOption(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, photometric); - uint16 spp, bps, compression; + uint16 compression; /* - Read some baseline TIFF tags which helps when re-saving a TIFF + Copy some baseline TIFF tags which helps when re-saving a TIFF to be similar to the original image. */ - if ( TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp) ) + if (samplesPerPixel) { - image->SetOption(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, spp); + image->SetOption(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, samplesPerPixel); } - if ( TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps) ) + if (bitsPerSample) { - image->SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, bps); + image->SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, bitsPerSample); } if ( TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression) ) @@ -528,7 +552,7 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos /* Set the image resolution if it's available. Resolution tag is not - dependant on RESOLUTIONUNIT != RESUNIT_NONE (according to TIFF spec). + dependent on RESOLUTIONUNIT != RESUNIT_NONE (according to TIFF spec). */ float resX, resY; @@ -591,7 +615,8 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo return false; } - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); + const int imageWidth = image->GetWidth(); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) imageWidth); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); @@ -655,37 +680,62 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo spp = 1; } } - else if (spp == 1) + else if (spp <= 2) { photometric = PHOTOMETRIC_MINISWHITE; } - const bool isColouredImage = (spp > 1) - && (photometric != PHOTOMETRIC_MINISWHITE) - && (photometric != PHOTOMETRIC_MINISBLACK); + const bool hasAlpha = image->HasAlpha(); int compression = image->GetOptionInt(wxIMAGE_OPTION_TIFF_COMPRESSION); - if ( !compression ) + if ( !compression || (compression == COMPRESSION_JPEG && hasAlpha) ) { - // we can't use COMPRESSION_LZW because current version of libtiff + // We can't use COMPRESSION_LZW because current version of libtiff // doesn't implement it ("no longer implemented due to Unisys patent // enforcement") and other compression methods are lossy so we - // shouldn't use them by default -- and the only remaining one is none + // shouldn't use them by default -- and the only remaining one is none. + // Also JPEG compression for alpha images is not a good idea (viewers + // not opening the image properly). compression = COMPRESSION_NONE; } - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); + if + ( + (photometric == PHOTOMETRIC_RGB && spp == 4) + || (photometric <= PHOTOMETRIC_MINISBLACK && spp == 2) + ) + { + // Compensate for user passing a SamplesPerPixel that includes + // the alpha channel. + spp--; + } + + + int extraSamples = hasAlpha ? 1 : 0; + + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp + extraSamples); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); - // scanlinesize is determined by spp and bps + if (extraSamples) + { + uint16 extra[] = { EXTRASAMPLE_UNSPECIFIED }; + TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, (long) 1, &extra); + } + + // scanlinesize is determined by spp+extraSamples and bps const tsize_t linebytes = - (tsize_t)((image->GetWidth() * spp * bps + 7) / 8); + (tsize_t)((imageWidth * (spp + extraSamples) * bps + 7) / 8); unsigned char *buf; - if (TIFFScanlineSize(tif) > linebytes || !isColouredImage) + const bool isColouredImage = (spp > 1) + && (photometric != PHOTOMETRIC_MINISWHITE) + && (photometric != PHOTOMETRIC_MINISBLACK); + + + if (TIFFScanlineSize(tif) > linebytes || !isColouredImage || hasAlpha) { buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) @@ -707,15 +757,16 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); - const int bitsPerPixel = spp * bps; + const int bitsPerPixel = (spp + extraSamples) * bps; + const int bytesPerPixel = (bitsPerPixel + 7) / 8; const int pixelsPerByte = 8 / bitsPerPixel; int remainingPixelCount = 0; if (pixelsPerByte) { // How many pixels to write in the last byte column? - remainingPixelCount = image->GetWidth() % pixelsPerByte; - if (!remainingPixelCount) remainingPixelCount = 8; + remainingPixelCount = imageWidth % pixelsPerByte; + if (!remainingPixelCount) remainingPixelCount = pixelsPerByte; } const bool minIsWhite = (photometric == PHOTOMETRIC_MINISWHITE); @@ -726,12 +777,25 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo { if (isColouredImage) { - // color image - memcpy(buf, ptr, image->GetWidth()); + // colour image + if (hasAlpha) + { + for ( int column = 0; column < imageWidth; column++ ) + { + buf[column*4 ] = ptr[column*3 ]; + buf[column*4 + 1] = ptr[column*3 + 1]; + buf[column*4 + 2] = ptr[column*3 + 2]; + buf[column*4 + 3] = image->GetAlpha(column, row); + } + } + else + { + memcpy(buf, ptr, imageWidth * 3); + } } else if (spp * bps == 8) // greyscale image { - for ( int column = 0; column < linebytes; column++ ) + for ( int column = 0; column < imageWidth; column++ ) { uint8 value = ptr[column*3 + 1]; if (minIsWhite) @@ -739,7 +803,14 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo value = 255 - value; } - buf[column] = value; + buf[column * bytesPerPixel] = value; + + if (hasAlpha) + { + value = image->GetAlpha(column, row); + buf[column*bytesPerPixel+1] + = minIsWhite ? 255 - value : value; + } } } else // black and white image @@ -752,10 +823,18 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo : remainingPixelCount; for ( int bp = 0; bp < pixelsPerByteCount; bp++ ) { - if ( (ptr[column*24 + bp*3 + 1] <=127) == minIsWhite ) + if ( (ptr[column * 3 * pixelsPerByte + bp*3 + 1] <=127) + == minIsWhite ) { // check only green as this is sufficient - reverse = (uint8)(reverse | 128 >> bp); + reverse |= (uint8) (128 >> (bp * bitsPerPixel)); + } + + if (hasAlpha + && (image->GetAlpha(column * pixelsPerByte + bp, + row) <= 127) == minIsWhite) + { + reverse |= (uint8) (64 >> (bp * bitsPerPixel)); } } @@ -778,7 +857,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo return false; } - ptr += image->GetWidth()*3; + ptr += imageWidth * 3; } (void) TIFFClose(tif);