int wxTIFFHandler::GetImageCount( wxInputStream& stream ) { TIFF *tif = TIFFwxOpen( stream, "image", "r" ); if (!tif) return 0; int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? do { dircount++; } while (TIFFReadDirectory(tif)); TIFFClose( tif ); return dircount; }
int wxTIFFHandler::DoGetImageCount( wxInputStream& stream ) { TIFF *tif = TIFFwxOpen( stream, "image", "r" ); if (!tif) return 0; int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? do { dircount++; } while (TIFFReadDirectory(tif)); TIFFClose( tif ); // NOTE: this function modifies the current stream position but it's ok // (see wxImageHandler::GetImageCount) return dircount; }
bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) { TIFF *tif = TIFFwxOpen( stream, "image", "w" ); if (!tif) { if (verbose) wxLogError( _("TIFF: Error saving image.") ); return false; } TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) { TIFFSetField(tif, TIFFTAG_XRESOLUTION, image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); TIFFSetField(tif, TIFFTAG_YRESOLUTION, image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); } int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); if ( !spp ) spp = 3; int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); if ( !bpp ) bpp=8; int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); if ( !compression ) compression=COMPRESSION_LZW; TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); // scanlinesize if determined by spp and bpp tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) linebytes+=1; unsigned char *buf; if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) { buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) { if (verbose) wxLogError( _("TIFF: Couldn't allocate memory.") ); TIFFClose( tif ); return false; } } else { buf = NULL; } TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); uint8 bitmask; unsigned char *ptr = image->GetData(); for ( int row = 0; row < image->GetHeight(); row++ ) { if ( buf ) { if ( spp * bpp > 1 ) { // color image memcpy(buf, ptr, image->GetWidth()); } else // black and white image { for ( int column = 0; column < linebytes; column++ ) { uint8 reverse = 0; bitmask = 1; for ( int bp = 0; bp < 8; bp++ ) { if ( ptr[column*24 + bp*3] > 0 ) { // check only red as this is sufficient reverse = reverse | 128 >> bp; } bitmask <<= 1; } buf[column] = reverse; } } } if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) { if (verbose) wxLogError( _("TIFF: Error writing image.") ); TIFFClose( tif ); if (buf) _TIFFfree(buf); return false; } ptr += image->GetWidth()*3; }
bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) { if (index == -1) index = 0; image->Destroy(); TIFF *tif = TIFFwxOpen( stream, "image", "r" ); if (!tif) { if (verbose) wxLogError( _("TIFF: Error loading image.") ); return false; } if (!TIFFSetDirectory( tif, (tdir_t)index )) { if (verbose) wxLogError( _("Invalid TIFF image index.") ); TIFFClose( tif ); return false; } uint32 w, h; uint32 npixels; uint32 *raster; TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); npixels = w * h; raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) ); if (!raster) { if (verbose) wxLogError( _("TIFF: Couldn't allocate memory.") ); TIFFClose( tif ); return false; } image->Create( (int)w, (int)h ); if (!image->Ok()) { if (verbose) wxLogError( _("TIFF: Couldn't allocate memory.") ); _TIFFfree( raster ); TIFFClose( tif ); return false; } if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) { if (verbose) wxLogError( _("TIFF: Error reading image.") ); _TIFFfree( raster ); image->Destroy(); TIFFClose( tif ); return false; } bool hasmask = false; unsigned char *ptr = image->GetData(); ptr += w*3*(h-1); uint32 pos = 0; for (uint32 i = 0; i < h; i++) { for (uint32 j = 0; j < w; j++) { unsigned char alpha = (unsigned char)TIFFGetA(raster[pos]); if (alpha < 127) { hasmask = true; ptr[0] = image->GetMaskRed(); ptr++; ptr[0] = image->GetMaskGreen(); ptr++; ptr[0] = image->GetMaskBlue(); ptr++; } else { ptr[0] = (unsigned char)TIFFGetR(raster[pos]); ptr++; ptr[0] = (unsigned char)TIFFGetG(raster[pos]); ptr++; ptr[0] = (unsigned char)TIFFGetB(raster[pos]); ptr++; } pos++; } ptr -= 2*w*3; // subtract line we just added plus one line } _TIFFfree( raster ); TIFFClose( tif ); image->SetMask( hasmask ); return true; }
bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) { if (index == -1) index = 0; image->Destroy(); TIFF *tif = TIFFwxOpen( stream, "image", "r" ); if (!tif) { if (verbose) wxLogError( _("TIFF: Error loading image.") ); return false; } if (!TIFFSetDirectory( tif, (tdir_t)index )) { if (verbose) wxLogError( _("Invalid TIFF image index.") ); TIFFClose( tif ); return false; } uint32 w, h; uint32 *raster; TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); uint16 extraSamples; uint16* samplesInfo; TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extraSamples, &samplesInfo); const bool hasAlpha = (extraSamples == 1 && (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); // guard against integer overflow during multiplication which could result // in allocating a too small buffer and then overflowing it const double bytesNeeded = (double)w * (double)h * sizeof(uint32); if ( bytesNeeded >= 4294967295U /* UINT32_MAX */ ) { if ( verbose ) wxLogError( _("TIFF: Image size is abnormally big.") ); TIFFClose(tif); return false; } raster = (uint32*) _TIFFmalloc( bytesNeeded ); if (!raster) { if (verbose) wxLogError( _("TIFF: Couldn't allocate memory.") ); TIFFClose( tif ); return false; } image->Create( (int)w, (int)h ); if (!image->Ok()) { if (verbose) wxLogError( _("TIFF: Couldn't allocate memory.") ); _TIFFfree( raster ); TIFFClose( tif ); return false; } if ( hasAlpha ) image->SetAlpha(); if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) { if (verbose) wxLogError( _("TIFF: Error reading image.") ); _TIFFfree( raster ); image->Destroy(); TIFFClose( tif ); return false; } unsigned char *ptr = image->GetData(); ptr += w*3*(h-1); unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; if ( hasAlpha ) alpha += w*(h-1); uint32 pos = 0; for (uint32 i = 0; i < h; i++) { for (uint32 j = 0; j < w; j++) { *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); if ( hasAlpha ) *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); pos++; } // subtract line we just added plus one line: ptr -= 2*w*3; if ( hasAlpha ) alpha -= 2*w; } _TIFFfree( raster ); TIFFClose( tif ); return true; }
bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) { TIFF *tif = TIFFwxOpen( stream, "image", "w" ); if (!tif) { if (verbose) { wxLogError( _("TIFF: Error saving image.") ); } return false; } TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // save the image resolution if we have it int xres, yres; const wxImageResolution res = GetResolutionFromOptions(*image, &xres, &yres); uint16 tiffRes; switch ( res ) { default: wxFAIL_MSG( wxT("unknown image resolution units") ); // fall through case wxIMAGE_RESOLUTION_NONE: tiffRes = RESUNIT_NONE; break; case wxIMAGE_RESOLUTION_INCHES: tiffRes = RESUNIT_INCH; break; case wxIMAGE_RESOLUTION_CM: tiffRes = RESUNIT_CENTIMETER; break; } if ( tiffRes != RESUNIT_NONE ) { TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, tiffRes); TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres); TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres); } int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); if ( !spp ) spp = 3; int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); if ( !bpp ) bpp = 8; int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); if ( !compression ) { // 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 compression = COMPRESSION_NONE; } TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); // scanlinesize if determined by spp and bpp tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) linebytes+=1; unsigned char *buf; if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) { buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) { if (verbose) { wxLogError( _("TIFF: Couldn't allocate memory.") ); } TIFFClose( tif ); return false; } } else { buf = NULL; } TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); unsigned char *ptr = image->GetData(); for ( int row = 0; row < image->GetHeight(); row++ ) { if ( buf ) { if ( spp * bpp > 1 ) { // color image memcpy(buf, ptr, image->GetWidth()); } else // black and white image { for ( int column = 0; column < linebytes; column++ ) { uint8 reverse = 0; for ( int bp = 0; bp < 8; bp++ ) { if ( ptr[column*24 + bp*3] > 0 ) { // check only red as this is sufficient reverse = (uint8)(reverse | 128 >> bp); } } buf[column] = reverse; } } } if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) { if (verbose) { wxLogError( _("TIFF: Error writing image.") ); } TIFFClose( tif ); if (buf) _TIFFfree(buf); return false; } ptr += image->GetWidth()*3; }
bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) { if (index == -1) index = 0; image->Destroy(); TIFF *tif = TIFFwxOpen( stream, "image", "r" ); if (!tif) { if (verbose) { wxLogError( _("TIFF: Error loading image.") ); } return false; } if (!TIFFSetDirectory( tif, (tdir_t)index )) { if (verbose) { wxLogError( _("Invalid TIFF image index.") ); } TIFFClose( tif ); return false; } uint32 w, h; uint32 *raster; TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); uint16 extraSamples; uint16* samplesInfo; TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extraSamples, &samplesInfo); const bool hasAlpha = (extraSamples == 1 && (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); // guard against integer overflow during multiplication which could result // in allocating a too small buffer and then overflowing it const double bytesNeeded = (double)w * (double)h * sizeof(uint32); if ( bytesNeeded >= wxUINT32_MAX ) { if ( verbose ) { wxLogError( _("TIFF: Image size is abnormally big.") ); } TIFFClose(tif); return false; } raster = (uint32*) _TIFFmalloc( (uint32)bytesNeeded ); if (!raster) { if (verbose) { wxLogError( _("TIFF: Couldn't allocate memory.") ); } TIFFClose( tif ); return false; } image->Create( (int)w, (int)h ); if (!image->Ok()) { if (verbose) { wxLogError( _("TIFF: Couldn't allocate memory.") ); } _TIFFfree( raster ); TIFFClose( tif ); return false; } if ( hasAlpha ) image->SetAlpha(); if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) { if (verbose) { wxLogError( _("TIFF: Error reading image.") ); } _TIFFfree( raster ); image->Destroy(); TIFFClose( tif ); return false; } unsigned char *ptr = image->GetData(); ptr += w*3*(h-1); unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; if ( hasAlpha ) alpha += w*(h-1); uint32 pos = 0; for (uint32 i = 0; i < h; i++) { for (uint32 j = 0; j < w; j++) { *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); if ( hasAlpha ) *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); pos++; } // subtract line we just added plus one line: ptr -= 2*w*3; if ( hasAlpha ) alpha -= 2*w; } // set the image resolution if it's available uint16 tiffRes; if ( TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &tiffRes) ) { wxImageResolution res; switch ( tiffRes ) { default: wxLogWarning(_("Unknown TIFF resolution unit %d ignored"), tiffRes); // fall through case RESUNIT_NONE: res = wxIMAGE_RESOLUTION_NONE; break; case RESUNIT_INCH: res = wxIMAGE_RESOLUTION_INCHES; break; case RESUNIT_CENTIMETER: res = wxIMAGE_RESOLUTION_CM; break; } if ( res != wxIMAGE_RESOLUTION_NONE ) { float xres, yres; if ( TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) ) image->SetOption(wxIMAGE_OPTION_RESOLUTIONX, wxRound(xres)); if ( TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) ) image->SetOption(wxIMAGE_OPTION_RESOLUTIONY, wxRound(yres)); } } _TIFFfree( raster ); TIFFClose( tif ); return true; }