int ReadTIFF(const char* const filename, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { TIFF* const tif = TIFFOpen(filename, "r"); uint32 width, height; uint32* raster; int ok = 0; tdir_t dircount; if (tif == NULL) { fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename); return 0; } dircount = TIFFNumberOfDirectories(tif); if (dircount > 1) { fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n" "Only the first will be used, %d will be ignored.\n", dircount - 1); } if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) && TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) { fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); return 0; } raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster)); if (raster != NULL) { if (TIFFReadRGBAImageOriented(tif, width, height, raster, ORIENTATION_TOPLEFT, 1)) { const int stride = width * sizeof(*raster); pic->width = width; pic->height = height; // TIFF data is ABGR #ifdef WORDS_BIGENDIAN TIFFSwabArrayOfLong(raster, width * height); #endif ok = keep_alpha ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride) : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride); } _TIFFfree(raster); } else { fprintf(stderr, "Error allocating TIFF RGBA memory!\n"); } if (ok) { if (metadata != NULL) { ok = ExtractMetadataFromTIFF(tif, metadata); if (!ok) { fprintf(stderr, "Error extracting TIFF metadata!\n"); MetadataFree(metadata); WebPPictureFree(pic); } } } TIFFClose(tif); return ok; }
int GetTiffPages(const char *pFileName) { #ifndef WITH_TIFF return NOT_IMPLEMENTED; #else if (!pFileName) return BAD_ARGS; TIFFSetErrorHandler(NULL); TIFFSetWarningHandler(NULL); scoped_tiff_handle pTIF(TIFFOpen(pFileName, "r")); if (!pTIF) return FILE_ERROR; const int nPages = TIFFNumberOfDirectories(pTIF); if (nPages < 0) return INTERNAL_ERROR; return nPages; #endif // WITH_TIFF }
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; } }
bool CaViewerScanner::registerMasterImage(QString sPath, QString sFileName) { QString sFullName = sPath + sFileName; QString sHash = getHash(sFullName); if(sHash.isEmpty()) // couldn't get hash return false; if(m_slHash.contains(sHash)) return false; if(sFileName.endsWith(".tif", Qt::CaseInsensitive)) { TIFF* tif = TIFFOpen(sFullName.toStdString().c_str(), "r"); quint32 nColSize, nRowSize; TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &nColSize); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &nRowSize); char* imageDescBuf; TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &imageDescBuf); QTextStream imageDescAll(imageDescBuf, QIODevice::ReadOnly); QString sImageDesc = imageDescAll.readAll(); qDebug() << sImageDesc; const QRegularExpression regexpTimeSize("(\\t)*Repeat T \\- (?<timeSize>\\d+) times \\(.*\\)"); const QRegularExpressionMatch matchTimeSize = regexpTimeSize.match(sImageDesc); int nTimeSize = 0; if(matchTimeSize.hasMatch()) nTimeSize = matchTimeSize.captured("timeSize").toInt(); else nTimeSize = TIFFNumberOfDirectories(tif); TIFFClose(tif); const QRegularExpression regexpHeightSize("(\\t)*Repeat Z \\- .* in (?<heightSize>\\d+) planes .*"); const QRegularExpressionMatch matchHeightSize = regexpHeightSize.match(sImageDesc); int nHeightSize = 0; if(matchHeightSize.hasMatch()) nHeightSize = matchHeightSize.captured("heightSize").toInt(); else nHeightSize = 1; QStringList lParam; QString sSqlString("'%1'"); lParam << sSqlString.arg(sHash) << sSqlString.arg(sPath) << sSqlString.arg(sFileName); lParam << QString::number(nColSize) << QString::number(nRowSize) << QString::number(nHeightSize) << QString::number(nTimeSize); m_slQuery << "insert into ImageList (Hash, Path, FileName, ColSize, RowSize, HeightSize, TimeSize, Series)" "values (" + lParam.join(',') + ", False)"; return true; } else if(sFileName.endsWith(".avi", Qt::CaseInsensitive)) { cv::VideoCapture capture(sFullName.toStdString()); if(capture.isOpened()) { const int nRowSize = capture.get(CV_CAP_PROP_FRAME_HEIGHT); const int nColSize = capture.get(CV_CAP_PROP_FRAME_WIDTH); const int nTimeSize = capture.get(CV_CAP_PROP_FRAME_COUNT); const int nHeightSize = 1; // fix later capture.release(); QStringList lParam; QString sSqlString("'%1'"); lParam << sSqlString.arg(sHash) << sSqlString.arg(sPath) << sSqlString.arg(sFileName); lParam << QString::number(nColSize) << QString::number(nRowSize) << QString::number(nHeightSize) << QString::number(nTimeSize); m_slQuery << "insert into ImageList (Hash, Path, FileName, ColSize, RowSize, HeightSize, TimeSize, Series)" "values (" + lParam.join(',') + ", False)"; return true; } else return false; } else return false; }
CPL_C_END /************************************************************************/ /* GTIFFWriteDirectory() */ /* */ /* Create a new directory, without any image data for an overview */ /* or a mask */ /* Returns offset of newly created directory, but the */ /* current directory is reset to be the one in used when this */ /* function is called. */ /************************************************************************/ long GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
int LoadTiff ( const MinImg *pImg, const char *pFileName, int page ) { #ifndef WITH_TIFF return NOT_IMPLEMENTED; #else if (!pImg || !pFileName || page < 0) return BAD_ARGS; if (!pImg->pScan0) return BAD_ARGS; TIFFSetErrorHandler(NULL); TIFFSetWarningHandler(NULL); scoped_tiff_handle pTIF(TIFFOpen(pFileName, "r")); if (!pTIF) return FILE_ERROR; const int nPages = TIFFNumberOfDirectories(pTIF); if (page >= nPages) return BAD_ARGS; TIFFSetDirectory(pTIF, page); int nc = 0, typ = PLANARCONFIG_CONTIG; _TIFFGetField(pTIF, TIFFTAG_SAMPLESPERPIXEL, &nc, 1); if (nc > 1) _TIFFGetField(pTIF, TIFFTAG_PLANARCONFIG, &typ, PLANARCONFIG_CONTIG); if (typ != PLANARCONFIG_CONTIG) return NOT_IMPLEMENTED; int wd = 0, ht = 0, bpc = 0; _TIFFGetField(pTIF, TIFFTAG_IMAGEWIDTH, &wd, 0); _TIFFGetField(pTIF, TIFFTAG_IMAGELENGTH, &ht, 0); _TIFFGetField(pTIF, TIFFTAG_BITSPERSAMPLE, &bpc, 0); if (bpc != 1 && bpc & 7) return NOT_IMPLEMENTED; bpc = bpc >> 3; if (pImg->channels != nc) return BAD_ARGS; if (bpc == 0 && pImg->channelDepth > 1) return BAD_ARGS; if (bpc > 0 && pImg->channelDepth != bpc) return BAD_ARGS; if (pImg->height < ht || pImg->width < wd) return BAD_ARGS; int metr = 0; _TIFFGetField(pTIF, TIFFTAG_PHOTOMETRIC, &metr, PHOTOMETRIC_MINISWHITE); if (metr == PHOTOMETRIC_MINISWHITE && bpc > 0) return NOT_IMPLEMENTED; int dtyp = SAMPLEFORMAT_UINT; _TIFFGetField(pTIF, TIFFTAG_SAMPLEFORMAT, &dtyp, SAMPLEFORMAT_UINT); switch (dtyp) { case SAMPLEFORMAT_UINT: if (pImg->format != FMT_UINT) return BAD_ARGS; break; case SAMPLEFORMAT_INT: if (pImg->format != FMT_INT) return BAD_ARGS; break; case SAMPLEFORMAT_IEEEFP: if (pImg->format != FMT_REAL) return BAD_ARGS; break; default: return NOT_IMPLEMENTED; } const tsize_t scanLen = TIFFScanlineSize(pTIF); scoped_scanline pScanLine(_TIFFmalloc(scanLen)); if (!pScanLine) return NO_MEMORY; const int byteWidth = pImg->channelDepth > 0 ? pImg->width * pImg->channels * pImg->channelDepth : (pImg->width * pImg->channels + 7) >> 3; if (byteWidth < scanLen) return INTERNAL_ERROR; bool invert = (metr == PHOTOMETRIC_MINISWHITE); uint8_t *pScanLineUint8 = (uint8_t *)((void *)(pScanLine)); for (int y = 0; y < ht; y++) { SHOULD_WORK(TIFFReadScanline(pTIF, pScanLine, y)); if (bpc == 0 && bpc == pImg->channelDepth) CopyBits(pImg->pScan0 + pImg->stride * y, pScanLineUint8, wd, invert); else if (bpc == 0 && bpc < pImg->channelDepth) UnpackLine(pImg->pScan0 + pImg->stride * y, pScanLineUint8, wd, invert); else memcpy(pImg->pScan0 + pImg->stride * y, pScanLine, scanLen); } return NO_ERRORS; #endif // WITH_TIFF }
int GetTiffPropsEx ( MinImg *pImg, ExtImgProps *pProps, const char *pFileName, int page ) { #ifndef WITH_TIFF return NOT_IMPLEMENTED; #else if (!pFileName || page < 0) return BAD_ARGS; if (pImg && pImg->pScan0) return BAD_ARGS; TIFFSetErrorHandler(NULL); TIFFSetWarningHandler(NULL); scoped_tiff_handle pTIF(TIFFOpen(pFileName, "r")); if (!pTIF) return FILE_ERROR; const int nPages = TIFFNumberOfDirectories(pTIF); if (page >= nPages) return BAD_ARGS; TIFFSetDirectory(pTIF, page); if (pImg) { int nc = 0, typ = PLANARCONFIG_CONTIG; _TIFFGetField(pTIF, TIFFTAG_SAMPLESPERPIXEL, &nc, 1); if (nc > 1) _TIFFGetField(pTIF, TIFFTAG_PLANARCONFIG, &typ, PLANARCONFIG_CONTIG); if (typ != PLANARCONFIG_CONTIG) return NOT_IMPLEMENTED; int wd = 0, ht = 0, bpc = 0; _TIFFGetField(pTIF, TIFFTAG_IMAGEWIDTH, &wd, 0); _TIFFGetField(pTIF, TIFFTAG_IMAGELENGTH, &ht, 0); _TIFFGetField(pTIF, TIFFTAG_BITSPERSAMPLE, &bpc, 0); if (bpc != 1 && bpc & 7) return NOT_IMPLEMENTED; bpc = bpc >> 3; int dtyp = 0; _TIFFGetField(pTIF, TIFFTAG_SAMPLEFORMAT, &dtyp, 0); switch (dtyp) { case 0: case SAMPLEFORMAT_UINT: dtyp = FMT_UINT; break; case SAMPLEFORMAT_INT: dtyp = FMT_INT; break; case SAMPLEFORMAT_IEEEFP: dtyp = FMT_REAL; break; default: return NOT_IMPLEMENTED; } pImg->width = wd; pImg->height = ht; pImg->channels = nc; pImg->channelDepth = bpc; pImg->format = (MinFmt)dtyp; pImg->stride = 0; } if (pProps) { pProps->iff = IFF_TIFF; pProps->comp = IFC_NONE; int compression = 0; _TIFFGetField(pTIF, TIFFTAG_COMPRESSION, &compression, COMPRESSION_NONE); switch(compression) { case COMPRESSION_LZW: pProps->comp = IFC_LZW; break; case COMPRESSION_DEFLATE: pProps->comp = IFC_DEFLATE; break; case COMPRESSION_PACKBITS: pProps->comp = IFC_PACKBITS; break; case COMPRESSION_JPEG: pProps->comp = IFC_JPEG; break; case COMPRESSION_CCITTRLE: pProps->comp = IFC_RLE; break; case COMPRESSION_CCITTFAX3: pProps->comp = IFC_GROUP3; break; case COMPRESSION_CCITTFAX4: pProps->comp = IFC_GROUP4; break; default: pProps->comp = IFC_NONE; } int unit = 0; _TIFFGetField(pTIF, TIFFTAG_XRESOLUTION, &pProps->xDPI, 0.f); _TIFFGetField(pTIF, TIFFTAG_YRESOLUTION, &pProps->yDPI, 0.f); _TIFFGetField(pTIF, TIFFTAG_RESOLUTIONUNIT, &unit, 0); switch (unit) { case RESUNIT_INCH: break; case RESUNIT_CENTIMETER: pProps->xDPI *= 2.54f; pProps->yDPI *= 2.54f; break; default: pProps->xDPI = 0.f; pProps->yDPI = 0.f; } } return NO_ERRORS; #endif // WITH_TIFF }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GError *error = NULL; INIT_I18N (); gegl_init (NULL, NULL); run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; if (strcmp (name, LOAD_PROC) == 0) { const gchar *filename = param[1].data.d_string; TIFF *tif; tif = tiff_open (filename, "r", &error); if (tif) { TiffSelectedPages pages; pages.target = GIMP_PAGE_SELECTOR_TARGET_LAYERS; gimp_get_data (LOAD_PROC, &pages.target); pages.n_pages = pages.o_pages = TIFFNumberOfDirectories (tif); if (pages.n_pages == 0) { g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("TIFF '%s' does not contain any directories"), gimp_filename_to_utf8 (filename)); status = GIMP_PDB_EXECUTION_ERROR; } else { gboolean run_it = FALSE; gint i; if (run_mode != GIMP_RUN_INTERACTIVE) { pages.pages = g_new (gint, pages.n_pages); for (i = 0; i < pages.n_pages; i++) pages.pages[i] = i; run_it = TRUE; } else { gimp_ui_init (PLUG_IN_BINARY, FALSE); } if (pages.n_pages == 1) { pages.pages = g_new0 (gint, pages.n_pages); pages.target = GIMP_PAGE_SELECTOR_TARGET_LAYERS; run_it = TRUE; } if ((! run_it) && (run_mode == GIMP_RUN_INTERACTIVE)) run_it = load_dialog (tif, LOAD_PROC, &pages); if (run_it) { gint32 image; gboolean resolution_loaded = FALSE; gimp_set_data (LOAD_PROC, &pages.target, sizeof (pages.target)); image = load_image (param[1].data.d_string, tif, &pages, &resolution_loaded, &error); g_free (pages.pages); if (image > 0) { GFile *file; GimpMetadata *metadata; file = g_file_new_for_path (param[1].data.d_string); metadata = gimp_image_metadata_load_prepare (image, "image/tiff", file, NULL); if (metadata) { GimpMetadataLoadFlags flags = GIMP_METADATA_LOAD_ALL; if (resolution_loaded) flags &= ~GIMP_METADATA_LOAD_RESOLUTION; gimp_image_metadata_load_finish (image, "image/tiff", metadata, flags, run_mode == GIMP_RUN_INTERACTIVE); g_object_unref (metadata); } g_object_unref (file); *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = image; } else { status = GIMP_PDB_EXECUTION_ERROR; } } else { status = GIMP_PDB_CANCEL; } } TIFFClose (tif); } else { status = GIMP_PDB_EXECUTION_ERROR; } } else if ((strcmp (name, SAVE_PROC) == 0) || (strcmp (name, SAVE2_PROC) == 0)) { /* Plug-in is either file_tiff_save or file_tiff_save2 */ GimpMetadata *metadata; GimpMetadataSaveFlags metadata_flags; GimpParasite *parasite; gint32 image = param[1].data.d_int32; gint32 drawable = param[2].data.d_int32; gint32 orig_image = image; GimpExportReturn export = GIMP_EXPORT_CANCEL; switch (run_mode) { case GIMP_RUN_INTERACTIVE: case GIMP_RUN_WITH_LAST_VALS: gimp_ui_init (PLUG_IN_BINARY, FALSE); export = gimp_export_image (&image, &drawable, "TIFF", GIMP_EXPORT_CAN_HANDLE_RGB | GIMP_EXPORT_CAN_HANDLE_GRAY | GIMP_EXPORT_CAN_HANDLE_INDEXED | GIMP_EXPORT_CAN_HANDLE_ALPHA); if (export == GIMP_EXPORT_CANCEL) { values[0].data.d_status = GIMP_PDB_CANCEL; return; } break; default: break; }
/** * Loads a TIFF file. * * * \param mem: Memory containing the TIFF file. * \param size: Size of the mem buffer. * \param flags: If flags has IB_test set then the file is not actually loaded, * but all other operations take place. * * \return: A newly allocated ImBuf structure if successful, otherwise NULL. */ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { TIFF *image = NULL; ImBuf *ibuf = NULL, *hbuf; ImbTIFFMemFile memFile; uint32 width, height; char *format = NULL; int level; short spp; int ib_depth; /* check whether or not we have a TIFF file */ if (size < IMB_TIFF_NCB) { fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n"); return NULL; } if (imb_is_a_tiff(mem) == 0) return NULL; /* both 8 and 16 bit PNGs are default to standard byte colorspace */ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); image = imb_tiff_client_open(&memFile, mem, size); if (image == NULL) { printf("imb_loadtiff: could not open TIFF IO layer.\n"); return NULL; } /* allocate the image buffer */ TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); ib_depth = (spp == 3) ? 24 : 32; ibuf = IMB_allocImBuf(width, height, ib_depth, 0); if (ibuf) { ibuf->ftype = TIF; } else { fprintf(stderr, "imb_loadtiff: could not allocate memory for TIFF " "image.\n"); TIFFClose(image); return NULL; } /* get alpha mode from file header */ if (flags & IB_alphamode_detect) { if (spp == 4) { unsigned short extra, *extraSampleTypes; TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); if (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA) ibuf->flags |= IB_alphamode_premul; } } /* if testing, we're done */ if (flags & IB_test) { TIFFClose(image); return ibuf; } /* detect if we are reading a tiled/mipmapped texture, in that case * we don't read pixels but leave it to the cache to load tiles */ if (flags & IB_tilecache) { format = NULL; TIFFGetField(image, TIFFTAG_PIXAR_TEXTUREFORMAT, &format); if (format && strcmp(format, "Plain Texture") == 0 && TIFFIsTiled(image)) { int numlevel = TIFFNumberOfDirectories(image); /* create empty mipmap levels in advance */ for (level = 0; level < numlevel; level++) { if (!TIFFSetDirectory(image, level)) break; if (level > 0) { width = (width > 1) ? width / 2 : 1; height = (height > 1) ? height / 2 : 1; hbuf = IMB_allocImBuf(width, height, 32, 0); hbuf->miplevel = level; hbuf->ftype = ibuf->ftype; ibuf->mipmap[level - 1] = hbuf; } else hbuf = ibuf; hbuf->flags |= IB_tilecache; TIFFGetField(image, TIFFTAG_TILEWIDTH, &hbuf->tilex); TIFFGetField(image, TIFFTAG_TILELENGTH, &hbuf->tiley); hbuf->xtiles = ceil(hbuf->x / (float)hbuf->tilex); hbuf->ytiles = ceil(hbuf->y / (float)hbuf->tiley); imb_addtilesImBuf(hbuf); ibuf->miptot++; } } } /* read pixels */ if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image)) { fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n"); TIFFClose(image); return NULL; } /* close the client layer interface to the in-memory file */ TIFFClose(image); /* return successfully */ return ibuf; }
uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int bUseSubIFDs, int nHorSubsampling, int nVerSubsampling ) { uint32 nBaseDirOffset; uint32 nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB ) { TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, nHorSubsampling, nVerSubsampling); /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */ } /* TODO: add command-line parameter for selecting jpeg compression quality * that gets ignored when compression isn't jpeg */ /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 ) return 0; TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
static uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize, int nBitsPerPixel, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int bUseSubIFDs ) { uint32 nBaseDirOffset; uint32 nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ); TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, TIFFNumberOfDirectories(hTIFF)-1 ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
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; }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GError *error = NULL; gint32 image; TiffSelectedPages pages; run_mode = param[0].data.d_int32; INIT_I18N (); *nreturn_vals = 1; *return_vals = values; gegl_init (NULL, NULL); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; TIFFSetWarningHandler (tiff_warning); TIFFSetErrorHandler (tiff_error); if (strcmp (name, LOAD_PROC) == 0) { const gchar *filename = param[1].data.d_string; TIFF *tif = NULL; gint fd; fd = g_open (filename, O_RDONLY | _O_BINARY, 0); if (fd == -1) { g_set_error (&error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); status = GIMP_PDB_EXECUTION_ERROR; } else { tif = TIFFFdOpen (fd, filename, "r"); } if (tif) { gimp_get_data (LOAD_PROC, &target); pages.n_pages = pages.o_pages = TIFFNumberOfDirectories (tif); if (pages.n_pages == 0) { g_set_error (&error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("TIFF '%s' does not contain any directories"), gimp_filename_to_utf8 (filename)); status = GIMP_PDB_EXECUTION_ERROR; } else { gboolean run_it = FALSE; gint i; if (run_mode != GIMP_RUN_INTERACTIVE) { pages.pages = g_new (gint, pages.n_pages); for (i = 0; i < pages.n_pages; i++) pages.pages[i] = i; run_it = TRUE; } if (pages.n_pages == 1) { target = GIMP_PAGE_SELECTOR_TARGET_LAYERS; pages.pages = g_new0 (gint, pages.n_pages); run_it = TRUE; } if ((! run_it) && (run_mode == GIMP_RUN_INTERACTIVE)) run_it = load_dialog (tif, &pages); if (run_it) { gimp_set_data (LOAD_PROC, &target, sizeof (target)); image = load_image (param[1].data.d_string, tif, &pages, &error); g_free (pages.pages); if (image != -1) { *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = image; } else { status = GIMP_PDB_EXECUTION_ERROR; } } else { status = GIMP_PDB_CANCEL; } } TIFFClose (tif); close (fd); } else { close (fd); status = GIMP_PDB_EXECUTION_ERROR; } } else { status = GIMP_PDB_CALLING_ERROR; } if (status != GIMP_PDB_SUCCESS && error) { *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; values[1].data.d_string = error->message; } values[0].data.d_status = status; }
toff_t GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata ) { toff_t nBaseDirOffset; toff_t nOffset; nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */ TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if (panExtraSampleValues != NULL) { TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if ( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
toff_t GTIFFWriteDirectory( TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize, int nBitsPerPixel, int nPlanarConfig, int nSamples, int nBlockXSize, int nBlockYSize, int bTiled, int nCompressFlag, int nPhotometric, int nSampleFormat, int nPredictor, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int nExtraSamples, unsigned short *panExtraSampleValues, const char *pszMetadata, const char* pszJPEGQuality, const char* pszJPEGTablesMode, const char* pszNoData, CPL_UNUSED const uint32* panLercAddCompressionAndVersion ) { const toff_t nBaseDirOffset = TIFFCurrentDirOffset( hTIFF ); // This is a bit of a hack to cause (*tif->tif_cleanup)(tif); to be called. // See https://trac.osgeo.org/gdal/ticket/2055 TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_NONE ); #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 // 3.8.0 TIFFFreeDirectory( hTIFF ); #endif TIFFCreateDirectory( hTIFF ); /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); if( nSamples == 1 ) TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); else TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ); } else { TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize ); } TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType ); if( panExtraSampleValues != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues ); } if( nCompressFlag == COMPRESSION_LZW || nCompressFlag == COMPRESSION_ADOBE_DEFLATE || nCompressFlag == COMPRESSION_ZSTD ) TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write metadata if we have some. */ /* -------------------------------------------------------------------- */ if( pszMetadata && strlen(pszMetadata) > 0 ) TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata ); /* -------------------------------------------------------------------- */ /* Write JPEG tables if needed. */ /* -------------------------------------------------------------------- */ if( nCompressFlag == COMPRESSION_JPEG ) { GTiffWriteJPEGTables( hTIFF, (nPhotometric == PHOTOMETRIC_RGB) ? "RGB" : (nPhotometric == PHOTOMETRIC_YCBCR) ? "YCBCR" : "MINISBLACK", pszJPEGQuality, pszJPEGTablesMode ); if( nPhotometric == PHOTOMETRIC_YCBCR ) { // Explicitly register the subsampling so that JPEGFixupTags // is a no-op (helps for cloud optimized geotiffs) TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 2, 2 ); } } #ifdef HAVE_LERC if( nCompressFlag == COMPRESSION_LERC && panLercAddCompressionAndVersion ) { TIFFSetField(hTIFF, TIFFTAG_LERC_PARAMETERS, 2, panLercAddCompressionAndVersion); } #endif /* -------------------------------------------------------------------- */ /* Write no data value if we have one. */ /* -------------------------------------------------------------------- */ if( pszNoData != nullptr ) { TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, pszNoData ); } /* -------------------------------------------------------------------- */ /* Write directory, and return byte offset. */ /* -------------------------------------------------------------------- */ if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 ) { TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return 0; } TIFFWriteDirectory( hTIFF ); TIFFSetDirectory( hTIFF, static_cast<tdir_t>(TIFFNumberOfDirectories(hTIFF) - 1) ); const toff_t nOffset = TIFFCurrentDirOffset( hTIFF ); TIFFSetSubDirectory( hTIFF, nBaseDirOffset ); return nOffset; }
main(int argc, char* argv[]) { //START; // the required page number in a multipage tiff, use 0 for first page int dir_num; dir_num = atoi(argv[2]); //time_t start, end; double duration; TIFF* tif = TIFFOpen(argv[1], "r"); //get number of pages (Directories) in a tiff file int dir_count; dir_count = TIFFNumberOfDirectories(tif); if(dir_num < 0 || dir_num > (dir_count-1)){ printf("Error: invalid directory number\n"); exit -1; } else{ if (tif) { uint32 w, h; size_t npixels; uint32* raster; // set the required page (directory) // change to the requested directory and read its contents with TIFFReadDirectory TIFFSetDirectory(tif,dir_num); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); npixels = w * h; int r,v; //Foreground and Background pixel values int F = 1, B = 0; size_t c_h, c_w; raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); // image matrix with added boundary pixels int** I = malloc((h+2) * sizeof(int*)); // allocate the rows for ( r = 0; r < (h+2); ++r) { I[r] = malloc((w+2) * sizeof(int)); // allocate the columns //for ( cx = 0; cx < COLS; ++cx) // I[r][cx] = 0; } // an array of pixel runs (hashtable of pixel runs) // each run is a linked list of pixels struct pixel **runs = malloc((h*w/4) * sizeof(struct pixel)); //initialise arrays and linked list for ( v = 0; v < (h*w/4); ++v) { //C[r] = r; // initialise labels init_pixel(runs[v], 99,99); } // arrays to save classes and their mappings //uint32* C = malloc((ROWS*COLS/2) * sizeof(uint32*)); uint32* rl_table = malloc((h*w/4) * sizeof(uint32*)); uint32* n_label = malloc((h*w/4) * sizeof(uint32*)); uint32* t_label = malloc((h*w/4) * sizeof(uint32*)); for ( v = 0; v < (h*w/4); ++v) { //C[r] = r; // initialise classes rl_table[v] = v; n_label[v] = -1; t_label[v] = v; } // load image into matrix of F and B pixels (1's and 0's) if (raster != NULL) { if (TIFFReadRGBAImage(tif, w, h, raster, 0)) { for(c_h=0;c_h<h;c_h++) { for(c_w=0;c_w<w;c_w++) { v = raster[(w*h)-((c_h*w)+(w-c_w))]%256; if (v == 0) I[c_h+1][c_w+1] = F; else I[c_h+1][c_w+1] = B; } } } _TIFFfree(raster); } /* c2 c3 c4 c1 x */ // FIRST SCAN int i,j,k; int NewLabel=5; int c1,c2,c3,c4,uu,vv,ii; for(c_h=1;c_h<(h-1);c_h++) for(c_w=1;c_w<(w-1);c_w++){ // for COLS if (I[c_h][c_w] == F) { c3 = I[c_h-1][c_w] ; if (c3 != B) { I[c_h][c_w] = c3; } else // else1 { c4 = I[c_h-1][c_w+1] ; c1 = I[c_h][c_w-1] ; if (c1 != B) { I[c_h][c_w] = c1; if (c4 != B && c4 != c1) { //printf ("(%d,%d);", c1, c4); //(* resolve c2 c4 *) uu = rl_table[c1]; vv = rl_table[c4]; if(uu<vv){ ii = vv; while(ii != -1){ rl_table[ii] = uu; ii = n_label[ii]; } n_label[t_label[uu]] = vv; t_label[uu] = t_label[vv]; } else{ if(vv<uu){ ii = uu; while(ii != -1){ rl_table[ii] = vv; ii = n_label[ii]; } n_label[t_label[vv]] = uu; t_label[vv] = t_label[uu]; } } } } else // else2 { c2 = I[c_h-1][c_w-1] ; if (c2 != B) { I[c_h][c_w] = c2; if (c4 != B && c4 != c2) { //printf("(%d,%d);\n", c2, c4); //(* resolve c2 c4 *) uu = rl_table[c2]; vv = rl_table[c4]; if(uu<vv){ ii = vv; while(ii != -1){ rl_table[ii] = uu; ii = n_label[ii]; } n_label[t_label[uu]] = vv; t_label[uu] = t_label[vv]; } else{ if(vv<uu){ ii = uu; while(ii != -1){ rl_table[ii] = vv; ii = n_label[ii]; } n_label[t_label[vv]] = uu; t_label[vv] = t_label[uu]; } } } } else if (c4 != B) { I[c_h][c_w] = c4; } else { I[c_h][c_w] = NewLabel; NewLabel=NewLabel+1; } }// else2 }// else1 } } // end for COLS // SECOND SCAN for(c_h=0;c_h<h;c_h++) for(c_w=0;c_w<w;c_w++) // for COLS if (I[c_h][c_w] != B) I[c_h][c_w] = rl_table[I[c_h][c_w]]; //get linked lists of pixels with the same class //i.e. pixels that belong to the same CC for(c_h=0;c_h<h;c_h++){ for(c_w=0;c_w<w;c_w++){ if (I[c_h][c_w] != B) { push(&runs[I[c_h][c_w]], c_w,c_h); } } } //now open a file, find coords of each CC and save them // char *base = get_basename(argv[1]);// = "filename"; char *base = argv[1]; // find location of last '.' in filename to chop extension char *pos = strrchr (base, '.'); int pos1 = pos ? (pos - base ) : -1; if(pos1 != -1){ base[pos1] = 0; // remove file extension //printf("%d, %s\n",pos1, base); } //I'm assuming length of filename doesn't exceed 50 chars //I'll deal with this later char filename[256]; FILE *file; //fname1[strlen(fname1) - 4] = 0; // remove file extension sprintf(filename, "%s-%d.json", base, dir_num); //printf("%s\n", filename); file = fopen(filename,"w+"); fprintf(file,"{\n"); fprintf(file," \"SrcImage\": \"\",\n"); fprintf(file," \"Page\": %d,\n",dir_num); fprintf(file," \"PageWidth\": %d,\n", w); fprintf(file," \"PageHeight\": %d,\n",h); fprintf(file," \"ClipX\": %d,\n",0); fprintf(file," \"ClipY\": %d,\n",0); fprintf(file," \"ClipWidth\": %d,\n", w); fprintf(file," \"ClipHeight\": %d,\n",h); fprintf(file," \"ClipImage\": \"\",\n"); fprintf(file," \"glyphs\": [\n"); //count++; //file = fopen("file.txt","w+"); int len; for ( v = 0; v < (h*w/4); ++v) { len = length(runs[v]); if (len > 0 ){ //printf("run ID: %d, run length %d\n", r, len ); struct bbox* b = find_bbox (runs[v]); //printf("bbox: (%d,%d),(%d,%d)\n", b->x1, b->y1, b->x2, b->y2 ); fprintf(file," { \"x\" : %d, \"y\" : %d, \"w\" : %d, \"h\" : %d }",(b->x1-1),(b->y1-1), (b->x2 - b->x1 + 1), (b->y2 - b->y1 + 1)); fprintf(file, ",\n"); free(runs[v]);// = NULL; free(b); } } // trick by Volker to remove comma after last glyph fseek(file, -( 2*(int)sizeof(char) ), SEEK_CUR); fprintf(file,"\n ]\n"); fprintf(file,"}\n"); // close file fclose(file); //printf("Generated: %s\n",filename); //manually free space allocated to various arrays and matrices for (v = 0; v < h; ++v) { free(I[v]); // this frees the columns } free(I); // this frees the rows free(runs); //free(C); free(rl_table); free(n_label); free(t_label); TIFFClose(tif); }//end if tif } //end else //STOP; //PRINTTIME; }
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) {