static int check_rgba_pixel( int pixel, int min_red, int max_red, int min_green, int max_green, int min_blue, int max_blue, int min_alpha, int max_alpha, uint32 *buffer ) { /* RGBA images are upside down - adjust for normal ordering */ int adjusted_pixel = pixel % 128 + (127 - (pixel/128)) * 128; uint32 rgba = buffer[adjusted_pixel]; if( TIFFGetR(rgba) >= (uint32) min_red && TIFFGetR(rgba) <= (uint32) max_red && TIFFGetG(rgba) >= (uint32) min_green && TIFFGetG(rgba) <= (uint32) max_green && TIFFGetB(rgba) >= (uint32) min_blue && TIFFGetB(rgba) <= (uint32) max_blue && TIFFGetA(rgba) >= (uint32) min_alpha && TIFFGetA(rgba) <= (uint32) max_alpha ) { return 0; } fprintf( stderr, "Pixel %d did not match expected results.\n", pixel ); fprintf( stderr, "Got R=%d (expected %d..%d), G=%d (expected %d..%d), B=%d (expected %d..%d), A=%d (expected %d..%d)\n", TIFFGetR(rgba), min_red, max_red, TIFFGetG(rgba), min_green, max_green, TIFFGetB(rgba), min_blue, max_blue, TIFFGetA(rgba), min_alpha, max_alpha ); return 1; }
static void cvtClump(unsigned char* op, uint32* raster, uint32 ch, uint32 cw, uint32 w) { float Y, Cb = 0, Cr = 0; uint32 j, k; /* * Convert ch-by-cw block of RGB * to YCbCr and sample accordingly. */ for (k = 0; k < ch; k++) { for (j = 0; j < cw; j++) { uint32 RGB = (raster - k*w)[j]; Y = lumaRed[TIFFGetR(RGB)] + lumaGreen[TIFFGetG(RGB)] + lumaBlue[TIFFGetB(RGB)]; /* accumulate chrominance */ Cb += (TIFFGetB(RGB) - Y) * D1; Cr += (TIFFGetR(RGB) - Y) * D2; /* emit luminence */ *op++ = V2Code(Y, refBlackWhite[0], refBlackWhite[1], 255); } for (; j < horizSubSampling; j++) *op++ = Yzero; } for (; k < vertSubSampling; k++) { for (j = 0; j < horizSubSampling; j++) *op++ = Yzero; } /* emit sampled chrominance values */ *op++ = V2Code(Cb / (ch*cw), refBlackWhite[2], refBlackWhite[3], 127); *op++ = V2Code(Cr / (ch*cw), refBlackWhite[4], refBlackWhite[5], 127); }
static int check_rgba_pixel( int pixel, int red, int green, int blue, int alpha, uint32 *buffer ) { /* RGBA images are upside down - adjust for normal ordering */ int adjusted_pixel = pixel % 128 + (127 - (pixel/128)) * 128; uint32 rgba = buffer[adjusted_pixel]; if( TIFFGetR(rgba) == (uint32) red && TIFFGetG(rgba) == (uint32) green && TIFFGetB(rgba) == (uint32) blue && TIFFGetA(rgba) == (uint32) alpha ) { return 0; } fprintf( stderr, "Pixel %d did not match expected results.\n", pixel ); fprintf( stderr, "Expect: %3d %3d %3d %3d\n", red, green, blue, alpha ); fprintf( stderr, " Got: %3d %3d %3d %3d\n", TIFFGetR(rgba), TIFFGetG(rgba), TIFFGetB(rgba), TIFFGetA(rgba) ); return 1; }
void TiffImage::transformToComplementary() { if (this->imgBuffer.size() > 0) //Look if there is something in the image Buffer { vector<int> rgba; int newDec = 0; vector<uint32>::iterator vit = imgBuffer.begin(); for (auto i : imgBuffer) //Loop over Im age Buffer { //Get RGB values if (i != 0) { rgba.push_back(TIFFGetR(i)); rgba.push_back(TIFFGetG(i)); rgba.push_back(TIFFGetB(i)); //request complementary color newDec = getComplementaryColour(rgba); *vit = bUIntValue + newDec; //use iterator to update data in buffer } vit++; //don't forget to increase the iterator so we look at the right position rgba.clear(); //deletes all entries in the vector rgba.shrink_to_fit(); //shrinks vector to fit actual size. } } }
timg_t *timg_readtiff(const char *fname) { TIFF *tif = TIFFOpen(fname, "r"); uint32_t width=0, height=0; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); uint32_t *raster = (uint32_t*)_TIFFmalloc(width*height*sizeof(uint32_t)); if(TIFFReadRGBAImage(tif, width, height, raster, 0) == 0) { fprintf(stderr, "An error occurred reading the TIFF file.\n"); exit(1); } timg_t *img = timg_create(height, width); int i; for(i=0; i<height*width; ++i) { img->pixels[i].r = (uint8_t)TIFFGetR(raster[i]); img->pixels[i].g = (uint8_t)TIFFGetG(raster[i]); img->pixels[i].b = (uint8_t)TIFFGetB(raster[i]); img->pixels[i].a = (uint8_t)TIFFGetA(raster[i]); } _TIFFfree(raster); TIFFClose(tif); return img; }
void TiffImage::readImage() { TIFF *tif = TIFFOpen(this->getimageFile().c_str(), "r"); if (tif) { size_t npixels; uint32* raster; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imgWidth); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imgHeight); TIFFGetField(tif, TIFFTAG_ORIENTATION, &imgOrientation); npixels = imgWidth * imgHeight; //no of pixels in image raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); if (raster != NULL) { if (TIFFReadRGBAImage(tif, imgWidth, imgHeight, raster, 0)) { //...process raster data... //write data in vector member so we can do with it what we want uint32 *rasterPrint = raster; for(size_t n=0;n<npixels;n++) { imgBuffer.push_back(raster[n]); cout << "New Pixel R: "; cout << TIFFGetR(*rasterPrint) << " G: "; cout << TIFFGetG(*rasterPrint) << " B: "; cout << TIFFGetB(*rasterPrint) << " A: "; cout << TIFFGetA(*rasterPrint) << " uint32: "; cout << *rasterPrint << endl; *rasterPrint++; } } _TIFFfree(raster); //TIFFRedRGBAImage is starting in the lower left corner, so we //got to swap our vector. this means we hve to swap first row with last //and so on. uint32 upBufPos, downBufPos; for (uint32 i = 0 ; i < this->imgHeight / 2; i++) { for (uint32 j = 0 ; j < this->imgWidth; j++) { upBufPos = i * this->imgWidth + j; if (i*j == 0) { upBufPos = i+j; } downBufPos = ((this->imgHeight - i - 1) * this->imgWidth) + j; swap(this->imgBuffer[upBufPos], this->imgBuffer[downBufPos]); } } } TIFFClose(tif); } }
static void unpack_tiff_raster(Pic *pic, uint32 *raster) { int x,y; uint32 pixel; uint32 pic_index = 0; for(y=(pic->ny-1); y>=0; y--) for(x=0; x<pic->nx; x++) { pixel = raster[y*pic->nx + x]; pic->pix[pic_index++] = TIFFGetR(pixel); pic->pix[pic_index++] = TIFFGetG(pixel); pic->pix[pic_index++] = TIFFGetB(pixel); } }
tdata_t tif_ReadRGBData(TIFF* tif) { int* buffer = (int*)tif_Malloc(tif); char* raster = (char*)tif_Malloc(tif); printf("sizeof(raster) = %ld\n", malloc_usable_size(raster)); printf("sizeof(buffer) = %ld\n", malloc_usable_size(buffer)); int rgba; tsize_t result; uint16 c = tif_nChannels(tif); uint32 w = tif_Width(tif); uint32 h = tif_Height(tif); uint16 ic; uint32 iw, ih; if (tif == NULL) return NULL; if (buffer != NULL) { printf("Reading raster rgba: w = %d, h = %d, c = %d, tif = %p, buffer = %p, raster = %p\n", w, h, c, tif, buffer, raster); result = TIFFReadRGBAImage(tif, w, h, (uint32*)buffer, 0); printf("Result = %ld\n", result); if (result == 0) { printf("Read error on input rgba image.\n"); } printf("Read ok: result = %ld\n", result); } if (raster != NULL) { for(ih = 0; ih < h; ih++){ for(iw = 0; iw < w; iw++){ rgba = buffer[(h-ih-1)*w+iw]; ic = 0; raster[macro_RasterPos2dRgb] = TIFFGetR(rgba); ic = 1; if (c >= 2) raster[macro_RasterPos2dRgb] = TIFFGetG(rgba); ic = 2; if (c >= 3) raster[macro_RasterPos2dRgb] = TIFFGetB(rgba); ic = 3; if (c >= 4) raster[macro_RasterPos2dRgb] = TIFFGetA(rgba); } } } return (tdata_t)raster; }
static void raster(TIFFRGBAImage_Extra * img, uint32 * rast, uint32 x, uint32 y, uint32 w, uint32 h) { int image_width, image_height; uint32 *pixel, pixel_value; int i, j, dy, rast_offset; DATA32 *buffer_pixel, *buffer = evas_cache_image_pixels(img->image); int alpha_premult = 0; image_width = img->image->w; image_height = img->image->h; dy = h > y ? -1 : y - h; /* rast seems to point to the beginning of the last strip processed */ /* so you need use negative offsets. Bizzare. Someone please check this */ /* I don't understand why, but that seems to be what's going on. */ /* libtiff needs better docs! */ if (img->rgba.alpha == EXTRASAMPLE_UNASSALPHA) alpha_premult = 1; for (i = y, rast_offset = 0; i > dy; i--, rast_offset--) { pixel = rast + (rast_offset * image_width); buffer_pixel = buffer + ((((image_height - 1) - i) * image_width) + x); for (j = 0; j < w; j++) { int a, r, g, b; pixel_value = (*(pixel++)); a = TIFFGetA(pixel_value); r = TIFFGetR(pixel_value); g = TIFFGetG(pixel_value); b = TIFFGetB(pixel_value); if (!alpha_premult && (a < 255)) { r = (r * (a + 1)) >> 8; g = (g * (a + 1)) >> 8; b = (b * (a + 1)) >> 8; } (*(buffer_pixel++)) = ARGB_JOIN(a, r, g, b); } }
GImage * GImageReadTiff (char *filename) { TIFF *tif; uint32_t w, h, i, j; uint32_t *ipt, *fpt; size_t npixels; uint32 *raster; GImage *ret = NULL; struct _GImage *base; tif = TIFFOpen (filename, "r"); if (tif == NULL) return (ret); TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &h); npixels = w * h; raster = (uint32_t *) xmalloc (szmax (1, npixels * sizeof (uint32_t))); if (raster != NULL) { if (TIFFReadRGBAImage (tif, w, h, raster, 0)) { ret = GImageCreate (it_true, w, h); if (ret != NULL) { base = ret->u.image; for (i = 0; i < h; ++i) { ipt = (uint32_t *) (base->data + i * base->bytes_per_line); fpt = raster + (h - 1 - i) * w; for (j = 0; j < w; ++j) *ipt++ = COLOR_CREATE (TIFFGetR (fpt[j]), TIFFGetG (fpt[j]), TIFFGetB (fpt[j])); } } } free (raster); } TIFFClose (tif); return (ret); }
static int TifReadImage(Tcl_Interp *interp, TIFF *tifPtr, Blt_Chain chain) { int w, h, nPixels; uint32 *srcBits, *sp; Picture *destPtr; Blt_Pixel *destRowPtr; int y; TIFFGetField(tifPtr, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tifPtr, TIFFTAG_IMAGELENGTH, &h); nPixels = w * h; srcBits = _TIFFmalloc(sizeof(uint32) * nPixels); if (srcBits == NULL) { Tcl_AppendResult(interp, "can't allocate ", Blt_Itoa(nPixels), " buffer for TIF image", (char *)NULL); return TCL_ERROR; } if (!TIFFReadRGBAImage(tifPtr, w, h, srcBits, /*stopOnError*/0)) { Tcl_AppendResult(interp, "can't read image in directory", (char *)NULL); _TIFFfree(srcBits); return TCL_ERROR; } destPtr = Blt_CreatePicture(w, h); destRowPtr = destPtr->bits + (destPtr->pixelsPerRow * (h - 1)); sp = srcBits; for (y = h - 1; y >= 0; y--) { Blt_Pixel *dp, *dend; for (dp = destRowPtr, dend = dp + w; dp < dend; dp++) { dp->Red = TIFFGetR(*sp); dp->Green = TIFFGetG(*sp); dp->Blue = TIFFGetB(*sp); dp->Alpha = TIFFGetA(*sp); sp++; } destRowPtr -= destPtr->pixelsPerRow; } Blt_Chain_Append(chain, destPtr); return TCL_OK; }
static void read_directory(TIFF *tif, Image *image, char *routine) // Used by all readers// { uint32 *raster; uint8 *row; int width, height; width = image->width; height = image->height; raster = get_raster(width*height,routine); row = image->array; if (image->kind != GREY16) { int i, j; uint32 *in; uint8 *out; if (TIFFReadRGBAImage(tif,width,height,raster,0) == 0) error("read of tif failed in read_directory()", NULL); in = raster; if (image->kind == GREY) { for (j = height-1; j >= 0; j--) { out = row; for (i = 0; i < width; i++) { uint32 pixel = *in++; *out++ = TIFFGetR(pixel); } row += width; } } else { for (j = height-1; j >= 0; j--) { out = row; for (i = 0; i < width; i++) { uint32 pixel = *in++; *out++ = TIFFGetR(pixel); *out++ = TIFFGetG(pixel); *out++ = TIFFGetB(pixel); } row += width*3; } } } else { int tile_width, tile_height; if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width)) // File is tiled { int x, y; int i, j; int m, n; uint16 *buffer = (uint16 *) raster; uint16 *out, *in, *rous; TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height); for (y = 0; y < height; y += tile_height) { if (y + tile_height > height) n = height - y; else n = tile_height; for (x = 0; x < width; x += tile_width) { TIFFReadTile(tif, buffer, x, y, 0, 0); if (x + tile_width > width) m = width - x; else m = tile_width; for (j = 0; j < n; j++) { out = (uint16 *) (row + 2*(j*width + x)); in = buffer + j*tile_width; for (i = 0; i < m; i++) *out++ = *in++; } } row += n*width*2; } } else // File is striped { int y; for (y = 0; y < height; y++) { TIFFReadScanline(tif, row, y, 0); row += width*2; } } } }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors TIFFSetErrorHandler(NULL); //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data cx_try { //check if it's a tiff file if (!m_tif) cx_throw("Error encountered while opening TIFF file"); // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) cx_throw("Error: page not present in TIFF file"); //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; info.dwType = CXIMAGE_FORMAT_TIF; cx_throw("output dimensions returned"); } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) { head.biBitCount=24; head.biClrUsed =0; } } if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) cx_throw("CxImageTIF can't create image"); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) cx_throw("No space for raster buffer"); // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); cx_throw("Corrupted TIFF file!"); } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); cx_throw("Cancelled"); } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { int BIG_palette = (bitspersample > 8) && // + VK (photometric==PHOTOMETRIC_PALETTE); if (BIG_palette && (bitspersample > 24)) // + VK cx_throw("Too big palette to handle"); // + VK RGBQUAD *pal; pal=(RGBQUAD*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQUAD)); // ! VK: it coasts nothing but more correct to use 256 as temp palette storage // ! VK: but for case of BIG palette it just copied if (pal==NULL) cx_throw("Unable to allocate TIFF palette"); int bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8) // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/((1<<bpp)-1))); } } else { for (int i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/((1<<bpp)-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = /*FALSE*/ BIG_palette; if (!BIG_palette) { int n= 1<<bpp; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } } // load the palette in the DIB for (int i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { if (Palette16Bits) {
BOOL CImageTIFF::Read(FILE* stream) { TIFF* m_tif = TIFFOpenEx(stream, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=-1; uint16 photometric=0; uint16 compression=1; uint32 x, y; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; m_info.nNumFrames=0; while(TIFFSetDirectory(m_tif,(uint16)m_info.nNumFrames)) m_info.nNumFrames++; if (!TIFFSetDirectory(m_tif, (uint16)m_info.nFrame)) throw "Error: page not present in TIFF file"; //get image m_info TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); if (compression == COMPRESSION_LZW) throw "LZW compression is no longer supported due to Unisys patent enforcement"; TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); m_header.biWidth = width; m_header.biHeight = height; m_header.biClrUsed=0; m_info.nBkgndIndex =-1; isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ m_header.biBitCount=24; m_info.bColorType = COLORTYPE_COLOR; }else{ m_info.bColorType = COLORTYPE_PALETTE; if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ m_header.biBitCount=1; //B&W image m_header.biClrUsed =2; } else { m_header.biBitCount=8; //gray scale m_header.biClrUsed =256; } } else if (bitspersample == 4) { m_header.biBitCount=4; // 16 colors m_header.biClrUsed=16; } else { m_header.biBitCount=8; //256 colors m_header.biClrUsed=256; } } Create(m_header.biWidth,m_header.biHeight,m_header.biBitCount); //image creation if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = m_info.pImage; for (y = 0; y < height; y++) { bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); } row += width; bits2 += m_info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = i; } } else { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = 255 - i; } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,m_header.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); // int pitch = CalculatePitch(line); long bitsize= TIFFStripSize(m_tif); bits = (BYTE*)malloc(bitsize); for (ys = 0; ys < height; ys += rowsperstrip) { nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } for (y = 0; y < nrow; y++) { memcpy(m_info.pImage+m_info.dwEffWidth*(height-ys-nrow+y),bits+(nrow-y-1)*line,line); } /*if (m_header.biClrUsed==2){ for (y = 0; y < nrow; y++) { for (x = 0; x < width; x++) { SetPixelIndex(x,y+ys,(bits[y*line+(x>>3)]>>(7-x%8))&0x01); }}}*/ } free(bits); } } catch (char *message) { strncpy(m_info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); return FALSE; } TIFFClose(m_tif); return TRUE; }
GthImage * _cairo_image_surface_create_from_tiff (GInputStream *istream, GthFileData *file_data, int requested_size, int *original_width_p, int *original_height_p, gboolean *loaded_original_p, gpointer user_data, GCancellable *cancellable, GError **error) { GthImage *image; Handle handle; TIFF *tif; gboolean first_directory; int best_directory; int max_width, max_height, min_diff; uint32 image_width; uint32 image_height; uint32 spp; uint16 extrasamples; uint16 *sampleinfo; uint16 orientation; char emsg[1024]; cairo_surface_t *surface; cairo_surface_metadata_t*metadata; uint32 *raster; image = gth_image_new (); handle.cancellable = cancellable; handle.size = 0; if ((file_data != NULL) && (file_data->info != NULL)) { handle.istream = g_buffered_input_stream_new (istream); handle.size = g_file_info_get_size (file_data->info); } else { void *data; gsize size; /* read the whole stream to get the file size */ if (! _g_input_stream_read_all (istream, &data, &size, cancellable, error)) return image; handle.istream = g_memory_input_stream_new_from_data (data, size, g_free); handle.size = size; } TIFFSetErrorHandler (tiff_error_handler); TIFFSetWarningHandler (tiff_error_handler); tif = TIFFClientOpen ("gth-tiff-reader", "r", &handle, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); if (tif == NULL) { g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } /* find the best image to load */ first_directory = TRUE; best_directory = -1; max_width = -1; max_height = -1; min_diff = 0; do { int width; int height; if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) != 1) continue; if (TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) != 1) continue; if (! TIFFRGBAImageOK (tif, emsg)) continue; if (width > max_width) { max_width = width; max_height = height; if (requested_size <= 0) best_directory = TIFFCurrentDirectory (tif); } if (requested_size > 0) { int diff = abs (requested_size - width); if (first_directory) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } else if (diff < min_diff) { min_diff = diff; best_directory = TIFFCurrentDirectory (tif); } } first_directory = FALSE; } while (TIFFReadDirectory (tif)); if (best_directory == -1) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid TIFF format"); return image; } /* read the image */ TIFFSetDirectory (tif, best_directory); TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width); TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height); TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted (tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation) != 1) orientation = ORIENTATION_TOPLEFT; if (original_width_p) *original_width_p = max_width; if (original_height_p) *original_height_p = max_height; if (loaded_original_p) *loaded_original_p = (max_width == image_width); surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image_width, image_height); if (surface == NULL) { TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } metadata = _cairo_image_surface_get_metadata (surface); _cairo_metadata_set_has_alpha (metadata, (extrasamples == 1) || (spp == 4)); _cairo_metadata_set_original_size (metadata, max_width, max_height); raster = (uint32*) _TIFFmalloc (image_width * image_height * sizeof (uint32)); if (raster == NULL) { cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for writing TIFF file"); return image; } if (TIFFReadRGBAImageOriented (tif, image_width, image_height, raster, orientation, 0)) { guchar *surface_row; int line_step; int x, y, temp; guchar r, g, b, a; uint32 *src_pixel; surface_row = _cairo_image_surface_flush_and_get_data (surface); line_step = cairo_image_surface_get_stride (surface); src_pixel = raster; for (y = 0; y < image_height; y++) { guchar *dest_pixel = surface_row; if (g_cancellable_is_cancelled (cancellable)) goto stop_loading; for (x = 0; x < image_width; x++) { r = TIFFGetR (*src_pixel); g = TIFFGetG (*src_pixel); b = TIFFGetB (*src_pixel); a = TIFFGetA (*src_pixel); CAIRO_SET_RGBA (dest_pixel, r, g, b, a); dest_pixel += 4; src_pixel += 1; } surface_row += line_step; } } stop_loading: cairo_surface_mark_dirty (surface); if (! g_cancellable_is_cancelled (cancellable)) gth_image_set_cairo_surface (image, surface); _TIFFfree (raster); cairo_surface_destroy (surface); TIFFClose (tif); g_object_unref (handle.istream); return image; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) throw "Error: page not present in TIFF file"; //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; throw "output dimensions returned"; } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } } if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) throw "CxImageTIF can't create image"; #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); throw "Cancelled"; } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/(head.biClrUsed-1))); } } else { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/(head.biClrUsed-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,head.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); long bitsize= TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel; int tiled_image = TIFFIsTiled(m_tif); uint32 tw, tl; BYTE* tilebuf; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); } bits = (BYTE*)malloc(bitsize); if (bits==NULL){ throw "CxImageTIF can't allocate memory"; } for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); throw "Cancelled"; } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); throw "Corrupted tiled TIFF file!"; } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } } for (y = 0; y < nrow; y++) { long offset=(nrow-y-1)*line; if (bitspersample==16) for (DWORD xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; if (samplesperpixel==1) { //simple 8bpp image memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth); } else if (samplesperpixel==2) { //8bpp image with alpha layer int xi=0; int ii=0; int yi=height-ys-nrow+y; while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int xi=0; int ii=0; int yi=height-ys-nrow+y; RGBQUAD c; int l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii<line){ bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int)width){ yi--; xi=0; } } } } } free(bits); if (tiled_image) free(tilebuf); switch(orientation){ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ Mirror(); break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ Flip(); Mirror(); break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ Flip(); break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ RotateRight(); Mirror(); break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ RotateLeft(); break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ RotateLeft(); Mirror(); break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ RotateRight(); break; } } } catch (char *message) { strncpy(info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); if (info.nEscape==-1) return true; return false; } TIFFClose(m_tif); 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 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; }
HANDLE TIFFRGBA2DIB(TIFFDibImage* dib, uint32* raster) { void* pDIB = 0; TIFFRGBAImage* img = &dib->tif; uint32 imageLength; uint32 imageWidth; uint16 BitsPerSample; uint16 SamplePerPixel; uint32 RowsPerStrip; uint16 PhotometricInterpretation; BITMAPINFOHEADER bi; int dwDIBSize ; TIFFGetField(img->tif, TIFFTAG_IMAGEWIDTH, &imageWidth); TIFFGetField(img->tif, TIFFTAG_IMAGELENGTH, &imageLength); TIFFGetField(img->tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(img->tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(img->tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetField(img->tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); if ( BitsPerSample == 1 && SamplePerPixel == 1 && dib->dibinstalled ) { // bilevel bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = imageWidth; bi.biHeight = imageLength; bi.biPlanes = 1; // always bi.biBitCount = 1; bi.biCompression = BI_RGB; bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; // must be zero for RGB compression (none) bi.biClrImportant = 0; // always // Get the size of the DIB dwDIBSize = GetDIBSize( &bi ); // Allocate for the BITMAPINFO structure and the color table. pDIB = GlobalAllocPtr( GHND, dwDIBSize ); if (pDIB == 0) { return( NULL ); } // Copy the header info *((BITMAPINFOHEADER*)pDIB) = bi; // Get a pointer to the color table RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); pRgbq[0].rgbRed = 0; pRgbq[0].rgbBlue = 0; pRgbq[0].rgbGreen = 0; pRgbq[0].rgbReserved = 0; pRgbq[1].rgbRed = 255; pRgbq[1].rgbBlue = 255; pRgbq[1].rgbGreen = 255; pRgbq[1].rgbReserved = 255; // Pointers to the bits //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); // // In the BITMAPINFOHEADER documentation, it appears that // there should be no color table for 32 bit images, but // experience shows that the image is off by 3 words if it // is not included. So here it is. PVOID pbiBits = GetDIBImagePtr((BITMAPINFOHEADER*)pDIB); //(LPSTR)pRgbq + 3 * sizeof(RGBQUAD); int sizeWords = bi.biSizeImage/4; RGBQUAD* rgbDib = (RGBQUAD*)pbiBits; long* rgbTif = (long*)raster; _TIFFmemcpy(pbiBits, raster, bi.biSizeImage); } // For now just always default to the RGB 32 bit form. // save as 32 bit for simplicity else if ( true /*BitsPerSample == 8 && SamplePerPixel == 3*/ ) { // 24 bit color bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = imageWidth; bi.biHeight = imageLength; bi.biPlanes = 1; // always bi.biBitCount = 32; bi.biCompression = BI_RGB; bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; // must be zero for RGB compression (none) bi.biClrImportant = 0; // always // Get the size of the DIB dwDIBSize = GetDIBSize( &bi ); // Allocate for the BITMAPINFO structure and the color table. pDIB = GlobalAllocPtr( GHND, dwDIBSize ); if (pDIB == 0) { return( NULL ); } // Copy the header info *((BITMAPINFOHEADER*)pDIB) = bi; // Get a pointer to the color table RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); // Pointers to the bits //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); // // In the BITMAPINFOHEADER documentation, it appears that // there should be no color table for 32 bit images, but // experience shows that the image is off by 3 words if it // is not included. So here it is. PVOID pbiBits = (LPSTR)pRgbq + 3 * sizeof(RGBQUAD); int sizeWords = bi.biSizeImage/4; RGBQUAD* rgbDib = (RGBQUAD*)pbiBits; long* rgbTif = (long*)raster; // Swap the byte order while copying for ( int i = 0 ; i < sizeWords ; ++i ) { rgbDib[i].rgbRed = TIFFGetR(rgbTif[i]); rgbDib[i].rgbBlue = TIFFGetB(rgbTif[i]); rgbDib[i].rgbGreen = TIFFGetG(rgbTif[i]); rgbDib[i].rgbReserved = 0; } } return pDIB; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(uint32_t)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; bool isRGB; uint8_t *bits; //pointer to source data uint8_t *bits2; //pointer to destination data cx_try { //check if it's a tiff file if (!m_tif) cx_throw("Error encountered while opening TIFF file"); // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) cx_throw("Error: page not present in TIFF file"); //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; info.dwType = CXIMAGE_FORMAT_TIF; cx_throw("output dimensions returned"); } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (int32_t)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (int32_t)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) { head.biBitCount=24; head.biClrUsed =0; } } if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) cx_throw("CxImageTIF can't create image"); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) cx_throw("No space for raster buffer"); // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); cx_throw("Corrupted TIFF file!"); } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); cx_throw("Cancelled"); } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (uint8_t)TIFFGetB(row[x]); *bits++ = (uint8_t)TIFFGetG(row[x]); *bits++ = (uint8_t)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(uint8_t)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { int32_t BIG_palette = (bitspersample > 8) && // + VK (photometric==PHOTOMETRIC_PALETTE); if (BIG_palette && (bitspersample > 24)) // + VK cx_throw("Too big palette to handle"); // + VK RGBQuad *pal; pal=(RGBQuad*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQuad)); // ! VK: it coasts nothing but more correct to use 256 as temp palette storage // ! VK: but for case of BIG palette it just copied if (pal==NULL) cx_throw("Unable to allocate TIFF palette"); int32_t bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8) // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(i*(255/((1<<bpp)-1))); } } else { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(255-i*(255/((1<<bpp)-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? bool Palette16Bits = /*false*/ BIG_palette; if (!BIG_palette) { int32_t n= 1<<bpp; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=true; break; } } } // load the palette in the DIB for (int32_t i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(uint8_t) CVT(red[i]); pal[i].rgbGreen = (uint8_t) CVT(green[i]); pal[i].rgbBlue = (uint8_t) CVT(blue[i]); } else { pal[i].rgbRed = (uint8_t) red[i]; pal[i].rgbGreen = (uint8_t) green[i]; pal[i].rgbBlue = (uint8_t) blue[i]; } } break; } if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK free(pal); pal = NULL; } // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int32_t line = CalculateLine(width, bitspersample * samplesperpixel); int32_t bitsize = TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(int32_t)(head.biSizeImage*samplesperpixel)) bitsize = head.biSizeImage*samplesperpixel; if (bitsize<(int32_t)(info.dwEffWidth*rowsperstrip)) bitsize = info.dwEffWidth*rowsperstrip; if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 bitsize *= (bitspersample + 7)/8; int32_t tiled_image = TIFFIsTiled(m_tif); uint32 tw=0, tl=0; uint8_t* tilebuf=NULL; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int32_t)(1+width/tw); tilebuf = (uint8_t*)malloc(TIFFTileSize(m_tif)); } bits = (uint8_t*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK uint8_t * bits16 = NULL; // + VK int32_t line16 = 0; // + VK if (!tiled_image && bitspersample==16) { // + VK + line16 = line; line = CalculateLine(width, 8 * samplesperpixel); bits16 = bits; bits = (uint8_t*)malloc(bitsize); } if (bits==NULL){ if (bits16) free(bits16); // + VK if (pal) free(pal); // + VK if (tilebuf)free(tilebuf); // + VK cx_throw("CxImageTIF can't allocate memory"); } #ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it uint8_t* row_shifts = NULL; if (bits16) row_shifts = (uint8_t*)malloc(height); #endif for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); cx_throw("Cancelled"); } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int32_t iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); cx_throw("Corrupted tiled TIFF file!"); } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK #ifdef NOT_IGNORE_CORRUPTED free(bits); if (bits16) free(bits16); // + VK cx_throw("Corrupted TIFF file!"); #else break; #endif } } for (y = 0; y < nrow; y++) { int32_t offset=(nrow-y-1)*line; if ((bitspersample==16) && !BIG_palette) { // * VK int32_t offset16 = (nrow-y-1)*line16; // + VK if (bits16) { // + VK + #ifdef FIX_16BPP_DARKIMG int32_t the_shift; uint8_t hi_byte, hi_max=0; uint32_t xi; for (xi=0;xi<(uint32)line;xi++) { hi_byte = bits16[xi*2+offset16+1]; if(hi_byte>hi_max) hi_max = hi_byte; } the_shift = (hi_max == 0) ? 8 : 0; if (!the_shift) while( ! (hi_max & 0x80) ) { the_shift++; hi_max <<= 1; } row_shifts[height-ys-nrow+y] = the_shift; the_shift = 8 - the_shift; for (xi=0;xi<(uint32)line;xi++) bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; #else for (uint32_t xi=0;xi<(uint32)line;xi++) bits[xi+offset]=bits16[xi*2+offset16+1]; #endif } else { for (uint32_t xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; } } if (samplesperpixel==1) { if (BIG_palette) if (bits16) { int32_t offset16 = (nrow-y-1)*line16; // + VK MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits16 + offset16, width, bitspersample, pal ); } else MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample, pal ); else if ((bitspersample == head.biBitCount) || (bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,min((unsigned)line, info.dwEffWidth)); else MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample ); } else if (samplesperpixel==2) { //8bpp image with alpha layer int32_t xi=0; int32_t ii=0; int32_t yi=height-ys-nrow+y; #if CXIMAGE_SUPPORT_ALPHA if (!pAlpha) AlphaCreate(); // + VK #endif //CXIMAGE_SUPPORT_ALPHA while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int32_t xi=0; uint32 ii=0; int32_t yi=height-ys-nrow+y; RGBQuad c; int32_t l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii</*line*/width){ // * VK bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(uint8_t)max(0,min(255,(int32_t)(cr*255))); c.rgbGreen=(uint8_t)max(0,min(255,(int32_t)(cg*255))); c.rgbBlue =(uint8_t)max(0,min(255,(int32_t)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } } } free(bits); if (bits16) free(bits16); #ifdef FIX_16BPP_DARKIMG if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { // 1. calculate maximum necessary shift int32_t min_row_shift = 8; for( y=0; y<height; y++ ) { if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y]; } // 2. for rows having less shift value, correct such rows: for( y=0; y<height; y++ ) { if (min_row_shift < row_shifts[y]) { int32_t need_shift = row_shifts[y] - min_row_shift; uint8_t* data = info.pImage + info.dwEffWidth * y; for( x=0; x<width; x++, data++ ) *data >>= need_shift; } }
static GdkPixbuf * tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error) { guchar *pixels = NULL; gint width, height, rowstride, bytes; GdkPixbuf *pixbuf; guint16 bits_per_sample = 0; uint16 orientation = 0; uint16 transform = 0; uint16 codec; gchar *icc_profile_base64; const gchar *icc_profile; guint icc_profile_size; uint16 resolution_unit; gchar *density_str; gint retval; /* We're called with the lock held. */ if (!TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width)) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Could not get image width (bad TIFF file)")); return NULL; } if (!TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height)) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Could not get image height (bad TIFF file)")); return NULL; } if (width <= 0 || height <= 0) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Width or height of TIFF image is zero")); return NULL; } rowstride = width * 4; if (rowstride / 4 != width) { /* overflow */ g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Dimensions of TIFF image too large")); return NULL; } bytes = height * rowstride; if (bytes / rowstride != height) { /* overflow */ g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Dimensions of TIFF image too large")); return NULL; } if (context && context->size_func) { gint w = width; gint h = height; (* context->size_func) (&w, &h, context->user_data); /* This is a signal that this function is being called to support gdk_pixbuf_get_file_info, so we can stop parsing the tiff file at this point. It is not an error condition. */ if (w == 0 || h == 0) return NULL; } pixels = g_try_malloc (bytes); if (!pixels) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Insufficient memory to open TIFF file")); return NULL; } pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8, width, height, rowstride, free_buffer, NULL); if (!pixbuf) { g_free (pixels); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Insufficient memory to open TIFF file")); return NULL; } /* Save the bits per sample as an option since pixbufs are expected to be always 8 bits per sample. */ TIFFGetField (tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); if (bits_per_sample > 0) { gchar str[5]; g_snprintf (str, sizeof (str), "%d", bits_per_sample); gdk_pixbuf_set_option (pixbuf, "bits-per-sample", str); } /* Set the "orientation" key associated with this image. libtiff orientation handling is odd, so further processing is required by higher-level functions based on this tag. If the embedded orientation tag is 1-4, libtiff flips/mirrors the image as required, and no client processing is required - so we report no orientation. Orientations 5-8 require rotations which would swap the width and height of the image. libtiff does not do this. Instead it interprets orientations 5-8 the same as 1-4. See http://bugzilla.remotesensing.org/show_bug.cgi?id=1548. To correct for this, the client must apply the transform normally used for orientation 5 to both orientations 5 and 7, and apply the transform normally used for orientation 7 for both orientations 6 and 8. Then everythings works out OK! */ TIFFGetField (tiff, TIFFTAG_ORIENTATION, &orientation); switch (orientation) { case 5: case 7: transform = 5; break; case 6: case 8: transform = 7; break; default: transform = 0; break; } if (transform > 0 ) { gchar str[5]; g_snprintf (str, sizeof (str), "%d", transform); gdk_pixbuf_set_option (pixbuf, "orientation", str); } TIFFGetField (tiff, TIFFTAG_COMPRESSION, &codec); if (codec > 0) { gchar str[5]; g_snprintf (str, sizeof (str), "%d", codec); gdk_pixbuf_set_option (pixbuf, "compression", str); } /* Extract embedded ICC profile */ retval = TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_profile_size, &icc_profile); if (retval == 1) { icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, icc_profile_size); gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64); g_free (icc_profile_base64); } retval = TIFFGetField (tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit); if (retval == 1) { float x_resolution = 0, y_resolution = 0; TIFFGetField (tiff, TIFFTAG_XRESOLUTION, &x_resolution); TIFFGetField (tiff, TIFFTAG_YRESOLUTION, &y_resolution); switch (resolution_unit) { case RESUNIT_INCH: density_str = g_strdup_printf ("%d", (int) round (x_resolution)); gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str); g_free (density_str); density_str = g_strdup_printf ("%d", (int) round (y_resolution)); gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str); g_free (density_str); break; case RESUNIT_CENTIMETER: density_str = g_strdup_printf ("%d", DPCM_TO_DPI (x_resolution)); gdk_pixbuf_set_option (pixbuf, "x-dpi", density_str); g_free (density_str); density_str = g_strdup_printf ("%d", DPCM_TO_DPI (y_resolution)); gdk_pixbuf_set_option (pixbuf, "y-dpi", density_str); g_free (density_str); break; } } if (context && context->prepare_func) (* context->prepare_func) (pixbuf, NULL, context->user_data); if (!TIFFReadRGBAImageOriented (tiff, width, height, (uint32 *)pixels, ORIENTATION_TOPLEFT, 1)) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Failed to load RGB data from TIFF file")); g_object_unref (pixbuf); return NULL; } /* Flag multi-page documents, because this loader only handles the first page. The client app may wish to warn the user. */ if (TIFFReadDirectory (tiff)) gdk_pixbuf_set_option (pixbuf, "multipage", "yes"); #if G_BYTE_ORDER == G_BIG_ENDIAN /* Turns out that the packing used by TIFFRGBAImage depends on * the host byte order... */ while (pixels < pixbuf->pixels + bytes) { uint32 pixel = *(uint32 *)pixels; int r = TIFFGetR(pixel); int g = TIFFGetG(pixel); int b = TIFFGetB(pixel); int a = TIFFGetA(pixel); *pixels++ = r; *pixels++ = g; *pixels++ = b; *pixels++ = a; } #endif if (context && context->update_func) (* context->update_func) (pixbuf, 0, 0, width, height, context->user_data); return pixbuf; }
void TifReader::readLine(char *buffer, int x0, int x1, int shrink) { if (this->m_info.m_bitsPerSample == 16 && this->m_info.m_samplePerPixel >= 3) { std::vector<short> app(4 * (m_info.m_lx)); readLine(&app[0], x0, x1, shrink); TPixel64 *pixin = (TPixel64 *)&app[0]; TPixel32 *pixout = (TPixel32 *)buffer; for (int j = 0; j < x0; j++) { pixout++; pixin++; } for (int i = 0; i < (x1 - x0) + 1; i++) *pixout++ = PixelConverter<TPixel32>::from(*pixin++); return; } assert(shrink > 0); const int pixelSize = 4; int stripRowSize = m_rowLength * pixelSize; if (m_row < m_info.m_y0 || m_row > m_info.m_y1) { memset(buffer, 0, (x1 - x0 + 1) * pixelSize); m_row++; return; } int stripIndex = m_row / m_rowsPerStrip; if (m_stripIndex != stripIndex) { m_stripIndex = stripIndex; if (TIFFIsTiled(m_tiff)) { uint32 tileWidth = 0, tileHeight = 0; TIFFGetField(m_tiff, TIFFTAG_TILEWIDTH, &tileWidth); TIFFGetField(m_tiff, TIFFTAG_TILELENGTH, &tileHeight); assert(tileWidth > 0 && tileHeight > 0); int tileSize = tileWidth * tileHeight; std::unique_ptr<uint32[]> tile(new uint32[tileSize]); int x = 0; int y = tileHeight * m_stripIndex; int lastTy = std::min((int)tileHeight, m_info.m_ly - y); while (x < m_info.m_lx) { int ret = TIFFReadRGBATile(m_tiff, x, y, tile.get()); assert(ret); int tileRowSize = std::min((int)tileWidth, (int)(m_info.m_lx - x)) * pixelSize; for (int ty = 0; ty < lastTy; ++ty) { memcpy( m_stripBuffer + (ty * m_rowLength + x) * pixelSize, (UCHAR *)tile.get() + ty * tileWidth * pixelSize, tileRowSize); } x += tileWidth; } } else { int y = m_rowsPerStrip * m_stripIndex; int ok = TIFFReadRGBAStrip(m_tiff, y, (uint32 *)m_stripBuffer); assert(ok); } } uint16 orient = ORIENTATION_TOPLEFT; TIFFGetField(m_tiff, TIFFTAG_ORIENTATION, &orient); int r = m_rowsPerStrip - 1 - (m_row % m_rowsPerStrip); switch (orient) // Pretty weak check for top/bottom orientation { case ORIENTATION_TOPLEFT: case ORIENTATION_TOPRIGHT: case ORIENTATION_LEFTTOP: case ORIENTATION_RIGHTTOP: // We have to invert the fixed BOTTOM-UP returned by TIFF functions - since this function is // supposed to ignore orientation issues (which are managed outside). // The last tiles row will actually start at the END OF THE IMAGE (not necessarily at // m_rowsPerStrip multiples). So, we must adjust for that. r = std::min(m_rowsPerStrip, m_info.m_ly - m_rowsPerStrip * m_stripIndex) - 1 - (m_row % m_rowsPerStrip); break; case ORIENTATION_BOTRIGHT: case ORIENTATION_BOTLEFT: case ORIENTATION_RIGHTBOT: case ORIENTATION_LEFTBOT: r = m_row % m_rowsPerStrip; break; } TPixel32 *pix = (TPixel32 *)buffer; uint32 *v = (uint32 *)(m_stripBuffer + r * stripRowSize); pix += x0; v += x0; int width = (x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1; for (int i = 0; i < width; i++) { uint32 c = *v; pix->r = (UCHAR)TIFFGetR(c); pix->g = (UCHAR)TIFFGetG(c); pix->b = (UCHAR)TIFFGetB(c); pix->m = (UCHAR)TIFFGetA(c); v += shrink; pix += shrink; } m_row++; }
unsigned char * loader_tiff(FILE *f, char *file, int *w, int *h, int *t) { TIFF *tif; unsigned char *data, *ptr, r, g, b, a; int x, y; uint32 ww, hh, *rast, *tptr; size_t npix; int istransp; int fd; istransp = 0; if (!f) return NULL; fd = fileno(f); /* Apparently rewind(f) isn't sufficient */ lseek(fd, (long) 0, 0); /* So why does libtif need a filename here ??? */ tif = TIFFFdOpen(fd, file, "r"); if (!tif) return NULL; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &ww); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &hh); npix = ww * hh; *w = (int)ww; *h = (int)hh; if(ww > 32767 || hh > 32767) { TIFFClose(tif); return NULL; } rast = (uint32 *) _TIFFmalloc(npix * sizeof(uint32)); if (!rast) { TIFFClose(tif); return NULL; } data = NULL; if (TIFFReadRGBAImage(tif, ww, hh, rast, 0)) { data = (unsigned char *)malloc(*w ** h * 3); if (!data) { _TIFFfree(rast); TIFFClose(tif); return NULL; } ptr = data; for (y = 0; y < *h; y++) { tptr = rast; tptr += ((*h - y - 1) ** w); for (x = 0; x < *w; x++) { a = TIFFGetA(*tptr); b = TIFFGetB(*tptr); g = TIFFGetG(*tptr); r = TIFFGetR(*tptr); tptr++; if (a < 128) { *ptr++ = 255; *ptr++ = 0; *ptr++ = 255; istransp = 1; } else { if ((r == 255) && (g == 0) && (b == 255)) r = 254; *ptr++ = r; *ptr++ = g; *ptr++ = b; } } } } _TIFFfree(rast); TIFFClose(tif); *t = istransp; return data; }
ImageIO::errorType ImageIO::loadTIFF(const char * filename) { #ifdef ENABLE_TIFF TIFF * tiff = TIFFOpen(filename, "r"); if (!tiff) return IO_ERROR; // read the dimensions uint32 tiff_width, tiff_height; uint16 tiff_samplesPerPixel; uint16 tiff_bits; TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &tiff_width); TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &tiff_height); TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &tiff_samplesPerPixel); TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &tiff_bits); //printf("tiff_width: %d tiff_height: %d tiff_samplesPerPixel: %d tiff_bits: %d\n", tiff_width, tiff_height, tiff_samplesPerPixel, tiff_bits); if ((tiff_samplesPerPixel != IMAGE_IO_RGB) && (tiff_samplesPerPixel != IMAGE_IO_RGB_ALPHA)) { printf("Error in loadTIFF: Sorry, cannot handle %d-channel images.\n", tiff_samplesPerPixel); TIFFClose(tiff); return OTHER_ERROR; } if (tiff_bits != BITS_PER_CHANNEL_8) { printf("Error in loadTIFF: Sorry, cannot handle %d-bit images.\n", tiff_bits); TIFFClose(tiff); return OTHER_ERROR; } width = tiff_width; height = tiff_height; bytesPerPixel = tiff_samplesPerPixel; uint32 * tiff_pixels = (uint32*) _TIFFmalloc(tiff_width * tiff_height * sizeof(uint32)); if (!tiff_pixels) { TIFFClose(tiff); return MEMORY_ERROR; } printf("Loading TIFF image from file %s: resolution: %d x %d, %d-bit.\n", filename, width, height, 8 * bytesPerPixel); int stopOnError = 1; if (!TIFFReadRGBAImage(tiff, tiff_width, tiff_height, tiff_pixels, stopOnError)) { _TIFFfree(tiff_pixels); TIFFClose(tiff); printf("Error in loadTIFF: Unknown error when calling TIFFReadRGBAImage.\n"); return IO_ERROR; } pixels = (unsigned char*) malloc (sizeof(unsigned char) * width * height * bytesPerPixel); // write tiff_pixels into the pixels array int counter = 0; for(unsigned int row=0; row < height; row++) { for(unsigned int column=0; column < width; column++) { // read the uint32 pixel uint32 tiff_pixel = tiff_pixels[row * tiff_width + column]; // write R,G,B,A in place into pixels pixels[counter] = TIFFGetR(tiff_pixel); counter++; if (bytesPerPixel < 3) continue; pixels[counter] = TIFFGetG(tiff_pixel); counter++; pixels[counter] = TIFFGetB(tiff_pixel); counter++; if (bytesPerPixel < 4) continue; // alpha channel pixels[counter] = TIFFGetA(tiff_pixel); counter++; } } _TIFFfree(tiff_pixels); TIFFClose(tiff); return OK; #else return INVALID_FILE_FORMAT; #endif }
/** * Retrieves the blue component of the given pixel. * * @param pixel Representation of a LibTIFF pixel value * * @return The blue component */ int TiffImporter::getBlue(int pixel) const { return TIFFGetB(pixel); }
Image *Read (IStream *file, const Image::ReadOptions& options) { int nrow; int result = 0; long LineSize; TIFF *tif; Image *image ; uint16 BitsPerSample; uint16 BytesPerSample = 1; uint16 PhotometricInterpretation; uint16 SamplePerPixel; uint16 Orientation; uint32 RowsPerStrip; unsigned int width; unsigned int height; // TODO - TIFF files probably have some gamma info in them by default, but we're currently ignorant about that. // Until that is fixed, use whatever the user has chosen as default. GammaCurvePtr gamma; if (options.gammacorrect && options.defaultGamma) gamma = TranscodingGammaCurve::Get(options.workingGamma, options.defaultGamma); // [CLi] TIFF is specified to use associated (= premultiplied) alpha, so that's the preferred mode to use for the image container unless the user overrides // (e.g. to handle a non-compliant file). bool premul = true; if (options.premultiplyOverride) premul = options.premultiply; // Rather than have libTIFF complain about tags it doesn't understand, // we just suppress all the warnings. TIFFSetWarningHandler(SuppressTIFFWarnings); TIFFSetErrorHandler(SuppressTIFFWarnings); // Open and do initial processing tif = TIFFClientOpen("Dummy File Name", "r", file, Tiff_Read, Tiff_Write, Tiff_Seek, Tiff_Close, Tiff_Size, Tiff_Map, Tiff_Unmap); if (!tif) return (NULL) ; // Get basic information about the image int ExtraSamples, ExtraSampleInfo; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); TIFFGetField(tif, TIFFTAG_ORIENTATION, &Orientation); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &ExtraSamples, &ExtraSampleInfo); // don't support more than 16 bits per sample if (BitsPerSample == 16) { BytesPerSample = 2 ; options.warnings.push_back ("Warning: reading 16 bits/sample TIFF file; components crunched to 8"); } LineSize = TIFFScanlineSize(tif); assert (SamplePerPixel == (int) (LineSize / width) / BytesPerSample); // SamplePerPixel = (int)(LineSize / width); #if 0 // For now we are ignoring the orientation of the image... switch (Orientation) { case ORIENTATION_TOPLEFT: break; case ORIENTATION_TOPRIGHT: break; case ORIENTATION_BOTRIGHT: break; case ORIENTATION_BOTLEFT: break; case ORIENTATION_LEFTTOP: break; case ORIENTATION_RIGHTTOP: break; case ORIENTATION_RIGHTBOT: break; case ORIENTATION_LEFTBOT: break; default: break; } #endif //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image have a color palette if (PhotometricInterpretation == PHOTOMETRIC_PALETTE && (TIFFIsTiled(tif) == 0)) { uint16 *red, *green, *blue; //load the palette int cmap_len = (1 << BitsPerSample); TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); vector<Image::RGBMapEntry> colormap ; Image::RGBMapEntry entry; // I may be mistaken, but it appears that alpha/opacity information doesn't // appear in a Paletted Tiff image. Well - if it does, it's not as easy to // get at as RGB. // Read the palette // Is the palette 16 or 8 bits ? if (checkcmap(cmap_len, red, green, blue) == 16) { for (int i=0;i<cmap_len;i++) { entry.red = IntDecode(gamma, red[i], 65535); entry.green = IntDecode(gamma, green[i], 65535); entry.blue = IntDecode(gamma, blue[i], 65535); colormap.push_back (entry); } } else { for (int i=0;i<cmap_len;i++) { entry.red = IntDecode(gamma, red[i], 255); entry.green = IntDecode(gamma, green[i], 255); entry.blue = IntDecode(gamma, blue[i], 255); colormap.push_back (entry); } } Image::ImageDataType imagetype = options.itype; if (imagetype == Image::Undefined) imagetype = Image::Colour_Map; image = Image::Create (width, height, imagetype, colormap) ; image->SetPremultiplied(premul); // specify whether the color map data has premultiplied alpha boost::scoped_array<unsigned char> buf (new unsigned char [TIFFStripSize(tif)]); //read the tiff lines and save them in the image //with RGB mode, we have to change the order of the 3 samples RGB <=> BGR for (int row=0;row<height;row+=RowsPerStrip) { nrow = (row + (int)RowsPerStrip > height ? height - row : RowsPerStrip); TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf.get(), nrow * LineSize); for (int l = 0, offset = 0; l < nrow ; l++, offset += LineSize) for (int x = 0 ; x < width ; x++) image->SetIndexedValue (x, row+l, buf[offset+x]) ; } } else { // Allocate the row buffers for the image boost::scoped_array<uint32> buf (new uint32 [width * height]) ; Image::ImageDataType imagetype = options.itype; if (imagetype == Image::Undefined) imagetype = ( GammaCurve::IsNeutral(gamma) ? Image::RGBA_Int8 : Image::RGBA_Gamma8 ); image = Image::Create (width, height, imagetype) ; image->SetPremultiplied(premul); // set desired storage mode regarding alpha premultiplication image->TryDeferDecoding(gamma, 255); // try to have gamma adjustment being deferred until image evaluation. TIFFReadRGBAImage(tif, width, height, buf.get(), 0); uint32 abgr, *tbuf = buf.get(); for (int i=height-1;i>=0;i--) { for (int j=0;j<width;j++) { abgr = *tbuf++; unsigned int b = (unsigned char)TIFFGetB(abgr); unsigned int g = (unsigned char)TIFFGetG(abgr); unsigned int r = (unsigned char)TIFFGetR(abgr); unsigned int a = (unsigned char)TIFFGetA(abgr); SetEncodedRGBAValue(image, j, i, gamma, 255, r, g, b, a, premul) ; } } } TIFFClose(tif); return (image) ; }
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; }
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; }
main(int argc, char* argv[]) { TIFF* tif; uint8 r,g,b,a,i,bpp; FILE *rgbf; char rgbfile[50]; if (argc!=2 && argc!=3) { printf("Usage: %s [-32] filename.tiff\n",argv[0]); exit(1); } if (argc==2) bpp=16; else bpp=32; tif = TIFFOpen(argv[1], "r"); if (tif) { uint32 w, h, pixel,rgba32_pixel; uint16 rgba16_pixel; size_t npixels; uint32* raster; int n; strcpy(rgbfile,argv[1]); strcpy((char*)strrchr(rgbfile,'.'),".rgb"); rgbf=fopen(rgbfile,"wb"); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); npixels = w * h; raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); if (raster != NULL) { if (TIFFReadRGBAImage(tif,w,h,raster,0)) { int mw,mh; // save rgb data to file fputc((w>>8)&0xFF,rgbf); fputc(w&0xFF,rgbf); // u16 w,h header fputc((h>>8)&0xFF,rgbf); fputc(h&0xFF,rgbf); for (n=0; n<4; n++) fputc(0x0,rgbf); // alignment for (mh=h-1; mh>=0; mh--) for (mw=0; mw<w; mw++) { pixel=raster[w*mh+mw]; r=TIFFGetR(pixel); g=TIFFGetG(pixel); b=TIFFGetB(pixel); a=TIFFGetA(pixel); if (bpp==16) { rgba16_pixel=PACK_RGBA5551(r,g,b,a); // use white as the mask // if (r==0xff && g==0xff && b==0xff) a|=1; else a&=~(uint16)1; // if (a==0xcff) rgba16_pixel|=1; else rgba16_pixel&=~(uint16)1; fputc((rgba16_pixel>>8)&0xFF,rgbf); fputc(rgba16_pixel&0xFF,rgbf); } else { // rgba32_pixel=PACK_RGBA8888(r,g,b,a); fputc(r,rgbf); fputc(g,rgbf); fputc(b,rgbf); fputc(a,rgbf); } } }