diff --git a/docs/reST/ref/transform.rst b/docs/reST/ref/transform.rst index fd7f6663f1..58b986967a 100644 --- a/docs/reST/ref/transform.rst +++ b/docs/reST/ref/transform.rst @@ -109,8 +109,8 @@ Instead, always begin with the original image and scale to the desired size.) This maps an image to a new surface warping the image so that its corners match the provided points in a clockwise order: top left, top right, bottom right, bottom left. Provided points represent the pixel coordinates of the - new corners of the image and can be positive or negative provided they fit - in the new surface. + new corners of the image, they must be unique and can be positive or negative + provided they fit in the new surface. When no 'dest_surface' is provided, the 'adjust_size' option will set the size of the resulting surface to be the smallest surface the points are diff --git a/src_c/transform.c b/src_c/transform.c index d62cab3c2c..02eb85ee4f 100644 --- a/src_c/transform.c +++ b/src_c/transform.c @@ -1065,6 +1065,13 @@ surf_skew(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; surf = pgSurface_AsSurface(surfobj); SURF_INIT_CHECK(surf) + + if ((x1 == x2 && y1 == y2) || (x1 == x3 && y1 == y3) || + (x1 == x4 && y1 == y4) || (x2 == x3 && y2 == y3) || + (x2 == x4 && y2 == y4) || (x3 == x4 && y3 == y4)) { + return RAISE(PyExc_ValueError, "all four points must be unique"); + } + if (!dest_surface) { if (adjust_size) { start = MIN(MIN(x1, x2), MIN(x3, x4)); @@ -1096,7 +1103,7 @@ surf_skew(PyObject *self, PyObject *args, PyObject *kwargs) if (PG_SURF_BytesPerPixel(surf) == 0 || PG_SURF_BytesPerPixel(surf) > 4) return RAISE(PyExc_ValueError, - "unsupported surface bit depth for transform"); + "unsupported Surface bit depth for transform"); SDL_Point points[4] = {{x1 - start, y1 - top}, {x2 - start, y2 - top}, @@ -1107,7 +1114,7 @@ surf_skew(PyObject *self, PyObject *args, PyObject *kwargs) _check_inside(newsurf, points[2]) && _check_inside(newsurf, points[3]))) { return RAISE(PyExc_ValueError, - "points are not within specified surface"); + "points are not within specified Surface"); } SDL_LockSurface(newsurf); @@ -1141,8 +1148,7 @@ surf_skew(PyObject *self, PyObject *args, PyObject *kwargs) } } else { - if (!pg_MappedColorFromObj(colorobj, surf->format, &bgcolor, - PG_COLOR_HANDLE_ALL)) + if (_color_from_obj(colorobj, surf, NULL, &bgcolor)) return RAISE(PyExc_TypeError, "invalid bg_color argument"); } diff --git a/test/transform_test.py b/test/transform_test.py index 3e5ad06b68..15d27bc819 100644 --- a/test/transform_test.py +++ b/test/transform_test.py @@ -1450,6 +1450,50 @@ def test_rotate__lossless_at_90_degrees(self): for pt, color in gradient: self.assertTrue(s.get_at(pt) == color) + def test_skew(self): + blue = (0, 0, 255, 255) + red = (255, 0, 0, 255) + black = (0, 0, 0) + w, h = 32, 32 + s = pygame.Surface((w, h), pygame.SRCALPHA, 32) + s.fill(red) + s.fill(black, pygame.rect.Rect(0, 0, 16, 16)) + corner_points = [ + [(1, 1), (19, 1), (19, 19), (1, 19)], + [(0, 10), (31, 0), (3, 31), (0, 13)], + [(5, 16), (17, 2), (19, 13), (2, 18)], + [(5, 4), (28, 2), (8, 25), (27, 20)], + [(20, 20), (15, 5), (30, 30), (5, 15)], + ] + test_points = [ + [((0, 31), blue), ((5, 16), red), ((4, 4), black)], + [((7, 7), black), ((6, 7), blue), ((16, 16), red)], + [((19, 13), red), ((10, 9), black), ((11, 9), red)], + [((10, 8), black), ((18, 14), red), ((20, 14), blue)], + [((17, 14), black), ((17, 13), red), ((16, 14), blue)], + ] + + # check specified test points are correct + for i in range(len(corner_points)): + s2 = pygame.transform.skew(s, corner_points[i], blue, False) + for test in test_points[i]: + self.assertEqual( + s2.get_at(test[0]), + test[1], + "Failed for {0} at {1}".format(corner_points[i], test[0]), + ) + + def test_skew_adjust_size(self): + w, h = 32, 32 + s = pygame.Surface((w, h), pygame.SRCALPHA, 32) + size_values = [-100, -72, -23, -1, 1, 15, 104, 1009] + for x in size_values: + for y in size_values: + s2 = pygame.transform.skew( + s, [(x, 0), (0, 0), (x, y), (0, y)], adjust_size=True + ) + self.assertEqual(s2.size, (abs(x) + 1, abs(y) + 1)) + def test_scale2x(self): # __doc__ (as of 2008-06-25) for pygame.transform.scale2x: