/**************************************************************************** ** ** Copyright (C) 1999-2001 NVIDIA Corporation. ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt 3D Studio. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ //============================================================================== // Includes //============================================================================== #include "Qt3DSRender.h" #include "foundation/Qt3DSMath.h" #include "foundation/Qt3DSAllocatorCallback.h" #include "Qt3DSRenderImageScaler.h" #include "foundation/Qt3DSMemoryBuffer.h" using namespace qt3ds::render; //============================================================================== // Namespace //============================================================================== CImageScaler::CImageScaler(NVAllocatorCallback &inAlloc) : m_Allocator(inAlloc) { } //============================================================================== /** * Scales the given image by the given scale factor. * * This method creates a new image based on the parameters given. * * @param inScaleMethod type of scaling operation * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::Scale(EScaleMethod inScaleMethod, unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { switch (inScaleMethod) { case SCALEMETHOD_CROP: CImageScaler::Crop(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); break; case SCALEMETHOD_BILINEAR: CImageScaler::Bilinear(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); break; default: QT3DS_ASSERT(false); break; } } //============================================================================== /** * Scales the given image by the given scale factor. * * This method creates a new image based on the parameters given. * * @param inScaleMethod type of scaling operation * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::FastScale(EScaleMethod inScaleMethod, unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { switch (inScaleMethod) { case SCALEMETHOD_CROP: CImageScaler::Crop(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); break; case SCALEMETHOD_POINTSAMPLE: CImageScaler::FastPointSample(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); break; default: QT3DS_ASSERT(false); break; } } //============================================================================== /** * Debug method that simply crops the picture instead of scaling. * * Not for use in production. This is a test method to exercise the framework. * * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::Crop(unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { Q_UNUSED(inOldHeight); QT3DS_ASSERT(inNewWidth <= inOldWidth); QT3DS_ASSERT(inNewHeight <= inOldHeight); long theMinWidth = NVMin(inOldWidth, inNewWidth); outNewBuffer = new unsigned char[inNewWidth * inNewHeight * inPlanes]; ::memset(outNewBuffer, 0, inNewWidth * inNewHeight * inPlanes); for (unsigned long theRow = 0; theRow < inNewHeight; ++theRow) { ::memcpy(outNewBuffer + theRow * inNewWidth * inPlanes, inOldBuffer + theRow * inOldWidth * inPlanes, theMinWidth * inPlanes); } } //============================================================================== /** * Plain scaling. * * Code adopted from http://www.codeguru.com/bitmap/SmoothBitmapResizing.html * Preliminary formatting completed but still needs work. * * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::Bilinear(unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { QT3DS_ASSERT(inPlanes > 0); outNewBuffer = new unsigned char[inNewWidth * inNewHeight * inPlanes]; CImageScaler::Resize(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); } //============================================================================== /** * Fast removal of selected pixels. * * Really fast scanning of every n-th pixel. This algorithm works basically by * adding a fraction to the source pointer for each pixel destination, using * fixed point arithmetic. * * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::FastPointSample(unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { unsigned long theXAccum; unsigned long theYAccum; unsigned long theXConst; unsigned long theYConst; unsigned long theRow; unsigned long theColumn; unsigned long theAdd; unsigned long theSrcIndex; outNewBuffer = new unsigned char[inNewWidth * inNewHeight * inPlanes]; // *** Debug *** // char dMessage[100]; //::sprintf( dMessage, "PointSample: %ldx%ld to %ldx%ld\n",inOldInfo.m_Width, inOldInfo.m_Height, outNewInfo.m_Width, outNewInfo.m_Height ); //::OutputDebugString( dMessage ); switch (inPlanes) { case 4: { long *theSrc; long *theDst; theSrc = reinterpret_cast(inOldBuffer); theDst = reinterpret_cast(outNewBuffer); theYAccum = 0; theXConst = (inOldWidth << 16) / inNewWidth; theYConst = (inOldHeight << 16) / inNewHeight; unsigned long theAdd; for (theRow = 0; theRow < inNewHeight; theRow++) { theXAccum = 0; theSrcIndex = 0; for (theColumn = 0; theColumn < inNewWidth; theColumn++) { theXAccum += theXConst; theAdd = theXAccum >> 16; *theDst = theSrc[theSrcIndex]; theDst++; theSrcIndex += theAdd; // Clear out the integer portion of the accumulator. theXAccum = theXAccum & 0xFFFF; } theYAccum += theYConst; theAdd = (theYAccum) >> 16; theSrc += theAdd * inOldWidth; // Clear out the integer portion of the accumulator. theYAccum = theYAccum & 0xFFFF; } } break; case 3: { unsigned char *theDest; unsigned char *theSource; theDest = reinterpret_cast(outNewBuffer); theSource = reinterpret_cast(inOldBuffer); theYAccum = 0; theXConst = (inOldWidth << 16) / inNewWidth; theYConst = (inOldHeight << 16) / inNewHeight; for (theRow = 0; theRow < inNewHeight; ++theRow) { theXAccum = 0; theSrcIndex = 0; for (theColumn = 0; theColumn < inNewWidth; ++theColumn) { theDest[0] = theSource[0]; theDest[1] = theSource[1]; theDest[2] = theSource[2]; theDest += 3; theSrcIndex += 3 * (theXAccum) >> 16; theXAccum = theXAccum & 0xFFFF; } theYAccum += theYConst; theAdd = (theYAccum) >> 16; theSource += theAdd * inOldWidth * 3; theYAccum = theYAccum & 0xFFFF; } } break; case 2: { short *theDest; short *theSource; theDest = reinterpret_cast(outNewBuffer); theSource = reinterpret_cast(inOldBuffer); theYAccum = 0; theXConst = (inOldWidth << 16) / inNewWidth; theYConst = (inOldHeight << 16) / inNewHeight; for (unsigned long theY = 0; theY < inNewHeight; ++theY) { theXAccum = 0; theSrcIndex = 0; for (unsigned long theX = 0; theX < inNewWidth; ++theX) { *theDest = *theSource; ++theDest; theXAccum += theXConst; theSrcIndex += (theXAccum) >> 16; theXAccum = theXAccum & 0xFFFF; } theYAccum += theYConst; theAdd = (theYAccum) >> 16; theSource += theAdd * inOldWidth; theYAccum = theYAccum & 0xFFFF; } } break; case 1: { unsigned char *theDest; unsigned char *theSource; theDest = reinterpret_cast(outNewBuffer); theSource = reinterpret_cast(inOldBuffer); theYAccum = 0; theXConst = (inOldWidth << 16) / inNewWidth; theYConst = (inOldHeight << 16) / inNewHeight; for (unsigned long theY = 0; theY < inNewHeight; ++theY) { theXAccum = 0; theSrcIndex = 0; for (unsigned long theX = 0; theX < inNewWidth; ++theX) { *theDest = *theSource; ++theDest; theXAccum += theXConst; theSrcIndex += (theXAccum) >> 16; theXAccum = theXAccum & 0xFFFF; } theYAccum += theYConst; theAdd = (theYAccum) >> 16; theSource += theAdd * inOldWidth; theYAccum = theYAccum & 0xFFFF; } } break; default: QT3DS_ASSERT(false); break; } } //============================================================================== /** * @param inWidth * @param inHeight * @return unsigned char* */ unsigned char *CImageScaler::AllocateBuffer(long inWidth, long inHeight) { unsigned char *theBuffer = new unsigned char[inHeight * inWidth * 4]; return theBuffer; } //============================================================================== /** * @param ioBuffer the buffer to release */ void CImageScaler::ReleaseBuffer(unsigned char *&ioBuffer) { delete[] ioBuffer; ioBuffer = NULL; } //============================================================================== /** * @param inOldBuffer points to the old picture * @param inOldWidth width of the old picture * @param inOldHeight height of the old picture * @param inNewBuffer will point to the scaled picture * @param inNewWidth width of the new picture * @param inNewHeight height of the new picture * @param inPlanes number of planes (1 for greyscale, 3 for rgb, etc) * also equivalent to the return value of the CTextureType::PixelSize method. */ void CImageScaler::Resize(unsigned char *inOldBuffer, unsigned long inOldWidth, unsigned long inOldHeight, unsigned char *&outNewBuffer, unsigned long inNewWidth, unsigned long inNewHeight, unsigned long inPlanes) { QT3DS_ASSERT(inPlanes == 4); // only do the temporary allocation if necessary if (inOldWidth < inNewWidth || inOldHeight < inNewHeight) { CImageScaler::ExpandRowsAndColumns(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth, inNewHeight, inPlanes); return; } else { // The downsampling algorithms *do* assume four planes. if (inOldWidth > inNewWidth && inOldHeight > inNewHeight) { MemoryBuffer<> theBuffer(ForwardingAllocator(m_Allocator, "ImageScaler::TempBuffer")); theBuffer.reserve(inNewWidth * inOldHeight * 4); unsigned char *theTempBuffer = theBuffer.begin(); CImageScaler::ReduceCols(inOldBuffer, inOldWidth, inOldHeight, theTempBuffer, inNewWidth); CImageScaler::ReduceRows(theTempBuffer, inNewWidth, inOldHeight, outNewBuffer, inNewHeight); } else if (inOldWidth > inNewWidth) { CImageScaler::ReduceCols(inOldBuffer, inOldWidth, inOldHeight, outNewBuffer, inNewWidth); } else if (inOldHeight > inNewHeight) { CImageScaler::ReduceRows(inOldBuffer, inNewWidth, inOldHeight, outNewBuffer, inNewHeight); } } } void CImageScaler::ExpandRowsAndColumns(unsigned char *inBuffer, unsigned long inWidth, unsigned long inHeight, unsigned char *outBuffer, unsigned long inDstWidth, unsigned long inDstHeight, unsigned long inPlanes) { if (inDstWidth < inWidth || inDstHeight < inHeight) { return; } /*if( inPlanes == 4 ) { FastExpandRowsAndColumns( inBuffer, inWidth, inHeight, outBuffer, inDstWidth, inDstHeight ); return; }*/ unsigned long theYPosition; unsigned short theYRatio; unsigned short theYInvRatio; unsigned long theXPosition; unsigned short theXRatio; unsigned short theXInvRatio; unsigned long theRow; unsigned long theColumn; unsigned long theSrcIndex; unsigned long theDstIndex; unsigned long theSrcLineLength; unsigned long theTemp; unsigned long thePixel; theDstIndex = 0; theSrcIndex = 0; theSrcLineLength = inWidth * inPlanes; theYPosition = inDstHeight; theYRatio = 1 << 8; theYInvRatio = 0; theXInvRatio = 0; // Here we go.... // This algorithm will be quite a bit hairy, if you want // to understand it, then look at the two expand alogorithms above // and realize the this is just the logical combination of the two for (theRow = 0; theRow < inDstHeight; theRow++) { // Run through all the rows, multiplying if necessary the two ratio's together theXPosition = inDstWidth; if (theYPosition < inHeight) { // We have crossed a row boundary theYRatio = (unsigned short)((theYPosition << 8) / inHeight); theYInvRatio = (unsigned short)((1 << 8) - theYRatio); for (theColumn = 0; theColumn < inDstWidth; theColumn++) { if (theXPosition < inWidth) { theXRatio = (unsigned short)((theXPosition << 8) / inWidth); theXInvRatio = (unsigned short)((1 << 8) - theXRatio); // The combination of both the x and y ratio's unsigned long theLeftRatio = (theXRatio * theYRatio) >> 8; unsigned long theRightRatio = (theXInvRatio * theYRatio) >> 8; unsigned long theLowLeftRatio = (theXRatio * theYInvRatio) >> 8; unsigned long theLowRightRatio = (theXInvRatio * theYInvRatio) >> 8; // We are on a row and column boundary, thus each pixel here is the // combination of four pixels (left right, low left, low right) for (thePixel = 0; thePixel < inPlanes; thePixel++) { // Left side first theTemp = (theLeftRatio * inBuffer[theSrcIndex]); theTemp += (theRightRatio * inBuffer[theSrcIndex + inPlanes]); theTemp += (theLowLeftRatio * inBuffer[theSrcIndex + theSrcLineLength]); theTemp += (theLowRightRatio * inBuffer[theSrcIndex + theSrcLineLength + inPlanes]); outBuffer[theDstIndex] = (unsigned char)(theTemp >> 8); theDstIndex++; theSrcIndex++; } // Reset our position calculation theXPosition = inDstWidth - inWidth + theXPosition; } else { for (thePixel = 0; thePixel < inPlanes; thePixel++) { theTemp = theYRatio * inBuffer[theSrcIndex + thePixel]; theTemp += theYInvRatio * inBuffer[theSrcIndex + theSrcLineLength + thePixel]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 8); theDstIndex++; } // Reset our position calculation theXPosition -= inWidth; } } // Reset our position calculation theYPosition = inDstHeight - inHeight + theYPosition; // Make the src index point to the next line theSrcIndex += inPlanes; } // Ends the if to check if we are crossing a row boundary // Else we are not crossing a row boundary else { for (theColumn = 0; theColumn < inDstWidth; theColumn++) { // If we are crossing a column boundary if (theXPosition < inWidth) { theXRatio = (unsigned short)((theXPosition << 8) / inWidth); theXInvRatio = (unsigned short)((1 << 8) - theXRatio); for (thePixel = 0; thePixel < inPlanes; thePixel++) { theTemp = theXRatio * inBuffer[theSrcIndex]; theTemp += theXInvRatio * inBuffer[theSrcIndex + inPlanes]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 8); theSrcIndex++; theDstIndex++; } theXPosition = inDstWidth - inWidth + theXPosition; } // Else we are not crossing a column boundary else { for (thePixel = 0; thePixel < inPlanes; thePixel++) { outBuffer[theDstIndex] = inBuffer[theSrcIndex + thePixel]; theDstIndex++; } theXPosition -= inWidth; } } // reset our y position indicator theYPosition -= inHeight; // reset the src index to the beginning the next line theSrcIndex += inPlanes; // reset src index to the beginning of this line theSrcIndex -= theSrcLineLength; } // End of else for row boundary } // End of for loop for iterating through all rows } // Assuming the number of planes is four void CImageScaler::FastExpandRowsAndColumns(unsigned char *inBuffer, unsigned long inWidth, unsigned long inHeight, unsigned char *outBuffer, unsigned long inDstWidth, unsigned long inDstHeight) { if (inDstWidth < inWidth || inDstHeight < inHeight) { return; } unsigned long theYPosition; unsigned short theYRatio; unsigned short theYInvRatio; unsigned long theXPosition; unsigned short theXRatio; unsigned short theXInvRatio; // The combination of both the x and y ratio's unsigned long theLeftRatio; unsigned long theRightRatio; unsigned long theLowLeftRatio; unsigned long theLowRightRatio; unsigned long theRow; unsigned long theColumn; unsigned long theSrcIndex; unsigned long theDstIndex; unsigned long theSrcLineLength; unsigned long theTemp; theDstIndex = 0; theSrcIndex = 0; theSrcLineLength = inWidth * 4; theYPosition = inDstHeight; theYInvRatio = 0; theXInvRatio = 0; // Here we go.... // This algorithm will be quite a bit hairy, if you want // to understand it, then look at the two expand alogorithms above // and realize the this is just the logical combination of the two for (theRow = 0; theRow < inDstHeight; theRow++) { // Run through all the rows, multiplying if necessary the two ratio's together theXPosition = inDstWidth; if (theYPosition < inHeight) { // We have crossed a row boundary theYRatio = (unsigned short)((theYPosition << 8) / inHeight); theYInvRatio = (unsigned short)((1 << 8) - theYRatio); for (theColumn = 0; theColumn < inDstWidth; theColumn++) { if (theXPosition < inWidth) { theXRatio = (unsigned short)((theXPosition << 8) / inWidth); theXInvRatio = (unsigned short)((1 << 8) - theXRatio); theLeftRatio = (theXRatio * theYRatio) >> 8; theRightRatio = (theXInvRatio * theYRatio) >> 8; theLowLeftRatio = (theXRatio * theYInvRatio) >> 8; theLowRightRatio = (theXInvRatio * theYInvRatio) >> 8; // We are on a row and column boundary, thus each pixel here is the // combination of four pixels (left right, low left, low right) // Left side first theTemp = (inBuffer[theSrcIndex]); theTemp += (inBuffer[theSrcIndex + 4]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength + 4]); outBuffer[theDstIndex] = (unsigned char)(theTemp >> 2); theDstIndex++; theSrcIndex++; // Left side first theTemp = (inBuffer[theSrcIndex]); theTemp += (inBuffer[theSrcIndex + 4]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength + 4]); outBuffer[theDstIndex] = (unsigned char)(theTemp >> 2); theDstIndex++; theSrcIndex++; // Left side first theTemp = (inBuffer[theSrcIndex]); theTemp += (inBuffer[theSrcIndex + 4]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength + 4]); outBuffer[theDstIndex] = (unsigned char)(theTemp >> 2); theDstIndex++; theSrcIndex++; // Left side first theTemp = (inBuffer[theSrcIndex]); theTemp += (inBuffer[theSrcIndex + 4]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength]); theTemp += (inBuffer[theSrcIndex + theSrcLineLength + 4]); outBuffer[theDstIndex] = (unsigned char)(theTemp >> 2); theDstIndex++; theSrcIndex++; // Reset our position calculation theXPosition = inDstWidth - inWidth + theXPosition; } else { theTemp = inBuffer[theSrcIndex]; theTemp += inBuffer[theSrcIndex + theSrcLineLength]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theDstIndex++; theTemp = inBuffer[theSrcIndex + 1]; theTemp += inBuffer[theSrcIndex + theSrcLineLength + 1]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theDstIndex++; theTemp = inBuffer[theSrcIndex + 2]; theTemp += inBuffer[theSrcIndex + theSrcLineLength + 2]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theDstIndex++; theTemp = inBuffer[theSrcIndex + 3]; theTemp += inBuffer[theSrcIndex + theSrcLineLength + 3]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theDstIndex++; // Reset our position calculation theXPosition -= inWidth; } } // Reset our position calculation theYPosition = inDstHeight - inHeight + theYPosition; // Make the src index point to the next line theSrcIndex += 4; } // Ends the if to check if we are crossing a row boundary // Else we are not crossing a row boundary else { for (theColumn = 0; theColumn < inDstWidth; theColumn++) { // If we are crossing a column boundary if (theXPosition < inWidth) { theXRatio = (unsigned short)((theXPosition << 8) / inWidth); theXInvRatio = (unsigned short)((1 << 8) - theXRatio); theTemp = inBuffer[theSrcIndex]; theTemp += inBuffer[theSrcIndex + 4]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theSrcIndex++; theDstIndex++; theTemp = inBuffer[theSrcIndex]; theTemp += inBuffer[theSrcIndex + 4]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theSrcIndex++; theDstIndex++; theTemp = inBuffer[theSrcIndex]; theTemp += inBuffer[theSrcIndex + 4]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theSrcIndex++; theDstIndex++; theTemp = inBuffer[theSrcIndex]; theTemp += inBuffer[theSrcIndex + 4]; outBuffer[theDstIndex] = (unsigned char)(theTemp >> 1); theSrcIndex++; theDstIndex++; theXPosition = inDstWidth - inWidth + theXPosition; } // Else we are not crossing a column boundary else { *((long *)(outBuffer + theDstIndex)) = *((long *)(inBuffer + theSrcIndex)); theDstIndex += 4; theXPosition -= inWidth; } } // reset our y position indicator theYPosition -= inHeight; // reset the src index to the beginning the next line theSrcIndex += 4; // reset src index to the beginning of this line theSrcIndex -= theSrcLineLength; } // End of else for row boundary } // End of for loop for iterating through all rows } //============================================================================== /** * @param inSrcBuffer */ void CImageScaler::ReduceCols(unsigned char *inSrcBuffer, long inSrcWidth, long inSrcHeight, unsigned char *&outDstBuffer, long inDstWidth) { long theDDAConst = static_cast(1024.0 * inDstWidth / inSrcWidth); long theDDAAccum = 0L; long thePixelCount; long theSrcRow; long theSrcCol; long theDstCol; long theRedAccum; long theGreenAccum; long theBlueAccum; long theAlphaAccum; unsigned char *theDstPointer = outDstBuffer; unsigned char *theSrcPointer = inSrcBuffer; unsigned char *theSrcRowPointer; unsigned char *theDstRowPointer; long theSrcStepSize = 4; long theDstStepSize = 4; for (theSrcRow = 0; theSrcRow < inSrcHeight; ++theSrcRow) { theSrcRowPointer = theSrcPointer + (theSrcRow * inSrcWidth * theSrcStepSize); theDstRowPointer = theDstPointer + (theSrcRow * inDstWidth * theDstStepSize); theSrcCol = 0L; theDstCol = 0L; theRedAccum = 0L; theGreenAccum = 0L; theBlueAccum = 0L; theAlphaAccum = 0L; thePixelCount = 0L; theDDAAccum = 0L; while (theSrcCol < inSrcWidth) { while ((theDDAAccum < 1024L) && (theSrcCol < inSrcWidth)) { theRedAccum += 1024L * theSrcRowPointer[(theSrcCol * theSrcStepSize) + 0]; theGreenAccum += 1024L * theSrcRowPointer[(theSrcCol * theSrcStepSize) + 1]; theBlueAccum += 1024L * theSrcRowPointer[(theSrcCol * theSrcStepSize) + 2]; theAlphaAccum += 1024L * theSrcRowPointer[(theSrcCol * theSrcStepSize) + 3]; theDDAAccum += theDDAConst; thePixelCount += 1024L; ++theSrcCol; } theDDAAccum = (theSrcCol < inSrcWidth) ? (theDDAAccum - 1024L) : (0L); thePixelCount -= theDDAAccum; theRedAccum -= theDDAAccum * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 0]; theGreenAccum -= theDDAAccum * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 1]; theBlueAccum -= theDDAAccum * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 2]; theAlphaAccum -= theDDAAccum * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 3]; theDstRowPointer[(theDstCol * theDstStepSize) + 0] = (unsigned char)(theRedAccum / thePixelCount); theDstRowPointer[(theDstCol * theDstStepSize) + 1] = (unsigned char)(theGreenAccum / thePixelCount); theDstRowPointer[(theDstCol * theDstStepSize) + 2] = (unsigned char)(theBlueAccum / thePixelCount); theDstRowPointer[(theDstCol * theDstStepSize) + 3] = (unsigned char)(theAlphaAccum / thePixelCount); thePixelCount = 1024L - theDDAAccum; ++theDstCol; if (theDstCol >= inDstWidth) { break; } theRedAccum = thePixelCount * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 0]; theGreenAccum = thePixelCount * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 1]; theBlueAccum = thePixelCount * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 2]; theAlphaAccum = thePixelCount * (long)theSrcRowPointer[((theSrcCol - 1) * theSrcStepSize) + 3]; } } } //============================================================================== /** * @param inSrcBuffer */ void CImageScaler::ReduceRows(unsigned char *inSrcBuffer, long inSrcWidth, long inSrcHeight, unsigned char *&outDstBuffer, long inDstHeight) { long theDDAConst = static_cast(1024.0 * inDstHeight / inSrcHeight); long theDDAAccum = 0; long thePixelCount; long theSrcRow; long theSrcCol; long theDstRow; long theRedAccum; long theGreenAccum; long theBlueAccum; long theAlphaAccum; unsigned char *theDstPointer = outDstBuffer; unsigned char *theSrcPointer = inSrcBuffer; unsigned char *theSrcColPointer = NULL; unsigned char *theDstColPointer = NULL; long theStepSize = 4; long theSrcStride = 4 * inSrcWidth; long theDstStride = 4 * inSrcWidth; for (theSrcCol = 0; theSrcCol < inSrcWidth; ++theSrcCol) { theSrcColPointer = theSrcPointer + (theSrcCol * theStepSize); theDstColPointer = theDstPointer + (theSrcCol * theStepSize); theSrcRow = 0L; theDstRow = 0L; theRedAccum = 0L; theGreenAccum = 0L; theBlueAccum = 0L; theAlphaAccum = 0L; thePixelCount = 0L; theDDAAccum = 0L; while (theSrcRow < inSrcHeight) { while ((theDDAAccum < 1024L) && (theSrcRow < inSrcHeight)) { theRedAccum += 1024L * theSrcColPointer[(theSrcRow * theSrcStride) + 0]; theGreenAccum += 1024L * theSrcColPointer[(theSrcRow * theSrcStride) + 1]; theBlueAccum += 1024L * theSrcColPointer[(theSrcRow * theSrcStride) + 2]; theAlphaAccum += 1024L * theSrcColPointer[(theSrcRow * theSrcStride) + 3]; theDDAAccum += theDDAConst; thePixelCount += 1024L; ++theSrcRow; } theDDAAccum = (theSrcRow < inSrcHeight) ? (theDDAAccum - 1024L) : (0L); thePixelCount -= theDDAAccum; theRedAccum -= theDDAAccum * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 0]; theGreenAccum -= theDDAAccum * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 1]; theBlueAccum -= theDDAAccum * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 2]; theAlphaAccum -= theDDAAccum * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 3]; theDstColPointer[(theDstRow * theDstStride) + 0] = (unsigned char)(theRedAccum / thePixelCount); theDstColPointer[(theDstRow * theDstStride) + 1] = (unsigned char)(theGreenAccum / thePixelCount); theDstColPointer[(theDstRow * theDstStride) + 2] = (unsigned char)(theBlueAccum / thePixelCount); theDstColPointer[(theDstRow * theDstStride) + 3] = (unsigned char)(theAlphaAccum / thePixelCount); thePixelCount = 1024L - theDDAAccum; ++theDstRow; if (theDstRow >= inDstHeight) { break; } theRedAccum = thePixelCount * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 0]; theGreenAccum = thePixelCount * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 1]; theBlueAccum = thePixelCount * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 2]; theAlphaAccum = thePixelCount * (long)theSrcColPointer[((theSrcRow - 1) * theSrcStride) + 3]; } } }