Commits

Chris Reuter  committed be3c8cb

Cleaned up floating-point rescaling code.

These changes improve readability without negatively affecting
correctness or performance.

1) The code to do horizontal and vertical scaling were mostly
identical. This change merges them.

2) The case where the original and result sizes were identical were
handled inefficiently (and probably incorrectly) by copying the source
to the destination with memcpy. This change makes a simple copy if
both dimensions are the same (i.e. no resizing is requested) and skips
resizing in the unchanged dimension if only one dimension is
different.

3) Other cleanups: removed dead code, improved variable names, added
assertions to document expections, etc.

  • Participants
  • Parent commits 3c5c639

Comments (0)

Files changed (2)

 gdImagePtr gdImageScaleBicubic(gdImagePtr src_img, const unsigned int new_width, const unsigned int new_height);
 gdImagePtr gdImageScaleBicubicFixed(gdImagePtr src, const unsigned int width, const unsigned int height);
 gdImagePtr gdImageScaleNearestNeighbour(gdImagePtr im, const unsigned int width, const unsigned int height);
-gdImagePtr gdImageScaleTwoPass(const gdImagePtr pOrigImage, const unsigned int uOrigWidth, const unsigned int uOrigHeight, const unsigned int uNewWidth, const unsigned int uNewHeight);
 BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height);
 
 gdImagePtr gdImageRotate90(gdImagePtr src, int ignoretransparent);

File src/gd_interpolation.c

 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <assert.h>
+
+#define NDEBUG 1 /* TODO: disable/enable assertions in configure. */
+#include <assert.h>
 
 #include "gd.h"
 #include "gdhelpers.h"
 	return gdTrueColorAlpha(((int)new_r), ((int)new_g), ((int)new_b), ((int)new_a));
 }
 
+
+typedef enum {
+    HORIZONTAL,
+    VERTICAL,
+} gdAxis;
+
+
 static inline LineContribType * _gdContributionsAlloc(unsigned int line_length, unsigned int windows_size)
 {
 	unsigned int u = 0;
 	return res;
 }
 
-static inline void _gdScaleRow(gdImagePtr pSrc,  unsigned int src_width, gdImagePtr dst, unsigned int dst_width, unsigned int row, LineContribType *contrib)
+
+static inline void
+_gdScaleOneAxis(gdImagePtr pSrc, gdImagePtr dst,
+                unsigned int dst_len, unsigned int row, LineContribType *contrib,
+                gdAxis axis)
 {
-	int *p_src_row = pSrc->tpixels[row];
-	int *p_dst_row = dst->tpixels[row];
-	unsigned int x;
+	unsigned int ndx;
 
-	for (x = 0; x < dst_width - 1; x++) {
+	for (ndx = 0; ndx < dst_len - 1; ndx++) {
 		register unsigned char r = 0, g = 0, b = 0, a = 0;
-		const int left = contrib->ContribRow[x].Left;
-		const int right = contrib->ContribRow[x].Right;
+		const int left = contrib->ContribRow[ndx].Left;
+		const int right = contrib->ContribRow[ndx].Right;
+        int *dest = (axis == HORIZONTAL) ? 
+            &dst->tpixels[row][ndx] : 
+            &dst->tpixels[ndx][row];
+
 		int i;
 
 		/* Accumulate each channel */
 		for (i = left; i <= right; i++) {
 			const int left_channel = i - left;
-			r += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetRed(p_src_row[i])));
-			g += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetGreen(p_src_row[i])));
-			b += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetBlue(p_src_row[i])));
-			a += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetAlpha(p_src_row[i])));
-		}
-		p_dst_row[x] = gdTrueColorAlpha(r, g, b, a);
-	}
-}
-
-static inline void _gdScaleHoriz(gdImagePtr pSrc, unsigned int src_width, unsigned int src_height, gdImagePtr pDst,  unsigned int dst_width, unsigned int dst_height)
+            const int srcpx = (axis == HORIZONTAL) ?
+                pSrc->tpixels[row][i] : 
+                pSrc->tpixels[i][row];
+
+			r += (unsigned char)(contrib->ContribRow[ndx].Weights[left_channel] * (double)(gdTrueColorGetRed(srcpx)));
+			g += (unsigned char)(contrib->ContribRow[ndx].Weights[left_channel] * (double)(gdTrueColorGetGreen(srcpx)));
+			b += (unsigned char)(contrib->ContribRow[ndx].Weights[left_channel] * (double)(gdTrueColorGetBlue(srcpx)));
+			a += (unsigned char)(contrib->ContribRow[ndx].Weights[left_channel] * (double)(gdTrueColorGetAlpha(srcpx)));
+		}/* for */
+
+        *dest = gdTrueColorAlpha(r, g, b, a);
+	}/* for */
+}/* _gdScaleOneAxis*/
+
+
+static inline int
+_gdScalePass(const gdImagePtr pSrc, const unsigned int src_len,
+             const gdImagePtr pDst, const unsigned int dst_len,
+             const unsigned int num_lines,
+             const gdAxis axis)
 {
-	unsigned int u;
+	unsigned int line_ndx;
 	LineContribType * contrib;
 
-	/* same width, just copy it */
-	if (dst_width == src_width) {
-		unsigned int y;
-		for (y = 0; y < src_height - 1; ++y) {
-			memcpy(pDst->tpixels[y], pSrc->tpixels[y], src_width);
-		}
-	}
+    /* Same dim, just copy it. */
+    assert(dst_len != src_len); // TODO: caller should handle this.
 
-	contrib = _gdContributionsCalc(dst_width, src_width, (double)dst_width / (double)src_width, pSrc->interpolation);
+	contrib = _gdContributionsCalc(dst_len, src_len,
+                                   (double)dst_len / (double)src_len,
+                                   pSrc->interpolation);
 	if (contrib == NULL) {
-		return;
-	}
-	/* Scale each row */
-	for (u = 0; u < dst_height - 1; u++) {
-		_gdScaleRow(pSrc, src_width, pDst, dst_width, u, contrib);
+		return 0;
 	}
-	_gdContributionsFree (contrib);
-}
 
-static inline void _gdScaleCol (gdImagePtr pSrc,  unsigned int src_width, gdImagePtr pRes, unsigned int dst_width, unsigned int dst_height, unsigned int uCol, LineContribType *contrib)
-{
-	unsigned int y;
-	for (y = 0; y < dst_height - 1; y++) {
-		register unsigned char r = 0, g = 0, b = 0, a = 0;
-		const int iLeft = contrib->ContribRow[y].Left;
-		const int iRight = contrib->ContribRow[y].Right;
-		int i;
-
-		/* Accumulate each channel */
-		for (i = iLeft; i <= iRight; i++) {
-			const int pCurSrc = pSrc->tpixels[i][uCol];
-			const int i_iLeft = i - iLeft;
-			r += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetRed(pCurSrc)));
-			g += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetGreen(pCurSrc)));
-			b += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetBlue(pCurSrc)));
-			a += (unsigned char)(contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetAlpha(pCurSrc)));
-		}
-		pRes->tpixels[y][uCol] = gdTrueColorAlpha(r, g, b, a);
+	/* Scale each line */
+    for (line_ndx = 0; line_ndx < num_lines - 1; line_ndx++) {
+        _gdScaleOneAxis(pSrc, pDst, dst_len, line_ndx, contrib, axis);
 	}
-}
-
-static inline void _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_width, const unsigned int src_height, const gdImagePtr pDst, const unsigned int dst_width, const unsigned int dst_height)
-{
-	unsigned int u;
-	LineContribType * contrib;
+	_gdContributionsFree (contrib);
 
-	/* same height, copy it */
-	if (src_height == dst_height) {
-		unsigned int y;
-		for (y = 0; y < src_height - 1; ++y) {
-			memcpy(pDst->tpixels[y], pSrc->tpixels[y], src_width);
-		}
-	}
+    return 1;
+}/* _gdScalePass*/
 
-	contrib = _gdContributionsCalc(dst_height, src_height, (double)(dst_height) / (double)(src_height), pSrc->interpolation);
-	/* scale each column */
-	for (u = 0; u < dst_width - 1; u++) {
-		_gdScaleCol(pSrc, src_width, pDst, dst_width, dst_height, u, contrib);
-	}
-	_gdContributionsFree(contrib);
-}
 
-gdImagePtr gdImageScaleTwoPass(const gdImagePtr src, const unsigned int src_width, const unsigned int src_height, const unsigned int new_width, const unsigned int new_height)
+static gdImagePtr
+gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
+                    const unsigned int new_height)
 {
-	gdImagePtr tmp_im;
-	gdImagePtr dst;
-
-	tmp_im = gdImageCreateTrueColor(new_width, src_height);
-	if (tmp_im == NULL) {
-		return NULL;
-	}
-	gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
-	_gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
-
+    const unsigned int src_width = src->sx;
+    const unsigned int src_height = src->sy;
+	gdImagePtr tmp_im = NULL;;
+	gdImagePtr dst = NULL;
+
+    /* First, handle the trivial case. */
+    if (src_width == new_width && src_height == new_height) {
+        return gdImageClone(src);
+    }/* if */
+
+    /* Scale horizontally unless sizes are the same. */
+    if (src_width == new_width) {
+        tmp_im = src;
+    } else {
+        tmp_im = gdImageCreateTrueColor(new_width, src_height);
+        if (tmp_im == NULL) {
+            return NULL;
+        }
+        gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
+
+        _gdScalePass(src, src_width, tmp_im, new_width, src_height, HORIZONTAL);
+    }/* if .. else*/
+
+    /* If vertical sizes match, we're done. */
+    if (src_height == new_height) {
+        assert(tmp_im != src);
+        return tmp_im;
+    }/* if */
+
+    /* Otherwise, we need to scale vertically. */
 	dst = gdImageCreateTrueColor(new_width, new_height);
-	if (dst == NULL) {
-		gdFree(tmp_im);
-		return NULL;
-	}
-	_gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
-	gdFree(tmp_im);
-
-	return dst;
-}
-
-gdImagePtr Scale(const gdImagePtr src, const unsigned int src_width, const unsigned int src_height, const gdImagePtr dst, const unsigned int new_width, const unsigned int new_height)
-{
-	gdImagePtr tmp_im;
-
-	tmp_im = gdImageCreateTrueColor(new_width, src_height);
-	if (tmp_im == NULL) {
-		return NULL;
-	}
-	_gdScaleHoriz(src, src_width, src_height, tmp_im, new_width, src_height);
+	if (dst != NULL) {
+        gdImageSetInterpolationMethod(dst, src->interpolation_id);
+        _gdScalePass(tmp_im, src_height, dst, new_height, new_width, VERTICAL);
+    }/* if */
 
-	_gdScaleVert(tmp_im, new_width, src_height, dst, new_width, new_height);
+    if (src != tmp_im) {
+        gdFree(tmp_im);
+    }/* if */
 
-	gdFree(tmp_im);
 	return dst;
-}
+}/* gdImageScaleTwoPass*/
+
 
 /*
 	BilinearFixed, BicubicFixed and nearest implementations are rewamped versions of the implementation in CBitmapEx
 			if (src->interpolation == NULL) {
 				return NULL;
 			}
-			im_scaled = gdImageScaleTwoPass(src, src->sx, src->sy, new_width, new_height);
+			im_scaled = gdImageScaleTwoPass(src, new_width, new_height);
 			break;
 	}
 	return im_scaled;