Fixed #596: gdTransformAffineCopy run error

And add test case for it.
master
wilson chen 2020-03-21 15:31:40 +08:00 committed by GitHub
parent 08238a0ac2
commit 3f50ffaefd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 16 deletions

View File

@ -1975,6 +1975,51 @@ BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst,
}
}
/** Function: getPixelRgbInterpolated
* get the index of the image's colors
*
* Parameters:
* im - Image to draw the transformed image
* tcolor - TrueColor
*
* Return:
* index of colors
*/
static int getPixelRgbInterpolated(gdImagePtr im, const int tcolor)
{
unsigned char r, g, b, a;
int ct;
b = (unsigned char)tcolor;
g = (unsigned char)tcolor >> 8;
r = (unsigned char)tcolor >> 16;
a = (unsigned char)tcolor >> 24;
b = CLAMP(b, 0, 255);
g = CLAMP(g, 0, 255);
r = CLAMP(r, 0, 255);
a = CLAMP(a, 0, 127);
for (int i = 0; i < im->colorsTotal; i++) {
if (im->red[i] == r && im->green[i] == g && im->blue[i] == b && im->alpha[i] == a) {
return i;
}
}
ct = im->colorsTotal;
if (ct == gdMaxColors) {
return -1;
}
im->colorsTotal++;
im->red[ct] = r;
im->green[ct] = g;
im->blue[ct] = b;
im->alpha[ct] = a;
im->open[ct] = 0;
return ct;
}
/**
* Function: gdTransformAffineCopy
* Applies an affine transformation to a region and copy the result
@ -2011,8 +2056,11 @@ BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst,
gdImageSetInterpolationMethod(src, GD_BICUBIC);
}
gdImageClipRectangle(src, src_region);
c1x = src_region->x;
c1y = src_region->y;
c2x = src_region->x + src_region->width -1;
c2y = src_region->y + src_region->height -1;
if (src_region->x > 0 || src_region->y > 0
|| src_region->width < gdImageSX(src)
@ -2036,8 +2084,6 @@ BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst,
return GD_FALSE;
}
gdImageGetClip(dst, &c1x, &c1y, &c2x, &c2y);
end_x = bbox.width + abs(bbox.x);
end_y = bbox.height + abs(bbox.y);
@ -2053,18 +2099,24 @@ BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst,
if (dst->alphaBlendingFlag) {
for (y = bbox.y; y <= end_y; y++) {
pt.y = y + 0.5;
for (x = 0; x <= end_x; x++) {
for (x = bbox.x; x <= end_x; x++) {
pt.x = x + 0.5;
gdAffineApplyToPointF(&src_pt, &pt, inv);
gdImageSetPixel(dst, dst_x + x, dst_y + y, getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, 0));
if (floor(src_offset_x + src_pt.x) < c1x
|| floor(src_offset_x + src_pt.x) > c2x
|| floor(src_offset_y + src_pt.y) < c1y
|| floor(src_offset_y + src_pt.y) > c2y) {
continue;
}
gdImageSetPixel(dst, dst_x + x, dst_y + y, getPixelInterpolated(src, (int)(src_offset_x + src_pt.x), (int)(src_offset_y + src_pt.y), 0));
}
}
} else {
for (y = 0; y <= end_y; y++) {
for (y = bbox.y; y <= end_y; y++) {
unsigned char *dst_p = NULL;
int *tdst_p = NULL;
pt.y = y + 0.5 + bbox.y;
pt.y = y + 0.5;
if ((dst_y + y) < 0 || ((dst_y + y) > gdImageSY(dst) -1)) {
continue;
}
@ -2074,17 +2126,23 @@ BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst,
dst_p = dst->pixels[dst_y + y] + dst_x;
}
for (x = 0; x <= end_x; x++) {
pt.x = x + 0.5 + bbox.x;
for (x = bbox.x; x <= end_x; x++) {
pt.x = x + 0.5;
gdAffineApplyToPointF(&src_pt, &pt, inv);
if ((dst_x + x) < 0 || (dst_x + x) > (gdImageSX(dst) - 1)) {
break;
}
if (floor(src_offset_x + src_pt.x) < c1x
|| floor(src_offset_x + src_pt.x) > c2x
|| floor(src_offset_y + src_pt.y) < c1y
|| floor(src_offset_y + src_pt.y) > c2y) {
continue;
}
if (dst->trueColor) {
*(tdst_p++) = getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, -1);
*(tdst_p + dst_x + x) = getPixelInterpolated(src, (int)(src_offset_x + src_pt.x), (int)(src_offset_y + src_pt.y), -1);
} else {
*(dst_p++) = getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, -1);
*(dst_p + dst_x + x) = getPixelRgbInterpolated(dst, getPixelInterpolated(src, (int)(src_offset_x + src_pt.x), (int)(src_offset_y + src_pt.y), -1));
}
}
}
@ -2148,8 +2206,8 @@ BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine
}
bbox->x = (int) min.x;
bbox->y = (int) min.y;
bbox->width = (int) ceil((max.x - min.x)) + 1;
bbox->height = (int) ceil(max.y - min.y) + 1;
bbox->width = (int) ceil((max.x - min.x));
bbox->height = (int) ceil(max.y - min.y);
return GD_TRUE;
}

View File

@ -63,7 +63,7 @@ BGD_DECLARE(int) gdAffineInvert (double dst[6], const double src[6])
{
double r_det = (src[0] * src[3] - src[1] * src[2]);
if (r_det <= 0.0) {
if (fabs(r_det) <= 0.0) {
return GD_FALSE;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -24,7 +24,7 @@ int main()
if (gdTransformAffineBoundingBox(&area, affine, &bbox) != GD_TRUE) {
return 1;
}
if (!(bbox.x ==-253 && bbox.y ==-228 && bbox.width == 298 && bbox.height == 230)) {
if (!(bbox.x ==-253 && bbox.y ==-228 && bbox.width == 297 && bbox.height == 229)) {
return 1;
}

View File

@ -1,3 +1,4 @@
/github_bug_00583
/github_bug_00585
/github_bug_00586
/github_bug_00596

View File

@ -2,6 +2,7 @@ LIST(APPEND TESTS_FILES
github_bug_00583
github_bug_00585
github_bug_00586
github_bug_00596
)
ADD_GD_TESTS()

View File

@ -1,7 +1,8 @@
libgd_test_programs += \
gdtransformaffinecopy/github_bug_00583 \
gdtransformaffinecopy/github_bug_00585 \
gdtransformaffinecopy/github_bug_00586
gdtransformaffinecopy/github_bug_00586 \
gdtransformaffinecopy/github_bug_00596
EXTRA_DIST += \
gdtransformaffinecopy/CMakeLists.txt

View File

@ -0,0 +1,42 @@
/**
* Test gdTransformAffineCopy() run error
*
* See <https://github.com/libgd/libgd/issues/596>
*
*/
#include "gd.h"
#include "gdtest.h"
int main()
{
double matrix[] = {1, 0, 0, 1, 0, 0};
gdImagePtr src, dst;
gdRect rect = {0, 0, 16, 16};
int white, green;
int status = 0;
int res;
int actual_color = 0;
int expected_color = 0x00ff00;
src = gdImageCreateTrueColor(16, 16);
gdTestAssert(src != NULL);
white = gdImageColorAllocate(src, 255, 255, 255);
gdImageFilledRectangle(src, 0, 0, 16, 16, white);
dst = gdImageCreateTrueColor(50, 50);
gdTestAssert(dst != NULL);
green = gdImageColorAllocate(dst, 0, 255, 0);
gdImageFilledRectangle(dst, 0, 0, 50, 50, green);
res = gdTransformAffineCopy(dst, 4, 4, src, &rect, matrix);
gdTestAssert(res != GD_FALSE);
status = gdNumFailures();
actual_color = gdImageGetPixel(dst, 20, 5);
status = (actual_color == expected_color) ? status : 1;
gdImageDestroy(src);
gdImageDestroy(dst);
return status;
}