//////////////////////////////////////////////////////////////////////////////// // Global object (clipboard paste) constructor // § the clipboard format must be CF_DIB. // > hMem: source bitmap object bool CxImage::CreateFromHANDLE(HANDLE hMem) { if (pDib) {free(pDib); pDib=NULL;} BYTE *lpVoid; //pointer to the bitmap lpVoid = (BYTE *)GlobalLock(hMem); BITMAPINFOHEADER *pHead; //pointer to the bitmap header pHead = (BITMAPINFOHEADER *)lpVoid; if (lpVoid){ //copy the bitmap header memcpy(&head,pHead,sizeof(BITMAPINFOHEADER)); //create the image if(!Create(head.biWidth,head.biHeight,head.biBitCount)){ GlobalUnlock(lpVoid); return false; } //preserve DPI if (head.biXPelsPerMeter) SetXDPI((long)floor(head.biXPelsPerMeter * 254.0 / 10000.0 + 0.5)); else SetXDPI(96); if (head.biYPelsPerMeter) SetYDPI((long)floor(head.biYPelsPerMeter * 254.0 / 10000.0 + 0.5)); else SetYDPI(96); //copy the pixels if((pHead->biCompression != BI_RGB) || (pHead->biBitCount == 32)){ //<Jörgen Alfredsson> // BITFIELD case // set the internal header in the dib memcpy(pDib,&head,sizeof(head)); // get the bitfield masks DWORD bf[3]; memcpy(bf,lpVoid+pHead->biSize,12); // transform into RGB Bitfield2RGB(lpVoid+pHead->biSize+12,(WORD)bf[0],(WORD)bf[1],(WORD)bf[2],(BYTE)pHead->biBitCount); } else { //normal bitmap memcpy(pDib,lpVoid,GetSize()); } GlobalUnlock(lpVoid); return true; } return false; }
bool CxImageJPG::Decode(CxFile * hFile) { bool is_exif = false; #if CXIMAGEJPG_SUPPORT_EXIF is_exif = DecodeExif(hFile); #endif CImageIterator iter(this); /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. <CSC> */ struct ima_error_mgr jerr; jerr.buffer=info.szLastError; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = ima_jpeg_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); return 0; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ //jpeg_stdio_src(&cinfo, infile); CxFileJpg src(hFile); cinfo.src = &src; /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* Step 4 <chupeev> handle decoder options*/ if ((GetCodecOption() & DECODE_GRAYSCALE) != 0) cinfo.out_color_space = JCS_GRAYSCALE; if ((GetCodecOption() & DECODE_QUANTIZE) != 0) { cinfo.quantize_colors = TRUE; cinfo.desired_number_of_colors = info.nQuality; } if ((GetCodecOption() & DECODE_DITHER) != 0) cinfo.dither_mode = m_nDither; if ((GetCodecOption() & DECODE_ONEPASS) != 0) cinfo.two_pass_quantize = FALSE; if ((GetCodecOption() & DECODE_NOSMOOTH) != 0) cinfo.do_fancy_upsampling = FALSE; //<DP>: Load true color images as RGB (no quantize) /* Step 4: set parameters for decompression */ /* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) { * cinfo.quantize_colors = TRUE; * cinfo.desired_number_of_colors = 128; *} */ //</DP> // Set the scale <ignacio> cinfo.scale_denom = info.nScale; // Borrowed the idea from GIF implementation <ignacio> if (info.nEscape == -1) { // Return output dimensions only jpeg_calc_output_dimensions(&cinfo); head.biWidth = cinfo.output_width; head.biHeight = cinfo.output_height; jpeg_destroy_decompress(&cinfo); return true; } /* Step 5: Start decompressor */ jpeg_start_decompress(&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. */ //Create the image using output dimensions <ignacio> //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); if (!pDib) longjmp(jerr.setjmp_buffer, 1); //<DP> check if the image has been created if (is_exif){ #if CXIMAGEJPG_SUPPORT_EXIF if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit)); if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit)); #endif } else { if (cinfo.density_unit==2){ SetXDPI((long)floor(cinfo.X_density * 254.0 / 10000.0 + 0.5)); SetYDPI((long)floor(cinfo.Y_density * 254.0 / 10000.0 + 0.5)); } else { SetXDPI(cinfo.X_density); SetYDPI(cinfo.Y_density); } } if (cinfo.out_color_space==JCS_GRAYSCALE){ SetGrayPalette(); head.biClrUsed =256; } else { if (cinfo.quantize_colors==TRUE){ SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]); head.biClrUsed=cinfo.actual_number_of_colors; } else { head.biClrUsed=0; } } /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ iter.Upset(); while (cinfo.output_scanline < cinfo.output_height) { if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding (void) jpeg_read_scanlines(&cinfo, buffer, 1); // info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height); //<DP> Step 6a: CMYK->RGB */ if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){ BYTE k,*dst,*src; dst=iter.GetRow(); src=buffer[0]; for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){ k=src[x4+3]; dst[x3] =(BYTE)((k * src[x4+2])/255); dst[x3+1]=(BYTE)((k * src[x4+1])/255); dst[x3+2]=(BYTE)((k * src[x4+0])/255); } } else { /* Assume put_scanline_someplace wants a pointer and sample count. */ iter.SetRow(buffer[0], row_stride); } iter.PrevRow(); } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ //<DP> Step 7A: Swap red and blue components // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison> if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){ BYTE* r0=GetBits(); for(long y=0;y<head.biHeight;y++){ if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding RGBtoBGR(r0,3*head.biWidth); r0+=info.dwEffWidth; } } /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ return true; }
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 CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) throw "Error: page not present in TIFF file"; //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; throw "output dimensions returned"; } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } } if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) throw "CxImageTIF can't create image"; #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); throw "Cancelled"; } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/(head.biClrUsed-1))); } } else { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/(head.biClrUsed-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,head.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); long bitsize= TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel; int tiled_image = TIFFIsTiled(m_tif); uint32 tw, tl; BYTE* tilebuf; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); } bits = (BYTE*)malloc(bitsize); if (bits==NULL){ throw "CxImageTIF can't allocate memory"; } for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); throw "Cancelled"; } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); throw "Corrupted tiled TIFF file!"; } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } } for (y = 0; y < nrow; y++) { long offset=(nrow-y-1)*line; if (bitspersample==16) for (DWORD xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; if (samplesperpixel==1) { //simple 8bpp image memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth); } else if (samplesperpixel==2) { //8bpp image with alpha layer int xi=0; int ii=0; int yi=height-ys-nrow+y; while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int xi=0; int ii=0; int yi=height-ys-nrow+y; RGBQUAD c; int l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii<line){ bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int)width){ yi--; xi=0; } } } } } free(bits); if (tiled_image) free(tilebuf); switch(orientation){ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ Mirror(); break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ Flip(); Mirror(); break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ Flip(); break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ RotateRight(); Mirror(); break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ RotateLeft(); break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ RotateLeft(); Mirror(); break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ RotateRight(); break; } } } catch (char *message) { strncpy(info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); if (info.nEscape==-1) return true; return false; } TIFFClose(m_tif); return true; }
bool 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) {