/** * 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; }
bool CxImageICO::Decode(CxFile *hFile) { if (hFile==NULL) return false; DWORD off = hFile->Tell(); //<yuandi> int page=info.nFrame; //internal icon structure indexes // read the first part of the header ICONHEADER icon_header; hFile->Read(&icon_header,sizeof(ICONHEADER),1); icon_header.idType = my_ntohs(icon_header.idType); icon_header.idCount = my_ntohs(icon_header.idCount); // check if it's an icon or a cursor if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) { info.nNumFrames = icon_header.idCount; // load the icon descriptions ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY)); int c; for (c = 0; c < icon_header.idCount; c++) { hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1); icon_list[c].wPlanes = my_ntohs(icon_list[c].wPlanes); icon_list[c].wBitCount = my_ntohs(icon_list[c].wBitCount); icon_list[c].dwBytesInRes = my_ntohl(icon_list[c].dwBytesInRes); icon_list[c].dwImageOffset = my_ntohl(icon_list[c].dwImageOffset); } if ((page>=0)&&(page<icon_header.idCount)){ if (info.nEscape == -1) { // Return output dimensions only head.biWidth = icon_list[page].bWidth; head.biHeight = icon_list[page].bHeight; #if CXIMAGE_SUPPORT_PNG if (head.biWidth==0 && head.biHeight==0) { // Vista icon support hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET); CxImage png; png.SetEscape(-1); if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ Transfer(png); info.nNumFrames = icon_header.idCount; } } #endif //CXIMAGE_SUPPORT_PNG free(icon_list); info.dwType = CXIMAGE_FORMAT_ICO; return true; } // get the bit count for the colors in the icon <CoreyRLucier> BITMAPINFOHEADER bih; hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET); if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0) { // Vista icon support #if CXIMAGE_SUPPORT_PNG CxImage png; if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ Transfer(png); info.nNumFrames = icon_header.idCount; } SetType(CXIMAGE_FORMAT_ICO); #endif //CXIMAGE_SUPPORT_PNG } else { // standard icon hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1); bihtoh(&bih); c = bih.biBitCount; // allocate memory for one icon Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation // read the palette RGBQUAD pal[256]; if (bih.biClrUsed) hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1); else hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1); SetPalette(pal,head.biClrUsed); //palette assign //read the icon if (c<=24){ hFile->Read(info.pImage, head.biSizeImage, 1); } else { // 32 bit icon BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth); BYTE* src = buf; hFile->Read(buf, 4*head.biHeight*head.biWidth, 1); #if CXIMAGE_SUPPORT_ALPHA if (!AlphaIsValid()) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA for (long y = 0; y < head.biHeight; y++) { BYTE* dst = GetBits(y); for(long x=0;x<head.biWidth;x++){ *dst++=src[0]; *dst++=src[1]; *dst++=src[2]; #if CXIMAGE_SUPPORT_ALPHA AlphaSet(x,y,src[3]); #endif //CXIMAGE_SUPPORT_ALPHA src+=4; } } free(buf); } // apply the AND and XOR masks int maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp) int masksize = head.biHeight * maskwdt; //size of mask BYTE *mask = (BYTE *)malloc(masksize); if (hFile->Read(mask, masksize, 1)){ bool bGoodMask=false; for (int im=0;im<masksize;im++){ if (mask[im]!=255){ bGoodMask=true; break; } } if (bGoodMask && c != 32){ #if CXIMAGE_SUPPORT_ALPHA bool bNeedAlpha = false; if (!AlphaIsValid()){ AlphaCreate(); } else { bNeedAlpha=true; //32bit icon } int x,y; for (y = 0; y < head.biHeight; y++) { for (x = 0; x < head.biWidth; x++) { if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){ AlphaSet(x,y,0); bNeedAlpha=true; } } } if (!bNeedAlpha) AlphaDelete(); #endif //CXIMAGE_SUPPORT_ALPHA //check if there is only one transparent color RGBQUAD cc,ct; long* pcc = (long*)&cc; long* pct = (long*)&ct; int nTransColors=0; int nTransIndex=0; for (y = 0; y < head.biHeight; y++){ for (x = 0; x < head.biWidth; x++){ if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ cc = GetPixelColor(x,y,false); if (nTransColors==0){ nTransIndex = GetPixelIndex(x,y); nTransColors++; ct = cc; } else { if (*pct!=*pcc){ nTransColors++; } } } } } if (nTransColors==1){ SetTransColor(ct); SetTransIndex(nTransIndex); #if CXIMAGE_SUPPORT_ALPHA AlphaDelete(); //because we have a unique transparent color in the image #endif //CXIMAGE_SUPPORT_ALPHA } // <vho> - Transparency support w/o Alpha support if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha). // find a color index, which is not used in the image // it is almost sure to find one, bcs. nobody uses all possible colors for an icon BYTE colorsUsed[256]; memset(colorsUsed, 0, sizeof(colorsUsed)); for (y = 0; y < head.biHeight; y++){ for (x = 0; x < head.biWidth; x++){ colorsUsed[BlindGetPixelIndex(x,y)] = 1; } } int iTransIdx = -1; for (x = (int)(head.biClrUsed-1); x>=0 ; x--){ if (colorsUsed[x] == 0){ iTransIdx = x; // this one is not in use. we may use it as transparent color break; } } // Go thru image and set unused color as transparent index if needed if (iTransIdx >= 0){ bool bNeedTrans = false; for (y = 0; y < head.biHeight; y++){ for (x = 0; x < head.biWidth; x++){ // AND mask (Each Byte represents 8 Pixels) if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ // AND mask is set (!=0). This is a transparent part SetPixelIndex(x, y, (BYTE)iTransIdx); bNeedTrans = true; } } } // set transparent index if needed if (bNeedTrans) SetTransIndex(iTransIdx); #if CXIMAGE_SUPPORT_ALPHA AlphaDelete(); //because we have a transparent color in the palette #endif //CXIMAGE_SUPPORT_ALPHA } } } else if(c != 32){