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] <bd6d2e101f>
[2] <6d21d30429>
[3] <9df878a400>

Closes GH-17375.
This commit is contained in:
Christoph M. Becker 2025-01-06 22:57:17 +01:00
parent e421a44ac6
commit 0f40e62ca7
No known key found for this signature in database
GPG key ID: D66C9593118BCCB6
4 changed files with 90 additions and 426 deletions

4
NEWS
View file

@ -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

View file

@ -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; */

View file

@ -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;

View file

@ -0,0 +1,29 @@
--TEST--
Bug #68629 (Transparent artifacts when using imagerotate)
--EXTENSIONS--
gd
--SKIPIF--
<?php
if (!GD_BUNDLED && version_compare(GD_VERSION, "2.2.2") < 0) die("skip only fixed as of libgd 2.2.2");
?>
--FILE--
<?php
$im1 = imagecreatetruecolor(200, 200);
$trans = imagecolorallocatealpha($im1, 0, 0, 0, 127);
imagefill($im1, 0, 0, $trans);
$im2 = imagerotate($im1, 45, $trans);
$count = 0;
$width = imagesx($im2);
$height = imagesy($im2);
for ($y = 0; $y < $height; $y++) {
for ($x = 0; $x < $width; $x++) {
$rgb = imagecolorat($im2, $x, $y);
if ($rgb !== 0x7f000000) {
$count++;
}
}
}
var_dump($count);
?>
--EXPECT--
int(0)