mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	Merge pull request #994 from homm/add-transpose
Add transpose and cache aware rotation
This commit is contained in:
		
						commit
						cfbe49f124
					
				|  | @ -150,6 +150,7 @@ FLIP_TOP_BOTTOM = 1 | |||
| ROTATE_90 = 2 | ||||
| ROTATE_180 = 3 | ||||
| ROTATE_270 = 4 | ||||
| TRANSPOSE = 5 | ||||
| 
 | ||||
| # transforms | ||||
| AFFINE = 0 | ||||
|  | @ -1920,13 +1921,13 @@ class Image: | |||
| 
 | ||||
|         :param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`, | ||||
|           :py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`, | ||||
|           :py:attr:`PIL.Image.ROTATE_180`, or :py:attr:`PIL.Image.ROTATE_270`. | ||||
|           :py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270` or | ||||
|           :py:attr:`PIL.Image.TRANSPOSE`. | ||||
|         :returns: Returns a flipped or rotated copy of this image. | ||||
|         """ | ||||
| 
 | ||||
|         self.load() | ||||
|         im = self.im.transpose(method) | ||||
|         return self._new(im) | ||||
|         return self._new(self.im.transpose(method)) | ||||
| 
 | ||||
|     def effect_spread(self, distance): | ||||
|         """ | ||||
|  |  | |||
|  | @ -1,30 +1,114 @@ | |||
| from helper import unittest, PillowTestCase, hopper | ||||
| 
 | ||||
| from PIL import Image | ||||
| 
 | ||||
| FLIP_LEFT_RIGHT = Image.FLIP_LEFT_RIGHT | ||||
| FLIP_TOP_BOTTOM = Image.FLIP_TOP_BOTTOM | ||||
| ROTATE_90 = Image.ROTATE_90 | ||||
| ROTATE_180 = Image.ROTATE_180 | ||||
| ROTATE_270 = Image.ROTATE_270 | ||||
| from PIL.Image import (FLIP_LEFT_RIGHT, FLIP_TOP_BOTTOM, ROTATE_90, ROTATE_180, | ||||
|     ROTATE_270, TRANSPOSE) | ||||
| 
 | ||||
| 
 | ||||
| class TestImageTranspose(PillowTestCase): | ||||
| 
 | ||||
|     def test_sanity(self): | ||||
|     hopper = { | ||||
|         'L': hopper('L').crop((0, 0, 121, 127)).copy(), | ||||
|         'RGB': hopper('RGB').crop((0, 0, 121, 127)).copy(), | ||||
|     } | ||||
| 
 | ||||
|         im = hopper() | ||||
|     def test_flip_left_right(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(FLIP_LEFT_RIGHT) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size) | ||||
| 
 | ||||
|         im.transpose(FLIP_LEFT_RIGHT) | ||||
|         im.transpose(FLIP_TOP_BOTTOM) | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((x-2, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((1, 1))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((x-2, y-2))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((1, y-2))) | ||||
| 
 | ||||
|         im.transpose(ROTATE_90) | ||||
|         im.transpose(ROTATE_180) | ||||
|         im.transpose(ROTATE_270) | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_flip_top_bottom(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(FLIP_TOP_BOTTOM) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size) | ||||
| 
 | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, y-2))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((x-2, y-2))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((1, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((x-2, 1))) | ||||
| 
 | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_rotate_90(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(ROTATE_90) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size[::-1]) | ||||
| 
 | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, x-2))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((1, 1))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((y-2, x-2))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((y-2, 1))) | ||||
| 
 | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_rotate_180(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(ROTATE_180) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size) | ||||
| 
 | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((x-2, y-2))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((1, y-2))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((x-2, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((1, 1))) | ||||
| 
 | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_rotate_270(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(ROTATE_270) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size[::-1]) | ||||
| 
 | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((y-2, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((y-2, x-2))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((1, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((1, x-2))) | ||||
| 
 | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_transpose(self): | ||||
|         def transpose(mode): | ||||
|             im = self.hopper[mode] | ||||
|             out = im.transpose(TRANSPOSE) | ||||
|             self.assertEqual(out.mode, mode) | ||||
|             self.assertEqual(out.size, im.size[::-1]) | ||||
| 
 | ||||
|             x, y = im.size | ||||
|             self.assertEqual(im.getpixel((1, 1)), out.getpixel((1, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, 1)), out.getpixel((1, x-2))) | ||||
|             self.assertEqual(im.getpixel((1, y-2)), out.getpixel((y-2, 1))) | ||||
|             self.assertEqual(im.getpixel((x-2, y-2)), out.getpixel((y-2, x-2))) | ||||
| 
 | ||||
|         for mode in ("L", "RGB"): | ||||
|             transpose(mode) | ||||
| 
 | ||||
|     def test_roundtrip(self): | ||||
| 
 | ||||
|         im = hopper() | ||||
|         im = self.hopper['L'] | ||||
| 
 | ||||
|         def transpose(first, second): | ||||
|             return im.transpose(first).transpose(second) | ||||
|  | @ -33,12 +117,13 @@ class TestImageTranspose(PillowTestCase): | |||
|             im, transpose(FLIP_LEFT_RIGHT, FLIP_LEFT_RIGHT)) | ||||
|         self.assert_image_equal( | ||||
|             im, transpose(FLIP_TOP_BOTTOM, FLIP_TOP_BOTTOM)) | ||||
| 
 | ||||
|         self.assert_image_equal(im, transpose(ROTATE_90, ROTATE_270)) | ||||
|         self.assert_image_equal(im, transpose(ROTATE_180, ROTATE_180)) | ||||
|         self.assert_image_equal( | ||||
|             im.transpose(TRANSPOSE), transpose(ROTATE_90, FLIP_TOP_BOTTOM)) | ||||
|         self.assert_image_equal( | ||||
|             im.transpose(TRANSPOSE), transpose(ROTATE_270, FLIP_LEFT_RIGHT)) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
| 
 | ||||
| # End of file | ||||
|  |  | |||
|  | @ -1750,6 +1750,7 @@ _transpose(ImagingObject* self, PyObject* args) | |||
|         break; | ||||
|     case 2: /* rotate 90 */ | ||||
|     case 4: /* rotate 270 */ | ||||
|     case 5: /* transpose */ | ||||
|         imOut = ImagingNew(imIn->mode, imIn->ysize, imIn->xsize); | ||||
|         break; | ||||
|     default: | ||||
|  | @ -1774,6 +1775,9 @@ _transpose(ImagingObject* self, PyObject* args) | |||
|         case 4: | ||||
|             (void) ImagingRotate270(imOut, imIn); | ||||
|             break; | ||||
|         case 5: | ||||
|             (void) ImagingTranspose(imOut, imIn); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|     return PyImagingNew(imOut); | ||||
|  |  | |||
|  | @ -30,11 +30,18 @@ | |||
| /* Undef if you don't need resampling filters */ | ||||
| #define WITH_FILTERS | ||||
| 
 | ||||
| /* For large images rotation is an inefficient operation in terms of CPU cache.
 | ||||
|    One row in the source image affects each column in destination. | ||||
|    Rotating in chunks that fit in the cache can speed up rotation | ||||
|    8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough | ||||
|    that the overhead from the extra loops are not apparent. */ | ||||
| #define ROTATE_CHUNK 128 | ||||
| 
 | ||||
| #define COORD(v) ((v) < 0.0 ? -1 : ((int)(v))) | ||||
| #define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v))) | ||||
| 
 | ||||
| /* -------------------------------------------------------------------- */ | ||||
| /* Transpose operations							*/ | ||||
| /* Transpose operations                                                 */ | ||||
| 
 | ||||
| Imaging | ||||
| ImagingFlipLeftRight(Imaging imOut, Imaging imIn) | ||||
|  | @ -43,25 +50,25 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) | |||
|     int x, y, xr; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) | ||||
| 	return (Imaging) ImagingError_Mismatch(); | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
| #define	FLIP_HORIZ(image)\ | ||||
| #define FLIP_HORIZ(image)\ | ||||
|     for (y = 0; y < imIn->ysize; y++) {\ | ||||
| 	xr = imIn->xsize-1;\ | ||||
| 	for (x = 0; x < imIn->xsize; x++, xr--)\ | ||||
| 	    imOut->image[y][x] = imIn->image[y][xr];\ | ||||
|         xr = imIn->xsize-1;\ | ||||
|         for (x = 0; x < imIn->xsize; x++, xr--)\ | ||||
|             imOut->image[y][x] = imIn->image[y][xr];\ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	FLIP_HORIZ(image8) | ||||
|         FLIP_HORIZ(image8) | ||||
|     else | ||||
| 	FLIP_HORIZ(image32) | ||||
|         FLIP_HORIZ(image32) | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -76,9 +83,9 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) | |||
|     int y, yr; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) | ||||
| 	return (Imaging) ImagingError_Mismatch(); | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|  | @ -86,7 +93,7 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) | |||
| 
 | ||||
|     yr = imIn->ysize-1; | ||||
|     for (y = 0; y < imIn->ysize; y++, yr--) | ||||
| 	memcpy(imOut->image[yr], imIn->image[y], imIn->linesize); | ||||
|         memcpy(imOut->image[yr], imIn->image[y], imIn->linesize); | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -98,28 +105,35 @@ Imaging | |||
| ImagingRotate90(Imaging imOut, Imaging imIn) | ||||
| { | ||||
|     ImagingSectionCookie cookie; | ||||
|     int x, y, xr; | ||||
|     int x, y, xx, yy, xr, xxsize, yysize; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) | ||||
| 	return (Imaging) ImagingError_Mismatch(); | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
| #define	ROTATE_90(image)\ | ||||
|     for (y = 0; y < imIn->ysize; y++) {\ | ||||
| 	xr = imIn->xsize-1;\ | ||||
| 	for (x = 0; x < imIn->xsize; x++, xr--)\ | ||||
| 	    imOut->image[xr][y] = imIn->image[y][x];\ | ||||
| #define ROTATE_90(image) \ | ||||
|     for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ | ||||
|         for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ | ||||
|             yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ | ||||
|             xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ | ||||
|             for (yy = y; yy < yysize; yy++) { \ | ||||
|                 xr = imIn->xsize - 1 - x; \ | ||||
|                 for (xx = x; xx < xxsize; xx++, xr--) { \ | ||||
|                     imOut->image[xr][yy] = imIn->image[yy][xx]; \ | ||||
|                 } \ | ||||
|             } \ | ||||
|         } \ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	ROTATE_90(image8) | ||||
|         ROTATE_90(image8) | ||||
|     else | ||||
| 	ROTATE_90(image32) | ||||
|         ROTATE_90(image32) | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -127,6 +141,43 @@ ImagingRotate90(Imaging imOut, Imaging imIn) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| Imaging | ||||
| ImagingTranspose(Imaging imOut, Imaging imIn) | ||||
| { | ||||
|     ImagingSectionCookie cookie; | ||||
|     int x, y, xx, yy, xxsize, yysize; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
| #define TRANSPOSE(image) \ | ||||
|     for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ | ||||
|         for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ | ||||
|             yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ | ||||
|             xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ | ||||
|             for (yy = y; yy < yysize; yy++) { \ | ||||
|                 for (xx = x; xx < xxsize; xx++) { \ | ||||
|                     imOut->image[xx][yy] = imIn->image[yy][xx]; \ | ||||
|                 } \ | ||||
|             } \ | ||||
|         } \ | ||||
|     } | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
|     if (imIn->image8) | ||||
|         TRANSPOSE(image8) | ||||
|     else | ||||
|         TRANSPOSE(image32) | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|     return imOut; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Imaging | ||||
| ImagingRotate180(Imaging imOut, Imaging imIn) | ||||
| { | ||||
|  | @ -134,27 +185,27 @@ ImagingRotate180(Imaging imOut, Imaging imIn) | |||
|     int x, y, xr, yr; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) | ||||
| 	return (Imaging) ImagingError_Mismatch(); | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|     yr = imIn->ysize-1; | ||||
| 
 | ||||
| #define	ROTATE_180(image)\ | ||||
| #define ROTATE_180(image)\ | ||||
|     for (y = 0; y < imIn->ysize; y++, yr--) {\ | ||||
| 	xr = imIn->xsize-1;\ | ||||
| 	for (x = 0; x < imIn->xsize; x++, xr--)\ | ||||
| 	    imOut->image[y][x] = imIn->image[yr][xr];\ | ||||
|         xr = imIn->xsize-1;\ | ||||
|         for (x = 0; x < imIn->xsize; x++, xr--)\ | ||||
|             imOut->image[y][x] = imIn->image[yr][xr];\ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	ROTATE_180(image8) | ||||
|         ROTATE_180(image8) | ||||
|     else | ||||
| 	ROTATE_180(image32) | ||||
|         ROTATE_180(image32) | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -166,28 +217,35 @@ Imaging | |||
| ImagingRotate270(Imaging imOut, Imaging imIn) | ||||
| { | ||||
|     ImagingSectionCookie cookie; | ||||
|     int x, y, yr; | ||||
|     int x, y, xx, yy, yr, xxsize, yysize; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
|     if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) | ||||
| 	return (Imaging) ImagingError_Mismatch(); | ||||
|         return (Imaging) ImagingError_Mismatch(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|     yr = imIn->ysize - 1; | ||||
| 
 | ||||
| #define	ROTATE_270(image)\ | ||||
|     for (y = 0; y < imIn->ysize; y++, yr--)\ | ||||
| 	for (x = 0; x < imIn->xsize; x++)\ | ||||
| 	    imOut->image[x][y] = imIn->image[yr][x]; | ||||
| #define ROTATE_270(image) \ | ||||
|     for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \ | ||||
|         for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \ | ||||
|             yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \ | ||||
|             xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \ | ||||
|             yr = imIn->ysize - 1 - y; \ | ||||
|             for (yy = y; yy < yysize; yy++, yr--) { \ | ||||
|                 for (xx = x; xx < xxsize; xx++) { \ | ||||
|                     imOut->image[xx][yr] = imIn->image[yy][xx]; \ | ||||
|                 } \ | ||||
|             } \ | ||||
|         } \ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	ROTATE_270(image8) | ||||
|         ROTATE_270(image8) | ||||
|     else | ||||
| 	ROTATE_270(image32) | ||||
|         ROTATE_270(image32) | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -196,7 +254,7 @@ ImagingRotate270(Imaging imOut, Imaging imIn) | |||
| 
 | ||||
| 
 | ||||
| /* -------------------------------------------------------------------- */ | ||||
| /* Transforms								*/ | ||||
| /* Transforms                                                           */ | ||||
| 
 | ||||
| /* transform primitives (ImagingTransformMap) */ | ||||
| 
 | ||||
|  | @ -597,7 +655,7 @@ ImagingTransform( | |||
|     double xx, yy; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|  | @ -613,15 +671,15 @@ ImagingTransform( | |||
|         y1 = imOut->ysize; | ||||
| 
 | ||||
|     for (y = y0; y < y1; y++) { | ||||
| 	out = imOut->image[y] + x0*imOut->pixelsize; | ||||
| 	for (x = x0; x < x1; x++) { | ||||
| 	    if (!transform(&xx, &yy, x-x0, y-y0, transform_data) || | ||||
|         out = imOut->image[y] + x0*imOut->pixelsize; | ||||
|         for (x = x0; x < x1; x++) { | ||||
|             if (!transform(&xx, &yy, x-x0, y-y0, transform_data) || | ||||
|                 !filter(out, imIn, xx, yy, filter_data)) { | ||||
|                 if (fill) | ||||
|                     memset(out, 0, imOut->pixelsize); | ||||
|             } | ||||
|             out += imOut->pixelsize; | ||||
| 	} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
|  | @ -644,7 +702,7 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, | |||
|     int *xintab; | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
| 
 | ||||
|     ImagingCopyInfo(imOut, imIn); | ||||
| 
 | ||||
|  | @ -659,8 +717,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, | |||
| 
 | ||||
|     xintab = (int*) malloc(imOut->xsize * sizeof(int)); | ||||
|     if (!xintab) { | ||||
| 	ImagingDelete(imOut); | ||||
| 	return (Imaging) ImagingError_MemoryError(); | ||||
|         ImagingDelete(imOut); | ||||
|         return (Imaging) ImagingError_MemoryError(); | ||||
|     } | ||||
| 
 | ||||
|     xo = a[0]; | ||||
|  | @ -671,29 +729,29 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn, | |||
| 
 | ||||
|     /* Pretabulate horizontal pixel positions */ | ||||
|     for (x = x0; x < x1; x++) { | ||||
| 	xin = COORD(xo); | ||||
| 	if (xin >= 0 && xin < (int) imIn->xsize) { | ||||
| 	    xmax = x+1; | ||||
| 	    if (x < xmin) | ||||
| 		xmin = x; | ||||
| 	    xintab[x] = xin; | ||||
| 	} | ||||
| 	xo += a[1]; | ||||
|         xin = COORD(xo); | ||||
|         if (xin >= 0 && xin < (int) imIn->xsize) { | ||||
|             xmax = x+1; | ||||
|             if (x < xmin) | ||||
|                 xmin = x; | ||||
|             xintab[x] = xin; | ||||
|         } | ||||
|         xo += a[1]; | ||||
|     } | ||||
| 
 | ||||
| #define	AFFINE_SCALE(pixel, image)\ | ||||
| #define AFFINE_SCALE(pixel, image)\ | ||||
|     for (y = y0; y < y1; y++) {\ | ||||
| 	int yi = COORD(yo);\ | ||||
| 	pixel *in, *out;\ | ||||
| 	out = imOut->image[y];\ | ||||
|         int yi = COORD(yo);\ | ||||
|         pixel *in, *out;\ | ||||
|         out = imOut->image[y];\ | ||||
|         if (fill && x1 > x0)\ | ||||
|             memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ | ||||
| 	if (yi >= 0 && yi < imIn->ysize) {\ | ||||
| 	    in = imIn->image[yi];\ | ||||
| 	    for (x = xmin; x < xmax; x++)\ | ||||
| 		out[x] = in[xintab[x]];\ | ||||
| 	}\ | ||||
| 	yo += a[5];\ | ||||
|         if (yi >= 0 && yi < imIn->ysize) {\ | ||||
|             in = imIn->image[yi];\ | ||||
|             for (x = xmin; x < xmax; x++)\ | ||||
|                 out[x] = in[xintab[x]];\ | ||||
|         }\ | ||||
|         yo += a[5];\ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
|  | @ -743,32 +801,32 @@ affine_fixed(Imaging imOut, Imaging imIn, | |||
|     a0 = FIX(a[0]); a1 = FIX(a[1]); a2 = FIX(a[2]); | ||||
|     a3 = FIX(a[3]); a4 = FIX(a[4]); a5 = FIX(a[5]); | ||||
| 
 | ||||
| #define	AFFINE_TRANSFORM_FIXED(pixel, image)\ | ||||
| #define AFFINE_TRANSFORM_FIXED(pixel, image)\ | ||||
|     for (y = y0; y < y1; y++) {\ | ||||
| 	pixel *out;\ | ||||
| 	xx = a0;\ | ||||
| 	yy = a3;\ | ||||
| 	out = imOut->image[y];\ | ||||
|         pixel *out;\ | ||||
|         xx = a0;\ | ||||
|         yy = a3;\ | ||||
|         out = imOut->image[y];\ | ||||
|         if (fill && x1 > x0)\ | ||||
|             memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ | ||||
|         for (x = x0; x < x1; x++, out++) {\ | ||||
| 	    xin = xx >> 16;\ | ||||
| 	    if (xin >= 0 && xin < xsize) {\ | ||||
| 	        yin = yy >> 16;\ | ||||
| 		if (yin >= 0 && yin < ysize)\ | ||||
|             xin = xx >> 16;\ | ||||
|             if (xin >= 0 && xin < xsize) {\ | ||||
|                 yin = yy >> 16;\ | ||||
|                 if (yin >= 0 && yin < ysize)\ | ||||
|                     *out = imIn->image[yin][xin];\ | ||||
|             }\ | ||||
| 	    xx += a1;\ | ||||
| 	    yy += a4;\ | ||||
| 	}\ | ||||
| 	a0 += a2;\ | ||||
| 	a3 += a5;\ | ||||
|             xx += a1;\ | ||||
|             yy += a4;\ | ||||
|         }\ | ||||
|         a0 += a2;\ | ||||
|         a3 += a5;\ | ||||
|     } | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	AFFINE_TRANSFORM_FIXED(UINT8, image8) | ||||
|         AFFINE_TRANSFORM_FIXED(UINT8, image8) | ||||
|     else | ||||
| 	AFFINE_TRANSFORM_FIXED(INT32, image32) | ||||
|         AFFINE_TRANSFORM_FIXED(INT32, image32) | ||||
| 
 | ||||
|     return imOut; | ||||
| } | ||||
|  | @ -801,11 +859,11 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, | |||
|     } | ||||
| 
 | ||||
|     if (a[2] == 0 && a[4] == 0) | ||||
| 	/* Scaling */ | ||||
| 	return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill); | ||||
|         /* Scaling */ | ||||
|         return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill); | ||||
| 
 | ||||
|     if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) | ||||
| 	return (Imaging) ImagingError_ModeError(); | ||||
|         return (Imaging) ImagingError_ModeError(); | ||||
| 
 | ||||
|     if (x0 < 0) | ||||
|         x0 = 0; | ||||
|  | @ -835,34 +893,34 @@ ImagingTransformAffine(Imaging imOut, Imaging imIn, | |||
|     xo = a[0]; | ||||
|     yo = a[3]; | ||||
| 
 | ||||
| #define	AFFINE_TRANSFORM(pixel, image)\ | ||||
| #define AFFINE_TRANSFORM(pixel, image)\ | ||||
|     for (y = y0; y < y1; y++) {\ | ||||
| 	pixel *out;\ | ||||
| 	xx = xo;\ | ||||
| 	yy = yo;\ | ||||
| 	out = imOut->image[y];\ | ||||
|         pixel *out;\ | ||||
|         xx = xo;\ | ||||
|         yy = yo;\ | ||||
|         out = imOut->image[y];\ | ||||
|         if (fill && x1 > x0)\ | ||||
|             memset(out+x0, 0, (x1-x0)*sizeof(pixel));\ | ||||
|         for (x = x0; x < x1; x++, out++) {\ | ||||
| 	    xin = COORD(xx);\ | ||||
| 	    if (xin >= 0 && xin < xsize) {\ | ||||
| 	        yin = COORD(yy);\ | ||||
| 		if (yin >= 0 && yin < ysize)\ | ||||
|             xin = COORD(xx);\ | ||||
|             if (xin >= 0 && xin < xsize) {\ | ||||
|                 yin = COORD(yy);\ | ||||
|                 if (yin >= 0 && yin < ysize)\ | ||||
|                     *out = imIn->image[yin][xin];\ | ||||
|             }\ | ||||
| 	    xx += a[1];\ | ||||
| 	    yy += a[4];\ | ||||
| 	}\ | ||||
| 	xo += a[2];\ | ||||
| 	yo += a[5];\ | ||||
|             xx += a[1];\ | ||||
|             yy += a[4];\ | ||||
|         }\ | ||||
|         xo += a[2];\ | ||||
|         yo += a[5];\ | ||||
|     } | ||||
| 
 | ||||
|     ImagingSectionEnter(&cookie); | ||||
| 
 | ||||
|     if (imIn->image8) | ||||
| 	AFFINE_TRANSFORM(UINT8, image8) | ||||
|         AFFINE_TRANSFORM(UINT8, image8) | ||||
|     else | ||||
| 	AFFINE_TRANSFORM(INT32, image32) | ||||
|         AFFINE_TRANSFORM(INT32, image32) | ||||
| 
 | ||||
|     ImagingSectionLeave(&cookie); | ||||
| 
 | ||||
|  | @ -912,7 +970,7 @@ ImagingResize(Imaging imOut, Imaging imIn, int filterid) | |||
|     double a[6]; | ||||
| 
 | ||||
|     if (imOut->xsize == imIn->xsize && imOut->ysize == imIn->ysize) | ||||
| 	return ImagingCopy2(imOut, imIn); | ||||
|         return ImagingCopy2(imOut, imIn); | ||||
| 
 | ||||
|     memset(a, 0, sizeof a); | ||||
|     a[1] = (double) imIn->xsize / imOut->xsize; | ||||
|  |  | |||
|  | @ -292,6 +292,7 @@ extern Imaging ImagingRotate90(Imaging imOut, Imaging imIn); | |||
| extern Imaging ImagingRotate180(Imaging imOut, Imaging imIn); | ||||
| extern Imaging ImagingRotate270(Imaging imOut, Imaging imIn); | ||||
| extern Imaging ImagingStretch(Imaging imOut, Imaging imIn, int filter); | ||||
| extern Imaging ImagingTranspose(Imaging imOut, Imaging imIn); | ||||
| extern Imaging ImagingTransformPerspective( | ||||
|     Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, | ||||
|     double a[8], int filter, int fill); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user