X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=utilities%2FCxImage%2Fximatif.cpp;h=6b4e7ad6c8749d2edc782b68260228a95c2251b0;hb=d268b74408bad9a7388c864e01627d8217549bd6;hp=b7415ed1da5d8079b3a62e726051c3e7ca182a7d;hpb=19d5db17f1c0e98cf84a6cb83643404a550a12a4;p=clitk.git diff --git a/utilities/CxImage/ximatif.cpp b/utilities/CxImage/ximatif.cpp index b7415ed..6b4e7ad 100644 --- a/utilities/CxImage/ximatif.cpp +++ b/utilities/CxImage/ximatif.cpp @@ -1,980 +1,980 @@ -/* - * File: ximatif.cpp - * Purpose: Platform Independent TIFF Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximatif.h" - -#if CXIMAGE_SUPPORT_TIF - -#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed - -#include "../tiff/tiffio.h" - -#define CVT(x) (((x) * 255L) / ((1L<<16)-1)) -#define SCALE(x) (((x)*((1L<<16)-1))/255) -#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8) -#define CalculatePitch(line) (line + 3 & ~3) - -extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode); - -//////////////////////////////////////////////////////////////////////////////// -CxImageTIF::~CxImageTIF() -{ - if (m_tif2) TIFFClose(m_tif2); -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -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; // - uint16 res_unit; // - 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"); - - // - 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"); // - 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); // 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){ // - 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< 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< 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) { - 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; - } - if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) - SetPalette(pal,/*head.biClrUsed*/ 1< 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 - bitsize *= (bitspersample + 7)/8; - - int tiled_image = TIFFIsTiled(m_tif); - uint32 tw=0, tl=0; - BYTE* tilebuf=NULL; - 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(bitspersample==16? bitsize*2 : bitsize); // * VK - BYTE * bits16 = NULL; // + VK - int line16 = 0; // + VK - - if (!tiled_image && bitspersample==16) { // + VK + - line16 = line; - line = CalculateLine(width, 8 * samplesperpixel); - bits16 = bits; - bits = (BYTE*)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 - BYTE* row_shifts = NULL; - if (bits16) row_shifts = (BYTE*)malloc(height); -#endif - - for (ys = 0; ys < height; ys += rowsperstrip) { - - if (info.nEscape){ // - 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); - 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); - 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++) { - long offset=(nrow-y-1)*line; - if ((bitspersample==16) && !BIG_palette) { // * VK - long offset16 = (nrow-y-1)*line16; // + VK - if (bits16) { // + VK + -#ifdef FIX_16BPP_DARKIMG - int the_shift; - BYTE hi_byte, hi_max=0; - DWORD 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 (DWORD xi=0;xi<(uint32)line;xi++) - bits[xi+offset]=bits16[xi*2+offset16+1]; -#endif - } else { - for (DWORD xi=0;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; - uint32 ii=0; - int yi=height-ys-nrow+y; - RGBQUAD c; - int l,a,b,bitsoffset; - double p,cx,cy,cz,cr,cg,cb; - while (ii127) 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 (bits16) free(bits16); - -#ifdef FIX_16BPP_DARKIMG - if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { - // 1. calculate maximum necessary shift - int min_row_shift = 8; - for( y=0; y row_shifts[y]) min_row_shift = row_shifts[y]; - } - // 2. for rows having less shift value, correct such rows: - for( y=0; y>= need_shift; - } - } - } - if (row_shifts) free( row_shifts ); -#endif - - if (tiled_image) free(tilebuf); - if (pal) free(pal); - - 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; - } - - } - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (m_tif) TIFFClose(m_tif); - if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true; - return false; - } - TIFFClose(m_tif); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageTIF::Encode(CxFile * hFile, bool bAppend) -{ - cx_try - { - if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE); - if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE); - - // replaced "w+b" with "a", to append an image directly on an existing file - if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a"); - if (m_tif2==NULL) cx_throw("initialization fail"); - - if (bAppend || m_pages) m_multipage=true; - m_pages++; - - if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file"); - if (bAppend) { - if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory"); - } - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (m_tif2){ - TIFFClose(m_tif2); - m_tif2=NULL; - m_multipage=false; - m_pages=0; - } - return false; - } - if (!bAppend){ - TIFFClose(m_tif2); - m_tif2=NULL; - m_multipage=false; - m_pages=0; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// Thanks to Abe -bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int pagecount) -{ - cx_try - { - if (hFile==NULL) cx_throw("invalid file pointer"); - if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!"); - - int i; - for (i=0; iIsValid())) - cx_throw("Empty image"); - } - - CxImageTIF ghost; - for (i=0; i some viewers do not handle PHOTOMETRIC_MINISBLACK: - * let's transform the image in PHOTOMETRIC_MINISWHITE - */ - //invert the colors - RGBQUAD tempRGB=GetPaletteColor(0); - SetPaletteColor(0,GetPaletteColor(1)); - SetPaletteColor(1,tempRGB); - //invert the pixels - BYTE *iSrc=info.pImage; - for (unsigned long i=0;irgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){ - photometric = PHOTOMETRIC_PALETTE; - break; - } - rgb++; - } - break; - case 24: - case 32: - photometric = PHOTOMETRIC_RGB; - break; - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer -#endif //CXIMAGE_SUPPORT_ALPHA - -// line = CalculateLine(width, bitspersample * samplesperpixel); -// pitch = (uint16)CalculatePitch(line); - - //prepare the palette struct - RGBQUAD pal[256]; - if (GetPalette()){ - BYTE b; - memcpy(pal,GetPalette(),GetPaletteSize()); - for(WORD a=0;a gives better compression - TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); - - // handle metrics - TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI); - TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI); -// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset); -// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset); - - // multi-paging - Thanks to Abe - if (multipage) - { - char page_number[20]; - sprintf(page_number, "Page %d", page); - - TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount); - TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number); - } else { - TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0); - } - - // palettes (image colormaps are automatically scaled to 16-bits) - if (photometric == PHOTOMETRIC_PALETTE) { - uint16 *r, *g, *b; - r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256); - g = r + 256; - b = g + 256; - - for (int i = 255; i >= 0; i--) { - b[i] = (uint16)SCALE((uint16)pal[i].rgbRed); - g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen); - r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue); - } - - TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b); - _TIFFfree(r); - } - - // compression - if (GetCodecOption(CXIMAGE_FORMAT_TIF)) { - compression = (WORD)GetCodecOption(CXIMAGE_FORMAT_TIF); - } else { - switch (bitcount) { - case 1 : - compression = COMPRESSION_CCITTFAX4; - break; - case 4 : - case 8 : - compression = COMPRESSION_LZW; - break; - case 24 : - case 32 : - compression = COMPRESSION_JPEG; - break; - default : - compression = COMPRESSION_NONE; - break; - } - } - TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression); - - switch (compression) { - case COMPRESSION_JPEG: - TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality()); - TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3); - break; - case COMPRESSION_LZW: - if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2); - break; - } - - // read the DIB lines from bottom to top and save them in the TIF - - BYTE *bits; - switch(bitcount) { - case 1 : - case 4 : - case 8 : - { - if (samplesperpixel==1){ - bits = (BYTE*)malloc(info.dwEffWidth); - if (!bits) return false; - for (y = 0; y < height; y++) { - memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth); - if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){ - free(bits); - return false; - } - } - free(bits); - } -#if CXIMAGE_SUPPORT_ALPHA - else { //8bpp + alpha layer - bits = (BYTE*)malloc(2*width); - if (!bits) return false; - for (y = 0; y < height; y++) { - for (x=0;x 0) { - uint32 j = cols; - while (j-- > 0) - *out++ = *in++; - out += outskew; - in += inskew; - } -} -//////////////////////////////////////////////////////////////////////////////// -TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile) -{ - if (hFile) return _TIFFOpenEx(hFile, "rb"); - return NULL; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::TIFFCloseEx(TIFF* tif) -{ - if (tif) TIFFClose(tif); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::MoveBits( BYTE* dest, BYTE* from, int count, int bpp ) -{ int offbits = 0; - uint16 w; - uint32 d; - if (bpp <= 8) { - while (count-- > 0) { - if (offbits + bpp <= 8) - w = *from >> (8 - offbits - bpp); - else { - w = *from++ << (offbits + bpp - 8); - w |= *from >> (16 - offbits - bpp); - } - offbits += bpp; - if (offbits >= 8) { - offbits -= 8; - if (offbits == 0) from++; - } - *dest++ = (BYTE)w & ((1 << bpp)-1); - } - } else if (bpp < 16) { - while (count-- > 0) { - d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; - d >>= (24 - offbits); - *dest++ = (BYTE) ( d ); - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } - } else if (bpp < 32) { - while (count-- > 0) { - d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; - //d = *(uint32*)from; - *dest++ = (BYTE) ( d >> (offbits + bpp - 8) ); - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } - } else { - while (count-- > 0) { - d = *(uint32*)from; - *dest++ = (BYTE) (d >> 24); - from += 4; - } - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ) -{ int offbits = 0; - uint32 d; - uint16 palidx; - while (count-- > 0) { - d = (*from << 24) | ( *( from + 1 ) << 16 ) - | ( *( from + 2 ) << 8 ) - | ( *( from + 3 ) ); - palidx = (uint16) (d >> (32 - offbits - bpp)); - if (bpp < 16) { - palidx <<= 16-bpp; - palidx = (palidx >> 8) | (palidx <<8); - palidx >>= 16-bpp; - } else palidx = (palidx >> 8) | (palidx << 8); - *dest++ = pal[palidx].rgbBlue; - *dest++ = pal[palidx].rgbGreen; - *dest++ = pal[palidx].rgbRed; - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } -} -//////////////////////////////////////////////////////////////////////////////// - -#endif // CXIMAGE_SUPPORT_TIF +/* + * File: ximatif.cpp + * Purpose: Platform Independent TIFF Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximatif.h" + +#if CXIMAGE_SUPPORT_TIF + +#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed + +#include "../tiff/tiffio.h" + +#define CVT(x) (((x) * 255L) / ((1L<<16)-1)) +#define SCALE(x) (((x)*((1L<<16)-1))/255) +#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8) +#define CalculatePitch(line) (line + 3 & ~3) + +extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode); + +//////////////////////////////////////////////////////////////////////////////// +CxImageTIF::~CxImageTIF() +{ + if (m_tif2) TIFFClose(m_tif2); +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +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; // + uint16 res_unit; // + 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"); + + // - 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"); // - 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); // 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){ // - 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< 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< 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) { + 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; + } + if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) + SetPalette(pal,/*head.biClrUsed*/ 1< 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 + bitsize *= (bitspersample + 7)/8; + + int tiled_image = TIFFIsTiled(m_tif); + uint32 tw=0, tl=0; + BYTE* tilebuf=NULL; + 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(bitspersample==16? bitsize*2 : bitsize); // * VK + BYTE * bits16 = NULL; // + VK + int line16 = 0; // + VK + + if (!tiled_image && bitspersample==16) { // + VK + + line16 = line; + line = CalculateLine(width, 8 * samplesperpixel); + bits16 = bits; + bits = (BYTE*)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 + BYTE* row_shifts = NULL; + if (bits16) row_shifts = (BYTE*)malloc(height); +#endif + + for (ys = 0; ys < height; ys += rowsperstrip) { + + if (info.nEscape){ // - 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); + 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); + 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++) { + long offset=(nrow-y-1)*line; + if ((bitspersample==16) && !BIG_palette) { // * VK + long offset16 = (nrow-y-1)*line16; // + VK + if (bits16) { // + VK + +#ifdef FIX_16BPP_DARKIMG + int the_shift; + BYTE hi_byte, hi_max=0; + DWORD 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 (DWORD xi=0;xi<(uint32)line;xi++) + bits[xi+offset]=bits16[xi*2+offset16+1]; +#endif + } else { + for (DWORD xi=0;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; + uint32 ii=0; + int yi=height-ys-nrow+y; + RGBQUAD c; + int l,a,b,bitsoffset; + double p,cx,cy,cz,cr,cg,cb; + while (ii127) 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 (bits16) free(bits16); + +#ifdef FIX_16BPP_DARKIMG + if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { + // 1. calculate maximum necessary shift + int min_row_shift = 8; + for( y=0; y row_shifts[y]) min_row_shift = row_shifts[y]; + } + // 2. for rows having less shift value, correct such rows: + for( y=0; y>= need_shift; + } + } + } + if (row_shifts) free( row_shifts ); +#endif + + if (tiled_image) free(tilebuf); + if (pal) free(pal); + + 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; + } + + } + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (m_tif) TIFFClose(m_tif); + if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true; + return false; + } + TIFFClose(m_tif); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageTIF::Encode(CxFile * hFile, bool bAppend) +{ + cx_try + { + if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE); + if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE); + + // replaced "w+b" with "a", to append an image directly on an existing file + if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a"); + if (m_tif2==NULL) cx_throw("initialization fail"); + + if (bAppend || m_pages) m_multipage=true; + m_pages++; + + if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file"); + if (bAppend) { + if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory"); + } + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (m_tif2){ + TIFFClose(m_tif2); + m_tif2=NULL; + m_multipage=false; + m_pages=0; + } + return false; + } + if (!bAppend){ + TIFFClose(m_tif2); + m_tif2=NULL; + m_multipage=false; + m_pages=0; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// Thanks to Abe +bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int pagecount) +{ + cx_try + { + if (hFile==NULL) cx_throw("invalid file pointer"); + if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!"); + + int i; + for (i=0; iIsValid())) + cx_throw("Empty image"); + } + + CxImageTIF ghost; + for (i=0; i some viewers do not handle PHOTOMETRIC_MINISBLACK: + * let's transform the image in PHOTOMETRIC_MINISWHITE + */ + //invert the colors + RGBQUAD tempRGB=GetPaletteColor(0); + SetPaletteColor(0,GetPaletteColor(1)); + SetPaletteColor(1,tempRGB); + //invert the pixels + BYTE *iSrc=info.pImage; + for (unsigned long i=0;irgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){ + photometric = PHOTOMETRIC_PALETTE; + break; + } + rgb++; + } + break; + case 24: + case 32: + photometric = PHOTOMETRIC_RGB; + break; + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer +#endif //CXIMAGE_SUPPORT_ALPHA + +// line = CalculateLine(width, bitspersample * samplesperpixel); +// pitch = (uint16)CalculatePitch(line); + + //prepare the palette struct + RGBQUAD pal[256]; + if (GetPalette()){ + BYTE b; + memcpy(pal,GetPalette(),GetPaletteSize()); + for(WORD a=0;a gives better compression + TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + // handle metrics + TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI); + TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI); +// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset); +// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset); + + // multi-paging - Thanks to Abe + if (multipage) + { + char page_number[20]; + sprintf(page_number, "Page %d", page); + + TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount); + TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number); + } else { + TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0); + } + + // palettes (image colormaps are automatically scaled to 16-bits) + if (photometric == PHOTOMETRIC_PALETTE) { + uint16 *r, *g, *b; + r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256); + g = r + 256; + b = g + 256; + + for (int i = 255; i >= 0; i--) { + b[i] = (uint16)SCALE((uint16)pal[i].rgbRed); + g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen); + r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue); + } + + TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b); + _TIFFfree(r); + } + + // compression + if (GetCodecOption(CXIMAGE_FORMAT_TIF)) { + compression = (WORD)GetCodecOption(CXIMAGE_FORMAT_TIF); + } else { + switch (bitcount) { + case 1 : + compression = COMPRESSION_CCITTFAX4; + break; + case 4 : + case 8 : + compression = COMPRESSION_LZW; + break; + case 24 : + case 32 : + compression = COMPRESSION_JPEG; + break; + default : + compression = COMPRESSION_NONE; + break; + } + } + TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression); + + switch (compression) { + case COMPRESSION_JPEG: + TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality()); + TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3); + break; + case COMPRESSION_LZW: + if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2); + break; + } + + // read the DIB lines from bottom to top and save them in the TIF + + BYTE *bits; + switch(bitcount) { + case 1 : + case 4 : + case 8 : + { + if (samplesperpixel==1){ + bits = (BYTE*)malloc(info.dwEffWidth); + if (!bits) return false; + for (y = 0; y < height; y++) { + memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth); + if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){ + free(bits); + return false; + } + } + free(bits); + } +#if CXIMAGE_SUPPORT_ALPHA + else { //8bpp + alpha layer + bits = (BYTE*)malloc(2*width); + if (!bits) return false; + for (y = 0; y < height; y++) { + for (x=0;x 0) { + uint32 j = cols; + while (j-- > 0) + *out++ = *in++; + out += outskew; + in += inskew; + } +} +//////////////////////////////////////////////////////////////////////////////// +TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile) +{ + if (hFile) return _TIFFOpenEx(hFile, "rb"); + return NULL; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::TIFFCloseEx(TIFF* tif) +{ + if (tif) TIFFClose(tif); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::MoveBits( BYTE* dest, BYTE* from, int count, int bpp ) +{ int offbits = 0; + uint16 w; + uint32 d; + if (bpp <= 8) { + while (count-- > 0) { + if (offbits + bpp <= 8) + w = *from >> (8 - offbits - bpp); + else { + w = *from++ << (offbits + bpp - 8); + w |= *from >> (16 - offbits - bpp); + } + offbits += bpp; + if (offbits >= 8) { + offbits -= 8; + if (offbits == 0) from++; + } + *dest++ = (BYTE)w & ((1 << bpp)-1); + } + } else if (bpp < 16) { + while (count-- > 0) { + d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; + d >>= (24 - offbits); + *dest++ = (BYTE) ( d ); + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } + } else if (bpp < 32) { + while (count-- > 0) { + d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; + //d = *(uint32*)from; + *dest++ = (BYTE) ( d >> (offbits + bpp - 8) ); + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } + } else { + while (count-- > 0) { + d = *(uint32*)from; + *dest++ = (BYTE) (d >> 24); + from += 4; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ) +{ int offbits = 0; + uint32 d; + uint16 palidx; + while (count-- > 0) { + d = (*from << 24) | ( *( from + 1 ) << 16 ) + | ( *( from + 2 ) << 8 ) + | ( *( from + 3 ) ); + palidx = (uint16) (d >> (32 - offbits - bpp)); + if (bpp < 16) { + palidx <<= 16-bpp; + palidx = (palidx >> 8) | (palidx <<8); + palidx >>= 16-bpp; + } else palidx = (palidx >> 8) | (palidx << 8); + *dest++ = pal[palidx].rgbBlue; + *dest++ = pal[palidx].rgbGreen; + *dest++ = pal[palidx].rgbRed; + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } +} +//////////////////////////////////////////////////////////////////////////////// + +#endif // CXIMAGE_SUPPORT_TIF