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);
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)
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);
{
if (isColouredImage)
{
- // color image
- memcpy(buf, ptr, image->GetWidth() * 3);
+ // 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)
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
: 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));
}
}
return false;
}
- ptr += image->GetWidth()*3;
+ ptr += imageWidth * 3;
}
(void) TIFFClose(tif);
const bool testAlpha = (properties & wxIMAGE_HAVE_ALPHA) != 0;
if (testAlpha
- && !(type == wxBITMAP_TYPE_PNG || type == wxBITMAP_TYPE_TGA) )
+ && !(type == wxBITMAP_TYPE_PNG || type == wxBITMAP_TYPE_TGA
+ || type == wxBITMAP_TYPE_TIFF) )
{
// don't test images with alpha if this handler doesn't support alpha
return;
);
}
+static void SetAlpha(wxImage *image)
+{
+ image->SetAlpha();
+
+ unsigned char *ptr = image->GetAlpha();
+ const int width = image->GetWidth();
+ const int height = image->GetHeight();
+ for (int y = 0; y < height; ++y)
+ {
+ for (int x = 0; x < width; ++x)
+ {
+ ptr[y*width + x] = (x*y) & wxIMAGE_ALPHA_OPAQUE;
+ }
+ }
+}
+
void ImageTestCase::CompareSavedImage()
{
// FIXME-VC6: Pre-declare the loop variables for compatibility with
// pre-standard compilers such as MSVC6 that don't implement proper scope
// for the variables declared in the for loops.
- int i, x, y;
+ int i;
wxImage expected24("horse.png");
CPPUNIT_ASSERT( expected24.IsOk() );
// Create an image with alpha based on the loaded image
wxImage expected32(expected24);
- expected32.SetAlpha();
- int width = expected32.GetWidth();
- int height = expected32.GetHeight();
- for (y = 0; y < height; ++y)
- {
- for (x = 0; x < width; ++x)
- {
- expected32.SetAlpha(x, y, (x*y) & wxIMAGE_ALPHA_OPAQUE);
- }
- }
+ SetAlpha(&expected32);
const wxList& list = wxImage::GetHandlers();
for ( wxList::compatibility_iterator node = list.GetFirst();
}
-static void TestTIFFImage(const wxString& option, int value)
+static void TestTIFFImage(const wxString& option, int value,
+ const wxImage *compareImage = NULL)
{
- wxImage image("horse.png");
+ wxImage image;
+ if (compareImage)
+ {
+ image = *compareImage;
+ }
+ else
+ {
+ (void) image.LoadFile("horse.png");
+ }
+ CPPUNIT_ASSERT( image.IsOk() );
wxMemoryOutputStream memOut;
image.SetOption(option, value);
WX_ASSERT_EQUAL_MESSAGE(("While testing for %s", option),
value, savedImage.GetOptionInt(option));
+
+ WX_ASSERT_EQUAL_MESSAGE(("HasAlpha() not equal"), image.HasAlpha(), savedImage.HasAlpha());
}
void ImageTestCase::SaveTIFF()
TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 1);
TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 0/*PHOTOMETRIC_MINISWHITE*/);
TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 1/*PHOTOMETRIC_MINISBLACK*/);
+
+ wxImage alphaImage("horse.png");
+ CPPUNIT_ASSERT( alphaImage.IsOk() );
+ SetAlpha(&alphaImage);
+
+ // RGB with alpha
+ TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 4, &alphaImage);
+
+ // Grey with alpha
+ TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 2, &alphaImage);
+
+ // B/W with alpha
+ alphaImage.SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1);
+ TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 2, &alphaImage);
}
void ImageTestCase::SaveAnimatedGIF()