/* * 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<(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel;*/ long bitsize = head.biSizeImage*samplesperpixel; if ((bitspersample > 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