//////////////////////////////////////////////////////////////////////////////// // HistogramLog function by <dave> : dave(at)posortho(dot)com bool CxImage::HistogramLog() { if (!pDib) return false; //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|); int x, y, i; RGBQUAD color; RGBQUAD yuvClr; unsigned int YVal, high = 1; // Find Highest Luminance Value in the Image if( head.biClrUsed == 0 ){ // No Palette for(y=0; y < head.biHeight; y++){ info.nProgress = (long)(50*y/head.biHeight); for(x=0; x < head.biWidth; x++){ color = GetPixelColor( x, y ); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if (YVal > high ) high = YVal; } } } else { // Palette for(i = 0; i < (int)head.biClrUsed; i++){ color = GetPaletteColor((BYTE)i); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if (YVal > high ) high = YVal; } } // Logarithm Operator double k = 255.0 / ::log( 1.0 + (double)high ); if( head.biClrUsed == 0 ){ for( y = 0; y < head.biHeight; y++ ){ info.nProgress = (long)(50+50*y/head.biHeight); for( x = 0; x < head.biWidth; x++ ){ color = GetPixelColor( x, y ); yuvClr = RGBtoYUV( color ); yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); color = YUVtoRGB( yuvClr ); SetPixelColor( x, y, color ); } } } else { for(i = 0; i < (int)head.biClrUsed; i++){ color = GetPaletteColor( (BYTE)i ); yuvClr = RGBtoYUV( color ); yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); color = YUVtoRGB( yuvClr ); SetPaletteColor( (BYTE)i, color ); } } return true; }
/** * Resets the alpha palette */ void CxImage::AlphaPaletteClear() { RGBQUAD c; for(WORD ip=0; ip<head.biClrUsed;ip++){ c=GetPaletteColor((BYTE)ip); c.rgbReserved=0; SetPaletteColor((BYTE)ip,c); } }
/** * Resets the alpha palette */ void CxImage::AlphaPaletteClear() { RGBQUAD c; for(uint16_t ip=0; ip<head.biClrUsed;ip++){ c=GetPaletteColor((uint8_t)ip); c.rgbReserved=0; SetPaletteColor((uint8_t)ip,c); } }
//////////////////////////////////////////////////////////////////////////////// // HistogramRoot function by <dave> : dave(at)posortho(dot)com bool CxImage::HistogramRoot() { if (!pDib) return false; //q(i,j) = sqrt(|p(i,j)|); int x, y, i; RGBQUAD color; RGBQUAD yuvClr; double dtmp; unsigned int YVal, high = 1; // Find Highest Luminance Value in the Image if( head.biClrUsed == 0 ){ // No Palette for(y=0; y < head.biHeight; y++){ info.nProgress = (long)(50*y/head.biHeight); if (info.nEscape) break; for(x=0; x < head.biWidth; x++){ color = BlindGetPixelColor( x, y ); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if (YVal > high ) high = YVal; } } } else { // Palette for(i = 0; i < (int)head.biClrUsed; i++){ color = GetPaletteColor((BYTE)i); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if (YVal > high ) high = YVal; } } // Root Operator double k = 128.0 / ::log( 1.0 + (double)high ); if( head.biClrUsed == 0 ){ for( y = 0; y < head.biHeight; y++ ){ info.nProgress = (long)(50+50*y/head.biHeight); if (info.nEscape) break; for( x = 0; x < head.biWidth; x++ ){ color = BlindGetPixelColor( x, y ); yuvClr = RGBtoYUV( color ); dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); if ( dtmp > 255.0 ) dtmp = 255.0; if ( dtmp < 0 ) dtmp = 0; yuvClr.rgbRed = (BYTE)dtmp; color = YUVtoRGB( yuvClr ); BlindSetPixelColor( x, y, color ); } } } else { for(i = 0; i < (int)head.biClrUsed; i++){ color = GetPaletteColor( (BYTE)i ); yuvClr = RGBtoYUV( color ); dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); if ( dtmp > 255.0 ) dtmp = 255.0; if ( dtmp < 0 ) dtmp = 0; yuvClr.rgbRed = (BYTE)dtmp; color = YUVtoRGB( yuvClr ); SetPaletteColor( (BYTE)i, color ); } } return true; }
//////////////////////////////////////////////////////////////////////////////// // HistogramNormalize function by <dave> : dave(at)posortho(dot)com bool CxImage::HistogramNormalize() { if (!pDib) return false; int histogram[256]; int threshold_intensity, intense; int x, y, i; unsigned int normalize_map[256]; unsigned int high, low, YVal; RGBQUAD color; RGBQUAD yuvClr; memset( &histogram, 0, sizeof( int ) * 256 ); memset( &normalize_map, 0, sizeof( unsigned int ) * 256 ); // form histogram for(y=0; y < head.biHeight; y++){ info.nProgress = (long)(50*y/head.biHeight); if (info.nEscape) break; for(x=0; x < head.biWidth; x++){ color = BlindGetPixelColor( x, y ); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); histogram[YVal]++; } } // find histogram boundaries by locating the 1 percent levels threshold_intensity = ( head.biWidth * head.biHeight) / 100; intense = 0; for( low = 0; low < 255; low++ ){ intense += histogram[low]; if( intense > threshold_intensity ) break; } intense = 0; for( high = 255; high != 0; high--){ intense += histogram[ high ]; if( intense > threshold_intensity ) break; } if ( low == high ){ // Unreasonable contrast; use zero threshold to determine boundaries. threshold_intensity = 0; intense = 0; for( low = 0; low < 255; low++){ intense += histogram[low]; if( intense > threshold_intensity ) break; } intense = 0; for( high = 255; high != 0; high-- ){ intense += histogram [high ]; if( intense > threshold_intensity ) break; } } if( low == high ) return false; // zero span bound // Stretch the histogram to create the normalized image mapping. for(i = 0; i <= 255; i++){ if ( i < (int) low ){ normalize_map[i] = 0; } else { if(i > (int) high) normalize_map[i] = 255; else normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low ); } } // Normalize if( head.biClrUsed == 0 ){ for( y = 0; y < head.biHeight; y++ ){ info.nProgress = (long)(50+50*y/head.biHeight); if (info.nEscape) break; for( x = 0; x < head.biWidth; x++ ){ color = BlindGetPixelColor( x, y ); yuvClr = RGBtoYUV( color ); yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; color = YUVtoRGB( yuvClr ); BlindSetPixelColor( x, y, color ); } } } else { for(i = 0; i < (int)head.biClrUsed; i++){ color = GetPaletteColor( (BYTE)i ); yuvClr = RGBtoYUV( color ); yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; color = YUVtoRGB( yuvClr ); SetPaletteColor( (BYTE)i, color ); } } return true; }
//////////////////////////////////////////////////////////////////////////////// // HistogramEqualize function by <dave> : dave(at)posortho(dot)com bool CxImage::HistogramEqualize() { if (!pDib) return false; int histogram[256]; int map[256]; int equalize_map[256]; int x, y, i, j; RGBQUAD color; RGBQUAD yuvClr; unsigned int YVal, high, low; memset( &histogram, 0, sizeof(int) * 256 ); memset( &map, 0, sizeof(int) * 256 ); memset( &equalize_map, 0, sizeof(int) * 256 ); // form histogram for(y=0; y < head.biHeight; y++){ info.nProgress = (long)(50*y/head.biHeight); if (info.nEscape) break; for(x=0; x < head.biWidth; x++){ color = BlindGetPixelColor( x, y ); YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); histogram[YVal]++; } } // integrate the histogram to get the equalization map. j = 0; for(i=0; i <= 255; i++){ j += histogram[i]; map[i] = j; } // equalize low = map[0]; high = map[255]; if (low == high) return false; for( i = 0; i <= 255; i++ ){ equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) ); } // stretch the histogram if(head.biClrUsed == 0){ // No Palette for( y = 0; y < head.biHeight; y++ ){ info.nProgress = (long)(50+50*y/head.biHeight); if (info.nEscape) break; for( x = 0; x < head.biWidth; x++ ){ color = BlindGetPixelColor( x, y ); yuvClr = RGBtoYUV(color); yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; color = YUVtoRGB(yuvClr); BlindSetPixelColor( x, y, color ); } } } else { // Palette for( i = 0; i < (int)head.biClrUsed; i++ ){ color = GetPaletteColor((BYTE)i); yuvClr = RGBtoYUV(color); yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; color = YUVtoRGB(yuvClr); SetPaletteColor( (BYTE)i, color ); } } return true; }
/** * HistogramStretch * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels. * \return true if everything is ok * \author [dave] and [nipper] */ bool CxImage::HistogramStretch(long method) { if (!pDib) return false; if ((head.biBitCount==8) && IsGrayScale()){ // get min/max info BYTE minc = 255, maxc = 0; BYTE gray; long y; double dbScaler = 50.0/head.biHeight; for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); for (long x=0; x<head.biWidth; x++) { gray = GetPixelIndex(x, y); if (gray < minc) minc = gray; if (gray > maxc) maxc = gray; } } if (minc == 0 && maxc == 255) return true; // calculate LUT BYTE lut[256]; BYTE range = maxc - minc; if (range != 0){ for (long x = minc; x <= maxc; x++){ lut[x] = (BYTE)(255 * (x - minc) / range); } } else lut[minc] = minc; for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(50.0+y*dbScaler); for (long x=0; x<head.biWidth; x++) { SetPixelIndex(x, y, lut[GetPixelIndex(x, y)]); } } } else { switch(method){ case 1: { // <nipper> // get min/max info BYTE minc = 255, maxc = 0; RGBQUAD color; long y; for (y=0; y<head.biHeight; y++) { for (long x=0; x<head.biWidth; x++) { color = GetPixelColor(x, y); if (color.rgbRed < minc) minc = color.rgbRed; if (color.rgbBlue < minc) minc = color.rgbBlue; if (color.rgbGreen < minc) minc = color.rgbGreen; if (color.rgbRed > maxc) maxc = color.rgbRed; if (color.rgbBlue > maxc) maxc = color.rgbBlue; if (color.rgbGreen > maxc) maxc = color.rgbGreen; } } if (minc == 0 && maxc == 255) return true; // calculate LUT BYTE lut[256]; BYTE range = maxc - minc; if (range != 0){ for (long x = minc; x <= maxc; x++){ lut[x] = (BYTE)(255 * (x - minc) / range); } } else lut[minc] = minc; // normalize image double dbScaler = 100.0/head.biHeight; for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); for (long x=0; x<head.biWidth; x++) { color = GetPixelColor(x, y); color.rgbRed = lut[color.rgbRed]; color.rgbBlue = lut[color.rgbBlue]; color.rgbGreen = lut[color.rgbGreen]; SetPixelColor(x, y, color); } } } break; case 2: { // <nipper> // get min/max info BYTE minR = 255, maxR = 0; BYTE minG = 255, maxG = 0; BYTE minB = 255, maxB = 0; RGBQUAD color; long y; for (y=0; y<head.biHeight; y++) { for (long x=0; x<head.biWidth; x++) { color = GetPixelColor(x, y); if (color.rgbRed < minR) minR = color.rgbRed; if (color.rgbBlue < minB) minB = color.rgbBlue; if (color.rgbGreen < minG) minG = color.rgbGreen; if (color.rgbRed > maxR) maxR = color.rgbRed; if (color.rgbBlue > maxB) maxB = color.rgbBlue; if (color.rgbGreen > maxG) maxG = color.rgbGreen; } } if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255) return true; // calculate LUT BYTE lutR[256]; BYTE range = maxR - minR; if (range != 0) { for (long x = minR; x <= maxR; x++){ lutR[x] = (BYTE)(255 * (x - minR) / range); } } else lutR[minR] = minR; BYTE lutG[256]; range = maxG - minG; if (range != 0) { for (long x = minG; x <= maxG; x++){ lutG[x] = (BYTE)(255 * (x - minG) / range); } } else lutG[minG] = minG; BYTE lutB[256]; range = maxB - minB; if (range != 0) { for (long x = minB; x <= maxB; x++){ lutB[x] = (BYTE)(255 * (x - minB) / range); } } else lutB[minB] = minB; // normalize image double dbScaler = 100.0/head.biHeight; for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); for (long x=0; x<head.biWidth; x++) { color = GetPixelColor(x, y); color.rgbRed = lutR[color.rgbRed]; color.rgbBlue = lutB[color.rgbBlue]; color.rgbGreen = lutG[color.rgbGreen]; SetPixelColor(x, y, color); } } } break; default: { // <dave> // S = ( R - C ) ( B - A / D - C ) double alimit = 0.0; double blimit = 255.0; double lowerc = 255.0; double upperd = 0.0; double tmpGray; RGBQUAD color; RGBQUAD yuvClr; double stretcheds; if ( head.biClrUsed == 0 ){ long x, y, xmin, xmax, ymin, ymax; xmin = ymin = 0; xmax = head.biWidth; ymax = head.biHeight; for( y = ymin; y < ymax; y++ ){ info.nProgress = (long)(50*y/ymax); for( x = xmin; x < xmax; x++ ){ color = GetPixelColor( x, y ); tmpGray = RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if ( tmpGray < lowerc ) lowerc = tmpGray; if ( tmpGray > upperd ) upperd = tmpGray; } } if (upperd==lowerc) return false; for( y = ymin; y < ymax; y++ ){ info.nProgress = (long)(50+50*y/ymax); for( x = xmin; x < xmax; x++ ){ color = GetPixelColor( x, y ); yuvClr = RGBtoYUV(color); // Stretch Luminance tmpGray = (double)yuvClr.rgbRed; stretcheds = (double)(tmpGray - lowerc) * ( (blimit - alimit) / (upperd - lowerc) ); // + alimit; if ( stretcheds < 0.0 ) stretcheds = 0.0; else if ( stretcheds > 255.0 ) stretcheds = 255.0; yuvClr.rgbRed = (BYTE)stretcheds; color = YUVtoRGB(yuvClr); SetPixelColor( x, y, color ); } } } else { DWORD j; for( j = 0; j < head.biClrUsed; j++ ){ color = GetPaletteColor( (BYTE)j ); tmpGray = RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if ( tmpGray < lowerc ) lowerc = tmpGray; if ( tmpGray > upperd ) upperd = tmpGray; } if (upperd==lowerc) return false; for( j = 0; j < head.biClrUsed; j++ ){ color = GetPaletteColor( (BYTE)j ); yuvClr = RGBtoYUV( color ); // Stretch Luminance tmpGray = (double)yuvClr.rgbRed; stretcheds = (double)(tmpGray - lowerc) * ( (blimit - alimit) / (upperd - lowerc) ); // + alimit; if ( stretcheds < 0.0 ) stretcheds = 0.0; else if ( stretcheds > 255.0 ) stretcheds = 255.0; yuvClr.rgbRed = (BYTE)stretcheds; color = YUVtoRGB(yuvClr); SetPaletteColor( (BYTE)j, color ); } } } } } return true; }
bool CxImagePCX::Decode(CxFile *hFile) { if (hFile == NULL) return false; PCXHEADER pcxHeader; int i, x, y, y2, nbytes, count, Height, Width; BYTE c, ColorMap[PCX_MAXCOLORS][3]; BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL; BYTE *pcxplanes, *pcxpixels; try { if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) throw "Can't read PCX image"; if (pcxHeader.Manufacturer != PCX_MAGIC) throw "Error: Not a PCX file"; // Check for PCX run length encoding if (pcxHeader.Encoding != 1) throw "PCX file has unknown encoding scheme"; Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1; Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1; info.xDPI = pcxHeader.Hres; info.yDPI = pcxHeader.Vres; // Check that we can handle this image format if (pcxHeader.ColorPlanes > 4) throw "Can't handle image with more than 4 planes"; // Create the image if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){ Create (Width, Height, 24, CXIMAGE_FORMAT_PCX); #if CXIMAGE_SUPPORT_ALPHA if (pcxHeader.ColorPlanes==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1) Create (Width, Height, 4, CXIMAGE_FORMAT_PCX); else Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX); if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding //Read the image and check if it's ok nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height; lpHead1 = pcximage = (BYTE*)malloc(nbytes); while (nbytes > 0){ if (hFile == NULL || hFile->Eof()) throw "corrupted PCX"; hFile->Read(&c,1,1); if ((c & 0XC0) != 0XC0){ // Repeated group *pcximage++ = c; --nbytes; continue; } count = c & 0X3F; // extract count hFile->Read(&c,1,1); if (count > nbytes) throw "repeat count spans end of image"; nbytes -= count; while (--count >=0) *pcximage++ = c; } pcximage = lpHead1; //store the palette for (i = 0; i < 16; i++){ ColorMap[i][0] = pcxHeader.ColorMap[i][0]; ColorMap[i][1] = pcxHeader.ColorMap[i][1]; ColorMap[i][2] = pcxHeader.ColorMap[i][2]; } if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){ hFile->Read(&c,1,1); if (c != PCX_256_COLORS) throw "bad color map signature"; for (i = 0; i < PCX_MAXCOLORS; i++){ hFile->Read(&ColorMap[i][0],1,1); hFile->Read(&ColorMap[i][1],1,1); hFile->Read(&ColorMap[i][2],1,1); } } if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0; ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255; } for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]); lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8); // Convert the image for (y = 0; y < Height; y++){ if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding y2=Height-1-y; pcxpixels = lpHead2; pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes); if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){ // Deal with 24 bit color image for (x = 0; x < Width; x++){ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); } continue; #if CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){ for (x = 0; x < Width; x++){ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]); } continue; #endif //CXIMAGE_SUPPORT_ALPHA } else if (pcxHeader.ColorPlanes == 1) { PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel); } else { PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel); } for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]); } } catch (char *message) { strncpy(info.szLastError,message,255); if (lpHead1){ free(lpHead1); lpHead1 = NULL; } if (lpHead2){ free(lpHead2); lpHead2 = NULL; } return false; } if (lpHead1){ free(lpHead1); lpHead1 = NULL; } if (lpHead2){ free(lpHead2); lpHead2 = NULL; } return true; }
bool CxImageTIF::EncodeBody(TIFF *m_tif, bool multipage, int page, int pagecount) { uint32 height=head.biHeight; uint32 width=head.biWidth; uint16 bitcount=head.biBitCount; uint16 bitspersample; uint16 samplesperpixel; uint16 photometric=0; uint16 compression; // uint16 pitch; // int line; uint32 x, y; samplesperpixel = ((bitcount == 24) || (bitcount == 32)) ? (BYTE)3 : (BYTE)1; #if CXIMAGE_SUPPORT_ALPHA if (bitcount==24 && AlphaIsValid()) { bitcount=32; samplesperpixel=4; } #endif //CXIMAGE_SUPPORT_ALPHA bitspersample = bitcount / samplesperpixel; //set the PHOTOMETRIC tag RGBQUAD *rgb = GetPalette(); switch (bitcount) { case 1: if (CompareColors(&rgb[0],&rgb[1])<0) { /* <abe> 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;i<head.biSizeImage;i++){ *iSrc=(BYTE)~(*(iSrc)); iSrc++; } photometric = PHOTOMETRIC_MINISWHITE; //photometric = PHOTOMETRIC_MINISBLACK; } else { photometric = PHOTOMETRIC_MINISWHITE; } break; case 4: // Check if the DIB has a color or a greyscale palette case 8: photometric = PHOTOMETRIC_MINISBLACK; //default to gray scale for (x = 0; x < head.biClrUsed; x++) { if ((rgb->rgbRed != 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<head.biClrUsed;a++){ //swap blue and red components b=pal[a].rgbBlue; pal[a].rgbBlue=pal[a].rgbRed; pal[a].rgbRed=b; } } // handle standard width/height/bpp stuff TIFFSetField(m_tif, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(m_tif, TIFFTAG_IMAGELENGTH, height); TIFFSetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); TIFFSetField(m_tif, TIFFTAG_BITSPERSAMPLE, bitspersample); TIFFSetField(m_tif, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(m_tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane TIFFSetField(m_tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); uint32 rowsperstrip = TIFFDefaultStripSize(m_tif, (uint32) -1); //<REC> 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 <God(dot)bless(at)marihuana(dot)com> 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, info.nQuality); 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){ for (y = 0; y < height; y++) { bits= info.pImage + (height - y - 1)*info.dwEffWidth; if (TIFFWriteScanline(m_tif,bits, y, 0)==-1) return false; } } #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<width;x++){ bits[2*x]=GetPixelIndex(x,height - y - 1); bits[2*x+1]=AlphaGet(x,height - y - 1); } if (TIFFWriteScanline(m_tif,bits, y, 0)==-1) { free(bits); return false; } } free(bits); } #endif //CXIMAGE_SUPPORT_ALPHA break; } case 24: { BYTE *buffer = (BYTE *)malloc(info.dwEffWidth); if (!buffer) return false; for (y = 0; y < height; y++) { // get a pointer to the scanline memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth); // TIFFs store color data RGB instead of BGR BYTE *pBuf = buffer; for (x = 0; x < width; x++) { BYTE tmp = pBuf[0]; pBuf[0] = pBuf[2]; pBuf[2] = tmp; pBuf += 3; } // write the scanline to disc if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){ free(buffer); return false; } } free(buffer); break; } case 32 : { #if CXIMAGE_SUPPORT_ALPHA BYTE *buffer = (BYTE *)malloc((info.dwEffWidth*4)/3); if (!buffer) return false; for (y = 0; y < height; y++) { // get a pointer to the scanline memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth); // TIFFs store color data RGB instead of BGR BYTE *pSrc = buffer + 3 * width; BYTE *pDst = buffer + 4 * width; for (x = 0; x < width; x++) { pDst-=4; pSrc-=3; pDst[3] = AlphaGet(width-x-1,height-y-1); pDst[2] = pSrc[0]; pDst[1] = pSrc[1]; pDst[0] = pSrc[2]; } // write the scanline to disc if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){ free(buffer); return false; } } free(buffer); #endif //CXIMAGE_SUPPORT_ALPHA break; } } return true; }