/**************************************************************************** SCALEBIT.C $Log: S:\products\wangview\oiwh\display\scalebit.c_v $ * * Rev 1.32 22 Apr 1996 09:38:58 BEG06016 * Cleaned up error checking. * * Rev 1.31 15 Apr 1996 08:25:24 BEG06016 * Fixed a build problem. * * Rev 1.30 12 Apr 1996 15:53:10 RC * Changed the way lines 1 & 2 were set up in scalebwstamp * * Rev 1.29 21 Mar 1996 10:49:46 RC * Changed the way lrrect was passed into functions from value to * reference (the power pc compiler couldnt handle those cases) * * Rev 1.28 07 Feb 1996 09:10:22 BLJ * Made scaling with a BW scale algorithm with non-BW data an error. * * Rev 1.27 02 Jan 1996 12:51:50 BLJ * Fixed bug in BW_AVG_TO_BW scale algorithm. * * Rev 1.26 02 Jan 1996 09:57:30 BLJ * Changed alot of UINTs to ints. * Changed IMG structure to include the image data. * Changed lp prefix to p. * * Rev 1.25 22 Dec 1995 11:11:30 BLJ * Added a parameter for zero init'ing to some memory manager calls. * * Rev 1.24 14 Dec 1995 08:39:12 BLJ * Added BW_AVERAGE_TO_BW scale algorithm. * Also fixed a problem with BW scaling to gray. * * Rev 1.23 29 Nov 1995 11:19:18 BLJ * Fixed 5436 Distortion of image when scrolled. * * Rev 1.22 19 Nov 1995 13:26:56 BLJ * Fixed 5370. Garbage during BW scale to gray. * * Rev 1.21 18 Nov 1995 16:31:24 RC * Fixed nloopend computation in scalebwtogray * * Rev 1.20 07 Nov 1995 09:41:02 BLJ * Added stack checking pragma. * * Rev 1.19 18 Aug 1995 11:06:52 RC * Initialized pLine1 * * Rev 1.18 17 Aug 1995 14:56:12 BLJ * Prevented freeing of non-allocated memory. * ****************************************************************************/ #include "privdisp.h" #pragma check_stack(on) // /**************************************************************************** FUNCTION: ScaleBits PURPOSE: Dispatches the scale operation. *****************************************************************************/ int WINAPI ScaleBits(PIMG pSourceImg, PIMG pDestImg, int nScaleAlgorithm, int nHScale, int nVScale, LRECT lrSourceRect, LRECT lrDestRect, LPRGBQUAD pPalette){ int nStatus = 0; LRECT lrRect; if (nHScale < 20 || nVScale < 20){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (!pSourceImg){ nStatus = Error(DISPLAY_IMAGETYPENOTSUPPORTED); goto Exit; } SetLRect(lrRect, 0, 0, lrDestRect.right - lrDestRect.left, lrDestRect.bottom - lrDestRect.top); switch (pSourceImg->nType){ case ITYPE_BI_LEVEL: switch (nScaleAlgorithm){ case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScaleBWToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_NORMAL: CheckError2( Scale1BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_STAMP: CheckError2( ScaleBWStamp(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: CheckError2( ScaleBWKeepBlack(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_BW_AVERAGE_TO_BW: CheckError2( ScaleBWAvgToBW(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; case ITYPE_GRAY4: switch (nScaleAlgorithm){ case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScaleGray4ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_NORMAL: CheckError2( Scale4BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_STAMP: CheckError2( ScaleGray4ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; case ITYPE_GRAY7: case ITYPE_GRAY8: switch (nScaleAlgorithm){ case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScaleGray8ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_NORMAL: CheckError2( Scale8BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_STAMP: CheckError2( ScaleGray8ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; case ITYPE_PAL4: switch (nScaleAlgorithm){ case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_NORMAL: case OI_SCALE_ALG_STAMP: CheckError2( Scale4BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScalePal4ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, &lrRect, pPalette)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; case ITYPE_COMPAL8: case ITYPE_CUSPAL8: switch (nScaleAlgorithm){ case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_STAMP: case OI_SCALE_ALG_NORMAL: CheckError2( Scale8BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScalePal8ToGray(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect, pPalette)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; case ITYPE_RGB24: case ITYPE_BGR24: switch (nScaleAlgorithm){ case OI_SCALE_ALG_AVERAGE_TO_GRAY4: case OI_SCALE_ALG_AVERAGE_TO_GRAY7: case OI_SCALE_ALG_AVERAGE_TO_GRAY8: CheckError2( ScaleRGBToGrayAvg(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_USE_DEFAULT: case OI_SCALE_ALG_STAMP: case OI_SCALE_ALG_NORMAL: CheckError2( Scale24BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, lrDestRect.left, lrDestRect.top, lrRect)); break; case OI_SCALE_ALG_BW_KEEP_BLACK: case OI_SCALE_ALG_BW_MINORITY: case OI_SCALE_ALG_BW_MAJORITY: default: nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } break; default: nStatus = Error(DISPLAY_IMAGETYPENOTSUPPORTED); goto Exit; } Exit: return(nStatus); } // /**************************************************************************** FUNCTION: ScaleBWAvgToBW PURPOSE: Scales BW images to BW via averaging and error diffusion. *****************************************************************************/ int WINAPI ScaleBWAvgToBW(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT *plrDestRect){ int nStatus = 0; int nDest[MAX_PIXELS_HANDLED]; int nDestPixel[MAX_BW_BYTES_HANDLED]; int nPixels[MAX_BW_BYTES_HANDLED]; int nMask0[MAX_BW_BYTES_HANDLED]; int nMask1[MAX_BW_BYTES_HANDLED]; int nMask2[MAX_BW_BYTES_HANDLED]; int nMask3[MAX_BW_BYTES_HANDLED]; int nMask4[MAX_BW_BYTES_HANDLED]; int nMask5[MAX_BW_BYTES_HANDLED]; int nMask6[MAX_BW_BYTES_HANDLED]; int nMask7[MAX_BW_BYTES_HANDLED]; int nMask8[MAX_BW_BYTES_HANDLED]; int nGrayScaleTable1[2500]; int nGrayScaleTable2[2500]; int nPixelIndex; int nDestWidth; int nDestWidthInts; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nDestLine; PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nFirstMask; int nSourcePixel; int nScaleDenominator; int nCountTable[256]; int nSourceWidth; int nSourceHeight; int nNumberOfSourceBitsPerDestBit; int nFirstSourceByte; int nSourceBytes; int nSourceByteIndex; int nDestPixel0; int nDestPixel1; int nDestPixel2; int nDestPixel3; int nDestPixel4; int nDestPixel5; int nDestPixel6; int nDestPixel7; int nDestPixel8; PINT pnLine0 = 0; PINT pnLine1 = 0; PINT pnThisLine; PINT pnNextLine; PINT pnDestLineGray; int nBitMask; int nLineSize; int nPixel; int nSourceByte; int nThreshold; int nThresholdTimes2; // Loop variables. int nLoop; int nLoop2; int nSourceLineCount; int nLoopEnd; LRECT lrDestRect ; CopyRect (lrDestRect, *plrDestRect) ; if (!pDestImg || pDestImg->nType != ITYPE_BI_LEVEL){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (lrDestRect.right - lrDestRect.left); nDestHeight = (lrDestRect.bottom - lrDestRect.top); nFirstSourceByte = ((((lrDestRect.left + nHDestOffset) * nScaleDenominator) / nHScale) / 8); nSourceWidth = pSourceImg->nWidth; nSourceBytes = ((min(nSourceWidth, (((lrDestRect.right + nHDestOffset) * nScaleDenominator) / nHScale)) + 7) / 8) - nFirstSourceByte; if (nSourceBytes * 8 > MAX_PIXELS_HANDLED || nDestWidth > MAX_PIXELS_HANDLED || nSourceWidth < (nScaleDenominator / nHScale)){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } memset((PSTR) nDestPixel, 0, sizeof(int) * (nDestWidth / 8)); memset((PSTR) nPixels, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask0, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask1, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask2, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask3, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask4, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask5, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask6, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask7, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask8, 0, sizeof(int) * nSourceBytes); memset(nGrayScaleTable1, 0, 2500); memset(nGrayScaleTable2, 0, 2500); nSourcePixelsPerLinePerPixel = (int)(nScaleDenominator / nHScale); if (nScaleDenominator % nHScale || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = (int)(nScaleDenominator / nVScale); if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } memcpy(nCountTable, nCountTheZerosTable, sizeof(int) * 256); // Produce scale table. if (nHScale >= 1000){ for (nLoop = 0; nLoop < nSourceBytes; nLoop++){ nSourcePixel = (nFirstSourceByte + nLoop) << 3; nDestPixel0 = max(0, ((nSourcePixel * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel1 = max(0, (((nSourcePixel + 1) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel2 = max(0, (((nSourcePixel + 2) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel3 = max(0, (((nSourcePixel + 3) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel4 = max(0, (((nSourcePixel + 4) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel5 = max(0, (((nSourcePixel + 5) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel6 = max(0, (((nSourcePixel + 6) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel7 = max(0, (((nSourcePixel + 7) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel8 = max(0, (((nSourcePixel + 8) * nHScale) / nScaleDenominator) - nHDestOffset); nDestPixel[nLoop] = nDestPixel0; nMask0[nLoop] = nDestPixel1 - nDestPixel0; nMask1[nLoop] = nDestPixel2 - nDestPixel1; nMask2[nLoop] = nDestPixel3 - nDestPixel2; nMask3[nLoop] = nDestPixel4 - nDestPixel3; nMask4[nLoop] = nDestPixel5 - nDestPixel4; nMask5[nLoop] = nDestPixel6 - nDestPixel5; nMask6[nLoop] = nDestPixel7 - nDestPixel6; nMask7[nLoop] = nDestPixel8 - nDestPixel7; } }else{ // Pixel 0 = 0x80, pixel 7 = 0x01. 0 = black, 1 = white. switch (nSourcePixelsPerLinePerPixel){ case 1: nFirstMask = 0xff7f; break; case 2: nFirstMask = 0xff3f; break; case 3: nFirstMask = 0xff1f; break; case 4: nFirstMask = 0xff0f; break; case 5: nFirstMask = 0xff07; break; case 6: nFirstMask = 0xff03; break; case 7: nFirstMask = 0xff01; break; default: nFirstMask = 0xff00; break; } for (nLoop = 0; nLoop < nDestWidth; nLoop++){ nSourcePixel = ((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale; if (nSourcePixel + nSourcePixelsPerLinePerPixel > nSourceWidth){ nSourcePixel = nSourceWidth - nSourcePixelsPerLinePerPixel; } // First byte. nSourceByteIndex = (nSourcePixel >> 3) - nFirstSourceByte; if (!(nPixels[nSourceByteIndex])){ nDestPixel[nSourceByteIndex] = nLoop; } switch (nPixels[nSourceByteIndex]){ case 0: nMask0[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 1: nMask1[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 2: nMask2[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 3: nMask3[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 4: nMask4[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 5: nMask5[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 6: nMask6[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 7: nMask7[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 8: nMask8[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; default: Error(DISPLAY_DATACORRUPTED); goto Exit; } nPixels[nSourceByteIndex]++; nSourcePixel += nSourcePixelsPerLinePerPixel - 1; if (nLoop2 = ((nSourcePixel >> 3) - (nSourceByteIndex + nFirstSourceByte))){ // Middle bytes. for (; nLoop2 > 1; nLoop2--){ nSourceByteIndex++; nDestPixel[nSourceByteIndex] = nLoop; switch (nPixels[nSourceByteIndex]){ case 0: nMask0[nSourceByteIndex] = 0; break; case 1: nMask1[nSourceByteIndex] = 0; break; case 2: nMask2[nSourceByteIndex] = 0; break; case 3: nMask3[nSourceByteIndex] = 0; break; case 4: nMask4[nSourceByteIndex] = 0; break; case 5: nMask5[nSourceByteIndex] = 0; break; case 6: nMask6[nSourceByteIndex] = 0; break; case 7: nMask7[nSourceByteIndex] = 0; break; case 8: nMask8[nSourceByteIndex] = 0; break; default: Error(DISPLAY_DATACORRUPTED); goto Exit; } nPixels[nSourceByteIndex]++; } // Last byte. nSourceByteIndex++; nDestPixel[nSourceByteIndex] = nLoop; nMask0[nSourceByteIndex] = (uchar) (0x7f >> (nSourcePixel & 7)); nPixels[nSourceByteIndex]++; } } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, ZERO_INIT)); nSourceHeight = pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Generate nGrayScaleTables. nNumberOfSourceBitsPerDestBit = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; nThreshold = 0x08000 * nNumberOfSourceBitsPerDestBit; nThresholdTimes2 = nThreshold * 2; nDestWidthInts = sizeof(int) * nDestWidth; nLineSize = (nDestWidth + 9) * sizeof(int); // pnLine0 = (nSourceLine & 1) == 0. // pnLine1 = (nSourceLine & 1) == 1. CheckError2( AllocateMemory(nLineSize, (PPSTR) &pnLine0, ZERO_INIT)); CheckError2( AllocateMemory(nLineSize, (PPSTR) &pnLine1, ZERO_INIT)); // Begin scaling the data. for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset((PSTR) nDest, 0, nDestWidthInts); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pSourceByte = pSourceLine + nFirstSourceByte; if (nHScale >= 1000){ nSourceByteIndex = 0; if ((int) pSourceByte & 3){ nLoopEnd = min(4 - ((int) pSourceByte & 3), nSourceBytes); }else{ nLoopEnd = 0; } while(nSourceByteIndex < nLoopEnd){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; } nLoopEnd = (nSourceBytes - nSourceByteIndex) & -4; while(nSourceByteIndex < nLoopEnd){ if (*((PDWORD) pSourceByte) == 0xffffffff){ nSourceByteIndex += 4; pSourceByte += 4; continue; }else{ do{ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; }while((int) pSourceByte & 3); } } while(nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; } }else{ // nHScale < 1000. nSourceByteIndex = 0; while (((int) pSourceByte & 3) && nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } nLoopEnd = (nSourceBytes - nSourceByteIndex) & -4; while(nSourceByteIndex < nLoopEnd){ if (*((PDWORD) pSourceByte) == 0xffffffff){ nSourceByteIndex += 4; pSourceByte += 4; continue; }else{ // Do Byte 1. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 2. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 3. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 4. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } } while(nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } } } // Error diffuse the line to BW. pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine) + (lrDestRect.left / 8); if (nDestLine & 1){ pnThisLine = &pnLine1[1]; pnNextLine = pnLine0; }else{ pnThisLine = &pnLine0[1]; pnNextLine = pnLine1; } // memset(pnNextLine, 0, nLineSize); pnNextLine[0] = 0; pnNextLine[1] = 0; nPixelIndex = 0; pnDestLineGray = &nDest[0]; nLoopEnd = nDestWidth; // Do first few pixels. if (lrDestRect.left & 7){ switch (lrDestRect.left & 7){ case 1: nBitMask = 0x40; nLoop = 7; break; case 2: nBitMask = 0x20; nLoop = 6; break; case 3: nBitMask = 0x10; nLoop = 5; break; case 4: nBitMask = 0x08; nLoop = 4; break; case 5: nBitMask = 0x04; nLoop = 3; break; case 6: nBitMask = 0x02; nLoop = 2; break; case 7: nBitMask = 0x01; nLoop = 1; break; } nLoop = min(nLoopEnd, nLoop); nLoopEnd -= nLoop; nDestPixel0 = *pDestLine; for (; nLoop; nLoop--){ // *pnDestLineGray = number of black pixels. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= ~nBitMask; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nDestPixel0 |= nBitMask; nPixel = nPixel / 4; } nBitMask >>= 1; *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; } *(pDestLine++) = nDestPixel0; } // Do middle bytes. if (nLoopEnd & ~7){ for (nLoop = nLoopEnd / 8; nLoop; nLoop--){ // Pixel 0. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 = 0x7f; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nDestPixel0 = 0xff; nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 1. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xbf; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 2. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xdf; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 3. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xef; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 4. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xf7; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 5. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xfb; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 6. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xfd; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; // Pixel 7. nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= 0xfe; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nPixel = nPixel / 4; } *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; *(pDestLine++) = nDestPixel0; } } // Do last few pixels. if (lrDestRect.right & 7){ nBitMask = 0x80; switch (lrDestRect.right & 7){ case 1: nLoop = 1; break; case 2: nLoop = 2; break; case 3: nLoop = 3; break; case 4: nLoop = 4; break; case 5: nLoop = 5; break; case 6: nLoop = 6; break; case 7: nLoop = 7; break; } nDestPixel0 = *pDestLine; for (; nLoop; nLoop--){ nPixel = *pnThisLine + (*(pnDestLineGray++) << 16); if (nPixel >= nThreshold){ nDestPixel0 &= ~nBitMask; nPixel = (nPixel - nThresholdTimes2) / 4; }else{ nDestPixel0 |= nBitMask; nPixel = nPixel / 4; } nBitMask >>= 1; *(++pnThisLine) += nPixel; *(pnNextLine++) += nPixel; *(pnNextLine) += nPixel; *(pnNextLine + 1) = nPixel; } *pDestLine = nDestPixel0; } } Exit: if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } if (pnLine0){ FreeMemory((PPSTR) &pnLine0); } if (pnLine1){ FreeMemory((PPSTR) &pnLine1); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleBWToGray PURPOSE: Scales BW images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScaleBWToGray(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT *plrDestRect){ int nStatus = 0; int nDest[MAX_PIXELS_HANDLED]; int nDestPixel[MAX_BW_BYTES_HANDLED]; int nPixels[MAX_BW_BYTES_HANDLED]; int nMask0[MAX_BW_BYTES_HANDLED]; int nMask1[MAX_BW_BYTES_HANDLED]; int nMask2[MAX_BW_BYTES_HANDLED]; int nMask3[MAX_BW_BYTES_HANDLED]; int nMask4[MAX_BW_BYTES_HANDLED]; int nMask5[MAX_BW_BYTES_HANDLED]; int nMask6[MAX_BW_BYTES_HANDLED]; int nMask7[MAX_BW_BYTES_HANDLED]; int nMask8[MAX_BW_BYTES_HANDLED]; int nGrayScaleTable1[2500]; int nGrayScaleTable2[2500]; int nPixelIndex; int nDestWidth; int nDestWidthInts; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; long lMultiplier; // Multiplier for averaging of all lines. int nDestLine; PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nFirstMask; int nSourcePixel; int nScaleDenominator; int nCountTable[256]; int nSourceWidth; int nSourceHeight; int nNumberOfSourceBitsPerDestBit; int nFirstSourceByte; int nSourceBytes; int nSourceByteIndex; int nTemp; int nDestPixel0; int nDestPixel1; int nDestPixel2; int nDestPixel3; int nDestPixel4; int nDestPixel5; int nDestPixel6; int nDestPixel7; int nDestPixel8; // Loop variables. int nLoop; int nLoop2; int nTempIndex; int nSourceLineCount; int nLoopEnd; int nSourceByte; LRECT lrDestRect ; CopyRect (lrDestRect, *plrDestRect) ; if (!pDestImg && pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nFirstSourceByte = (int) ((((lrDestRect.left + nHDestOffset) * nScaleDenominator) / nHScale) >> 3); nSourceWidth = pSourceImg->nWidth; nSourceBytes = ((min(nSourceWidth, (int) (((lrDestRect.right + nHDestOffset) * nScaleDenominator) / nHScale)) + 7) >> 3) - nFirstSourceByte; if (nSourceBytes * 8 > MAX_PIXELS_HANDLED || nDestWidth > MAX_PIXELS_HANDLED || nSourceWidth < (INT)(nScaleDenominator / nHScale)){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } memset((PSTR) nDestPixel, 0, sizeof(int) * (nDestWidth / 8)); memset((PSTR) nPixels, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask0, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask1, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask2, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask3, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask4, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask5, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask6, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask7, 0, sizeof(int) * nSourceBytes); memset((PSTR) nMask8, 0, sizeof(int) * nSourceBytes); memset(nGrayScaleTable1, 0, 2500); memset(nGrayScaleTable2, 0, 2500); nSourcePixelsPerLinePerPixel = (int)(nScaleDenominator / nHScale); if (nScaleDenominator % nHScale || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = (int)(nScaleDenominator / nVScale); if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } memcpy(nCountTable, nCountTheZerosTable, sizeof(int) * 256); // Produce scale table. if (nHScale >= 1000){ for (nLoop = 0; nLoop < nSourceBytes; nLoop++){ nSourcePixel = (nFirstSourceByte + nLoop) << 3; nDestPixel0 = max(0, ((nSourcePixel * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel1 = max(0, (((nSourcePixel + 1) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel2 = max(0, (((nSourcePixel + 2) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel3 = max(0, (((nSourcePixel + 3) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel4 = max(0, (((nSourcePixel + 4) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel5 = max(0, (((nSourcePixel + 5) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel6 = max(0, (((nSourcePixel + 6) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel7 = max(0, (((nSourcePixel + 7) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel8 = max(0, (((nSourcePixel + 8) * nHScale) / nScaleDenominator) - (int) nHDestOffset); nDestPixel[nLoop] = nDestPixel0; nMask0[nLoop] = nDestPixel1 - nDestPixel0; nMask1[nLoop] = nDestPixel2 - nDestPixel1; nMask2[nLoop] = nDestPixel3 - nDestPixel2; nMask3[nLoop] = nDestPixel4 - nDestPixel3; nMask4[nLoop] = nDestPixel5 - nDestPixel4; nMask5[nLoop] = nDestPixel6 - nDestPixel5; nMask6[nLoop] = nDestPixel7 - nDestPixel6; nMask7[nLoop] = nDestPixel8 - nDestPixel7; } }else{ // Pixel 0 = 0x80, pixel 7 = 0x01. 0 = black, 1 = white. switch (nSourcePixelsPerLinePerPixel){ case 1: nFirstMask = 0xff7f; break; case 2: nFirstMask = 0xff3f; break; case 3: nFirstMask = 0xff1f; break; case 4: nFirstMask = 0xff0f; break; case 5: nFirstMask = 0xff07; break; case 6: nFirstMask = 0xff03; break; case 7: nFirstMask = 0xff01; break; default: nFirstMask = 0xff00; break; } for (nLoop = 0; nLoop < nDestWidth; nLoop++){ nSourcePixel = ((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale; if (nSourcePixel + nSourcePixelsPerLinePerPixel > nSourceWidth){ nSourcePixel = nSourceWidth - nSourcePixelsPerLinePerPixel; } // First byte. nSourceByteIndex = (int) (nSourcePixel >> 3) - nFirstSourceByte; if (!(nPixels[nSourceByteIndex])){ nDestPixel[nSourceByteIndex] = nLoop; } switch (nPixels[nSourceByteIndex]){ case 0: nMask0[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 1: nMask1[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 2: nMask2[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 3: nMask3[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 4: nMask4[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 5: nMask5[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 6: nMask6[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 7: nMask7[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; case 8: nMask8[nSourceByteIndex] = (nFirstMask >> (nSourcePixel & 7)) & 0x0ff; break; default: Error(DISPLAY_DATACORRUPTED); goto Exit; } nPixels[nSourceByteIndex]++; nSourcePixel += nSourcePixelsPerLinePerPixel - 1; if (nLoop2 = (int) ((nSourcePixel >> 3) - (nSourceByteIndex + nFirstSourceByte))){ // Middle bytes. for (; nLoop2 > 1; nLoop2--){ nSourceByteIndex++; nDestPixel[nSourceByteIndex] = nLoop; switch (nPixels[nSourceByteIndex]){ case 0: nMask0[nSourceByteIndex] = 0; break; case 1: nMask1[nSourceByteIndex] = 0; break; case 2: nMask2[nSourceByteIndex] = 0; break; case 3: nMask3[nSourceByteIndex] = 0; break; case 4: nMask4[nSourceByteIndex] = 0; break; case 5: nMask5[nSourceByteIndex] = 0; break; case 6: nMask6[nSourceByteIndex] = 0; break; case 7: nMask7[nSourceByteIndex] = 0; break; case 8: nMask8[nSourceByteIndex] = 0; break; default: Error(DISPLAY_DATACORRUPTED); goto Exit; } nPixels[nSourceByteIndex]++; } // Last byte. nSourceByteIndex++; nDestPixel[nSourceByteIndex] = nLoop; nMask0[nSourceByteIndex] = (uchar) (0x7f >> (nSourcePixel & 7)); nPixels[nSourceByteIndex]++; } } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Generate nGrayScaleTables. nNumberOfSourceBitsPerDestBit = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; // Calculate the averaging divisors. // gray = ((0xff0000 / # of Total pixel) * # of 1's) / 0x10000 // # of 1's = # of Total pixels - # of 0's // 0xff0000 = 255 * 0x10000 if (pDestImg->nType == ITYPE_GRAY8){ lMultiplier = 0x0ff0000 / nNumberOfSourceBitsPerDestBit; }else if (pDestImg->nType == ITYPE_GRAY7){ lMultiplier = 0x07f0000 / nNumberOfSourceBitsPerDestBit; }else{ // ITYPE_GRAY4 lMultiplier = 0x00f0000 / nNumberOfSourceBitsPerDestBit; } for (nLoop = 0; nLoop < nNumberOfSourceBitsPerDestBit; nLoop++){ nTemp = (nNumberOfSourceBitsPerDestBit - nLoop) * lMultiplier; nGrayScaleTable1[nLoop] = ((nTemp >> 16) + ((nTemp >> 15) & 1)); } if (pDestImg->nType == ITYPE_GRAY4){ for (nLoop = 0; nLoop < nNumberOfSourceBitsPerDestBit; nLoop++){ nGrayScaleTable2[nLoop] = nGrayScaleTable1[nLoop] << 4; } } nDestWidthInts = sizeof(int) * nDestWidth; // Begin scaling the data. for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset((PSTR) nDest, 0, nDestWidthInts); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pSourceByte = pSourceLine + nFirstSourceByte; if (nHScale >= 1000){ nSourceByteIndex = 0; if ((int) pSourceByte & 3){ nLoopEnd = min(4 - ((int) pSourceByte & 3), nSourceBytes); }else{ nLoopEnd = 0; } while(nSourceByteIndex < nLoopEnd){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; } nLoopEnd = (nSourceBytes - nSourceByteIndex) & -4; while(nSourceByteIndex < nLoopEnd){ if (*((PDWORD) pSourceByte) == 0xffffffff){ nSourceByteIndex += 4; pSourceByte += 4; continue; }else{ do{ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; }while((int) pSourceByte & 3); } } while(nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; if (!(nSourceByte & 0x80)){ for (nLoop = nMask0[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask0[nSourceByteIndex]; } if (!(nSourceByte & 0x40)){ for (nLoop = nMask1[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask1[nSourceByteIndex]; } if (!(nSourceByte & 0x20)){ for (nLoop = nMask2[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask2[nSourceByteIndex]; } if (!(nSourceByte & 0x10)){ for (nLoop = nMask3[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask3[nSourceByteIndex]; } if (!(nSourceByte & 0x08)){ for (nLoop = nMask4[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask4[nSourceByteIndex]; } if (!(nSourceByte & 0x04)){ for (nLoop = nMask5[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask5[nSourceByteIndex]; } if (!(nSourceByte & 0x02)){ for (nLoop = nMask6[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } }else{ nPixelIndex += nMask6[nSourceByteIndex]; } if (!(nSourceByte & 0x01)){ for (nLoop = nMask7[nSourceByteIndex]; nLoop; nLoop--){ nDest[nPixelIndex++]++; } } } nSourceByteIndex++; } }else{ // nHScale < 1000. nSourceByteIndex = 0; while (((int) pSourceByte & 3) && nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } nLoopEnd = (nSourceBytes - nSourceByteIndex) & -4; while(nSourceByteIndex < nLoopEnd){ if (*((PDWORD) pSourceByte) == 0xffffffff){ nSourceByteIndex += 4; pSourceByte += 4; continue; }else{ // Do Byte 1. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 2. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 3. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; // Do Byte 4. if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } } while(nSourceByteIndex < nSourceBytes){ if ((nSourceByte = *(pSourceByte++)) != 0xff){ nPixelIndex = nDestPixel[nSourceByteIndex]; nDest[nPixelIndex] += nCountTable[nSourceByte | nMask0[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 1){ nDest[nPixelIndex + 1] += nCountTable[nSourceByte | nMask1[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 2){ nDest[nPixelIndex + 2] += nCountTable[nSourceByte | nMask2[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 3){ nDest[nPixelIndex + 3] += nCountTable[nSourceByte | nMask3[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 4){ nDest[nPixelIndex + 4] += nCountTable[nSourceByte | nMask4[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 5){ nDest[nPixelIndex + 5] += nCountTable[nSourceByte | nMask5[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 6){ nDest[nPixelIndex + 6] += nCountTable[nSourceByte | nMask6[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 7){ nDest[nPixelIndex + 7] += nCountTable[nSourceByte | nMask7[nSourceByteIndex]]; if (nPixels[nSourceByteIndex] > 8){ nDest[nPixelIndex + 8] += nCountTable[nSourceByte | nMask8[nSourceByteIndex]]; } } } } } } } } } nSourceByteIndex++; } } } // Average the line to gray. nPixelIndex = 0; pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY8 || pDestImg->nType == ITYPE_GRAY7){ pDestLine += lrDestRect.left; nTempIndex = nDestWidth + 1; while(--nTempIndex){ *(pDestLine++) = (BYTE) (nGrayScaleTable1[nDest[nPixelIndex++]]); } }else{ // GRAY4. pDestLine += lrDestRect.left / 2; nTempIndex = 0; if (lrDestRect.left & 1){ // Do first pixel. *pDestLine = (BYTE) ((*pDestLine & 0xf0) | nGrayScaleTable1[nDest[nPixelIndex++]]); pDestLine++; nTempIndex++; } // Do middle bytes. nLoopEnd = max (0, (nDestWidth - nTempIndex) >> 1); nTempIndex += nLoopEnd << 1; nLoopEnd++; while(--nLoopEnd){ *(pDestLine++) = (BYTE) (nGrayScaleTable2[nDest[nPixelIndex]] | nGrayScaleTable1[nDest[nPixelIndex + 1]]); nPixelIndex += 2; } // Do last pixel. if (nTempIndex < nDestWidth){ *pDestLine = (BYTE) ((*pDestLine & 0x0f) | nGrayScaleTable2[nDest[nPixelIndex++]]); } } } Exit: if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleRGBToGrayAvg PURPOSE: Scales RGB/BGR images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScaleRGBToGrayAvg(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; int nDestWidth; int nDestWidthBytes; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nPerLineDivisor; // Divisor for per line averaging. 1 if not needed. int nDivisor; // Divisor for averaging of all lines. int nDestLine; PINT pnSourceByteOffsets = 0; // Table nsed to translate dest pixel offsets to source byte offsets. PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. int nDestR; // Intermediate averaging value. int nDestG; // " int nDestB; // " PINT pnDestLineR = 0; // Temp buffer nsed to hold one line of average values. PINT pnDestLineG = 0; // " PINT pnDestLineB = 0; // " PBYTE pTempDestLine = 0; // Temp buffer nsed to hold one line of gray scale values. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nSourceBytes; int nSourceLines; int nDestByte; int nScaleDenominator; // Loop variables. int nLoop; PINT pnTempDestLineR; // Temp pointer nsed in loops. PINT pnTempDestLineG; // " PINT pnTempDestLineB; // " int nTempIndex; int nSourceLineCount; int nSourcePixelCount; if (!pDestImg && pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); if (pDestImg->nType == ITYPE_GRAY8 || pDestImg->nType == ITYPE_GRAY7){ nDestWidthBytes = nDestWidth; }else{ // GRAY4 nDestWidthBytes = nDestWidth / 2; } nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = nScaleDenominator / nHScale; if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = nScaleDenominator / nVScale; if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnDestLineR, NO_INIT)); CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnDestLineG, NO_INIT)); CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnDestLineB, NO_INIT)); CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pTempDestLine, NO_INIT)); // Produce table of source pixel offsets. CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnSourceByteOffsets, NO_INIT)); nSourceBytes = (int) pSourceImg->nWidth * 3; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pnSourceByteOffsets[nLoop] = (int)((((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale) * 3); if (pnSourceByteOffsets[nLoop] + (nSourcePixelsPerLinePerPixel * 3) >= nSourceBytes){ pnSourceByteOffsets[nLoop] = nSourceBytes - (nSourcePixelsPerLinePerPixel * 3); } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceLines = (int) pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceLines){ pnSourceLineOffsets[nLoop] = nSourceLines - nSourceLinesPerPixel; } } // Calculate the averaging divisors. if (nSourcePixelsPerLinePerPixel >= 16 || nSourceLinesPerPixel >= 16){ nPerLineDivisor = nSourcePixelsPerLinePerPixel; nDivisor = nSourceLinesPerPixel; }else{ nPerLineDivisor = 1; nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset(pnDestLineR, 0, sizeof(int) * nDestWidth); memset(pnDestLineG, 0, sizeof(int) * nDestWidth); memset(pnDestLineB, 0, sizeof(int) * nDestWidth); if (pSourceImg->nType == ITYPE_RGB24){ // Average first source line. for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pnTempDestLineR = pnDestLineR; pnTempDestLineG = pnDestLineG; pnTempDestLineB = pnDestLineB; for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ // Add source pixels for this line. pSourceByte = pSourceLine + pnSourceByteOffsets[nTempIndex]; nSourcePixelCount = nSourcePixelsPerLinePerPixel; nDestR = *(pSourceByte++); nDestG = *(pSourceByte++); nDestB = *(pSourceByte++); while(--nSourcePixelCount){ nDestR += *(pSourceByte++); nDestG += *(pSourceByte++); nDestB += *(pSourceByte++); } if (nPerLineDivisor != 1){ nDestR /= nPerLineDivisor; nDestG /= nPerLineDivisor; nDestB /= nPerLineDivisor; } *(pnTempDestLineR++) += nDestR; *(pnTempDestLineG++) += nDestG; *(pnTempDestLineB++) += nDestB; } } }else{ for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pnTempDestLineR = pnDestLineR; pnTempDestLineG = pnDestLineG; pnTempDestLineB = pnDestLineB; for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ // Add source pixels for this line. pSourceByte = pSourceLine + pnSourceByteOffsets[nTempIndex]; nSourcePixelCount = nSourcePixelsPerLinePerPixel; nDestB = *(pSourceByte++); nDestG = *(pSourceByte++); nDestR = *(pSourceByte++); while(--nSourcePixelCount){ nDestB += *(pSourceByte++); nDestG += *(pSourceByte++); nDestR += *(pSourceByte++); } if (nPerLineDivisor != 1){ nDestR /= nPerLineDivisor; nDestG /= nPerLineDivisor; nDestB /= nPerLineDivisor; } *(pnTempDestLineR++) += nDestR; *(pnTempDestLineG++) += nDestG; *(pnTempDestLineB++) += nDestB; } } } // Average the line to gray. pnTempDestLineR = pnDestLineR; pnTempDestLineG = pnDestLineG; pnTempDestLineB = pnDestLineB; pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY4){ for (nLoop = 0; nLoop < nDestWidthBytes; nLoop++){ nDestByte = (cRedToGray8Table[*(pnTempDestLineR++) / nDivisor] + cGreenToGray8Table[*(pnTempDestLineG++) / nDivisor] + cBlueToGray8Table[*(pnTempDestLineB++) / nDivisor]) & 0xf0; *(pDestLine++) = nDestByte | ((cRedToGray8Table[*(pnTempDestLineR++) / nDivisor] + cGreenToGray8Table[*(pnTempDestLineG++) / nDivisor] + cBlueToGray8Table[*(pnTempDestLineB++) / nDivisor]) >> 4); } if (nDestWidth & 1){ *pDestLine = (cRedToGray8Table[*pnTempDestLineR / nDivisor] + cGreenToGray8Table[*pnTempDestLineG / nDivisor] + cBlueToGray8Table[*pnTempDestLineB / nDivisor]) & 0xf0; } }else if (pDestImg->nType == ITYPE_GRAY8){ for (nLoop = 0; nLoop < nDestWidthBytes; nLoop++){ *(pDestLine++) = cRedToGray8Table[*(pnTempDestLineR++) / nDivisor] + cGreenToGray8Table[*(pnTempDestLineG++) / nDivisor] + cBlueToGray8Table[*(pnTempDestLineB++) / nDivisor]; } }else{ // GRAY7 for (nLoop = 0; nLoop < nDestWidthBytes; nLoop++){ *(pDestLine++) = (cRedToGray8Table[*(pnTempDestLineR++) / nDivisor] + cGreenToGray8Table[*(pnTempDestLineG++) / nDivisor] + cBlueToGray8Table[*(pnTempDestLineB++) / nDivisor]) >> 1; } } } Exit: if (pnSourceByteOffsets){ FreeMemory((PPSTR) &pnSourceByteOffsets); } if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } if (pnDestLineR){ FreeMemory((PPSTR) &pnDestLineR); } if (pnDestLineG){ FreeMemory((PPSTR) &pnDestLineG); } if (pnDestLineB){ FreeMemory((PPSTR) &pnDestLineB); } if (pTempDestLine){ FreeMemory((PPSTR) &pTempDestLine); } return(nStatus); } // /**************************************************************************** FUNCTION: Scale24BPPDecimate PURPOSE: Scales 24 BPP (Bit Per Pixel) images nsing decimation. *****************************************************************************/ int WINAPI Scale24BPPDecimate(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; int nDestWidth; int nDestHeight; int nDestLine; PINT pnSourceByteOffsets = 0; // Table nsed to translate dest pixel offsets to source byte offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nSourceBytes; int nLoop; int nTempIndex; int nScaleDenominator; if (pDestImg->nType != pSourceImg->nType){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); // Produce table of source pixel offsets. CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnSourceByteOffsets, NO_INIT)); nSourceBytes = (int) pSourceImg->nWidth * 3; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pnSourceByteOffsets[nLoop] = (int)((((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale) * 3); if (pnSourceByteOffsets[nLoop] >= nSourceBytes){ pnSourceByteOffsets[nLoop] = nSourceBytes - 3; } } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); pSourceLine = &pSourceImg->bImageData[0] + (((int)(((nDestLine + nVDestOffset + (int)lrDestRect.top) * nScaleDenominator) / nVScale)) * pSourceImg->nBytesPerLine); if (nHScale == 1000){ pSourceByte = pSourceLine + pnSourceByteOffsets[0]; memcpy(pDestLine + (lrDestRect.left * 3), pSourceByte, nDestWidth * 3); }else{ for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ pSourceByte = pSourceLine + pnSourceByteOffsets[nTempIndex]; *(pDestLine++) = *(pSourceByte++); *(pDestLine++) = *(pSourceByte++); *(pDestLine++) = *(pSourceByte++); } } } Exit: if (pnSourceByteOffsets){ FreeMemory((PPSTR) &pnSourceByteOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleBWKeepBlack PURPOSE: Scales BW images to BW keeping black pixels. *****************************************************************************/ int WINAPI ScaleBWKeepBlack(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT *plrDestRect){ int nStatus = 0; typedef struct tagBWKeepBlackScaleTable{ int nFirstByte; int nFirstMask; int nBytes; int nLastMask; } BW_KEEP_BLACK_SCALE_TABLE; BW_KEEP_BLACK_SCALE_TABLE ScaleTable[MAX_PIXELS_HANDLED]; int nDestWidth; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nDestLine; PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. PBYTE pDestByte; // The address of the dest byte currently being processed. int nFirstMask; int nLastMask; int nSourcePixel; int nScaleDenominator; int nXlatTable[2048]; int *pXlatTable; int nSourceWidth; int nSourceHeight; int nFirstDestByte; int nFirstDestBit; int nFirstDestMask; int nLastDestMask; int nMiddleDestBytes; int nSourceByte; // Loop variables. int nLoop; int nTempIndex; int nSourceLineCount; int nLoopEnd; int nDestBit; LRECT lrDestRect ; CopyRect (lrDestRect, *plrDestRect) ; if (pDestImg->nType != ITYPE_BI_LEVEL){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } if (nHScale >= 1000 || nHScale >= 1000){ nStatus = Scale1BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, nHDestOffset, nVDestOffset, &lrDestRect); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = (int)(nScaleDenominator / nHScale); if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = (int)(nScaleDenominator / nVScale); if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } // Init Scale table. pXlatTable = &nXlatTable[0]; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0x7f; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xbf; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xdf; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xef; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xf7; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xfb; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xfd; } *(pXlatTable++) = 0xff; for (nLoop = 255; nLoop; nLoop--){ *(pXlatTable++) = 0xfe; } *(pXlatTable++) = 0xff; // Produce scale table. // Pixel 0 = 0x80, pixel 7 = 0x01. 0 = black, 1 = white. switch (nSourcePixelsPerLinePerPixel){ case 1: nFirstMask = 0x80; break; case 2: nFirstMask = 0xc0; break; case 3: nFirstMask = 0xe0; break; case 4: nFirstMask = 0xf0; break; case 5: nFirstMask = 0xf8; break; case 6: nFirstMask = 0xfc; break; case 7: nFirstMask = 0xfe; break; default: nFirstMask = 0xff; break; } nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ nSourcePixel = ((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale; if (nSourcePixel + nSourcePixelsPerLinePerPixel > nSourceWidth){ nSourcePixel = nSourceWidth - nSourcePixelsPerLinePerPixel; } ScaleTable[nLoop].nFirstByte = (int) (nSourcePixel >> 3); ScaleTable[nLoop].nFirstMask = ~(nFirstMask >> (nSourcePixel & 7)) & 0xff; nSourcePixel += nSourcePixelsPerLinePerPixel - 1; if (!((nSourcePixel >> 3) - ScaleTable[nLoop].nFirstByte)){ ScaleTable[nLoop].nBytes = 0; ScaleTable[nLoop].nLastMask = 0; }else{ ScaleTable[nLoop].nBytes = ((int)(nSourcePixel >> 3) - ScaleTable[nLoop].nFirstByte) - 1; ScaleTable[nLoop].nLastMask = ~(0xff80 >> (nSourcePixel & 7)) & 0xff; } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * lrDestRect.bottom, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = (int) pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = (int)nSourceHeight - nSourceLinesPerPixel; } } nFirstDestByte = (lrDestRect.left >> 3); nFirstDestBit = lrDestRect.left & 7; switch (nFirstDestBit){ case 0: nDestBit = 0x80; break; case 1: nDestBit = 0x40; break; case 2: nDestBit = 0x20; break; case 3: nDestBit = 0x10; break; case 4: nDestBit = 0x08; break; case 5: nDestBit = 0x04; break; case 6: nDestBit = 0x02; break; case 7: nDestBit = 0x01; break; } nFirstDestMask = 0; for (nLoop = nDestWidth; nLoop && nDestBit; nLoop--){ nFirstDestMask |= nDestBit; nDestBit >>= 1; } nMiddleDestBytes = nLoop >> 3; nLastDestMask = 0xff; for (nLoop &= 7; nLoop; nLoop--){ nLastDestMask >>= 1; } nLastDestMask = ~nLastDestMask & 0xff; for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); // Initialize dest line to white. pDestByte = pDestLine + nFirstDestByte; *(pDestByte++) |= nFirstDestMask; if (nMiddleDestBytes){ memset(pDestByte, 0xff, nMiddleDestBytes); pDestByte += nMiddleDestBytes; } *pDestByte |= nLastDestMask; for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pSourceByte = pSourceLine + ScaleTable[0].nFirstByte; pDestByte = pDestLine + nFirstDestByte; switch (nHScale){ case 500: // Do first few pixels to align the data. nDestBit = nFirstDestBit << 8; nTempIndex = 0; while(ScaleTable[nTempIndex].nFirstMask != 0x3f && nTempIndex < nDestWidth){ *pDestByte &= nXlatTable[nDestBit + (*pSourceByte | ScaleTable[nTempIndex].nFirstMask)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } nTempIndex++; } if (nTempIndex){ pSourceByte++; } // Do middle pixels. nLoopEnd = (nDestWidth - nTempIndex) >> 2; for (; nLoopEnd; nLoopEnd--){ nSourceByte = *(pSourceByte++); *pDestByte &= nXlatTable[nDestBit + (nSourceByte | 0x3f)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } *pDestByte &= nXlatTable[nDestBit + (nSourceByte | 0xcf)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } *pDestByte &= nXlatTable[nDestBit + (nSourceByte | 0xf3)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } *pDestByte &= nXlatTable[nDestBit + (nSourceByte | 0xfc)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } } // Do last few pixels. nLoopEnd = (nDestWidth - nTempIndex) & 3; nLastMask = 0xff3f; for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + (*pSourceByte | (nLastMask & 0xff))]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } nLastMask >> 2; } break; case 250: // Do first few pixels to align the data. nDestBit = nFirstDestBit * 256; nTempIndex = 0; if (ScaleTable[nTempIndex].nFirstMask != 0x0f){ *pDestByte &= nXlatTable[nDestBit + (*pSourceByte | ScaleTable[nTempIndex].nFirstMask)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } nTempIndex++; pSourceByte++; } // Do middle pixels. nLoopEnd = (nDestWidth - nTempIndex) / 2; if (nLoopEnd){ for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + (*pSourceByte | 0x0f)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | 0xf0)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } } } // Do last few pixels. nLoopEnd = (nDestWidth - nTempIndex) & 1; nLastMask = 0xff3f; for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + (*pSourceByte | (nLastMask & 0xff))]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } nLastMask >> 2; } break; case 125: nLoopEnd = nDestWidth - 1; nDestBit = nFirstDestBit * 256; for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } } // Do last pixel via variable scale because it might start // to the left because of not enough source pixels. nTempIndex = nDestWidth - 1; pSourceByte = pSourceLine + ScaleTable[nTempIndex].nFirstByte; *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nFirstMask)]; for (nLoop = ScaleTable[nTempIndex].nBytes; nLoop; nLoop--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; } if (nLastMask = ScaleTable[nTempIndex].nLastMask){ *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nLastMask)]; } break; case 62: nDestBit = nFirstDestBit * 256; nLoopEnd = nDestWidth - 1; for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } } // Do last pixel via variable scale because it might start // to the left because of not enough source pixels. nTempIndex = nDestWidth - 1; pSourceByte = pSourceLine + ScaleTable[nTempIndex].nFirstByte; *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nFirstMask)]; for (nLoop = ScaleTable[nTempIndex].nBytes; nLoop; nLoop--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; } if (nLastMask = ScaleTable[nTempIndex].nLastMask){ *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nLastMask)]; } break; case 31: nDestBit = nFirstDestBit * 256; nLoopEnd = nDestWidth - 1; for (; nLoopEnd; nLoopEnd--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; if (!(nDestBit = (nDestBit + 256) & 0x700 )){ pDestByte++; } } // Do last pixel via variable scale because it might start // to the left because of not enough source pixels. nTempIndex = nDestWidth - 1; pSourceByte = pSourceLine + ScaleTable[nTempIndex].nFirstByte; *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nFirstMask)]; for (nLoop = ScaleTable[nTempIndex].nBytes; nLoop; nLoop--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; } if (nLastMask = ScaleTable[nTempIndex].nLastMask){ *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nLastMask)]; } break; default: // Variable scale. nDestBit = nFirstDestBit * 256; for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ pSourceByte = pSourceLine + ScaleTable[nTempIndex].nFirstByte; *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nFirstMask)]; for (nLoop = ScaleTable[nTempIndex].nBytes; nLoop; nLoop--){ *pDestByte &= nXlatTable[nDestBit + *(pSourceByte++)]; } if (nLastMask = ScaleTable[nTempIndex].nLastMask){ *pDestByte &= nXlatTable[nDestBit + (*(pSourceByte++) | ScaleTable[nTempIndex].nLastMask)]; } if ((nDestBit = (nDestBit + 256) & 0x700 )){ continue; } pDestByte++; } break; } } } Exit: if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleGray8ToGray PURPOSE: Scales GRAY8/GRAY7 images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScaleGray8ToGray(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; int nDestWidth; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nPerLineDivisor; // Divisor for per line averaging. 1 if not needed. int nDivisor; // Divisor for averaging of all lines. int nDestLine; PINT pnSourceByteOffsets = 0; // Table nsed to translate dest pixel offsets to source byte offsets. PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PINT pnDestLine = 0; // Temp buffer nsed to hold one line of average values. PBYTE pTempDestLine = 0; // Temp buffer nsed to hold one line of gray scale values. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pDestLine; // The address of the start of the dest line. int nSourceWidth; int nSourceHeight; int nScaleDenominator; // Loop variables. int nLoop; PINT pnTempDestLine; // Temp pointer nsed in loops. int nSourceLineCount; int nTempIndex; PBYTE pSourceByte; // The address of the source byte currently being processed. int nSourcePixelCount; int nDest; // Intermediate averaging value. if (pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale >= 1000 && nVScale >= 1000 && pSourceImg->nType == pDestImg->nType){ nStatus = Scale8BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, nHDestOffset, nVDestOffset, lrDestRect); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = nScaleDenominator / nHScale; if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = nScaleDenominator / nVScale; if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnDestLine, NO_INIT)); CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pTempDestLine, NO_INIT)); // Produce table of source pixel offsets. CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnSourceByteOffsets, NO_INIT)); nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pnSourceByteOffsets[nLoop] = (int)(((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale); if (pnSourceByteOffsets[nLoop] + nSourcePixelsPerLinePerPixel > nSourceWidth){ pnSourceByteOffsets[nLoop] = nSourceWidth - nSourcePixelsPerLinePerPixel; } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = (int) pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Calculate the averaging divisors. if (nSourcePixelsPerLinePerPixel >= 16 || nSourceLinesPerPixel >= 16){ nPerLineDivisor = nSourcePixelsPerLinePerPixel; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourceLinesPerPixel * 16; } }else{ nPerLineDivisor = 1; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 16; } } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset(pnDestLine, 0, sizeof(int) * nDestWidth); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine + lrDestRect.top] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pnTempDestLine = pnDestLine; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pSourceByte = pSourceLine + pnSourceByteOffsets[nLoop]; nSourcePixelCount = nSourcePixelsPerLinePerPixel; nDest = *(pSourceByte++); while(--nSourcePixelCount){ nDest += *(pSourceByte++); } if (nPerLineDivisor != 1){ nDest /= nPerLineDivisor; } *(pnTempDestLine++) += nDest; } } // Average the line to gray. pnTempDestLine = pnDestLine; pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY4){ pDestLine += lrDestRect.left / 2; nTempIndex = nDestWidth; if (lrDestRect.left & 1){ // Do first pixel. *pDestLine = (*pDestLine & 0xf0) | (*(pnTempDestLine++) / nDivisor); pDestLine++; nTempIndex--; } // Do middle bytes. for (nLoop = nTempIndex / 2; nLoop; nLoop--){ *pDestLine = *(pnTempDestLine++) / nDivisor << 4; *(pDestLine++) |= (*(pnTempDestLine++) / nDivisor); } if (nTempIndex & 1){ *pDestLine = *pnTempDestLine / nDivisor << 4; } }else{ // Dest == Gray 7/8. pDestLine += lrDestRect.left; for (nLoop = nDestWidth; nLoop; nLoop--){ *(pDestLine++) = *(pnTempDestLine++) / nDivisor; } } } Exit: if (pnSourceByteOffsets){ FreeMemory((PPSTR) &pnSourceByteOffsets); } if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } if (pnDestLine){ FreeMemory((PPSTR) &pnDestLine); } if (pTempDestLine){ FreeMemory((PPSTR) &pTempDestLine); } return(nStatus); } // /**************************************************************************** FUNCTION: Scale8BPPDecimate PURPOSE: Scales 8 BPP (Bit Per Pixel) images nsing decimation. *****************************************************************************/ int WINAPI Scale8BPPDecimate(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; int nDestWidth; int nDestHeight; int nDestLine; PINT pnSourceByteOffsets = 0; // Table nsed to translate dest pixel offsets to source byte offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nSourceByteAdder; int nSourceWidth; int nFirstPixels; int nMiddlePixels; int nLastPixels; int nScaleDenominator; // Loop variables. int nLoop; if (pDestImg->nType != pSourceImg->nType){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); // Produce table of source pixel offsets. CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnSourceByteOffsets, NO_INIT)); nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pnSourceByteOffsets[nLoop] = (int)((((nLoop + nHDestOffset) * nScaleDenominator) / nHScale)); if (pnSourceByteOffsets[nLoop] >= nSourceWidth){ pnSourceByteOffsets[nLoop] = nSourceWidth - 1; } } // Put stuff here that you only have to do once. switch (nHScale){ case 8000: nFirstPixels = min(nDestWidth, (8 - ((int)nHDestOffset + (int)lrDestRect.left)) & 7); nMiddlePixels = (nDestWidth - nFirstPixels) >> 3; nLastPixels = nDestWidth - nFirstPixels - (nMiddlePixels << 3); break; case 4000: nFirstPixels = min(nDestWidth, (4 - ((int)nHDestOffset + (int)lrDestRect.left)) & 3); nMiddlePixels = (nDestWidth - nFirstPixels) >> 2; nLastPixels = nDestWidth - nFirstPixels - (nMiddlePixels << 2); break; case 2000: nFirstPixels = min(nDestWidth, (2 - ((int)nHDestOffset + (int)lrDestRect.left)) & 1); nMiddlePixels = (nDestWidth - nFirstPixels) >> 1; nLastPixels = nDestWidth - nFirstPixels - (nMiddlePixels << 1); break; default: break; } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); pDestLine += lrDestRect.left; pSourceLine = &pSourceImg->bImageData[0] + (((int)(((nDestLine + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale)) * pSourceImg->nBytesPerLine); switch (nHScale){ case 8000: pSourceByte = pSourceLine + pnSourceByteOffsets[0]; if (nFirstPixels){ for (nLoop = nFirstPixels; nLoop; nLoop--){ *(pDestLine++) = *pSourceByte; } pSourceByte++; } for (nLoop = nMiddlePixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte++); } for (nLoop = nLastPixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); } break; case 4000: pSourceByte = pSourceLine + pnSourceByteOffsets[0]; if (nFirstPixels){ for (nLoop = nFirstPixels; nLoop; nLoop--){ *(pDestLine++) = *pSourceByte; } pSourceByte++; } for (nLoop = nMiddlePixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte++); } for (nLoop = nLastPixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); } break; case 2000: pSourceByte = pSourceLine + pnSourceByteOffsets[0]; if (nFirstPixels){ for (nLoop = nFirstPixels; nLoop; nLoop--){ *(pDestLine++) = *pSourceByte; } pSourceByte++; } for (nLoop = nMiddlePixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); *(pDestLine++) = *(pSourceByte++); } for (nLoop = nLastPixels; nLoop; nLoop--){ *(pDestLine++) = *(pSourceByte); } break; case 1000: pSourceByte = pSourceLine + pnSourceByteOffsets[0]; memcpy(pDestLine, pSourceByte, nDestWidth); break; case 500: case 250: case 125: case 62: case 31: pSourceByte = pSourceLine + pnSourceByteOffsets[0]; nSourceByteAdder = 1000 / nHScale; for (nLoop = nDestWidth; nLoop; nLoop--){ *(pDestLine++) = *pSourceByte; pSourceByte += nSourceByteAdder; } break; default: // Variable scale. for (nLoop = 0; nLoop < nDestWidth; nLoop++){ *(pDestLine++) = *(pSourceLine + pnSourceByteOffsets[nLoop]); } break; } } Exit: if (pnSourceByteOffsets){ FreeMemory((PPSTR) &pnSourceByteOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: Scale8BPPToGray PURPOSE: Scales CUSPAL8/COMPAL8 images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScalePal8ToGray(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect, LPRGBQUAD pPalette){ int nStatus = 0; int nDestWidth; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nPerLineDivisor; // Divisor for per line averaging. 1 if not needed. int nDivisor; // Divisor for averaging of all lines. int nDestLine; PINT pnSourceByteOffsets = 0; // Table nsed to translate dest pixel offsets to source byte offsets. PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PINT pnDestLine = 0; // Temp buffer nsed to hold one line of average values. PBYTE pTempDestLine = 0; // Temp buffer nsed to hold one line of gray scale values. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pDestLine; // The address of the start of the dest line. int nSourceWidth; int nSourceHeight; BYTE cPal8ToGray8Table[256]; int nScaleDenominator; // Loop variables. int nLoop; PINT pnTempDestLine; // Temp pointer nsed in loops. int nSourceLineCount; int nTempIndex; PBYTE pSourceByte; // The address of the source byte currently being processed. int nSourcePixelCount; int nDest; // Intermediate averaging value. if (pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = nScaleDenominator / nHScale; if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = nScaleDenominator / nVScale; if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnDestLine, NO_INIT)); CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pTempDestLine, NO_INIT)); // Produce table of source pixel offsets. CheckError2( AllocateMemory(sizeof(int) * nDestWidth, (PPSTR) &pnSourceByteOffsets, NO_INIT)); nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pnSourceByteOffsets[nLoop] = (int)(((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale); if (pnSourceByteOffsets[nLoop] + nSourcePixelsPerLinePerPixel > nSourceWidth){ pnSourceByteOffsets[nLoop] = nSourceWidth - nSourcePixelsPerLinePerPixel; } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = (int) pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Calculate the averaging divisors. if (nSourcePixelsPerLinePerPixel >= 16 || nSourceLinesPerPixel >= 16){ nPerLineDivisor = nSourcePixelsPerLinePerPixel; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourceLinesPerPixel * 16; } }else{ nPerLineDivisor = 1; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 16; } } // Generate palette to gray8 conversion table. // 74 = 256 * .29 // 144 = 256 * .56 // 38 = 256 * .15 for (nLoop = 0; nLoop < 256; nLoop++){ cPal8ToGray8Table[nLoop] = ((pPalette[nLoop].rgbRed * 74) + (pPalette[nLoop].rgbGreen * 144) + (pPalette[nLoop].rgbBlue * 38)) >> 8; } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset(pnDestLine, 0, sizeof(int) * nDestWidth); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine + lrDestRect.top] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pnTempDestLine = pnDestLine; if (nPerLineDivisor == 1){ for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pSourceByte = pSourceLine + pnSourceByteOffsets[nLoop]; nSourcePixelCount = nSourcePixelsPerLinePerPixel; nDest = cPal8ToGray8Table[*(pSourceByte++)]; while(--nSourcePixelCount){ nDest += cPal8ToGray8Table[*(pSourceByte++)]; } *(pnTempDestLine++) += nDest; } }else{ for (nLoop = 0; nLoop < nDestWidth; nLoop++){ pSourceByte = pSourceLine + pnSourceByteOffsets[nLoop]; nSourcePixelCount = nSourcePixelsPerLinePerPixel; nDest = cPal8ToGray8Table[*(pSourceByte++)]; while(--nSourcePixelCount){ nDest += cPal8ToGray8Table[*(pSourceByte++)]; } nDest /= nPerLineDivisor; *(pnTempDestLine++) += nDest; } } } // Average the line to gray. pnTempDestLine = pnDestLine; pDestLine = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY4){ pDestLine += lrDestRect.left / 2; nTempIndex = nDestWidth; if (lrDestRect.left & 1){ // Do first pixel. *pDestLine = (*pDestLine & 0xf0) | (*(pnTempDestLine++) / nDivisor); pDestLine++; nTempIndex--; } // Do middle bytes. for (nLoop = nTempIndex / 2; nLoop; nLoop--){ *pDestLine = *(pnTempDestLine++) / nDivisor << 4; *(pDestLine++) |= (*(pnTempDestLine++) / nDivisor); } if (nTempIndex & 1){ *pDestLine = *pnTempDestLine / nDivisor << 4; } }else{ // Dest == Gray 7/8. pDestLine += lrDestRect.left; for (nLoop = nDestWidth; nLoop; nLoop--){ *(pDestLine++) = *(pnTempDestLine++) / nDivisor; } } } Exit: if (pnSourceByteOffsets){ FreeMemory((PPSTR) &pnSourceByteOffsets); } if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } if (pnDestLine){ FreeMemory((PPSTR) &pnDestLine); } if (pTempDestLine){ FreeMemory((PPSTR) &pTempDestLine); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleGray4ToGray PURPOSE: Scales GRAY4 images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScaleGray4ToGray(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT *plrDestRect){ int nStatus = 0; int nFirstByte[MAX_PIXELS_HANDLED]; int nFirstMask[MAX_PIXELS_HANDLED]; int nBytes[MAX_PIXELS_HANDLED]; int nLastMask[MAX_PIXELS_HANDLED]; int nDestWidth; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nDivisor; // Divisor for averaging of all lines. int nDestLineNumber; int nDestLine[MAX_PIXELS_HANDLED]; // Temp buffer nsed to hold one line of average values. PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pDestLine; // The address of the start of the dest line. int nByteMask; long lSourcePixel; int nSourceWidth; int nSourceHeight; PBYTE pSourceByte; // The address of the source byte currently being processed. int nDest; // Intermediate averaging value. int nScaleDenominator; // Loop variables. int nLoop; int nTempIndex; int nSourceLineCount; int nLoopEnd; LRECT lrDestRect ; CopyRect (lrDestRect, *plrDestRect) ; if (pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale >= 1000 && nVScale >= 1000 && pSourceImg->nType == pDestImg->nType){ nStatus = Scale4BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, nHDestOffset, nVDestOffset, lrDestRect); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = nScaleDenominator / nHScale; if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = nScaleDenominator / nVScale; if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } // Produce scale table. // Pixel 0 = 0xf0, pixel 1 = 0x0f. 0 = black, f = white. if (nSourcePixelsPerLinePerPixel <= 1){ nByteMask = 0xf0; }else{ nByteMask = 0xff; } nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ lSourcePixel = ((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale; if (lSourcePixel + nSourcePixelsPerLinePerPixel > nSourceWidth){ lSourcePixel = nSourceWidth - nSourcePixelsPerLinePerPixel; } nFirstByte[nLoop] = (int) (lSourcePixel >> 1); if (lSourcePixel & 1){ nFirstMask[nLoop] = 0x0f; }else{ nFirstMask[nLoop] = nByteMask; } lSourcePixel += nSourcePixelsPerLinePerPixel; if (!((lSourcePixel >> 1) - nFirstByte[nLoop])){ nBytes[nLoop] = 0; nLastMask[nLoop] = 0; }else{ nBytes[nLoop] = ((int)(lSourcePixel >> 1) - nFirstByte[nLoop]) - 1; if (lSourcePixel & 1){ nLastMask[nLoop] = 0xf0; }else{ nLastMask[nLoop] = 0; } } } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = (int) pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (int)(((nLoop + nVDestOffset + (int)lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Calculate the averaging divisors. if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 16; } for (nDestLineNumber = 0; nDestLineNumber < nDestHeight; nDestLineNumber++){ memset(&nDestLine[0], 0, sizeof(int) * nDestWidth); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLineNumber] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ // Add source pixels for this line. pSourceByte = pSourceLine + nFirstByte[nTempIndex]; nDest = cGray4AddTable[*(pSourceByte++) & nFirstMask[nTempIndex]]; for (nLoop = nBytes[nTempIndex]; nLoop; nLoop--){ nDest += cGray4AddTable[*(pSourceByte++)]; } if (nLastMask[nTempIndex]){ nDest += cGray4AddTable[*(pSourceByte++) & nLastMask[nTempIndex]]; } nDestLine[nTempIndex] += nDest; } } // Average the line to gray. pDestLine = &pDestImg->bImageData[0] + ((nDestLineNumber + (int)lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY4){ pDestLine += lrDestRect.left / 2; nTempIndex = 0; if (lrDestRect.left & 1){ // Do first pixel. *(pDestLine++) = (*pDestLine & 0xf0) | ((nDestLine[nTempIndex++] << 4) / nDivisor); } // Do middle bytes. nLoopEnd = ((nDestWidth - nTempIndex) & -2) + nTempIndex; for (; nTempIndex < nLoopEnd;){ *pDestLine = (nDestLine[nTempIndex++] << 8) / nDivisor & 0xf0; *(pDestLine++) |= (nDestLine[nTempIndex++] << 4) / nDivisor; } if (nTempIndex < nDestWidth){ *pDestLine = (*pDestLine & 0x0f) | ((nDestLine[nTempIndex] << 8) / nDivisor & 0xf0); } }else{ // Dest = Gray 7/8. pDestLine += lrDestRect.left; for (nTempIndex = 0; nTempIndex < nDestWidth;){ *(pDestLine++) = (nDestLine[nTempIndex++] << 4) / nDivisor; } } } Exit: if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: Scale4BPPDecimate PURPOSE: Scales 4 BPP (Bit Per Pixel) images nsing decimation. *****************************************************************************/ int WINAPI Scale4BPPDecimate(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; typedef struct tagGray4DecimateScaleTable{ int nByte; int nMask; } GRAY4_DECIMATE_SCALE_TABLE, *PGRAY4_DECIMATE_SCALE_TABLE; PGRAY4_DECIMATE_SCALE_TABLE pScaleTable = 0; PGRAY4_DECIMATE_SCALE_TABLE pScaleTable1; uchar c4BPPTo0TableLocal[256]; // Table that moves the pixel to pixel 0 in the byte. uchar c4BPPTo1TableLocal[256]; // Table that moves the pixel to pixel 1 in the byte. int nDestLine; PBYTE pSourceLine; // The address of the start of the source line. PBYTE pSourceByte; // The address of the source byte currently being processed. PBYTE pDestLine; // The address of the start of the dest line. int nSourcePixel; int nSourceWidth; int nDestWidth; int nTempIndex; int nMiddleBytes; int nScaleDenominator; // Loop variables. int nLoop; int nDestByte; int nSourceByteAdder; if (pSourceImg->nType != pDestImg->nType){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); // Produce scale table . memcpy(c4BPPTo0TableLocal, c4BPPTo0Table, 256); memcpy(c4BPPTo1TableLocal, c4BPPTo1Table, 256); CheckError2( AllocateMemory(sizeof(GRAY4_DECIMATE_SCALE_TABLE) * nDestWidth, (PPSTR) &pScaleTable, NO_INIT)); // Pixel 0 = 0xf0, pixel 1 = 0x0f. 0 = black, f = white. nSourceWidth = (int) pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ nSourcePixel = (int)(((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale); if (nSourcePixel > nSourceWidth){ nSourcePixel = nSourceWidth - 1; } pScaleTable[nLoop].nByte = (int) (nSourcePixel >> 1); if (nSourcePixel & 1){ pScaleTable[nLoop].nMask = 0x0f; }else{ pScaleTable[nLoop].nMask = 0xf0; } } for (nDestLine = (int)lrDestRect.top; nDestLine < (int)lrDestRect.bottom; nDestLine++){ pDestLine = &pDestImg->bImageData[0] + (nDestLine * pDestImg->nBytesPerLine); pDestLine += lrDestRect.left / 2; pSourceLine = &pSourceImg->bImageData[0] + (((int)(((nDestLine + nVDestOffset) * nScaleDenominator) / nVScale)) * pSourceImg->nBytesPerLine); // Do first pixel. pSourceByte = pSourceLine + pScaleTable[0].nByte; pScaleTable1 = pScaleTable; nTempIndex = nDestWidth; if (lrDestRect.left & 1){ *pDestLine = *pDestLine | c4BPPTo1TableLocal[*(pSourceLine + pScaleTable1->nByte) & pScaleTable1->nMask]; pSourceByte = pSourceLine + pScaleTable[1].nByte; pScaleTable1++; pDestLine++; nTempIndex--; } // Do middle bytes. nMiddleBytes = nTempIndex / 2; if (nHScale == 1000 && !(nHDestOffset & 1)){ memcpy(pDestLine, pSourceByte, nMiddleBytes); pDestLine += nMiddleBytes; pSourceByte += nMiddleBytes; }else{ switch (nHScale){ case 500: case 250: case 125: case 62: case 31: nSourceByteAdder = (int)((1000 / nHScale) / 2); if (!(nHDestOffset & 1)){ for (nLoop = nMiddleBytes; nLoop; nLoop--){ nDestByte = *pSourceByte & 0xf0; pSourceByte += nSourceByteAdder; *(pDestLine++) = nDestByte | (*pSourceByte >> 4); pSourceByte += nSourceByteAdder; } }else{ for (nLoop = nMiddleBytes; nLoop; nLoop--){ nDestByte = (*pSourceByte << 4); pSourceByte += nSourceByteAdder; *(pDestLine++) = nDestByte | *pSourceByte & 0x0f; pSourceByte += nSourceByteAdder; } } break; default: // Variable Scale. for (nLoop = nMiddleBytes; nLoop; nLoop--){ nDestByte = c4BPPTo0TableLocal[*(pSourceLine + pScaleTable1->nByte) & pScaleTable1->nMask]; pScaleTable1++; *(pDestLine++) = nDestByte | c4BPPTo1TableLocal[*(pSourceLine + pScaleTable1->nByte) & pScaleTable1->nMask]; pScaleTable1++; } break; } } // Do last pixel. if (nTempIndex & 1){ pScaleTable1 = &pScaleTable[nDestWidth - 1]; *pDestLine = (*pDestLine & 0x0f) | c4BPPTo0TableLocal[*(pSourceLine + pScaleTable1->nByte) & pScaleTable1->nMask]; } } Exit: if (pScaleTable){ FreeMemory((PPSTR) &pScaleTable); } return(nStatus); } // /**************************************************************************** FUNCTION: ScalePAL4ToGray PURPOSE: Scales PAL4 images to GRAY8/GRAY7/GRAY4. *****************************************************************************/ int WINAPI ScalePal4ToGray(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT *plrDestRect, LPRGBQUAD pPalette){ int nStatus = 0; int nDestLineInts[MAX_PIXELS_HANDLED]; PINT pnDestLine = &nDestLineInts[0]; int nFirstByte[MAX_PIXELS_HANDLED]; BOOL bDoFirst[MAX_PIXELS_HANDLED]; int nBytes[MAX_PIXELS_HANDLED]; BOOL bDoLast[MAX_PIXELS_HANDLED]; BYTE cPal4ToGray8Table[256]; int nDestWidth; int nDestHeight; int nSourcePixelsPerLinePerPixel; int nSourceLinesPerPixel; int nPerLineDivisor; // Divisor for per line averaging. 1 if not needed. int nDivisor; // Divisor for averaging of all lines. int nDestLine; PINT pnSourceLineOffsets = 0; // Table nsed to translate dest line offsets to source line offsets. PBYTE pSourceLine; // The address of the start of the source line. PBYTE pDestLine; // The address of the start of the dest line. long lSourcePixel; int nSourceWidth; int nSourceHeight; int nPixels; int nScaleDenominator; // Loop variables. int nLoop; PINT pnTempDestLine; // Temp pointer nsed in loops. int nTempIndex; int nSourceLineCount; PBYTE pSourceByte; // The address of the source byte currently being processed. int nDest; // Intermediate averaging value. LRECT lrDestRect ; CopyRect (lrDestRect, *plrDestRect) ; if (pDestImg->nType != ITYPE_GRAY8 && pDestImg->nType != ITYPE_GRAY7 && pDestImg->nType != ITYPE_GRAY4){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (nHScale >= 1000 && nVScale >= 1000 && pSourceImg->nType == pDestImg->nType){ nStatus = Scale4BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, nHDestOffset, nVDestOffset, lrDestRect); goto Exit; } if (lrDestRect.right - lrDestRect.left > MAX_PIXELS_HANDLED || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } if (nHScale == 62 || nHScale == 31){ nScaleDenominator = 992; }else{ nScaleDenominator = SCALE_DENOMINATOR; } nDestWidth = (lrDestRect.right - lrDestRect.left); nDestHeight = (lrDestRect.bottom - lrDestRect.top); nSourcePixelsPerLinePerPixel = nScaleDenominator / nHScale; if ((nScaleDenominator % nHScale) || !nSourcePixelsPerLinePerPixel){ nSourcePixelsPerLinePerPixel++; } nSourceLinesPerPixel = nScaleDenominator / nVScale; if ((nScaleDenominator % nVScale) || !nSourceLinesPerPixel){ nSourceLinesPerPixel++; } // Generate palette to gray8 conversion table. // 74 = 256 * .29 // 144 = 256 * .56 // 38 = 256 * .15 for (nLoop = 0; nLoop < 16; nLoop++){ cPal4ToGray8Table[nLoop] = ((pPalette[nLoop].rgbRed * 74) + (pPalette[nLoop].rgbGreen * 144) + (pPalette[nLoop].rgbBlue * 38)) >> 8; cPal4ToGray8Table[nLoop << 4] = cPal4ToGray8Table[nLoop]; } // Produce scale table. // Pixel 0 = 0xf0, pixel 1 = 0x0f. nSourceWidth = pSourceImg->nWidth; for (nLoop = 0; nLoop < nDestWidth; nLoop++){ lSourcePixel = ((nLoop + nHDestOffset + lrDestRect.left) * nScaleDenominator) / nHScale; if (lSourcePixel + nSourcePixelsPerLinePerPixel > nSourceWidth){ lSourcePixel = nSourceWidth - nSourcePixelsPerLinePerPixel; } nFirstByte[nLoop] = lSourcePixel >> 1; nPixels = nSourcePixelsPerLinePerPixel; if (lSourcePixel & 1){ bDoFirst[nLoop] = 1; nPixels--; }else{ bDoFirst[nLoop] = 0; } nBytes[nLoop] = nPixels >> 1; bDoLast[nLoop] = nPixels & 1; } // Produce table of source line offsets. CheckError2( AllocateMemory(sizeof(int) * nDestHeight, (PPSTR) &pnSourceLineOffsets, NO_INIT)); nSourceHeight = pSourceImg->nHeight; for (nLoop = 0; nLoop < nDestHeight; nLoop++){ pnSourceLineOffsets[nLoop] = (((nLoop + nVDestOffset + lrDestRect.top) * nScaleDenominator) / nVScale); if (pnSourceLineOffsets[nLoop] + nSourceLinesPerPixel > nSourceHeight){ pnSourceLineOffsets[nLoop] = nSourceHeight - nSourceLinesPerPixel; } } // Calculate the averaging divisors. if (nSourcePixelsPerLinePerPixel >= 16 || nSourceLinesPerPixel >= 16){ nPerLineDivisor = nSourcePixelsPerLinePerPixel; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourceLinesPerPixel * 16; } }else{ nPerLineDivisor = 1; if (pDestImg->nType == ITYPE_GRAY8){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel; }else if(pDestImg->nType == ITYPE_GRAY7){ nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 2; }else{ // GRAY4 nDivisor = nSourcePixelsPerLinePerPixel * nSourceLinesPerPixel * 16; } } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ memset(pnDestLine, 0, sizeof(int) * nDestWidth); for (nSourceLineCount = nSourceLinesPerPixel; nSourceLineCount; nSourceLineCount--){ pSourceLine = &pSourceImg->bImageData[0] + ((pnSourceLineOffsets[nDestLine] + (nSourceLinesPerPixel - nSourceLineCount)) * pSourceImg->nBytesPerLine); pnTempDestLine = pnDestLine; if (nPerLineDivisor == 1){ for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ // Add source pixels for this line. pSourceByte = pSourceLine + nFirstByte[nTempIndex]; nDest = 0; if (bDoFirst[nTempIndex]){ nDest += cPal4ToGray8Table[*(pSourceByte++) & 0x0f]; } for (nLoop = nBytes[nTempIndex]; nLoop; nLoop--){ nDest += cPal4ToGray8Table[*pSourceByte & 0xf0]; nDest += cPal4ToGray8Table[*(pSourceByte++) & 0x0f]; } if (bDoLast[nTempIndex]){ nDest += cPal4ToGray8Table[*pSourceByte & 0xf0]; } *(pnTempDestLine++) += nDest; } }else{ for (nTempIndex = 0; nTempIndex < nDestWidth; nTempIndex++){ // Add source pixels for this line. pSourceByte = pSourceLine + nFirstByte[nTempIndex]; nDest = 0; if (bDoFirst[nTempIndex]){ nDest += cPal4ToGray8Table[*(pSourceByte++) & 0x0f]; } for (nLoop = nBytes[nTempIndex]; nLoop; nLoop--){ nDest += cPal4ToGray8Table[*pSourceByte & 0xf0]; nDest += cPal4ToGray8Table[*(pSourceByte++) & 0x0f]; } if (bDoLast[nTempIndex]){ nDest += cPal4ToGray8Table[*pSourceByte & 0xf0]; } *(pnTempDestLine++) += nDest / nPerLineDivisor; } } } // Average the line to gray. pnTempDestLine = pnDestLine; pDestLine = &pDestImg->bImageData[0] + ((nDestLine + lrDestRect.top) * pDestImg->nBytesPerLine); if (pDestImg->nType == ITYPE_GRAY4){ pDestLine += lrDestRect.left / 2; nTempIndex = nDestWidth; if (lrDestRect.left & 1){ // Do first pixel. *pDestLine = (*pDestLine & 0xf0) | (*(pnTempDestLine++) / nDivisor); pDestLine++; nTempIndex--; } // Do middle bytes. for (nLoop = nTempIndex / 2; nLoop; nLoop--){ *pDestLine = (*(pnTempDestLine++) / nDivisor) << 4; *(pDestLine++) |= *(pnTempDestLine++) / nDivisor; } if (nTempIndex & 1){ *(pDestLine++) = (*(pnTempDestLine++) / nDivisor) << 4; } }else{ // Dest = Gray 7/8. pDestLine += lrDestRect.left; for (nLoop = nDestWidth; nLoop; nLoop--){ *(pDestLine++) = *(pnTempDestLine++) / nDivisor; } } } Exit: if (pnSourceLineOffsets){ FreeMemory((PPSTR) &pnSourceLineOffsets); } return(nStatus); } // /**************************************************************************** FUNCTION: ScaleBWStamp PURPOSE: Scales BW images via Stamp. *****************************************************************************/ int WINAPI ScaleBWStamp(PIMG pSourceImg, PIMG pDestImg, int nHScale, int nVScale, int nHDestOffset, int nVDestOffset, LRECT lrDestRect){ int nStatus = 0; typedef struct tagBWToStampScaleTable{ int nFirstByte; int nFirstMask; int nBytes; int nLastMask; } BW_TO_STAMP_SCALE_TABLE, *PBW_TO_STAMP_SCALE_TABLE; PBW_TO_STAMP_SCALE_TABLE pScaleTable = 0; int nDestWidth; int nDestHeight; int nDestByte; // Dest byte. PBYTE pDestByte; // The address of the dest byte. PBYTE pLine1=0; // The address of the first source line. PBYTE pLine2; // The address of the second source line. PBYTE pLine3; // The address of the third source line. PBYTE pTempLine1; // The address of the current pixel -1 for line 1. PBYTE pTempLine2; // The address of the current pixel -1 for line 2. PBYTE pTempLine3; // The address of the current pixel -1 for line 3. PBYTE pBuffer[3]; // The address of the temporary buffers. int nNextTempBuffer = 0; // The index to the next temp buffer to nse. PIMG pImg = 0; int nPixel; LRECT lrRect; int nNeighbors; // The average of all neighboring pixels. int nDestMask; // Mask for setting bits in the dest byte. int nLines; // Loop variables. int nLoop; int nLoopEnd; int nDestLine; pBuffer[0] = 0; pBuffer[1] = 0; pBuffer[2] = 0; if (nHScale >= 1000 && nVScale >= 1000){ nStatus = Scale1BPPDecimate(pSourceImg, pDestImg, nHScale, nVScale, nHDestOffset, nVDestOffset, &lrDestRect); goto Exit; } if (pDestImg->nType != ITYPE_BI_LEVEL){ nStatus = Error(DISPLAY_INVALID_OPTIONS); goto Exit; } if (lrDestRect.right - lrDestRect.left > 0x7fff || lrDestRect.bottom - lrDestRect.top > 0x7fff){ nStatus = Error(DISPLAY_INVALIDRECT); goto Exit; } nDestWidth = (int)(lrDestRect.right - lrDestRect.left); nDestHeight = (int)(lrDestRect.bottom - lrDestRect.top); CheckError2( CreateAnyImgBuf(&pImg, nDestWidth, nDestHeight, ITYPE_GRAY8)); SetLRect(lrRect, 0, 0, nDestWidth, nDestHeight); CheckError2( ScaleBWToGray(pSourceImg, pImg, nHScale, nVScale, nHDestOffset + lrDestRect.left, nVDestOffset + lrDestRect.top, &lrRect)); // Convert the Gray8 img into a B + W stamp image. CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pBuffer[0], NO_INIT)); CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pBuffer[1], NO_INIT)); CheckError2( AllocateMemory(nDestWidth, (PPSTR) &pBuffer[2], NO_INIT)); // Init pointers to lines 1 and 2. pLine2 = pBuffer[0]; pLine3 = pBuffer[1]; nNextTempBuffer = 2; memcpy(pLine2, &pImg->bImageData[0], nDestWidth); if (pImg->nHeight > 1){ memcpy(pLine3, &pImg->bImageData[nDestWidth], nDestWidth); }else{ memcpy(pLine3, &pImg->bImageData[0], nDestWidth); } for (nDestLine = 0; nDestLine < nDestHeight; nDestLine++){ pDestByte = &pDestImg->bImageData[0] + ((nDestLine + (int)lrDestRect.top) * pDestImg->nBytesPerLine); pLine1 = pLine2; pLine2 = pLine3; if (nDestLine != (nDestHeight - 1)){ pLine3 = &pImg->bImageData[0] + ((nDestLine + 1) * pImg->nBytesPerLine); nLines = pImg->nHeight - (nDestLine + 1); if (nLines < 3){ memcpy(pBuffer[nNextTempBuffer], pLine3, nDestWidth); pLine3 = pBuffer[nNextTempBuffer++]; if (nNextTempBuffer >= 3){ nNextTempBuffer = 0; } } } pTempLine1 = pLine1; pTempLine2 = pLine2; pTempLine3 = pLine3; // Pixel 0 = 0x80, pixel 7 = 0x01. 0 = black, 1 = white. // Do first pixel. nNeighbors = pTempLine1[0]; nNeighbors += pTempLine1[1]; nNeighbors += pTempLine2[1]; nNeighbors += pTempLine3[0]; nNeighbors += pTempLine3[1]; nNeighbors /= 5; nPixel = pTempLine2[0]; if (nPixel > nNeighbors){ nDestByte = 0x80; }else if(nPixel < nNeighbors){ nDestByte = 0x00; }else if(nPixel >= 0x80){ nDestByte = 0x80; }else{ nDestByte = 0x00; } nDestMask = 0x40; // Do middle pixels. nLoopEnd = nDestWidth - 2; for (nLoop = 0; nLoop < nLoopEnd; nLoop++){ nNeighbors = pTempLine1[0]; nNeighbors += pTempLine1[1]; nNeighbors += pTempLine1[2]; nNeighbors += pTempLine2[0]; nNeighbors += pTempLine2[2]; nNeighbors += pTempLine3[0]; nNeighbors += pTempLine3[1]; nNeighbors += pTempLine3[2]; nNeighbors >>= 3; nPixel = pTempLine2[1]; if (nPixel > nNeighbors){ nDestByte |= nDestMask; }else if(nPixel == nNeighbors && nPixel >= 0x80){ nDestByte |= nDestMask; } nDestMask >>= 1; if (!nDestMask){ *(pDestByte++) = nDestByte; nDestByte = 0; nDestMask = 0x80; } pTempLine1++; pTempLine2++; pTempLine3++; } // Do last pixel. nNeighbors = pTempLine1[0]; nNeighbors += pTempLine1[1]; nNeighbors += pTempLine2[0]; nNeighbors += pTempLine3[0]; nNeighbors += pTempLine3[1]; nNeighbors /= 5; nPixel = pTempLine2[1]; if (nPixel > nNeighbors){ nDestByte |= nDestMask; }else if(nPixel == nNeighbors && nPixel >= 0x80){ nDestByte |= nDestMask; } nDestMask >> 1; *pDestByte = nDestByte; } Exit: if (pBuffer[0]){ FreeMemory((PPSTR) &pBuffer[0]); } if (pBuffer[1]){ FreeMemory((PPSTR) &pBuffer[1]); } if (pBuffer[2]){ FreeMemory((PPSTR) &pBuffer[2]); } FreeImgBuf(&pImg); return(nStatus); }