diff options
| author | Alan Third | 2019-06-16 20:46:31 +0100 |
|---|---|---|
| committer | Alan Third | 2019-06-16 20:46:42 +0100 |
| commit | beb572a7ddc07760e077867e286790ddae30a12d (patch) | |
| tree | 9595b80194dcc0a8ea3bf9c999b8dbe6cca82ba9 | |
| parent | cf3081d208814ea02fce33aac645abfc24f880a6 (diff) | |
| download | emacs-beb572a7ddc07760e077867e286790ddae30a12d.tar.gz emacs-beb572a7ddc07760e077867e286790ddae30a12d.zip | |
Revert "Simplify image transforms"
This reverts commit cf3081d208814ea02fce33aac645abfc24f880a6.
; Pushed in error.
| -rw-r--r-- | src/image.c | 310 | ||||
| -rw-r--r-- | test/manual/image-transforms-tests.el | 34 |
2 files changed, 243 insertions, 101 deletions
diff --git a/src/image.c b/src/image.c index 8b571dd72d6..a3747cfa6b7 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1967,7 +1967,8 @@ compute_image_size (size_t width, size_t height, | |||
| 1967 | } | 1967 | } |
| 1968 | #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ | 1968 | #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ |
| 1969 | 1969 | ||
| 1970 | /* image_set_transform uses affine transformation matrices to perform | 1970 | /* image_set_rotation, image_set_crop, image_set_size and |
| 1971 | image_set_transform use affine transformation matrices to perform | ||
| 1971 | various transforms on the image. The matrix is a 2D array of | 1972 | various transforms on the image. The matrix is a 2D array of |
| 1972 | doubles. It is laid out like this: | 1973 | doubles. It is laid out like this: |
| 1973 | 1974 | ||
| @@ -2038,6 +2039,10 @@ compute_image_size (size_t width, size_t height, | |||
| 2038 | finally move the origin back to the top left of the image, which | 2039 | finally move the origin back to the top left of the image, which |
| 2039 | may now be a different corner. | 2040 | may now be a different corner. |
| 2040 | 2041 | ||
| 2042 | Cropping is easier as we just move the origin to the top left of | ||
| 2043 | where we want to crop and set the width and height accordingly. | ||
| 2044 | The matrices don’t know anything about width and height. | ||
| 2045 | |||
| 2041 | It's possible to pre-calculate the matrix multiplications and just | 2046 | It's possible to pre-calculate the matrix multiplications and just |
| 2042 | generate one transform matrix that will do everything we need in a | 2047 | generate one transform matrix that will do everything we need in a |
| 2043 | single step, but the maths for each element is much more complex | 2048 | single step, but the maths for each element is much more complex |
| @@ -2065,7 +2070,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result) | |||
| 2065 | } | 2070 | } |
| 2066 | 2071 | ||
| 2067 | static void | 2072 | static void |
| 2068 | image_set_transform (struct frame *f, struct image *img) | 2073 | image_set_rotation (struct image *img, matrix3x3 tm) |
| 2069 | { | 2074 | { |
| 2070 | #ifdef HAVE_NATIVE_TRANSFORMS | 2075 | #ifdef HAVE_NATIVE_TRANSFORMS |
| 2071 | # ifdef HAVE_IMAGEMAGICK | 2076 | # ifdef HAVE_IMAGEMAGICK |
| @@ -2079,112 +2084,217 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 2079 | return; | 2084 | return; |
| 2080 | # endif | 2085 | # endif |
| 2081 | 2086 | ||
| 2082 | /* This is the transformation matrix we will use through all the | 2087 | int rotation, cos_r, sin_r, width, height; |
| 2083 | calculations. */ | ||
| 2084 | matrix3x3 tm = { [0][0] = 1, [1][1] = 1, [2][2] = 1 }; | ||
| 2085 | 2088 | ||
| 2086 | /* Calculate image rotation. */ | ||
| 2087 | Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL); | 2089 | Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL); |
| 2088 | if (NUMBERP (value)) | 2090 | if (! NUMBERP (value)) |
| 2091 | return; | ||
| 2092 | |||
| 2093 | Lisp_Object reduced_angle = Fmod (value, make_fixnum (360)); | ||
| 2094 | if (! FLOATP (reduced_angle)) | ||
| 2095 | rotation = XFIXNUM (reduced_angle); | ||
| 2096 | else | ||
| 2089 | { | 2097 | { |
| 2090 | int rotation, cos_r, sin_r, width, height; | 2098 | rotation = XFLOAT_DATA (reduced_angle); |
| 2099 | if (rotation != XFLOAT_DATA (reduced_angle)) | ||
| 2100 | goto not_a_multiple_of_90; | ||
| 2101 | } | ||
| 2091 | 2102 | ||
| 2092 | Lisp_Object reduced_angle = Fmod (value, make_fixnum (360)); | 2103 | if (rotation == 0) |
| 2093 | if (! FLOATP (reduced_angle)) | 2104 | return; |
| 2094 | rotation = XFIXNUM (reduced_angle); | ||
| 2095 | else | ||
| 2096 | { | ||
| 2097 | rotation = XFLOAT_DATA (reduced_angle); | ||
| 2098 | if (rotation != XFLOAT_DATA (reduced_angle)) | ||
| 2099 | goto not_a_multiple_of_90; | ||
| 2100 | } | ||
| 2101 | 2105 | ||
| 2102 | if (rotation != 0) | 2106 | if (rotation == 90) |
| 2103 | { | 2107 | { |
| 2104 | if (rotation == 90) | 2108 | width = img->height; |
| 2105 | { | 2109 | height = img->width; |
| 2106 | width = img->height; | ||
| 2107 | height = img->width; | ||
| 2108 | 2110 | ||
| 2109 | cos_r = 0; | 2111 | cos_r = 0; |
| 2110 | sin_r = 1; | 2112 | sin_r = 1; |
| 2111 | } | 2113 | } |
| 2112 | else if (rotation == 180) | 2114 | else if (rotation == 180) |
| 2113 | { | 2115 | { |
| 2114 | width = img->width; | 2116 | width = img->width; |
| 2115 | height = img->height; | 2117 | height = img->height; |
| 2116 | 2118 | ||
| 2117 | cos_r = -1; | 2119 | cos_r = -1; |
| 2118 | sin_r = 0; | 2120 | sin_r = 0; |
| 2119 | } | 2121 | } |
| 2120 | else if (rotation == 270) | 2122 | else if (rotation == 270) |
| 2121 | { | 2123 | { |
| 2122 | width = img->height; | 2124 | width = img->height; |
| 2123 | height = img->width; | 2125 | height = img->width; |
| 2124 | 2126 | ||
| 2125 | cos_r = 0; | 2127 | cos_r = 0; |
| 2126 | sin_r = -1; | 2128 | sin_r = -1; |
| 2127 | } | 2129 | } |
| 2128 | else | 2130 | else |
| 2129 | { | 2131 | { |
| 2130 | not_a_multiple_of_90: | 2132 | not_a_multiple_of_90: |
| 2131 | image_error ("Native image rotation supports " | 2133 | image_error ("Native image rotation supports " |
| 2132 | "only multiples of 90 degrees"); | 2134 | "only multiples of 90 degrees"); |
| 2133 | return; | 2135 | return; |
| 2134 | } | 2136 | } |
| 2135 | 2137 | ||
| 2136 | /* Translate so (0, 0) is in the center of the image. */ | 2138 | /* Translate so (0, 0) is in the center of the image. */ |
| 2137 | matrix3x3 t | 2139 | matrix3x3 t |
| 2138 | = { [0][0] = 1, [2][0] = img->width >> 1, | 2140 | = { [0][0] = 1, |
| 2139 | [1][1] = 1, [2][1] = img->height >> 1, | 2141 | [1][1] = 1, |
| 2140 | [2][2] = 1 }; | 2142 | [2][0] = img->width >> 1, [2][1] = img->height >> 1, [2][2] = 1 }; |
| 2141 | matrix3x3 tmp; | 2143 | matrix3x3 tmp; |
| 2142 | matrix3x3_mult (t, tm, tmp); | 2144 | matrix3x3_mult (t, tm, tmp); |
| 2143 | 2145 | ||
| 2144 | /* Rotate. */ | 2146 | /* Rotate. */ |
| 2145 | matrix3x3 rot = { [0][0] = cos_r, [1][0] = sin_r, | 2147 | matrix3x3 rot = { [0][0] = cos_r, [0][1] = -sin_r, |
| 2146 | [0][1] = -sin_r, [1][1] = cos_r, | 2148 | [1][0] = sin_r, [1][1] = cos_r, |
| 2147 | [2][2] = 1 }; | 2149 | [2][2] = 1 }; |
| 2148 | matrix3x3 tmp2; | 2150 | matrix3x3 tmp2; |
| 2149 | matrix3x3_mult (rot, tmp, tmp2); | 2151 | matrix3x3_mult (rot, tmp, tmp2); |
| 2150 | 2152 | ||
| 2151 | /* Translate back. */ | 2153 | /* Translate back. */ |
| 2152 | t[2][0] = - (width >> 1); | 2154 | t[2][0] = - (width >> 1); |
| 2153 | t[2][1] = - (height >> 1); | 2155 | t[2][1] = - (height >> 1); |
| 2154 | matrix3x3_mult (t, tmp2, tm); | 2156 | matrix3x3_mult (t, tmp2, tm); |
| 2155 | 2157 | ||
| 2156 | img->width = width; | 2158 | img->width = width; |
| 2157 | img->height = height; | 2159 | img->height = height; |
| 2158 | } | 2160 | #endif |
| 2161 | } | ||
| 2162 | |||
| 2163 | static void | ||
| 2164 | image_set_crop (struct image *img, matrix3x3 tm) | ||
| 2165 | { | ||
| 2166 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2167 | # ifdef HAVE_IMAGEMAGICK | ||
| 2168 | /* ImageMagick images are already cropped. */ | ||
| 2169 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | ||
| 2170 | return; | ||
| 2171 | # endif | ||
| 2172 | |||
| 2173 | # if !defined USE_CAIRO && defined HAVE_XRENDER | ||
| 2174 | if (!img->picture) | ||
| 2175 | return; | ||
| 2176 | # endif | ||
| 2177 | |||
| 2178 | Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL); | ||
| 2179 | |||
| 2180 | if (!CONSP (crop)) | ||
| 2181 | return; | ||
| 2182 | |||
| 2183 | Lisp_Object w = XCAR (crop), h = Qnil, x = Qnil, y = Qnil; | ||
| 2184 | crop = XCDR (crop); | ||
| 2185 | if (CONSP (crop)) | ||
| 2186 | { | ||
| 2187 | h = XCAR (crop); | ||
| 2188 | crop = XCDR (crop); | ||
| 2189 | if (CONSP (crop)) | ||
| 2190 | { | ||
| 2191 | x = XCAR (crop); | ||
| 2192 | crop = XCDR (crop); | ||
| 2193 | if (CONSP (crop)) | ||
| 2194 | y = XCAR (crop); | ||
| 2195 | } | ||
| 2159 | } | 2196 | } |
| 2160 | 2197 | ||
| 2161 | /* Calculate final image size. */ | 2198 | int width = img->width; |
| 2162 | { | 2199 | if (FIXNATP (w) && XFIXNAT (w) < img->width) |
| 2163 | int width, height; | 2200 | width = XFIXNAT (w); |
| 2201 | int left; | ||
| 2202 | if (TYPE_RANGED_FIXNUMP (int, x)) | ||
| 2203 | { | ||
| 2204 | left = XFIXNUM (x); | ||
| 2205 | if (left < 0) | ||
| 2206 | left = img->width - width + left; | ||
| 2207 | } | ||
| 2208 | else | ||
| 2209 | left = (img->width - width) >> 1; | ||
| 2164 | 2210 | ||
| 2165 | compute_image_size (img->width, img->height, img->spec, &width, &height); | 2211 | int height = img->height; |
| 2212 | if (FIXNATP (h) && XFIXNAT (h) < img->height) | ||
| 2213 | height = XFIXNAT (h); | ||
| 2214 | int top; | ||
| 2215 | if (TYPE_RANGED_FIXNUMP (int, y)) | ||
| 2216 | { | ||
| 2217 | top = XFIXNUM (y); | ||
| 2218 | if (top < 0) | ||
| 2219 | top = img->height - height + top; | ||
| 2220 | } | ||
| 2221 | else | ||
| 2222 | top = (img->height - height) >> 1; | ||
| 2166 | 2223 | ||
| 2167 | if (img->width != width || img->height != height) | 2224 | /* Negative values operate from the right and bottom of the image |
| 2168 | { | 2225 | instead of the left and top. */ |
| 2169 | double xscale = img->width / (double) width; | 2226 | if (left < 0) |
| 2170 | double yscale = img->height / (double) height; | 2227 | { |
| 2228 | width = img->width + left; | ||
| 2229 | left = 0; | ||
| 2230 | } | ||
| 2171 | 2231 | ||
| 2172 | matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 }; | 2232 | if (width + left > img->width) |
| 2173 | matrix3x3_mult (rm, tm, tmp); | 2233 | width = img->width - left; |
| 2174 | matrix3x3_copy (tmp, tm); | ||
| 2175 | 2234 | ||
| 2176 | img->width = width; | 2235 | if (top < 0) |
| 2177 | img->height = height; | 2236 | { |
| 2178 | } | 2237 | height = img->height + top; |
| 2179 | } | 2238 | top = 0; |
| 2239 | } | ||
| 2240 | |||
| 2241 | if (height + top > img->height) | ||
| 2242 | height = img->height - top; | ||
| 2243 | |||
| 2244 | matrix3x3 tmp, m = { [0][0] = 1, | ||
| 2245 | [1][1] = 1, | ||
| 2246 | [2][0] = left, [2][1] = top, [2][2] = 1 }; | ||
| 2247 | matrix3x3_mult (m, tm, tmp); | ||
| 2248 | matrix3x3_copy (tmp, tm); | ||
| 2249 | |||
| 2250 | img->width = width; | ||
| 2251 | img->height = height; | ||
| 2252 | #endif | ||
| 2253 | } | ||
| 2180 | 2254 | ||
| 2255 | static void | ||
| 2256 | image_set_size (struct image *img, matrix3x3 tm) | ||
| 2257 | { | ||
| 2258 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2259 | # ifdef HAVE_IMAGEMAGICK | ||
| 2260 | /* ImageMagick images are already the correct size. */ | ||
| 2261 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | ||
| 2262 | return; | ||
| 2263 | # endif | ||
| 2264 | |||
| 2265 | # if !defined USE_CAIRO && defined HAVE_XRENDER | ||
| 2266 | if (!img->picture) | ||
| 2267 | return; | ||
| 2268 | # endif | ||
| 2269 | |||
| 2270 | int width, height; | ||
| 2271 | |||
| 2272 | compute_image_size (img->width, img->height, img->spec, &width, &height); | ||
| 2273 | |||
| 2274 | double xscale = img->width / (double) width; | ||
| 2275 | double yscale = img->height / (double) height; | ||
| 2276 | |||
| 2277 | matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 }; | ||
| 2278 | matrix3x3_mult (rm, tm, tmp); | ||
| 2279 | matrix3x3_copy (tmp, tm); | ||
| 2280 | |||
| 2281 | img->width = width; | ||
| 2282 | img->height = height; | ||
| 2283 | #endif | ||
| 2284 | } | ||
| 2285 | |||
| 2286 | static void | ||
| 2287 | image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix) | ||
| 2288 | { | ||
| 2289 | /* TODO: Add MS Windows support. */ | ||
| 2290 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2181 | # if defined (HAVE_NS) | 2291 | # if defined (HAVE_NS) |
| 2182 | /* Under NS the transform is applied to the drawing surface at | 2292 | /* Under NS the transform is applied to the drawing surface at |
| 2183 | drawing time, so store it for later. */ | 2293 | drawing time, so store it for later. */ |
| 2184 | ns_image_set_transform (img->pixmap, tm); | 2294 | ns_image_set_transform (img->pixmap, matrix); |
| 2185 | # elif defined USE_CAIRO | 2295 | # elif defined USE_CAIRO |
| 2186 | cairo_matrix_t cr_matrix = {tm[0][0], tm[0][1], tm[1][0], | 2296 | cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0], |
| 2187 | tm[1][1], tm[2][0], tm[2][1]}; | 2297 | matrix[1][1], matrix[2][0], matrix[2][1]}; |
| 2188 | cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); | 2298 | cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); |
| 2189 | cairo_pattern_set_matrix (pattern, &cr_matrix); | 2299 | cairo_pattern_set_matrix (pattern, &cr_matrix); |
| 2190 | /* Dummy solid color pattern just to record pattern matrix. */ | 2300 | /* Dummy solid color pattern just to record pattern matrix. */ |
| @@ -2193,15 +2303,15 @@ image_set_transform (struct frame *f, struct image *img) | |||
| 2193 | if (img->picture) | 2303 | if (img->picture) |
| 2194 | { | 2304 | { |
| 2195 | XTransform tmat | 2305 | XTransform tmat |
| 2196 | = {{{XDoubleToFixed (tm[0][0]), | 2306 | = {{{XDoubleToFixed (matrix[0][0]), |
| 2197 | XDoubleToFixed (tm[1][0]), | 2307 | XDoubleToFixed (matrix[1][0]), |
| 2198 | XDoubleToFixed (tm[2][0])}, | 2308 | XDoubleToFixed (matrix[2][0])}, |
| 2199 | {XDoubleToFixed (tm[0][1]), | 2309 | {XDoubleToFixed (matrix[0][1]), |
| 2200 | XDoubleToFixed (tm[1][1]), | 2310 | XDoubleToFixed (matrix[1][1]), |
| 2201 | XDoubleToFixed (tm[2][1])}, | 2311 | XDoubleToFixed (matrix[2][1])}, |
| 2202 | {XDoubleToFixed (tm[0][2]), | 2312 | {XDoubleToFixed (matrix[0][2]), |
| 2203 | XDoubleToFixed (tm[1][2]), | 2313 | XDoubleToFixed (matrix[1][2]), |
| 2204 | XDoubleToFixed (tm[2][2])}}}; | 2314 | XDoubleToFixed (matrix[2][2])}}}; |
| 2205 | 2315 | ||
| 2206 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, | 2316 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, |
| 2207 | 0, 0); | 2317 | 0, 0); |
| @@ -2267,7 +2377,11 @@ lookup_image (struct frame *f, Lisp_Object spec) | |||
| 2267 | int relief_bound; | 2377 | int relief_bound; |
| 2268 | 2378 | ||
| 2269 | #ifdef HAVE_NATIVE_TRANSFORMS | 2379 | #ifdef HAVE_NATIVE_TRANSFORMS |
| 2270 | image_set_transform (f, img); | 2380 | matrix3x3 transform_matrix = { [0][0] = 1, [1][1] = 1, [2][2] = 1 }; |
| 2381 | image_set_size (img, transform_matrix); | ||
| 2382 | image_set_crop (img, transform_matrix); | ||
| 2383 | image_set_rotation (img, transform_matrix); | ||
| 2384 | image_set_transform (f, img, transform_matrix); | ||
| 2271 | #endif | 2385 | #endif |
| 2272 | 2386 | ||
| 2273 | ascent = image_spec_value (spec, QCascent, NULL); | 2387 | ascent = image_spec_value (spec, QCascent, NULL); |
diff --git a/test/manual/image-transforms-tests.el b/test/manual/image-transforms-tests.el index 907f0639e4c..d601b9397e3 100644 --- a/test/manual/image-transforms-tests.el +++ b/test/manual/image-transforms-tests.el | |||
| @@ -25,9 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | ;; Type M-x test-transforms RET to generate the test buffer. | 26 | ;; Type M-x test-transforms RET to generate the test buffer. |
| 27 | 27 | ||
| 28 | ;; There is a difference in how librsvg and ImageMagick draw some of | ||
| 29 | ;; the images. This results in what looks like a one pixel difference. | ||
| 30 | |||
| 31 | ;;; Code: | 28 | ;;; Code: |
| 32 | 29 | ||
| 33 | (defun test-rotation () | 30 | (defun test-rotation () |
| @@ -47,6 +44,36 @@ | |||
| 47 | (insert-test "45" up up '(:rotation 45))) | 44 | (insert-test "45" up up '(:rotation 45))) |
| 48 | (insert "\n\n")) | 45 | (insert "\n\n")) |
| 49 | 46 | ||
| 47 | (defun test-cropping () | ||
| 48 | (let ((image "<svg height='30' width='30'> | ||
| 49 | <rect x='0' y='0' width='10' height='10'/> | ||
| 50 | <rect x='10' y='10' width='10' height='10' | ||
| 51 | style='fill:none;stroke-width:1;stroke:#000'/> | ||
| 52 | <line x1='10' y1='10' x2='20' y2='20' style='stroke:#000'/> | ||
| 53 | <line x1='20' y1='10' x2='10' y2='20' style='stroke:#000'/> | ||
| 54 | <rect x='20' y='20' width='10' height='10' | ||
| 55 | style='fill:none;stroke-width:1;stroke:#000'/> | ||
| 56 | </svg>") | ||
| 57 | (top-left "<svg height='10' width='10'> | ||
| 58 | <rect x='0' y='0' width='10' height='10'/> | ||
| 59 | </svg>") | ||
| 60 | (middle "<svg height='10' width='10'> | ||
| 61 | <rect x='0' y='0' width='10' height='10' | ||
| 62 | style='fill:none;stroke-width:1;stroke:#000'/> | ||
| 63 | <line x1='0' y1='0' x2='10' y2='10' style='stroke:#000'/> | ||
| 64 | <line x1='10' y1='0' x2='0' y2='10' style='stroke:#000'/> | ||
| 65 | </svg>") | ||
| 66 | (bottom-right "<svg height='10' width='10'> | ||
| 67 | <rect x='0' y='0' width='10' height='10' | ||
| 68 | style='fill:none;stroke-width:1;stroke:#000'/> | ||
| 69 | </svg>")) | ||
| 70 | (insert-header "Test Crop: cropping an image") | ||
| 71 | (insert-test "all params" top-left image '(:crop (10 10 0 0))) | ||
| 72 | (insert-test "width/height only" middle image '(:crop (10 10))) | ||
| 73 | (insert-test "negative x y" middle image '(:crop (10 10 -10 -10))) | ||
| 74 | (insert-test "all params" bottom-right image '(:crop (10 10 20 20)))) | ||
| 75 | (insert "\n\n")) | ||
| 76 | |||
| 50 | (defun test-scaling () | 77 | (defun test-scaling () |
| 51 | (let ((image "<svg height='10' width='10'> | 78 | (let ((image "<svg height='10' width='10'> |
| 52 | <rect x='0' y='0' width='10' height='10' | 79 | <rect x='0' y='0' width='10' height='10' |
| @@ -143,6 +170,7 @@ | |||
| 143 | (unless #'imagemagick-types | 170 | (unless #'imagemagick-types |
| 144 | (insert "ImageMagick not detected. ImageMagick tests will be skipped.\n\n")) | 171 | (insert "ImageMagick not detected. ImageMagick tests will be skipped.\n\n")) |
| 145 | (test-rotation) | 172 | (test-rotation) |
| 173 | (test-cropping) | ||
| 146 | (test-scaling) | 174 | (test-scaling) |
| 147 | (test-scaling-rotation) | 175 | (test-scaling-rotation) |
| 148 | (goto-char (point-min)))) | 176 | (goto-char (point-min)))) |