From 0f40e62ca7d2b38ff3afa7fb500661724732f265 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 6 Jan 2025 22:57:17 +0100 Subject: [PATCH] Fix bug 68629: Transparent artifacts when using imagerotate We port the respective upstream fix[1], which dropped the special cased implementations of fixed-point arithmetic rotation in favor of the generic implementation. We also port follow-up upstream fixes[2][3]. [1] [2] [3] Closes GH-17375. --- NEWS | 4 + ext/gd/libgd/gd.h | 3 +- ext/gd/libgd/gd_interpolation.c | 480 ++++---------------------------- ext/gd/tests/bug68629.phpt | 29 ++ 4 files changed, 90 insertions(+), 426 deletions(-) create mode 100644 ext/gd/tests/bug68629.phpt diff --git a/NEWS b/NEWS index 59308b0242b..7089480653d 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,10 @@ PHP NEWS - Enchant: . Added enchant_dict_remove_from_session(). (nielsdos) +-GD: + . Fixed bug #68629 (Transparent artifacts when using imagerotate). (pierre, + cmb) + - Intl: . Bumped ICU requirement to ICU >= 57.1. (cmb) . IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h index a5ab6c00ca5..5325a637092 100644 --- a/ext/gd/libgd/gd.h +++ b/ext/gd/libgd/gd.h @@ -145,7 +145,8 @@ typedef enum { GD_SINC, GD_TRIANGLE, GD_WEIGHTED4, - GD_METHOD_COUNT = 21 + GD_LINEAR, + GD_METHOD_COUNT = 22 } gdInterpolationMethod; /* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */ diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index ac55dd43b64..9b0551c7afc 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -83,12 +83,6 @@ static gdImagePtr gdImageScaleTwoPass(const gdImagePtr pOrigImage, static gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, const int bgColor); -static gdImagePtr gdImageRotateBilinear(gdImagePtr src, - const float degrees, - const int bgColor); -static gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, - const float degrees, - const int bgColor); static gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor); @@ -134,28 +128,29 @@ typedef struct } LineContribType; /* Each core filter has its own radius */ -#define DEFAULT_FILTER_BICUBIC 3.0 -#define DEFAULT_FILTER_BOX 0.5 -#define DEFAULT_FILTER_GENERALIZED_CUBIC 0.5 -#define DEFAULT_FILTER_RADIUS 1.0 -#define DEFAULT_LANCZOS8_RADIUS 8.0 -#define DEFAULT_LANCZOS3_RADIUS 3.0 -#define DEFAULT_HERMITE_RADIUS 1.0 -#define DEFAULT_BOX_RADIUS 0.5 -#define DEFAULT_TRIANGLE_RADIUS 1.0 -#define DEFAULT_BELL_RADIUS 1.5 -#define DEFAULT_CUBICSPLINE_RADIUS 2.0 -#define DEFAULT_MITCHELL_RADIUS 2.0 -#define DEFAULT_COSINE_RADIUS 1.0 -#define DEFAULT_CATMULLROM_RADIUS 2.0 -#define DEFAULT_QUADRATIC_RADIUS 1.5 -#define DEFAULT_QUADRATICBSPLINE_RADIUS 1.5 -#define DEFAULT_CUBICCONVOLUTION_RADIUS 3.0 -#define DEFAULT_GAUSSIAN_RADIUS 1.0 -#define DEFAULT_HANNING_RADIUS 1.0 -#define DEFAULT_HAMMING_RADIUS 1.0 -#define DEFAULT_SINC_RADIUS 1.0 -#define DEFAULT_WELSH_RADIUS 1.0 +#define DEFAULT_FILTER_LINEAR 1.0f +#define DEFAULT_FILTER_BICUBIC 3.0f +#define DEFAULT_FILTER_BOX 0.5f +#define DEFAULT_FILTER_GENERALIZED_CUBIC 0.5f +#define DEFAULT_FILTER_RADIUS 1.0f +#define DEFAULT_LANCZOS8_RADIUS 8.0f +#define DEFAULT_LANCZOS3_RADIUS 3.0f +#define DEFAULT_HERMITE_RADIUS 1.0f +#define DEFAULT_BOX_RADIUS 0.5f +#define DEFAULT_TRIANGLE_RADIUS 1.0f +#define DEFAULT_BELL_RADIUS 1.5f +#define DEFAULT_CUBICSPLINE_RADIUS 2.0f +#define DEFAULT_MITCHELL_RADIUS 2.0f +#define DEFAULT_COSINE_RADIUS 1.0f +#define DEFAULT_CATMULLROM_RADIUS 2.0f +#define DEFAULT_QUADRATIC_RADIUS 1.5f +#define DEFAULT_QUADRATICBSPLINE_RADIUS 1.5f +#define DEFAULT_CUBICCONVOLUTION_RADIUS 3.0f +#define DEFAULT_GAUSSIAN_RADIUS 1.0f +#define DEFAULT_HANNING_RADIUS 1.0f +#define DEFAULT_HAMMING_RADIUS 1.0f +#define DEFAULT_SINC_RADIUS 1.0f +#define DEFAULT_WELSH_RADIUS 1.0f enum GD_RESIZE_FILTER_TYPE{ FILTER_DEFAULT = 0, @@ -331,6 +326,14 @@ static double filter_blackman(const double x) return (0.42f+0.5f*(double)cos(M_PI*x)+0.08f*(double)cos(2.0f*M_PI*x)); } +double filter_linear(const double x) { + double ax = fabs(x); + if (ax < 1.0f) { + return (1.0f - ax); + } + return 0.0f; +} + /** * Bicubic interpolation kernel (a=-1): \verbatim @@ -631,6 +634,9 @@ static double filter_welsh(const double x) } #endif + +/* keep it for future usage for affine copy over an existing image, targetting fix for 2.2.2 */ +#if 0 /* Copied from upstream's libgd */ static inline int _color_blend (const int dst, const int src) { @@ -663,6 +669,7 @@ static inline int _color_blend (const int dst, const int src) } } } +#endif static inline int getPixelOverflowTC(gdImagePtr im, const int x, const int y, const int bgColor) { @@ -764,7 +771,7 @@ int getPixelInterpolated(gdImagePtr im, const double x, const double y, const in double new_r = 0.0f, new_g = 0.0f, new_b = 0.0f, new_a = 0.0f; /* These methods use special implementations */ - if (im->interpolation_id == GD_BILINEAR_FIXED || im->interpolation_id == GD_BICUBIC_FIXED || im->interpolation_id == GD_NEAREST_NEIGHBOUR) { + if (im->interpolation_id == GD_NEAREST_NEIGHBOUR) { return -1; } @@ -1587,6 +1594,9 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons return NULL; } + if (new_width == gdImageSX(src) && new_height == gdImageSY(src)) { + return gdImageClone(src); + } switch (src->interpolation_id) { /*Special cases, optimized implementations */ case GD_NEAREST_NEIGHBOUR: @@ -1594,10 +1604,12 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons break; case GD_BILINEAR_FIXED: + case GD_LINEAR: im_scaled = gdImageScaleBilinear(src, new_width, new_height); break; case GD_BICUBIC_FIXED: + case GD_BICUBIC: im_scaled = gdImageScaleBicubicFixed(src, new_width, new_height); break; @@ -1706,6 +1718,10 @@ gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor) return NULL; } + if (src->interpolation == NULL) { + gdImageSetInterpolationMethod(src, GD_DEFAULT); + } + gdRotatedImageSize(src, degrees, &bbox); new_width = bbox.width; new_height = bbox.height; @@ -1738,389 +1754,6 @@ gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor) return dst; } -static gdImagePtr -gdImageRotateBilinear(gdImagePtr src, const float degrees, const int bgColor) -{ - float _angle = (float)((- degrees / 180.0f) * M_PI); - const unsigned int src_w = gdImageSX(src); - const unsigned int src_h = gdImageSY(src); - unsigned int new_width, new_height; - const gdFixed f_0_5 = gd_ftofx(0.5f); - const gdFixed f_H = gd_itofx(src_h/2); - const gdFixed f_W = gd_itofx(src_w/2); - const gdFixed f_cos = gd_ftofx(cos(-_angle)); - const gdFixed f_sin = gd_ftofx(sin(-_angle)); - const gdFixed f_1 = gd_itofx(1); - unsigned int i; - unsigned int dst_offset_x; - unsigned int dst_offset_y = 0; - unsigned int src_offset_x, src_offset_y; - gdImagePtr dst; - gdRect bbox; - - gdRotatedImageSize(src, degrees, &bbox); - - new_width = bbox.width; - new_height = bbox.height; - - dst = gdImageCreateTrueColor(new_width, new_height); - if (dst == NULL) { - return NULL; - } - dst->saveAlphaFlag = 1; - - for (i = 0; i < new_height; i++) { - unsigned int j; - dst_offset_x = 0; - - for (j=0; j < new_width; j++) { - const gdFixed f_i = gd_itofx((int)i - (int)new_height/2); - const gdFixed f_j = gd_itofx((int)j - (int)new_width/2); - const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H; - const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W; - const int m = gd_fxtoi(f_m); - const int n = gd_fxtoi(f_n); - - if ((m >= 0) && (m < src_h - 1) && (n >= 0) && (n < src_w - 1)) { - const gdFixed f_f = f_m - gd_itofx(m); - const gdFixed f_g = f_n - gd_itofx(n); - const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g); - const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g); - const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g); - const gdFixed f_w4 = gd_mulfx(f_f, f_g); - - if (m < src_h-1) { - src_offset_x = n; - src_offset_y = m + 1; - } - - if (!((n >= src_w-1) || (m >= src_h-1))) { - src_offset_x = n + 1; - src_offset_y = m + 1; - } - { - const int pixel1 = src->tpixels[src_offset_y][src_offset_x]; - register int pixel2, pixel3, pixel4; - - if (src_offset_y + 1 >= src_h) { - pixel2 = pixel1; - pixel3 = pixel1; - pixel4 = pixel1; - } else if (src_offset_x + 1 >= src_w) { - pixel2 = pixel1; - pixel3 = pixel1; - pixel4 = pixel1; - } else { - pixel2 = src->tpixels[src_offset_y][src_offset_x + 1]; - pixel3 = src->tpixels[src_offset_y + 1][src_offset_x]; - pixel4 = src->tpixels[src_offset_y + 1][src_offset_x + 1]; - } - { - const gdFixed f_r1 = gd_itofx(gdTrueColorGetRed(pixel1)); - const gdFixed f_r2 = gd_itofx(gdTrueColorGetRed(pixel2)); - const gdFixed f_r3 = gd_itofx(gdTrueColorGetRed(pixel3)); - const gdFixed f_r4 = gd_itofx(gdTrueColorGetRed(pixel4)); - const gdFixed f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1)); - const gdFixed f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2)); - const gdFixed f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3)); - const gdFixed f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4)); - const gdFixed f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1)); - const gdFixed f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2)); - const gdFixed f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3)); - const gdFixed f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4)); - const gdFixed f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1)); - const gdFixed f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2)); - const gdFixed f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3)); - const gdFixed f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4)); - const gdFixed f_red = gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4); - const gdFixed f_green = gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4); - const gdFixed f_blue = gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4); - const gdFixed f_alpha = gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4); - - const unsigned char red = (unsigned char) CLAMP(gd_fxtoi(f_red), 0, 255); - const unsigned char green = (unsigned char) CLAMP(gd_fxtoi(f_green), 0, 255); - const unsigned char blue = (unsigned char) CLAMP(gd_fxtoi(f_blue), 0, 255); - const unsigned char alpha = (unsigned char) CLAMP(gd_fxtoi(f_alpha), 0, 127); - - dst->tpixels[dst_offset_y][dst_offset_x++] = gdTrueColorAlpha(red, green, blue, alpha); - } - } - } else { - dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor; - } - } - dst_offset_y++; - } - return dst; -} - -static gdImagePtr -gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const int bgColor) -{ - const float _angle = (float)((- degrees / 180.0f) * M_PI); - const int src_w = gdImageSX(src); - const int src_h = gdImageSY(src); - unsigned int new_width, new_height; - const gdFixed f_0_5 = gd_ftofx(0.5f); - const gdFixed f_H = gd_itofx(src_h/2); - const gdFixed f_W = gd_itofx(src_w/2); - const gdFixed f_cos = gd_ftofx(cos(-_angle)); - const gdFixed f_sin = gd_ftofx(sin(-_angle)); - const gdFixed f_1 = gd_itofx(1); - const gdFixed f_2 = gd_itofx(2); - const gdFixed f_4 = gd_itofx(4); - const gdFixed f_6 = gd_itofx(6); - const gdFixed f_gama = gd_ftofx(1.04f); - - unsigned int dst_offset_x; - unsigned int dst_offset_y = 0; - unsigned int i; - gdImagePtr dst; - gdRect bbox; - - gdRotatedImageSize(src, degrees, &bbox); - new_width = bbox.width; - new_height = bbox.height; - dst = gdImageCreateTrueColor(new_width, new_height); - - if (dst == NULL) { - return NULL; - } - dst->saveAlphaFlag = 1; - - for (i=0; i < new_height; i++) { - unsigned int j; - dst_offset_x = 0; - - for (j=0; j < new_width; j++) { - const gdFixed f_i = gd_itofx((int)i - (int)new_height/2); - const gdFixed f_j = gd_itofx((int)j - (int)new_width/2); - const gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H; - const gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W; - const int m = gd_fxtoi(f_m); - const int n = gd_fxtoi(f_n); - - if ((m > 0) && (m < src_h - 1) && (n > 0) && (n < src_w-1)) { - const gdFixed f_f = f_m - gd_itofx(m); - const gdFixed f_g = f_n - gd_itofx(n); - unsigned int src_offset_x[16], src_offset_y[16]; - unsigned char red, green, blue, alpha; - gdFixed f_red=0, f_green=0, f_blue=0, f_alpha=0; - int k; - - if ((m < 1) || (n < 1)) { - src_offset_x[0] = n; - src_offset_y[0] = m; - } else { - src_offset_x[0] = n - 1; - src_offset_y[0] = m; - } - - src_offset_x[1] = n; - src_offset_y[1] = m; - - if ((m < 1) || (n >= src_w-1)) { - src_offset_x[2] = - 1; - src_offset_y[2] = - 1; - } else { - src_offset_x[2] = n + 1; - src_offset_y[2] = m ; - } - - if ((m < 1) || (n >= src_w-2)) { - src_offset_x[3] = - 1; - src_offset_y[3] = - 1; - } else { - src_offset_x[3] = n + 1 + 1; - src_offset_y[3] = m ; - } - - if (n < 1) { - src_offset_x[4] = - 1; - src_offset_y[4] = - 1; - } else { - src_offset_x[4] = n - 1; - src_offset_y[4] = m; - } - - src_offset_x[5] = n; - src_offset_y[5] = m; - if (n >= src_w-1) { - src_offset_x[6] = - 1; - src_offset_y[6] = - 1; - } else { - src_offset_x[6] = n + 1; - src_offset_y[6] = m; - } - - if (n >= src_w-2) { - src_offset_x[7] = - 1; - src_offset_y[7] = - 1; - } else { - src_offset_x[7] = n + 1 + 1; - src_offset_y[7] = m; - } - - if ((m >= src_h-1) || (n < 1)) { - src_offset_x[8] = - 1; - src_offset_y[8] = - 1; - } else { - src_offset_x[8] = n - 1; - src_offset_y[8] = m; - } - - if (m >= src_h-1) { - src_offset_x[9] = - 1; - src_offset_y[9] = - 1; - } else { - src_offset_x[9] = n; - src_offset_y[9] = m; - } - - if ((m >= src_h-1) || (n >= src_w-1)) { - src_offset_x[10] = - 1; - src_offset_y[10] = - 1; - } else { - src_offset_x[10] = n + 1; - src_offset_y[10] = m; - } - - if ((m >= src_h-1) || (n >= src_w-2)) { - src_offset_x[11] = - 1; - src_offset_y[11] = - 1; - } else { - src_offset_x[11] = n + 1 + 1; - src_offset_y[11] = m; - } - - if ((m >= src_h-2) || (n < 1)) { - src_offset_x[12] = - 1; - src_offset_y[12] = - 1; - } else { - src_offset_x[12] = n - 1; - src_offset_y[12] = m; - } - - if (m >= src_h-2) { - src_offset_x[13] = - 1; - src_offset_y[13] = - 1; - } else { - src_offset_x[13] = n; - src_offset_y[13] = m; - } - - if ((m >= src_h-2) || (n >= src_w - 1)) { - src_offset_x[14] = - 1; - src_offset_y[14] = - 1; - } else { - src_offset_x[14] = n + 1; - src_offset_y[14] = m; - } - - if ((m >= src_h-2) || (n >= src_w-2)) { - src_offset_x[15] = - 1; - src_offset_y[15] = - 1; - } else { - src_offset_x[15] = n + 1 + 1; - src_offset_y[15] = m; - } - - for (k=-1; k<3; k++) { - const gdFixed f = gd_itofx(k)-f_f; - const gdFixed f_fm1 = f - f_1; - const gdFixed f_fp1 = f + f_1; - const gdFixed f_fp2 = f + f_2; - gdFixed f_a = 0, f_b = 0,f_c = 0, f_d = 0; - gdFixed f_RY; - int l; - - if (f_fp2 > 0) { - f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2)); - } - - if (f_fp1 > 0) { - f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1)); - } - - if (f > 0) { - f_c = gd_mulfx(f,gd_mulfx(f,f)); - } - - if (f_fm1 > 0) { - f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1)); - } - f_RY = gd_divfx((f_a-gd_mulfx(f_4,f_b)+gd_mulfx(f_6,f_c)-gd_mulfx(f_4,f_d)),f_6); - - for (l=-1; l< 3; l++) { - const gdFixed f = gd_itofx(l) - f_g; - const gdFixed f_fm1 = f - f_1; - const gdFixed f_fp1 = f + f_1; - const gdFixed f_fp2 = f + f_2; - gdFixed f_a = 0, f_b = 0, f_c = 0, f_d = 0; - gdFixed f_RX, f_R; - const int _k = ((k + 1) * 4) + (l + 1); - register gdFixed f_rs, f_gs, f_bs, f_as; - register int c; - - if (f_fp2 > 0) { - f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2)); - } - - if (f_fp1 > 0) { - f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1)); - } - - if (f > 0) { - f_c = gd_mulfx(f,gd_mulfx(f,f)); - } - - if (f_fm1 > 0) { - f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1)); - } - - f_RX = gd_divfx((f_a - gd_mulfx(f_4, f_b) + gd_mulfx(f_6, f_c) - gd_mulfx(f_4, f_d)), f_6); - f_R = gd_mulfx(f_RY, f_RX); - - if ((src_offset_x[_k] <= 0) || (src_offset_y[_k] <= 0) || (src_offset_y[_k] >= src_h) || (src_offset_x[_k] >= src_w)) { - c = bgColor; - } else if ((src_offset_x[_k] <= 1) || (src_offset_y[_k] <= 1) || (src_offset_y[_k] >= (int)src_h - 1) || (src_offset_x[_k] >= (int)src_w - 1)) { - gdFixed f_127 = gd_itofx(127); - c = src->tpixels[src_offset_y[_k]][src_offset_x[_k]]; - c = c | (( (int) (gd_fxtof(gd_mulfx(f_R, f_127)) + 50.5f)) << 24); - c = _color_blend(bgColor, c); - } else { - c = src->tpixels[src_offset_y[_k]][src_offset_x[_k]]; - } - - f_rs = gd_itofx(gdTrueColorGetRed(c)); - f_gs = gd_itofx(gdTrueColorGetGreen(c)); - f_bs = gd_itofx(gdTrueColorGetBlue(c)); - f_as = gd_itofx(gdTrueColorGetAlpha(c)); - - f_red += gd_mulfx(f_rs, f_R); - f_green += gd_mulfx(f_gs, f_R); - f_blue += gd_mulfx(f_bs, f_R); - f_alpha += gd_mulfx(f_as, f_R); - } - } - - red = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_red, f_gama)), 0, 255); - green = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_green, f_gama)), 0, 255); - blue = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_blue, f_gama)), 0, 255); - alpha = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_alpha, f_gama)), 0, 127); - - dst->tpixels[dst_offset_y][dst_offset_x] = gdTrueColorAlpha(red, green, blue, alpha); - } else { - dst->tpixels[dst_offset_y][dst_offset_x] = bgColor; - } - dst_offset_x++; - } - - dst_offset_y++; - } - return dst; -} - gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor) { /* round to two decimals and keep the 100x multiplication to use it in the common square angles @@ -2177,13 +1810,7 @@ gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, in break; case GD_BILINEAR_FIXED: - return gdImageRotateBilinear(src, angle, bgcolor); - break; - case GD_BICUBIC_FIXED: - return gdImageRotateBicubicFixed(src, angle, bgcolor); - break; - default: return gdImageRotateGeneric(src, angle, bgcolor); } @@ -2471,24 +2098,24 @@ int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id) } switch (id) { - case GD_DEFAULT: - id = GD_BILINEAR_FIXED; - ZEND_FALLTHROUGH; - /* Optimized versions */ - case GD_BILINEAR_FIXED: - case GD_BICUBIC_FIXED: case GD_NEAREST_NEIGHBOUR: case GD_WEIGHTED4: im->interpolation = NULL; break; /* generic versions*/ + /* GD_BILINEAR_FIXED and GD_BICUBIC_FIXED are kept for BC reasons */ + case GD_BILINEAR_FIXED: + case GD_LINEAR: + im->interpolation = filter_linear; + break; case GD_BELL: im->interpolation = filter_bell; break; case GD_BESSEL: im->interpolation = filter_bessel; break; + case GD_BICUBIC_FIXED: case GD_BICUBIC: im->interpolation = filter_bicubic; break; @@ -2534,10 +2161,13 @@ int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id) case GD_TRIANGLE: im->interpolation = filter_triangle; break; + case GD_DEFAULT: + id = GD_LINEAR; + im->interpolation = filter_linear; + break; default: return 0; - break; } im->interpolation_id = id; return 1; diff --git a/ext/gd/tests/bug68629.phpt b/ext/gd/tests/bug68629.phpt new file mode 100644 index 00000000000..fe77229ee80 --- /dev/null +++ b/ext/gd/tests/bug68629.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #68629 (Transparent artifacts when using imagerotate) +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(0)