mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
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:
parent
e421a44ac6
commit
0f40e62ca7
4 changed files with 90 additions and 426 deletions
4
NEWS
4
NEWS
|
@ -32,6 +32,10 @@ PHP NEWS
|
||||||
- Enchant:
|
- Enchant:
|
||||||
. Added enchant_dict_remove_from_session(). (nielsdos)
|
. Added enchant_dict_remove_from_session(). (nielsdos)
|
||||||
|
|
||||||
|
-GD:
|
||||||
|
. Fixed bug #68629 (Transparent artifacts when using imagerotate). (pierre,
|
||||||
|
cmb)
|
||||||
|
|
||||||
- Intl:
|
- Intl:
|
||||||
. Bumped ICU requirement to ICU >= 57.1. (cmb)
|
. Bumped ICU requirement to ICU >= 57.1. (cmb)
|
||||||
. IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception
|
. IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception
|
||||||
|
|
|
@ -145,7 +145,8 @@ typedef enum {
|
||||||
GD_SINC,
|
GD_SINC,
|
||||||
GD_TRIANGLE,
|
GD_TRIANGLE,
|
||||||
GD_WEIGHTED4,
|
GD_WEIGHTED4,
|
||||||
GD_METHOD_COUNT = 21
|
GD_LINEAR,
|
||||||
|
GD_METHOD_COUNT = 22
|
||||||
} gdInterpolationMethod;
|
} gdInterpolationMethod;
|
||||||
|
|
||||||
/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */
|
/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */
|
||||||
|
|
|
@ -83,12 +83,6 @@ static gdImagePtr gdImageScaleTwoPass(const gdImagePtr pOrigImage,
|
||||||
static gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src,
|
static gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src,
|
||||||
const float degrees,
|
const float degrees,
|
||||||
const int bgColor);
|
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,
|
static gdImagePtr gdImageRotateGeneric(gdImagePtr src,
|
||||||
const float degrees,
|
const float degrees,
|
||||||
const int bgColor);
|
const int bgColor);
|
||||||
|
@ -134,28 +128,29 @@ typedef struct
|
||||||
} LineContribType;
|
} LineContribType;
|
||||||
|
|
||||||
/* Each core filter has its own radius */
|
/* Each core filter has its own radius */
|
||||||
#define DEFAULT_FILTER_BICUBIC 3.0
|
#define DEFAULT_FILTER_LINEAR 1.0f
|
||||||
#define DEFAULT_FILTER_BOX 0.5
|
#define DEFAULT_FILTER_BICUBIC 3.0f
|
||||||
#define DEFAULT_FILTER_GENERALIZED_CUBIC 0.5
|
#define DEFAULT_FILTER_BOX 0.5f
|
||||||
#define DEFAULT_FILTER_RADIUS 1.0
|
#define DEFAULT_FILTER_GENERALIZED_CUBIC 0.5f
|
||||||
#define DEFAULT_LANCZOS8_RADIUS 8.0
|
#define DEFAULT_FILTER_RADIUS 1.0f
|
||||||
#define DEFAULT_LANCZOS3_RADIUS 3.0
|
#define DEFAULT_LANCZOS8_RADIUS 8.0f
|
||||||
#define DEFAULT_HERMITE_RADIUS 1.0
|
#define DEFAULT_LANCZOS3_RADIUS 3.0f
|
||||||
#define DEFAULT_BOX_RADIUS 0.5
|
#define DEFAULT_HERMITE_RADIUS 1.0f
|
||||||
#define DEFAULT_TRIANGLE_RADIUS 1.0
|
#define DEFAULT_BOX_RADIUS 0.5f
|
||||||
#define DEFAULT_BELL_RADIUS 1.5
|
#define DEFAULT_TRIANGLE_RADIUS 1.0f
|
||||||
#define DEFAULT_CUBICSPLINE_RADIUS 2.0
|
#define DEFAULT_BELL_RADIUS 1.5f
|
||||||
#define DEFAULT_MITCHELL_RADIUS 2.0
|
#define DEFAULT_CUBICSPLINE_RADIUS 2.0f
|
||||||
#define DEFAULT_COSINE_RADIUS 1.0
|
#define DEFAULT_MITCHELL_RADIUS 2.0f
|
||||||
#define DEFAULT_CATMULLROM_RADIUS 2.0
|
#define DEFAULT_COSINE_RADIUS 1.0f
|
||||||
#define DEFAULT_QUADRATIC_RADIUS 1.5
|
#define DEFAULT_CATMULLROM_RADIUS 2.0f
|
||||||
#define DEFAULT_QUADRATICBSPLINE_RADIUS 1.5
|
#define DEFAULT_QUADRATIC_RADIUS 1.5f
|
||||||
#define DEFAULT_CUBICCONVOLUTION_RADIUS 3.0
|
#define DEFAULT_QUADRATICBSPLINE_RADIUS 1.5f
|
||||||
#define DEFAULT_GAUSSIAN_RADIUS 1.0
|
#define DEFAULT_CUBICCONVOLUTION_RADIUS 3.0f
|
||||||
#define DEFAULT_HANNING_RADIUS 1.0
|
#define DEFAULT_GAUSSIAN_RADIUS 1.0f
|
||||||
#define DEFAULT_HAMMING_RADIUS 1.0
|
#define DEFAULT_HANNING_RADIUS 1.0f
|
||||||
#define DEFAULT_SINC_RADIUS 1.0
|
#define DEFAULT_HAMMING_RADIUS 1.0f
|
||||||
#define DEFAULT_WELSH_RADIUS 1.0
|
#define DEFAULT_SINC_RADIUS 1.0f
|
||||||
|
#define DEFAULT_WELSH_RADIUS 1.0f
|
||||||
|
|
||||||
enum GD_RESIZE_FILTER_TYPE{
|
enum GD_RESIZE_FILTER_TYPE{
|
||||||
FILTER_DEFAULT = 0,
|
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));
|
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):
|
* Bicubic interpolation kernel (a=-1):
|
||||||
\verbatim
|
\verbatim
|
||||||
|
@ -631,6 +634,9 @@ static double filter_welsh(const double x)
|
||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/* Copied from upstream's libgd */
|
||||||
static inline int _color_blend (const int dst, const int src)
|
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)
|
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;
|
double new_r = 0.0f, new_g = 0.0f, new_b = 0.0f, new_a = 0.0f;
|
||||||
|
|
||||||
/* These methods use special implementations */
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1587,6 +1594,9 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_width == gdImageSX(src) && new_height == gdImageSY(src)) {
|
||||||
|
return gdImageClone(src);
|
||||||
|
}
|
||||||
switch (src->interpolation_id) {
|
switch (src->interpolation_id) {
|
||||||
/*Special cases, optimized implementations */
|
/*Special cases, optimized implementations */
|
||||||
case GD_NEAREST_NEIGHBOUR:
|
case GD_NEAREST_NEIGHBOUR:
|
||||||
|
@ -1594,10 +1604,12 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GD_BILINEAR_FIXED:
|
case GD_BILINEAR_FIXED:
|
||||||
|
case GD_LINEAR:
|
||||||
im_scaled = gdImageScaleBilinear(src, new_width, new_height);
|
im_scaled = gdImageScaleBilinear(src, new_width, new_height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GD_BICUBIC_FIXED:
|
case GD_BICUBIC_FIXED:
|
||||||
|
case GD_BICUBIC:
|
||||||
im_scaled = gdImageScaleBicubicFixed(src, new_width, new_height);
|
im_scaled = gdImageScaleBicubicFixed(src, new_width, new_height);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1706,6 +1718,10 @@ gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src->interpolation == NULL) {
|
||||||
|
gdImageSetInterpolationMethod(src, GD_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
gdRotatedImageSize(src, degrees, &bbox);
|
gdRotatedImageSize(src, degrees, &bbox);
|
||||||
new_width = bbox.width;
|
new_width = bbox.width;
|
||||||
new_height = bbox.height;
|
new_height = bbox.height;
|
||||||
|
@ -1738,389 +1754,6 @@ gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor)
|
||||||
return dst;
|
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)
|
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
|
/* 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;
|
break;
|
||||||
|
|
||||||
case GD_BILINEAR_FIXED:
|
case GD_BILINEAR_FIXED:
|
||||||
return gdImageRotateBilinear(src, angle, bgcolor);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GD_BICUBIC_FIXED:
|
case GD_BICUBIC_FIXED:
|
||||||
return gdImageRotateBicubicFixed(src, angle, bgcolor);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return gdImageRotateGeneric(src, angle, bgcolor);
|
return gdImageRotateGeneric(src, angle, bgcolor);
|
||||||
}
|
}
|
||||||
|
@ -2471,24 +2098,24 @@ int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (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_NEAREST_NEIGHBOUR:
|
||||||
case GD_WEIGHTED4:
|
case GD_WEIGHTED4:
|
||||||
im->interpolation = NULL;
|
im->interpolation = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* generic versions*/
|
/* 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:
|
case GD_BELL:
|
||||||
im->interpolation = filter_bell;
|
im->interpolation = filter_bell;
|
||||||
break;
|
break;
|
||||||
case GD_BESSEL:
|
case GD_BESSEL:
|
||||||
im->interpolation = filter_bessel;
|
im->interpolation = filter_bessel;
|
||||||
break;
|
break;
|
||||||
|
case GD_BICUBIC_FIXED:
|
||||||
case GD_BICUBIC:
|
case GD_BICUBIC:
|
||||||
im->interpolation = filter_bicubic;
|
im->interpolation = filter_bicubic;
|
||||||
break;
|
break;
|
||||||
|
@ -2534,10 +2161,13 @@ int gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id)
|
||||||
case GD_TRIANGLE:
|
case GD_TRIANGLE:
|
||||||
im->interpolation = filter_triangle;
|
im->interpolation = filter_triangle;
|
||||||
break;
|
break;
|
||||||
|
case GD_DEFAULT:
|
||||||
|
id = GD_LINEAR;
|
||||||
|
im->interpolation = filter_linear;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
im->interpolation_id = id;
|
im->interpolation_id = id;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
29
ext/gd/tests/bug68629.phpt
Normal file
29
ext/gd/tests/bug68629.phpt
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue