aboutsummaryrefslogtreecommitdiffstats
path: root/src/image.c
diff options
context:
space:
mode:
authorAlan Third2019-06-05 21:51:33 +0100
committerAlan Third2019-06-05 22:28:46 +0100
commit610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9 (patch)
tree8a3ee992ccc310071ac5a97ced8907652974c88e /src/image.c
parent9201cf62ce9f17793bb6103050c9ba27eb942e57 (diff)
downloademacs-610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9.tar.gz
emacs-610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9.zip
Add native image rotation and cropping
* lisp/image.el (image--get-imagemagick-and-warn): Only fallback to ImageMagick if native transforms aren't available. * src/dispextern.h (INIT_MATRIX, COPY_MATRIX, MULT_MATRICES): New macros for matrix manipulation. (HAVE_NATIVE_SCALING, HAVE_NATIVE_TRANSFORMS): Rename and change all relevant locations. * src/image.c (x_set_image_rotation): (x_set_transform): New functions. (x_set_image_size): Use transform matrix for resizing under X and NS. (x_set_image_crop): New function. (lookup_image): Use the new transform functions. (Fimage_scaling_p, Fimage_transforms_p): Rename and update all callers. * src/nsimage.m (ns_load_image): Remove rotation code. (ns_image_set_transform): New function. ([EmacsImage dealloc]): Release the saved transform. ([EmacsImage rotate:]): Remove unneeded method. ([EmacsImage setTransform:]): New method. * src/nsterm.h (EmacsImage): Add transform property and update method definitions. * src/nsterm.m (ns_dumpglyphs_image): Use the transform to draw the image correctly. * src/xterm.c (x_composite_image): Use PictOpSrc as we don't care about alpha values here. * doc/lispref/display.texi (Image Descriptors): Add :rotation. (ImageMagick Images): Remove :rotation.
Diffstat (limited to 'src/image.c')
-rw-r--r--src/image.c283
1 files changed, 257 insertions, 26 deletions
diff --git a/src/image.c b/src/image.c
index 9b0080130bc..a95a7bf27f9 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1841,7 +1841,7 @@ postprocess_image (struct frame *f, struct image *img)
1841 } 1841 }
1842} 1842}
1843 1843
1844#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING) 1844#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_TRANSFORMS)
1845/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER, 1845/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
1846 safely rounded and clipped to int range. */ 1846 safely rounded and clipped to int range. */
1847 1847
@@ -1940,49 +1940,241 @@ compute_image_size (size_t width, size_t height,
1940 *d_width = desired_width; 1940 *d_width = desired_width;
1941 *d_height = desired_height; 1941 *d_height = desired_height;
1942} 1942}
1943#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_SCALING */ 1943#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
1944 1944
1945static void 1945static void
1946image_set_image_size (struct frame *f, struct image *img) 1946image_set_rotation (struct image *img, double tm[3][3])
1947{ 1947{
1948#ifdef HAVE_NATIVE_SCALING 1948#ifdef HAVE_NATIVE_TRANSFORMS
1949# ifdef HAVE_IMAGEMAGICK 1949# ifdef HAVE_IMAGEMAGICK
1950 /* ImageMagick images are already the correct size. */ 1950 /* ImageMagick images are already rotated. */
1951 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) 1951 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
1952 return; 1952 return;
1953# endif 1953# endif
1954 1954
1955 int width, height; 1955# ifdef HAVE_XRENDER
1956 compute_image_size (img->width, img->height, img->spec, &width, &height); 1956 if (!img->picture)
1957 return;
1958# endif
1959
1960 Lisp_Object value;
1961 double t[3][3], rot[3][3], tmp[3][3], tmp2[3][3];
1962 int rotation, cos_r, sin_r, width, height;
1963
1964 value = image_spec_value (img->spec, QCrotation, NULL);
1965 if (! NUMBERP (value))
1966 return;
1967
1968 rotation = XFLOATINT (value);
1969 rotation = rotation % 360;
1970
1971 if (rotation < 0)
1972 rotation += 360;
1973
1974 if (rotation == 0)
1975 return;
1976
1977 if (rotation == 90)
1978 {
1979 width = img->height;
1980 height = img->width;
1981
1982 cos_r = 0;
1983 sin_r = 1;
1984 }
1985 else if (rotation == 180)
1986 {
1987 width = img->width;
1988 height = img->height;
1989
1990 cos_r = -1;
1991 sin_r = 0;
1992 }
1993 else if (rotation == 270)
1994 {
1995 width = img->height;
1996 height = img->width;
1997
1998 cos_r = 0;
1999 sin_r = -1;
2000 }
2001 else
2002 {
2003 image_error ("Native image rotation only supports multiples of 90 degrees");
2004 return;
2005 }
2006
2007 /* Translate so (0, 0) is in the centre of the image. */
2008 INIT_MATRIX (t);
2009 t[2][0] = img->width/2;
2010 t[2][1] = img->height/2;
2011
2012 MULT_MATRICES (tm, t, tmp);
2013
2014 /* Rotate. */
2015 INIT_MATRIX (rot);
2016 rot[0][0] = cos_r;
2017 rot[1][0] = sin_r;
2018 rot[0][1] = - sin_r;
2019 rot[1][1] = cos_r;
2020
2021 MULT_MATRICES (tmp, rot, tmp2);
2022
2023 /* Translate back. */
2024 INIT_MATRIX (t);
2025 t[2][0] = - width/2;
2026 t[2][1] = - height/2;
2027
2028 MULT_MATRICES (tmp2, t, tm);
1957 2029
1958# ifdef HAVE_NS
1959 ns_image_set_size (img->pixmap, width, height);
1960 img->width = width; 2030 img->width = width;
1961 img->height = height; 2031 img->height = height;
2032#endif
2033}
2034
2035static void
2036image_set_crop (struct image *img, double tm[3][3])
2037{
2038#ifdef HAVE_NATIVE_TRANSFORMS
2039# ifdef HAVE_IMAGEMAGICK
2040 /* ImageMagick images are already cropped. */
2041 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
2042 return;
1962# endif 2043# endif
1963 2044
1964# ifdef USE_CAIRO 2045# ifdef USE_CAIRO
1965 img->width = width; 2046 img->width = width;
1966 img->height = height; 2047 img->height = height;
1967# elif defined HAVE_XRENDER 2048# elif defined HAVE_XRENDER
1968 if (img->picture) 2049 if (!img->picture)
2050 return;
2051# endif
2052
2053 double m[3][3], tmp[3][3];
2054 int left, top, width, height;
2055 Lisp_Object x = Qnil;
2056 Lisp_Object y = Qnil;
2057 Lisp_Object w = Qnil;
2058 Lisp_Object h = Qnil;
2059 Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL);
2060
2061 if (!CONSP (crop))
2062 return;
2063 else
1969 { 2064 {
1970 double xscale = img->width / (double) width; 2065 w = XCAR (crop);
1971 double yscale = img->height / (double) height; 2066 crop = XCDR (crop);
2067 if (CONSP (crop))
2068 {
2069 h = XCAR (crop);
2070 crop = XCDR (crop);
2071 if (CONSP (crop))
2072 {
2073 x = XCAR (crop);
2074 crop = XCDR (crop);
2075 if (CONSP (crop))
2076 y = XCAR (crop);
2077 }
2078 }
2079 }
1972 2080
1973 XTransform tmat 2081 if (FIXNATP (w) && XFIXNAT (w) < img->width)
1974 = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)}, 2082 width = XFIXNAT (w);
1975 {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)}, 2083 else
1976 {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}}; 2084 width = img->width;
1977 2085
1978 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 2086 if (TYPE_RANGED_FIXNUMP (int, x))
1979 0, 0); 2087 {
1980 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); 2088 left = XFIXNUM (x);
2089 if (left < 0)
2090 left = img->width - width + left;
2091 }
2092 else
2093 left = (img->width - width)/2;
2094
2095 if (FIXNATP (h) && XFIXNAT (h) < img->height)
2096 height = XFIXNAT (h);
2097 else
2098 height = img->height;
2099
2100 if (TYPE_RANGED_FIXNUMP (int, y))
2101 {
2102 top = XFIXNUM (y);
2103 if (top < 0)
2104 top = img->height - height + top;
2105 }
2106 else
2107 top = (img->height - height)/2;
2108
2109 /* Negative values operate from the right and bottom of the image
2110 instead of the left and top. */
2111 if (left < 0)
2112 {
2113 width = img->width + left;
2114 left = 0;
2115 }
2116
2117 if (width + left > img->width)
2118 width = img->width - left;
1981 2119
1982 img->width = width; 2120 if (top < 0)
1983 img->height = height; 2121 {
2122 height = img->height + top;
2123 top = 0;
1984 } 2124 }
2125
2126 if (height + top > img->height)
2127 height = img->height - top;
2128
2129 INIT_MATRIX (m);
2130 m[2][0] = left;
2131 m[2][1] = top;
2132
2133 MULT_MATRICES (tm, m, tmp);
2134 COPY_MATRIX (tmp, tm);
2135
2136 img->width = width;
2137 img->height = height;
2138#endif
2139}
2140
2141static void
2142image_set_size (struct image *img, double tm[3][3])
2143{
2144#ifdef HAVE_NATIVE_TRANSFORMS
2145# ifdef HAVE_IMAGEMAGICK
2146 /* ImageMagick images are already the correct size. */
2147 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
2148 return;
2149# endif
2150
2151# ifdef HAVE_XRENDER
2152 if (!img->picture)
2153 return;
2154# endif
2155
2156 int width, height;
2157
2158 compute_image_size (img->width, img->height, img->spec, &width, &height);
2159
2160# if defined (HAVE_NS) || defined (HAVE_XRENDER)
2161 double rm[3][3], tmp[3][3];
2162 double xscale, yscale;
2163
2164 xscale = img->width / (double) width;
2165 yscale = img->height / (double) height;
2166
2167 INIT_MATRIX (rm);
2168 rm[0][0] = xscale;
2169 rm[1][1] = yscale;
2170
2171 MULT_MATRICES (tm, rm, tmp);
2172 COPY_MATRIX (tmp, tm);
2173
2174 img->width = width;
2175 img->height = height;
1985# endif 2176# endif
2177
1986# ifdef HAVE_NTGUI 2178# ifdef HAVE_NTGUI
1987 /* Under HAVE_NTGUI, we will scale the image on the fly, when we 2179 /* Under HAVE_NTGUI, we will scale the image on the fly, when we
1988 draw it. See w32term.c:x_draw_image_foreground. */ 2180 draw it. See w32term.c:x_draw_image_foreground. */
@@ -1992,6 +2184,36 @@ image_set_image_size (struct frame *f, struct image *img)
1992#endif 2184#endif
1993} 2185}
1994 2186
2187static void
2188image_set_transform (struct frame *f, struct image *img, double matrix[3][3])
2189{
2190 /* TODO: Add MS Windows support. */
2191#ifdef HAVE_NATIVE_TRANSFORMS
2192# if defined (HAVE_NS)
2193 /* Under NS the transform is applied to the drawing surface at
2194 drawing time, so store it for later. */
2195 ns_image_set_transform (img->pixmap, matrix);
2196# elif defined (HAVE_XRENDER)
2197 if (img->picture)
2198 {
2199 XTransform tmat
2200 = {{{XDoubleToFixed (matrix[0][0]),
2201 XDoubleToFixed (matrix[1][0]),
2202 XDoubleToFixed (matrix[2][0])},
2203 {XDoubleToFixed (matrix[0][1]),
2204 XDoubleToFixed (matrix[1][1]),
2205 XDoubleToFixed (matrix[2][1])},
2206 {XDoubleToFixed (matrix[0][2]),
2207 XDoubleToFixed (matrix[1][2]),
2208 XDoubleToFixed (matrix[2][2])}}};
2209
2210 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
2211 0, 0);
2212 XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
2213 }
2214# endif
2215#endif
2216}
1995 2217
1996/* Return the id of image with Lisp specification SPEC on frame F. 2218/* Return the id of image with Lisp specification SPEC on frame F.
1997 SPEC must be a valid Lisp image specification (see valid_image_p). */ 2219 SPEC must be a valid Lisp image specification (see valid_image_p). */
@@ -2047,7 +2269,16 @@ lookup_image (struct frame *f, Lisp_Object spec)
2047 `:background COLOR'. */ 2269 `:background COLOR'. */
2048 Lisp_Object ascent, margin, relief, bg; 2270 Lisp_Object ascent, margin, relief, bg;
2049 int relief_bound; 2271 int relief_bound;
2050 image_set_image_size (f, img); 2272
2273#ifdef HAVE_NATIVE_TRANSFORMS
2274 double transform_matrix[3][3];
2275
2276 INIT_MATRIX (transform_matrix);
2277 image_set_size (img, transform_matrix);
2278 image_set_crop (img, transform_matrix);
2279 image_set_rotation (img, transform_matrix);
2280 image_set_transform (f, img, transform_matrix);
2281#endif
2051 2282
2052 ascent = image_spec_value (spec, QCascent, NULL); 2283 ascent = image_spec_value (spec, QCascent, NULL);
2053 if (FIXNUMP (ascent)) 2284 if (FIXNUMP (ascent))
@@ -9673,9 +9904,9 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
9673 Initialization 9904 Initialization
9674 ***********************************************************************/ 9905 ***********************************************************************/
9675 9906
9676DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, 9907DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0,
9677 doc: /* Test whether FRAME supports resizing images. 9908 doc: /* Test whether FRAME supports image transformation.
9678Return t if FRAME supports native scaling, nil otherwise. */) 9909Return t if FRAME supports native transforms, nil otherwise. */)
9679 (Lisp_Object frame) 9910 (Lisp_Object frame)
9680{ 9911{
9681#if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI) 9912#if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI)
@@ -9935,7 +10166,7 @@ non-numeric, there is no explicit limit on the size of images. */);
9935 defsubr (&Slookup_image); 10166 defsubr (&Slookup_image);
9936#endif 10167#endif
9937 10168
9938 defsubr (&Simage_scaling_p); 10169 defsubr (&Simage_transforms_p);
9939 10170
9940 DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images, 10171 DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
9941 doc: /* Non-nil means always draw a cross over disabled images. 10172 doc: /* Non-nil means always draw a cross over disabled images.