Skip to content

Commit

Permalink
Merge branch 'PHP-7.1' into PHP-7.2
Browse files Browse the repository at this point in the history
* PHP-7.1:
  Fixed bug #65148 (imagerotate may alter image dimensions)
  • Loading branch information
cmb69 committed Oct 24, 2017
2 parents ca23b04 + 9c79de4 commit c04617a
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 22 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ PHP NEWS
- Fileinfo:
. Upgrade bundled libmagic to 5.31. (Anatol)

- GD:
. Fixed bug #65148 (imagerotate may alter image dimensions). (cmb)

- Intl:
. Fixed bug #75378 ([REGRESSION] IntlDateFormatter::parse() does not change
$position argument). (Laruence)
Expand Down
87 changes: 65 additions & 22 deletions ext/gd/libgd/gd_interpolation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1709,13 +1709,28 @@ gdImagePtr gdImageScale(const gdImagePtr src, const unsigned int new_width, cons
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)
{
float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
const int src_w = gdImageSX(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_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2);
Expand All @@ -1726,6 +1741,12 @@ gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, co
unsigned int dst_offset_y = 0;
unsigned int i;
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) {
return NULL;
Expand Down Expand Up @@ -1768,8 +1789,6 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
const int angle_rounded = (int)floor(degrees * 100);
const int src_w = gdImageSX(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_H = gd_itofx(src_h/2);
const gdFixed f_W = gd_itofx(src_w/2);
Expand All @@ -1780,6 +1799,8 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
unsigned int dst_offset_y = 0;
unsigned int i;
gdImagePtr dst;
int new_width, new_height;
gdRect bbox;

const gdFixed f_slop_y = f_sin;
const gdFixed f_slop_x = f_cos;
Expand All @@ -1792,6 +1813,10 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b
return NULL;
}

gdRotatedImageSize(src, degrees, &bbox);
new_width = bbox.width;
new_height = bbox.height;

dst = gdImageCreateTrueColor(new_width, new_height);
if (!dst) {
return NULL;
Expand Down Expand Up @@ -1831,8 +1856,7 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
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 = abs((int)(src_w*cos(_angle))) + abs((int)(src_h*sin(_angle) + 0.5f));
unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
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);
Expand All @@ -1844,6 +1868,12 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
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) {
Expand All @@ -1863,19 +1893,14 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
const unsigned int m = gd_fxtoi(f_m);
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_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 (n < src_w - 1) {
src_offset_x = n + 1;
src_offset_y = m;
}

if (m < src_h-1) {
src_offset_x = n;
src_offset_y = m + 1;
Expand All @@ -1890,13 +1915,13 @@ gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int
register int pixel2, pixel3, pixel4;

if (src_offset_y + 1 >= src_h) {
pixel2 = bgColor;
pixel3 = bgColor;
pixel4 = bgColor;
pixel2 = pixel1;
pixel3 = pixel1;
pixel4 = pixel1;
} else if (src_offset_x + 1 >= src_w) {
pixel2 = bgColor;
pixel3 = bgColor;
pixel4 = bgColor;
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];
Expand Down Expand Up @@ -1946,8 +1971,7 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
const float _angle = (float)((- degrees / 180.0f) * M_PI);
const int src_w = gdImageSX(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));
const unsigned int new_height = abs((int)(src_w*sin(_angle))) + abs((int)(src_h*cos(_angle) + 0.5f));
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);
Expand All @@ -1963,7 +1987,11 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const
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) {
Expand Down Expand Up @@ -2206,8 +2234,11 @@ gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const

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) {
return NULL;
}
Expand All @@ -2224,6 +2255,18 @@ gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, in

/* no interpolation needed here */
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 9000:
return gdImageRotate90(src, 0);
Expand Down
179 changes: 179 additions & 0 deletions ext/gd/tests/bug65148.phpt
Original file line number Diff line number Diff line change
@@ -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 modified ext/gd/tests/bug73272.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c04617a

Please sign in to comment.