Merge branch 'PHP-7.0' into PHP-7.1

* PHP-7.0:
  Fixed bug #65148 (imagerotate may alter image dimensions)
This commit is contained in:
Christoph M. Becker 2017-10-24 17:09:14 +02:00
commit 9c79de4d62
4 changed files with 247 additions and 22 deletions

3
NEWS
View File

@ -19,6 +19,9 @@ PHP NEWS
. Fixed bug #75301 (Exif extension has built in revision version). (Peter . Fixed bug #75301 (Exif extension has built in revision version). (Peter
Kokot) Kokot)
- GD:
. Fixed bug #65148 (imagerotate may alter image dimensions). (cmb)
- intl: - intl:
. Fixed bug #75317 (UConverter::setDestinationEncoding changes source instead . Fixed bug #75317 (UConverter::setDestinationEncoding changes source instead
of destination). (andrewnester) of destination). (andrewnester)

View File

@ -1709,13 +1709,28 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons
return im_scaled; return im_scaled;
} }
static int gdRotatedImageSize(gdImagePtr src, const float angle, gdRectPtr bbox)
{
gdRect src_area;
double m[6];
gdAffineRotate(m, angle);
src_area.x = 0;
src_area.y = 0;
src_area.width = gdImageSX(src);
src_area.height = gdImageSY(src);
if (gdTransformAffineBoundingBox(&src_area, m, bbox) != GD_TRUE) {
return GD_FALSE;
}
return GD_TRUE;
}
gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, const int bgColor) gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, const int bgColor)
{ {
float _angle = ((float) (-degrees / 180.0f) * (float)M_PI); float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
const int src_w = gdImageSX(src); const int src_w = gdImageSX(src);
const int src_h = gdImageSY(src); const int src_h = gdImageSY(src);
const unsigned int new_width = (unsigned int)(abs((int)(src_w * cos(_angle))) + abs((int)(src_h * sin(_angle))) + 0.5f);
const unsigned int new_height = (unsigned int)(abs((int)(src_w * sin(_angle))) + abs((int)(src_h * cos(_angle))) + 0.5f);
const gdFixed f_0_5 = gd_ftofx(0.5f); const gdFixed f_0_5 = gd_ftofx(0.5f);
const gdFixed f_H = gd_itofx(src_h/2); const gdFixed f_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2); const gdFixed f_W = gd_itofx(src_w/2);
@ -1726,6 +1741,12 @@ gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, co
unsigned int dst_offset_y = 0; unsigned int dst_offset_y = 0;
unsigned int i; unsigned int i;
gdImagePtr dst; gdImagePtr dst;
gdRect bbox;
int new_height, new_width;
gdRotatedImageSize(src, degrees, &bbox);
new_width = bbox.width;
new_height = bbox.height;
if (new_width == 0 || new_height == 0) { if (new_width == 0 || new_height == 0) {
return NULL; return NULL;
@ -1768,8 +1789,6 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
const int angle_rounded = (int)floor(degrees * 100); const int angle_rounded = (int)floor(degrees * 100);
const int src_w = gdImageSX(src); const int src_w = gdImageSX(src);
const int src_h = gdImageSY(src); const int src_h = gdImageSY(src);
const unsigned int new_width = (unsigned int)(abs((int)(src_w * cos(_angle))) + abs((int)(src_h * sin(_angle))) + 0.5f);
const unsigned int new_height = (unsigned int)(abs((int)(src_w * sin(_angle))) + abs((int)(src_h * cos(_angle))) + 0.5f);
const gdFixed f_0_5 = gd_ftofx(0.5f); const gdFixed f_0_5 = gd_ftofx(0.5f);
const gdFixed f_H = gd_itofx(src_h/2); const gdFixed f_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2); const gdFixed f_W = gd_itofx(src_w/2);
@ -1780,6 +1799,8 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
unsigned int dst_offset_y = 0; unsigned int dst_offset_y = 0;
unsigned int i; unsigned int i;
gdImagePtr dst; gdImagePtr dst;
int new_width, new_height;
gdRect bbox;
const gdFixed f_slop_y = f_sin; const gdFixed f_slop_y = f_sin;
const gdFixed f_slop_x = f_cos; const gdFixed f_slop_x = f_cos;
@ -1792,6 +1813,10 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
return NULL; return NULL;
} }
gdRotatedImageSize(src, degrees, &bbox);
new_width = bbox.width;
new_height = bbox.height;
dst = gdImageCreateTrueColor(new_width, new_height); dst = gdImageCreateTrueColor(new_width, new_height);
if (!dst) { if (!dst) {
return NULL; return NULL;
@ -1831,8 +1856,7 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
float _angle = (float)((- degrees / 180.0f) * M_PI); float _angle = (float)((- degrees / 180.0f) * M_PI);
const unsigned int src_w = gdImageSX(src); const unsigned int src_w = gdImageSX(src);
const unsigned int src_h = gdImageSY(src); const unsigned int src_h = gdImageSY(src);
unsigned int new_width = abs((int)(src_w*cos(_angle))) + abs((int)(src_h*sin(_angle) + 0.5f)); unsigned int new_width, new_height;
unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
const gdFixed f_0_5 = gd_ftofx(0.5f); const gdFixed f_0_5 = gd_ftofx(0.5f);
const gdFixed f_H = gd_itofx(src_h/2); const gdFixed f_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2); const gdFixed f_W = gd_itofx(src_w/2);
@ -1844,6 +1868,12 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
unsigned int dst_offset_y = 0; unsigned int dst_offset_y = 0;
unsigned int src_offset_x, src_offset_y; unsigned int src_offset_x, src_offset_y;
gdImagePtr dst; gdImagePtr dst;
gdRect bbox;
gdRotatedImageSize(src, degrees, &bbox);
new_width = bbox.width;
new_height = bbox.height;
dst = gdImageCreateTrueColor(new_width, new_height); dst = gdImageCreateTrueColor(new_width, new_height);
if (dst == NULL) { if (dst == NULL) {
@ -1863,7 +1893,7 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
const unsigned int m = gd_fxtoi(f_m); const unsigned int m = gd_fxtoi(f_m);
const unsigned int n = gd_fxtoi(f_n); const unsigned int n = gd_fxtoi(f_n);
if ((m > 0) && (m < src_h - 1) && (n > 0) && (n < src_w - 1)) { 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_f = f_m - gd_itofx(m);
const gdFixed f_g = f_n - gd_itofx(n); 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_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
@ -1871,11 +1901,6 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g); const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
const gdFixed f_w4 = gd_mulfx(f_f, f_g); const gdFixed f_w4 = gd_mulfx(f_f, f_g);
if (n < src_w - 1) {
src_offset_x = n + 1;
src_offset_y = m;
}
if (m < src_h-1) { if (m < src_h-1) {
src_offset_x = n; src_offset_x = n;
src_offset_y = m + 1; src_offset_y = m + 1;
@ -1890,13 +1915,13 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
register int pixel2, pixel3, pixel4; register int pixel2, pixel3, pixel4;
if (src_offset_y + 1 >= src_h) { if (src_offset_y + 1 >= src_h) {
pixel2 = bgColor; pixel2 = pixel1;
pixel3 = bgColor; pixel3 = pixel1;
pixel4 = bgColor; pixel4 = pixel1;
} else if (src_offset_x + 1 >= src_w) { } else if (src_offset_x + 1 >= src_w) {
pixel2 = bgColor; pixel2 = pixel1;
pixel3 = bgColor; pixel3 = pixel1;
pixel4 = bgColor; pixel4 = pixel1;
} else { } else {
pixel2 = src->tpixels[src_offset_y][src_offset_x + 1]; pixel2 = src->tpixels[src_offset_y][src_offset_x + 1];
pixel3 = src->tpixels[src_offset_y + 1][src_offset_x]; pixel3 = src->tpixels[src_offset_y + 1][src_offset_x];
@ -1946,8 +1971,7 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
const float _angle = (float)((- degrees / 180.0f) * M_PI); const float _angle = (float)((- degrees / 180.0f) * M_PI);
const int src_w = gdImageSX(src); const int src_w = gdImageSX(src);
const int src_h = gdImageSY(src); const int src_h = gdImageSY(src);
const unsigned int new_width = abs((int)(src_w*cos(_angle))) + abs((int)(src_h*sin(_angle) + 0.5f)); unsigned int new_width, new_height;
const unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
const gdFixed f_0_5 = gd_ftofx(0.5f); const gdFixed f_0_5 = gd_ftofx(0.5f);
const gdFixed f_H = gd_itofx(src_h/2); const gdFixed f_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2); const gdFixed f_W = gd_itofx(src_w/2);
@ -1963,7 +1987,11 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
unsigned int dst_offset_y = 0; unsigned int dst_offset_y = 0;
unsigned int i; unsigned int i;
gdImagePtr dst; gdImagePtr dst;
gdRect bbox;
gdRotatedImageSize(src, degrees, &bbox);
new_width = bbox.width;
new_height = bbox.height;
dst = gdImageCreateTrueColor(new_width, new_height); dst = gdImageCreateTrueColor(new_width, new_height);
if (dst == NULL) { if (dst == NULL) {
@ -2206,8 +2234,11 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor) gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor)
{ {
const int angle_rounded = (int)floor(angle * 100); /* round to two decimals and keep the 100x multiplication to use it in the common square angles
case later. Keep the two decimal precisions so smaller rotation steps can be done, useful for
slow animations, f.e. */
const int angle_rounded = fmod((int) floorf(angle * 100), 360 * 100);
if (bgcolor < 0) { if (bgcolor < 0) {
return NULL; return NULL;
} }
@ -2224,6 +2255,18 @@ gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, in
/* no interpolation needed here */ /* no interpolation needed here */
switch (angle_rounded) { switch (angle_rounded) {
case 0: {
gdImagePtr dst = gdImageCreateTrueColor(src->sx, src->sy);
if (dst == NULL) {
return NULL;
}
dst->transparent = src->transparent;
dst->saveAlphaFlag = 1;
dst->alphaBlendingFlag = gdEffectReplace;
gdImageCopy(dst, src, 0,0,0,0,src->sx,src->sy);
return dst;
}
case -27000: case -27000:
case 9000: case 9000:
return gdImageRotate90(src, 0); return gdImageRotate90(src, 0);

179
ext/gd/tests/bug65148.phpt Normal file
View File

@ -0,0 +1,179 @@
--TEST--
Bug #65148 (imagerotate may alter image dimensions)
--SKIPIF--
<?php
if (!extension_loaded('gd')) die('skip gd extension is not available');
?>
--FILE--
<?php
$interpolations = array(
'IMG_BELL' => IMG_BELL,
'IMG_BESSEL' => IMG_BESSEL,
'IMG_BICUBIC' => IMG_BICUBIC,
'IMG_BICUBIC_FIXED' => IMG_BICUBIC_FIXED,
'IMG_BILINEAR_FIXED' => IMG_BILINEAR_FIXED,
'IMG_BLACKMAN' => IMG_BLACKMAN,
'IMG_BOX' => IMG_BOX,
'IMG_BSPLINE' => IMG_BSPLINE,
'IMG_CATMULLROM' => IMG_CATMULLROM,
'IMG_GAUSSIAN' => IMG_GAUSSIAN,
'IMG_GENERALIZED_CUBIC' => IMG_GENERALIZED_CUBIC,
'IMG_HERMITE' => IMG_HERMITE,
'IMG_HAMMING' => IMG_HAMMING,
'IMG_HANNING' => IMG_HANNING,
'IMG_MITCHELL' => IMG_MITCHELL,
'IMG_POWER' => IMG_POWER,
'IMG_QUADRATIC' => IMG_QUADRATIC,
'IMG_SINC' => IMG_SINC,
'IMG_NEAREST_NEIGHBOUR' => IMG_NEAREST_NEIGHBOUR,
'IMG_WEIGHTED4' => IMG_WEIGHTED4,
'IMG_TRIANGLE' => IMG_TRIANGLE,
);
$img = imagecreate(40, 20);
$results = array();
foreach ($interpolations as $name => $interpolation) {
imagesetinterpolation($img, $interpolation);
$t = imagecolorallocatealpha($img, 0, 0, 0, 127);
$imgr = imagerotate($img, -5, $t);
$results[$name] = array('x' => imagesx($imgr), 'y' => imagesy($imgr));
imagedestroy($imgr);
}
imagedestroy($img);
print_r($results);
?>
===DONE===
--EXPECT--
Array
(
[IMG_BELL] => Array
(
[x] => 40
[y] => 23
)
[IMG_BESSEL] => Array
(
[x] => 40
[y] => 23
)
[IMG_BICUBIC] => Array
(
[x] => 40
[y] => 23
)
[IMG_BICUBIC_FIXED] => Array
(
[x] => 40
[y] => 23
)
[IMG_BILINEAR_FIXED] => Array
(
[x] => 40
[y] => 23
)
[IMG_BLACKMAN] => Array
(
[x] => 40
[y] => 23
)
[IMG_BOX] => Array
(
[x] => 40
[y] => 23
)
[IMG_BSPLINE] => Array
(
[x] => 40
[y] => 23
)
[IMG_CATMULLROM] => Array
(
[x] => 40
[y] => 23
)
[IMG_GAUSSIAN] => Array
(
[x] => 40
[y] => 23
)
[IMG_GENERALIZED_CUBIC] => Array
(
[x] => 40
[y] => 23
)
[IMG_HERMITE] => Array
(
[x] => 40
[y] => 23
)
[IMG_HAMMING] => Array
(
[x] => 40
[y] => 23
)
[IMG_HANNING] => Array
(
[x] => 40
[y] => 23
)
[IMG_MITCHELL] => Array
(
[x] => 40
[y] => 23
)
[IMG_POWER] => Array
(
[x] => 40
[y] => 23
)
[IMG_QUADRATIC] => Array
(
[x] => 40
[y] => 23
)
[IMG_SINC] => Array
(
[x] => 40
[y] => 23
)
[IMG_NEAREST_NEIGHBOUR] => Array
(
[x] => 40
[y] => 23
)
[IMG_WEIGHTED4] => Array
(
[x] => 40
[y] => 23
)
[IMG_TRIANGLE] => Array
(
[x] => 40
[y] => 23
)
)
===DONE===

Binary file not shown.

Before

Width:  |  Height:  |  Size: 739 B

After

Width:  |  Height:  |  Size: 741 B