From f723ba29e8dad2e9dc964183e87730a686ea651b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 20 Nov 2012 00:47:38 +1030 Subject: [PATCH] splash: implement bilinear scaling for scaling up --- splash/Splash.cc | 210 ++++++++++++++++++++++++------------------------------ 1 file changed, 92 insertions(+), 118 deletions(-) diff --git a/splash/Splash.cc b/splash/Splash.cc index e46a496..7c7b538 100644 --- a/splash/Splash.cc +++ b/splash/Splash.cc @@ -4524,160 +4524,134 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, gfree(lineBuf); } +// expand source row to scaledWidth using linear interpolation +static void expandRow(Guchar *srcBuf, Guchar *dstBuf, int srcWidth, int scaledWidth, int nComps) +{ + double xStep = (double)srcWidth/scaledWidth; + double xSrc = 0.0; + double xFrac, xInt; + int p; + + for (int x = 0; x < scaledWidth; x++) { + xFrac = modf(xSrc, &xInt); + p = (int)xInt; + for (int c = 0; c < nComps; c++) { + dstBuf[nComps*x + c] = srcBuf[nComps*p + c]*(1.0 - xFrac) + srcBuf[nComps*(p+1) + c]*xFrac; + } + xSrc += xStep; + } +} + void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { - Guchar *lineBuf, *alphaLineBuf; + Guchar *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2; Guint pix[splashMaxColorComps]; - Guint alpha; Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; - int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; - int i, j; - - // Bresenham parameters for y scale - yp = scaledHeight / srcHeight; - yq = scaledHeight % srcHeight; - - // Bresenham parameters for x scale - xp = scaledWidth / srcWidth; - xq = scaledWidth % srcWidth; + int i; // allocate buffers - lineBuf = (Guchar *)gmallocn(srcWidth, nComps); + srcBuf = (Guchar *)gmallocn(srcWidth, nComps); + lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps); + lineBuf2 = (Guchar *)gmallocn(scaledWidth, nComps); if (srcAlpha) { - alphaLineBuf = (Guchar *)gmalloc(srcWidth); + alphaSrcBuf = (Guchar *)gmalloc(srcWidth); + alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth); + alphaLineBuf2 = (Guchar *)gmalloc(scaledWidth); } else { - alphaLineBuf = NULL; + alphaSrcBuf = NULL; + alphaLineBuf1 = NULL; + alphaLineBuf2 = NULL; } - // init y scale Bresenham - yt = 0; + double ySrc = 0.0; + double yStep = (double)srcHeight/scaledHeight; + double yFrac, yInt; + int currentSrcRow = -1; + (*src)(srcData, srcBuf, alphaSrcBuf); + expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); + if (srcAlpha) + expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); destPtr0 = dest->data; destAlphaPtr0 = dest->alpha; - for (y = 0; y < srcHeight; ++y) { - - // y scale Bresenham - if ((yt += yq) >= srcHeight) { - yt -= srcHeight; - yStep = yp + 1; - } else { - yStep = yp; - } - - // read row from image - (*src)(srcData, lineBuf, alphaLineBuf); + for (int y = 0; y < scaledHeight; y++) { + yFrac = modf(ySrc, &yInt); + if ((int)yInt > currentSrcRow) { + memcpy(lineBuf1, lineBuf2, scaledWidth * nComps); + (*src)(srcData, srcBuf, alphaSrcBuf); + expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps); - // init x scale Bresenham - xt = 0; - - xx = 0; - for (x = 0; x < srcWidth; ++x) { - - // x scale Bresenham - if ((xt += xq) >= srcWidth) { - xt -= srcWidth; - xStep = xp + 1; - } else { - xStep = xp; + if (srcAlpha) { + memcpy(alphaLineBuf1, alphaLineBuf2, scaledWidth); + expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1); } + currentSrcRow++; + } + // write row y using linear interpolation on lineBuf1 and lineBuf2 + for (int x = 0; x < scaledWidth; ++x) { // compute the final pixel for (i = 0; i < nComps; ++i) { - pix[i] = lineBuf[x * nComps + i]; + pix[i] = lineBuf1[x*nComps + i]*(1.0 - yFrac) + lineBuf2[x*nComps + i]*yFrac; } // store the pixel + destPtr = destPtr0 + (y * scaledWidth + x) * nComps; switch (srcMode) { - case splashModeMono1: // mono1 is not allowed - break; - case splashModeMono8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - } - } - break; - case splashModeRGB8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - } - } - break; - case splashModeXBGR8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)255; - } - } - break; - case splashModeBGR8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[0]; - } - } - break; + case splashModeMono1: // mono1 is not allowed + break; + case splashModeMono8: + *destPtr++ = (Guchar)pix[0]; + break; + case splashModeRGB8: + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + break; + case splashModeXBGR8: + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)255; + break; + case splashModeBGR8: + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[0]; + break; #if SPLASH_CMYK - case splashModeCMYK8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - *destPtr++ = (Guchar)pix[0]; - *destPtr++ = (Guchar)pix[1]; - *destPtr++ = (Guchar)pix[2]; - *destPtr++ = (Guchar)pix[3]; - } - } - break; - case splashModeDeviceN8: - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; - for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) - *destPtr++ = (Guchar)pix[cp]; - } - } - break; + case splashModeCMYK8: + *destPtr++ = (Guchar)pix[0]; + *destPtr++ = (Guchar)pix[1]; + *destPtr++ = (Guchar)pix[2]; + *destPtr++ = (Guchar)pix[3]; + break; + case splashModeDeviceN8: + for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) + *destPtr++ = (Guchar)pix[cp]; + break; #endif } // process alpha if (srcAlpha) { - alpha = alphaLineBuf[x]; - for (i = 0; i < yStep; ++i) { - for (j = 0; j < xStep; ++j) { - destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j; - *destAlphaPtr = (Guchar)alpha; - } - } + destAlphaPtr = destAlphaPtr0 + y*scaledWidth + x; + *destAlphaPtr = alphaLineBuf1[x]*(1.0 - yFrac) + alphaLineBuf2[x]*yFrac; } - - xx += xStep; } - destPtr0 += yStep * scaledWidth * nComps; - if (srcAlpha) { - destAlphaPtr0 += yStep * scaledWidth; - } + ySrc += yStep; } - gfree(alphaLineBuf); - gfree(lineBuf); + gfree(alphaSrcBuf); + gfree(alphaLineBuf1); + gfree(alphaLineBuf2); + gfree(srcBuf); + gfree(lineBuf1); + gfree(lineBuf2); } void Splash::vertFlipImage(SplashBitmap *img, int width, int height, -- 1.7.10.4