aboutsummaryrefslogtreecommitdiffstats
path: root/src/image.c
diff options
context:
space:
mode:
authorAlan Third2019-06-16 20:10:20 +0100
committerAlan Third2019-06-16 20:24:53 +0100
commitcf3081d208814ea02fce33aac645abfc24f880a6 (patch)
tree7c840344a0a6edbf6bc9ee9debcb690877e417d8 /src/image.c
parent11b0e33462fa7ebef142953010e25728543d1be8 (diff)
downloademacs-cf3081d208814ea02fce33aac645abfc24f880a6.tar.gz
emacs-cf3081d208814ea02fce33aac645abfc24f880a6.zip
Simplify image transforms
* src/image.c: (image_set_rotation, image_set_size, image_set_transform): Combine into image_set_transform. (image_set_crop): Remove function. (lookup_image): Remove calls to removed functions and remove transform_matrix. * test/manual/image-transforms-tests.el (test-cropping): Remove function. (test-transforms): Remove reference to test-cropping.
Diffstat (limited to 'src/image.c')
-rw-r--r--src/image.c310
1 files changed, 98 insertions, 212 deletions
diff --git a/src/image.c b/src/image.c
index a3747cfa6b7..8b571dd72d6 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1967,8 +1967,7 @@ 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_rotation, image_set_crop, image_set_size and 1970/* image_set_transform uses affine transformation matrices to perform
1971 image_set_transform use affine transformation matrices to perform
1972 various transforms on the image. The matrix is a 2D array of 1971 various transforms on the image. The matrix is a 2D array of
1973 doubles. It is laid out like this: 1972 doubles. It is laid out like this:
1974 1973
@@ -2039,10 +2038,6 @@ compute_image_size (size_t width, size_t height,
2039 finally move the origin back to the top left of the image, which 2038 finally move the origin back to the top left of the image, which
2040 may now be a different corner. 2039 may now be a different corner.
2041 2040
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
2046 It's possible to pre-calculate the matrix multiplications and just 2041 It's possible to pre-calculate the matrix multiplications and just
2047 generate one transform matrix that will do everything we need in a 2042 generate one transform matrix that will do everything we need in a
2048 single step, but the maths for each element is much more complex 2043 single step, but the maths for each element is much more complex
@@ -2070,7 +2065,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
2070} 2065}
2071 2066
2072static void 2067static void
2073image_set_rotation (struct image *img, matrix3x3 tm) 2068image_set_transform (struct frame *f, struct image *img)
2074{ 2069{
2075#ifdef HAVE_NATIVE_TRANSFORMS 2070#ifdef HAVE_NATIVE_TRANSFORMS
2076# ifdef HAVE_IMAGEMAGICK 2071# ifdef HAVE_IMAGEMAGICK
@@ -2084,217 +2079,112 @@ image_set_rotation (struct image *img, matrix3x3 tm)
2084 return; 2079 return;
2085# endif 2080# endif
2086 2081
2087 int rotation, cos_r, sin_r, width, height; 2082 /* This is the transformation matrix we will use through all the
2083 calculations. */
2084 matrix3x3 tm = { [0][0] = 1, [1][1] = 1, [2][2] = 1 };
2088 2085
2086 /* Calculate image rotation. */
2089 Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL); 2087 Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL);
2090 if (! NUMBERP (value)) 2088 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
2097 {
2098 rotation = XFLOAT_DATA (reduced_angle);
2099 if (rotation != XFLOAT_DATA (reduced_angle))
2100 goto not_a_multiple_of_90;
2101 }
2102
2103 if (rotation == 0)
2104 return;
2105
2106 if (rotation == 90)
2107 {
2108 width = img->height;
2109 height = img->width;
2110
2111 cos_r = 0;
2112 sin_r = 1;
2113 }
2114 else if (rotation == 180)
2115 {
2116 width = img->width;
2117 height = img->height;
2118
2119 cos_r = -1;
2120 sin_r = 0;
2121 }
2122 else if (rotation == 270)
2123 { 2089 {
2124 width = img->height; 2090 int rotation, cos_r, sin_r, width, height;
2125 height = img->width;
2126 2091
2127 cos_r = 0; 2092 Lisp_Object reduced_angle = Fmod (value, make_fixnum (360));
2128 sin_r = -1; 2093 if (! FLOATP (reduced_angle))
2129 } 2094 rotation = XFIXNUM (reduced_angle);
2130 else 2095 else
2131 { 2096 {
2132 not_a_multiple_of_90: 2097 rotation = XFLOAT_DATA (reduced_angle);
2133 image_error ("Native image rotation supports " 2098 if (rotation != XFLOAT_DATA (reduced_angle))
2134 "only multiples of 90 degrees"); 2099 goto not_a_multiple_of_90;
2135 return; 2100 }
2136 }
2137
2138 /* Translate so (0, 0) is in the center of the image. */
2139 matrix3x3 t
2140 = { [0][0] = 1,
2141 [1][1] = 1,
2142 [2][0] = img->width >> 1, [2][1] = img->height >> 1, [2][2] = 1 };
2143 matrix3x3 tmp;
2144 matrix3x3_mult (t, tm, tmp);
2145
2146 /* Rotate. */
2147 matrix3x3 rot = { [0][0] = cos_r, [0][1] = -sin_r,
2148 [1][0] = sin_r, [1][1] = cos_r,
2149 [2][2] = 1 };
2150 matrix3x3 tmp2;
2151 matrix3x3_mult (rot, tmp, tmp2);
2152
2153 /* Translate back. */
2154 t[2][0] = - (width >> 1);
2155 t[2][1] = - (height >> 1);
2156 matrix3x3_mult (t, tmp2, tm);
2157
2158 img->width = width;
2159 img->height = height;
2160#endif
2161}
2162
2163static void
2164image_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 }
2196 }
2197 2101
2198 int width = img->width; 2102 if (rotation != 0)
2199 if (FIXNATP (w) && XFIXNAT (w) < img->width) 2103 {
2200 width = XFIXNAT (w); 2104 if (rotation == 90)
2201 int left; 2105 {
2202 if (TYPE_RANGED_FIXNUMP (int, x)) 2106 width = img->height;
2203 { 2107 height = img->width;
2204 left = XFIXNUM (x);
2205 if (left < 0)
2206 left = img->width - width + left;
2207 }
2208 else
2209 left = (img->width - width) >> 1;
2210 2108
2211 int height = img->height; 2109 cos_r = 0;
2212 if (FIXNATP (h) && XFIXNAT (h) < img->height) 2110 sin_r = 1;
2213 height = XFIXNAT (h); 2111 }
2214 int top; 2112 else if (rotation == 180)
2215 if (TYPE_RANGED_FIXNUMP (int, y)) 2113 {
2216 { 2114 width = img->width;
2217 top = XFIXNUM (y); 2115 height = img->height;
2218 if (top < 0)
2219 top = img->height - height + top;
2220 }
2221 else
2222 top = (img->height - height) >> 1;
2223 2116
2224 /* Negative values operate from the right and bottom of the image 2117 cos_r = -1;
2225 instead of the left and top. */ 2118 sin_r = 0;
2226 if (left < 0) 2119 }
2227 { 2120 else if (rotation == 270)
2228 width = img->width + left; 2121 {
2229 left = 0; 2122 width = img->height;
2230 } 2123 height = img->width;
2231 2124
2232 if (width + left > img->width) 2125 cos_r = 0;
2233 width = img->width - left; 2126 sin_r = -1;
2127 }
2128 else
2129 {
2130 not_a_multiple_of_90:
2131 image_error ("Native image rotation supports "
2132 "only multiples of 90 degrees");
2133 return;
2134 }
2234 2135
2235 if (top < 0) 2136 /* Translate so (0, 0) is in the center of the image. */
2236 { 2137 matrix3x3 t
2237 height = img->height + top; 2138 = { [0][0] = 1, [2][0] = img->width >> 1,
2238 top = 0; 2139 [1][1] = 1, [2][1] = img->height >> 1,
2140 [2][2] = 1 };
2141 matrix3x3 tmp;
2142 matrix3x3_mult (t, tm, tmp);
2143
2144 /* Rotate. */
2145 matrix3x3 rot = { [0][0] = cos_r, [1][0] = sin_r,
2146 [0][1] = -sin_r, [1][1] = cos_r,
2147 [2][2] = 1 };
2148 matrix3x3 tmp2;
2149 matrix3x3_mult (rot, tmp, tmp2);
2150
2151 /* Translate back. */
2152 t[2][0] = - (width >> 1);
2153 t[2][1] = - (height >> 1);
2154 matrix3x3_mult (t, tmp2, tm);
2155
2156 img->width = width;
2157 img->height = height;
2158 }
2239 } 2159 }
2240 2160
2241 if (height + top > img->height) 2161 /* Calculate final image size. */
2242 height = img->height - top; 2162 {
2243 2163 int width, height;
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}
2254
2255static void
2256image_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 2164
2272 compute_image_size (img->width, img->height, img->spec, &width, &height); 2165 compute_image_size (img->width, img->height, img->spec, &width, &height);
2273 2166
2274 double xscale = img->width / (double) width; 2167 if (img->width != width || img->height != height)
2275 double yscale = img->height / (double) height; 2168 {
2169 double xscale = img->width / (double) width;
2170 double yscale = img->height / (double) height;
2276 2171
2277 matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 }; 2172 matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 };
2278 matrix3x3_mult (rm, tm, tmp); 2173 matrix3x3_mult (rm, tm, tmp);
2279 matrix3x3_copy (tmp, tm); 2174 matrix3x3_copy (tmp, tm);
2280 2175
2281 img->width = width; 2176 img->width = width;
2282 img->height = height; 2177 img->height = height;
2283#endif 2178 }
2284} 2179 }
2285 2180
2286static void
2287image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
2288{
2289 /* TODO: Add MS Windows support. */
2290#ifdef HAVE_NATIVE_TRANSFORMS
2291# if defined (HAVE_NS) 2181# if defined (HAVE_NS)
2292 /* Under NS the transform is applied to the drawing surface at 2182 /* Under NS the transform is applied to the drawing surface at
2293 drawing time, so store it for later. */ 2183 drawing time, so store it for later. */
2294 ns_image_set_transform (img->pixmap, matrix); 2184 ns_image_set_transform (img->pixmap, tm);
2295# elif defined USE_CAIRO 2185# elif defined USE_CAIRO
2296 cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0], 2186 cairo_matrix_t cr_matrix = {tm[0][0], tm[0][1], tm[1][0],
2297 matrix[1][1], matrix[2][0], matrix[2][1]}; 2187 tm[1][1], tm[2][0], tm[2][1]};
2298 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); 2188 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
2299 cairo_pattern_set_matrix (pattern, &cr_matrix); 2189 cairo_pattern_set_matrix (pattern, &cr_matrix);
2300 /* Dummy solid color pattern just to record pattern matrix. */ 2190 /* Dummy solid color pattern just to record pattern matrix. */
@@ -2303,15 +2193,15 @@ image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
2303 if (img->picture) 2193 if (img->picture)
2304 { 2194 {
2305 XTransform tmat 2195 XTransform tmat
2306 = {{{XDoubleToFixed (matrix[0][0]), 2196 = {{{XDoubleToFixed (tm[0][0]),
2307 XDoubleToFixed (matrix[1][0]), 2197 XDoubleToFixed (tm[1][0]),
2308 XDoubleToFixed (matrix[2][0])}, 2198 XDoubleToFixed (tm[2][0])},
2309 {XDoubleToFixed (matrix[0][1]), 2199 {XDoubleToFixed (tm[0][1]),
2310 XDoubleToFixed (matrix[1][1]), 2200 XDoubleToFixed (tm[1][1]),
2311 XDoubleToFixed (matrix[2][1])}, 2201 XDoubleToFixed (tm[2][1])},
2312 {XDoubleToFixed (matrix[0][2]), 2202 {XDoubleToFixed (tm[0][2]),
2313 XDoubleToFixed (matrix[1][2]), 2203 XDoubleToFixed (tm[1][2]),
2314 XDoubleToFixed (matrix[2][2])}}}; 2204 XDoubleToFixed (tm[2][2])}}};
2315 2205
2316 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 2206 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
2317 0, 0); 2207 0, 0);
@@ -2377,11 +2267,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
2377 int relief_bound; 2267 int relief_bound;
2378 2268
2379#ifdef HAVE_NATIVE_TRANSFORMS 2269#ifdef HAVE_NATIVE_TRANSFORMS
2380 matrix3x3 transform_matrix = { [0][0] = 1, [1][1] = 1, [2][2] = 1 }; 2270 image_set_transform (f, img);
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);
2385#endif 2271#endif
2386 2272
2387 ascent = image_spec_value (spec, QCascent, NULL); 2273 ascent = image_spec_value (spec, QCascent, NULL);