int32_t CxImage::Histogram(int32_t* red, int32_t* green, int32_t* blue, int32_t* gray, int32_t colorspace) { if (!pDib) return 0; RGBQUAD color; if (red) memset(red,0,256*sizeof(int32_t)); if (green) memset(green,0,256*sizeof(int32_t)); if (blue) memset(blue,0,256*sizeof(int32_t)); if (gray) memset(gray,0,256*sizeof(int32_t)); int32_t xmin,xmax,ymin,ymax; if (pSelection){ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; } else { xmin = ymin = 0; xmax = head.biWidth; ymax=head.biHeight; } for(int32_t y=ymin; y<ymax; y++){ for(int32_t x=xmin; x<xmax; x++){ #if CXIMAGE_SUPPORT_SELECTION if (BlindSelectionIsInside(x,y)) #endif //CXIMAGE_SUPPORT_SELECTION { switch (colorspace){ case 1: color = HSLtoRGB(BlindGetPixelColor(x,y)); break; case 2: color = YUVtoRGB(BlindGetPixelColor(x,y)); break; case 3: color = YIQtoRGB(BlindGetPixelColor(x,y)); break; case 4: color = XYZtoRGB(BlindGetPixelColor(x,y)); break; default: color = BlindGetPixelColor(x,y); } if (red) red[color.rgbRed]++; if (green) green[color.rgbGreen]++; if (blue) blue[color.rgbBlue]++; if (gray) gray[(uint8_t)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++; } } } int32_t n=0; for (int32_t i=0; i<256; i++){ if (red && red[i]>n) n=red[i]; if (green && green[i]>n) n=green[i]; if (blue && blue[i]>n) n=blue[i]; if (gray && gray[i]>n) n=gray[i]; } return n; }
/** * Adds to the selection all the pixels matching the specified color. */ bool CxImage::SelectionAddColor(RGBQUAD c, uint8_t level) { if (pSelection==NULL) SelectionCreate(); if (pSelection==NULL) return false; RECT localbox = {head.biWidth,0,0,head.biHeight}; for (int32_t y = 0; y < head.biHeight; y++){ for (int32_t x = 0; x < head.biWidth; x++){ RGBQUAD color = BlindGetPixelColor(x, y); if (color.rgbRed == c.rgbRed && color.rgbGreen == c.rgbGreen && color.rgbBlue == c.rgbBlue) { pSelection[x + y * head.biWidth] = level; if (localbox.top < y) localbox.top = y; if (localbox.left > x) localbox.left = x; if (localbox.right < x) localbox.right = x; if (localbox.bottom > y) localbox.bottom = y; } } } if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1; if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left; if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1; if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom; return true; }
/** * exports the image into a RGBA buffer, Useful for OpenGL applications. * \param hFile: file handle (CxMemFile or CxIOFile), with write access. * \param bFlipY: direction of Y axis. default = false. * \return true if everything is ok */ bool CxImage::Encode2RGB(CxFile *hFile, bool bFlipY) { if (EncodeSafeCheck(hFile)) return false; for (int32_t y1 = 0; y1 < head.biHeight; y1++) { int32_t y = bFlipY ? head.biHeight - 1 - y1 : y1; for(int32_t x = 0; x < head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x,y); hFile->PutC(color.rgbRed); hFile->PutC(color.rgbGreen); hFile->PutC(color.rgbBlue); } } return true; }
/** * Blends the alpha channel and the alpha palette with the pixels. The result is a 24 bit image. * The background color can be selected using SetTransColor(). */ void CxImage::AlphaStrip() { bool bAlphaPaletteIsValid = AlphaPaletteIsValid(); bool bAlphaIsValid = AlphaIsValid(); if (!(bAlphaIsValid || bAlphaPaletteIsValid)) return; RGBQUAD c; long a, a1; if (head.biBitCount==24){ for(long y=0; y<head.biHeight; y++){ for(long x=0; x<head.biWidth; x++){ c = BlindGetPixelColor(x,y); if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax; a1 = 256-a; c.rgbBlue = (BYTE)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8); c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8); c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8); BlindSetPixelColor(x,y,c); } } AlphaDelete(); } else {
/** * HistogramStretch * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels. * \param threshold: minimum percentage level in the histogram to recognize it as meaningful. Range: 0.0 to 1.0; default = 0; typical = 0.005 (0.5%); * \return true if everything is ok * \author [dave] and [nipper]; changes [DP] */ bool CxImage::HistogramStretch(long method, double threshold) { if (!pDib) return false; double dbScaler = 50.0/head.biHeight; long x,y; if ((head.biBitCount==8) && IsGrayScale()){ double p[256]; memset(p, 0, 256*sizeof(double)); for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); if (info.nEscape) break; for (x=0; x<head.biWidth; x++) { p[BlindGetPixelIndex(x, y)]++; } } double maxh = 0; for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y]; threshold *= maxh; int minc = 0; while (minc<255 && p[minc]<=threshold) minc++; int maxc = 255; while (maxc>0 && p[maxc]<=threshold) maxc--; if (minc == 0 && maxc == 255) return true; if (minc >= maxc) return true; // calculate LUT BYTE lut[256]; for (x = 0; x <256; x++){ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); } for (y=0; y<head.biHeight; y++) { if (info.nEscape) break; info.nProgress = (long)(50.0+y*dbScaler); for (x=0; x<head.biWidth; x++) { BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]); } } } else { switch(method){ case 1: { // <nipper> double p[256]; memset(p, 0, 256*sizeof(double)); for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); if (info.nEscape) break; for (x=0; x<head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x, y); p[color.rgbRed]++; p[color.rgbBlue]++; p[color.rgbGreen]++; } } double maxh = 0; for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y]; threshold *= maxh; int minc = 0; while (minc<255 && p[minc]<=threshold) minc++; int maxc = 255; while (maxc>0 && p[maxc]<=threshold) maxc--; if (minc == 0 && maxc == 255) return true; if (minc >= maxc) return true; // calculate LUT BYTE lut[256]; for (x = 0; x <256; x++){ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); } // normalize image for (y=0; y<head.biHeight; y++) { if (info.nEscape) break; info.nProgress = (long)(50.0+y*dbScaler); for (x=0; x<head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x, y); color.rgbRed = lut[color.rgbRed]; color.rgbBlue = lut[color.rgbBlue]; color.rgbGreen = lut[color.rgbGreen]; BlindSetPixelColor(x, y, color); } } } break; case 2: { // <nipper> double pR[256]; memset(pR, 0, 256*sizeof(double)); double pG[256]; memset(pG, 0, 256*sizeof(double)); double pB[256]; memset(pB, 0, 256*sizeof(double)); for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); if (info.nEscape) break; for (long x=0; x<head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x, y); pR[color.rgbRed]++; pB[color.rgbBlue]++; pG[color.rgbGreen]++; } } double maxh = 0; for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y]; double threshold2 = threshold*maxh; int minR = 0; while (minR<255 && pR[minR]<=threshold2) minR++; int maxR = 255; while (maxR>0 && pR[maxR]<=threshold2) maxR--; maxh = 0; for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y]; threshold2 = threshold*maxh; int minG = 0; while (minG<255 && pG[minG]<=threshold2) minG++; int maxG = 255; while (maxG>0 && pG[maxG]<=threshold2) maxG--; maxh = 0; for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y]; threshold2 = threshold*maxh; int minB = 0; while (minB<255 && pB[minB]<=threshold2) minB++; int maxB = 255; while (maxB>0 && pB[maxB]<=threshold2) maxB--; 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 (x = 0; x <256; x++){ lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range))); } } else lutR[minR] = minR; BYTE lutG[256]; range = maxG - minG; if (range != 0) { for (x = 0; x <256; x++){ lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range))); } } else lutG[minG] = minG; BYTE lutB[256]; range = maxB - minB; if (range != 0) { for (x = 0; x <256; x++){ lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range))); } } else lutB[minB] = minB; // normalize image for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(50.0+y*dbScaler); if (info.nEscape) break; for (x=0; x<head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x, y); color.rgbRed = lutR[color.rgbRed]; color.rgbBlue = lutB[color.rgbBlue]; color.rgbGreen = lutG[color.rgbGreen]; BlindSetPixelColor(x, y, color); } } } break; default: { // <dave> double p[256]; memset(p, 0, 256*sizeof(double)); for (y=0; y<head.biHeight; y++) { info.nProgress = (long)(y*dbScaler); if (info.nEscape) break; for (x=0; x<head.biWidth; x++) { RGBQUAD color = BlindGetPixelColor(x, y); p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++; } } double maxh = 0; for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y]; threshold *= maxh; int minc = 0; while (minc<255 && p[minc]<=threshold) minc++; int maxc = 255; while (maxc>0 && p[maxc]<=threshold) maxc--; if (minc == 0 && maxc == 255) return true; if (minc >= maxc) return true; // calculate LUT BYTE lut[256]; for (x = 0; x <256; x++){ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); } for(y=0; y<head.biHeight; y++){ info.nProgress = (long)(50.0+y*dbScaler); if (info.nEscape) break; for(x=0; x<head.biWidth; x++){ RGBQUAD color = BlindGetPixelColor( x, y ); RGBQUAD yuvClr = RGBtoYUV(color); yuvClr.rgbRed = lut[yuvClr.rgbRed]; color = YUVtoRGB(yuvClr); BlindSetPixelColor( x, y, color ); } } } } } return true; }
//////////////////////////////////////////////////////////////////////////////// // 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; }
long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace) { if (!pDib) return 0; RGBQUAD color; if (red) memset(red,0,256*sizeof(long)); if (green) memset(green,0,256*sizeof(long)); if (blue) memset(blue,0,256*sizeof(long)); if (gray) memset(gray,0,256*sizeof(long)); long xmin,xmax,ymin,ymax; if (pSelection){ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; } else { xmin = ymin = 0; xmax = head.biWidth - 1; ymax=head.biHeight - 1; } for(long y=ymin; y<=ymax; y++){ for(long x=xmin; x<=xmax; x++){ #if CXIMAGE_SUPPORT_SELECTION if (BlindSelectionIsInside(x,y)) #endif //CXIMAGE_SUPPORT_SELECTION { switch (colorspace){ case 1: color = HSLtoRGB(BlindGetPixelColor(x,y)); break; case 2: color = YUVtoRGB(BlindGetPixelColor(x,y)); break; case 3: color = YIQtoRGB(BlindGetPixelColor(x,y)); break; case 4: color = XYZtoRGB(BlindGetPixelColor(x,y)); break; default: color = BlindGetPixelColor(x,y); } if (red) red[color.rgbRed]++; if (green) green[color.rgbGreen]++; if (blue) blue[color.rgbBlue]++; if (gray) gray[(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++; } } } long n=0; long nMed=(long)((xmax*ymax)/3); for (int i=0; i<256; i++){ if (red && red[i]>n) n=red[i]; if (green && green[i]>n) n=green[i]; if (blue && blue[i]>n) n=blue[i]; if (gray) { n+=gray[i]; if(n>nMed) return i; } } return n; }
bool CxImagePCX::Encode(CxFile * hFile) { if (EncodeSafeCheck(hFile)) return false; cx_try { PCXHEADER pcxHeader; memset(&pcxHeader,0,sizeof(pcxHeader)); pcxHeader.Manufacturer = PCX_MAGIC; pcxHeader.Version = 5; pcxHeader.Encoding = 1; pcxHeader.Xmin = 0; pcxHeader.Ymin = 0; pcxHeader.Xmax = (WORD)head.biWidth-1; pcxHeader.Ymax = (WORD)head.biHeight-1; pcxHeader.Hres = (WORD)info.xDPI; pcxHeader.Vres = (WORD)info.yDPI; pcxHeader.Reserved = 0; pcxHeader.PaletteType = head.biClrUsed==0; switch(head.biBitCount){ case 24: case 8: { pcxHeader.BitsPerPixel = 8; pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1; #if CXIMAGE_SUPPORT_ALPHA if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4; #endif //CXIMAGE_SUPPORT_ALPHA pcxHeader.BytesPerLine = (WORD)head.biWidth; break; } default: //(4 1) pcxHeader.BitsPerPixel = 1; pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1; pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3); } if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0; pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255; } if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){ RGBQUAD c; for (int i = 0; i < 16; i++){ c=GetPaletteColor(i); pcxHeader.ColorMap[i][0] = c.rgbRed; pcxHeader.ColorMap[i][1] = c.rgbGreen; pcxHeader.ColorMap[i][2] = c.rgbBlue; } } pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1); PCX_toh(&pcxHeader); if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 ) cx_throw("cannot write PCX header"); PCX_toh(&pcxHeader); CxMemFile buffer; buffer.Open(); BYTE c,n; long x,y; if (head.biClrUsed==0){ for (y = head.biHeight-1; y >=0 ; y--){ for (int p=0; p<pcxHeader.ColorPlanes; p++){ c=n=0; for (x = 0; x<head.biWidth; x++){ if (p==0) PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer); else if (p==1) PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer); else if (p==2) PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer); #if CXIMAGE_SUPPORT_ALPHA else if (p==3) PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer); #endif //CXIMAGE_SUPPORT_ALPHA } PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer); } } hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1); } else if (head.biBitCount==8) { for (y = head.biHeight-1; y >=0 ; y--){ c=n=0; for (x = 0; x<head.biWidth; x++){ PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer); } PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer); } hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1); if (head.biBitCount == 8){ hFile->PutC(0x0C); BYTE* pal = (BYTE*)malloc(768); RGBQUAD c; for (int i=0;i<256;i++){ c=GetPaletteColor(i); pal[3*i+0] = c.rgbRed; pal[3*i+1] = c.rgbGreen; pal[3*i+2] = c.rgbBlue; } hFile->Write(pal,768,1); free(pal); } } else { //(head.biBitCount==4) || (head.biBitCount==1) RGBQUAD *rgb = GetPalette(); bool binvert = false; if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1); BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine); BYTE* raw = (BYTE*)malloc(head.biWidth); for(y = head.biHeight-1; y >=0 ; y--) { for( x = 0; x < head.biWidth; x++) raw[x] = (BYTE)GetPixelIndex(x,y); if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x]; for( x = 0; x < pcxHeader.ColorPlanes; x++ ) { PCX_PixelsToPlanes(raw, head.biWidth, plane, x); PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer); } } free(plane); free(raw); hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1); } } cx_catch { if (strcmp(message,"")) strncpy(info.szLastError,message,255); return false; } return true; }
//////////////////////////////////////////////////////////////////////////////// // 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)|); int32_t x, y, i; RGBQUAD color; RGBQUAD yuvClr; uint32_t 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 = (int32_t)(50*y/head.biHeight); if (info.nEscape) break; for(x=0; x < head.biWidth; x++){ color = BlindGetPixelColor( x, y ); YVal = (uint32_t)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); if (YVal > high ) high = YVal; } } } else { // Palette for(i = 0; i < (int32_t)head.biClrUsed; i++){ color = GetPaletteColor((uint8_t)i); YVal = (uint32_t)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 = (int32_t)(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 = (uint8_t)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); color = YUVtoRGB( yuvClr ); BlindSetPixelColor( x, y, color ); } } } else { for(i = 0; i < (int32_t)head.biClrUsed; i++){ color = GetPaletteColor( (uint8_t)i ); yuvClr = RGBtoYUV( color ); yuvClr.rgbRed = (uint8_t)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); color = YUVtoRGB( yuvClr ); SetPaletteColor( (uint8_t)i, color ); } } return true; }
bool CxImage::Vibrance(long strength) { long xmin,xmax,ymin,ymax; if (pSelection){ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; } else { xmin = ymin = 0; xmax = head.biWidth - 1; ymax=head.biHeight - 1; } if (xmin==xmax || ymin==ymax) return false; int size = (xmax - xmin + 1) * (ymax - ymin + 1); int histDistrib[256]; ::memset(histDistrib,0,256 * sizeof(int)); BYTE maxSat = 0; for(long y=ymin; y<=ymax; y++){ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin)); if (info.nEscape) break; for(long x=xmin; x<=xmax; x++){ #if CXIMAGE_SUPPORT_SELECTION if (BlindSelectionIsInside(x,y)) #endif //CXIMAGE_SUPPORT_SELECTION { BYTE curSat = RGBtoHSL(BlindGetPixelColor(x,y)).rgbGreen; histDistrib[curSat]++; if (curSat > maxSat) maxSat = curSat; } } } BYTE ceilSat = (BYTE)min((int)maxSat + strength, 250); BYTE cTable[256]; float fCurCum = 0.0f; float fStdDev = 0.0f; float fCumDistrib[256]; for (int i=0;i<256;i++) { cTable[i] = (BYTE)max(0,min((int)ceilSat,i + strength) - i); fStdDev += pow((float)size / 2.0f - (float)histDistrib[i], 2.0f); fCurCum += (float)histDistrib[i] / (float)size; fCumDistrib[i] = max(0.0f, fCurCum); } fStdDev = (sqrt(fStdDev) / (float)size) * 255.0f; for (int i=0;i<256;i++) cTable[i] = (BYTE)(fCumDistrib[i] * (float)cTable[i] * CxMath::NormalDistrib (127.0f, fStdDev, (float)i, false)); for(long y=ymin; y<=ymax; y++){ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin)); if (info.nEscape) break; for(long x=xmin; x<=xmax; x++){ #if CXIMAGE_SUPPORT_SELECTION if (BlindSelectionIsInside(x,y)) #endif //CXIMAGE_SUPPORT_SELECTION { RGBQUAD c = RGBtoHSL(BlindGetPixelColor(x,y)); BYTE curSat = c.rgbGreen; c.rgbGreen = (BYTE)min((int)ceilSat, (int)curSat + (int)cTable[curSat]); c = HSLtoRGB(c); BlindSetPixelColor(x,y,c); } } } return true; }