diff options
| author | Alan Third | 2019-06-11 20:31:24 +0100 |
|---|---|---|
| committer | Alan Third | 2019-06-16 20:24:53 +0100 |
| commit | 11b0e33462fa7ebef142953010e25728543d1be8 (patch) | |
| tree | 9595b80194dcc0a8ea3bf9c999b8dbe6cca82ba9 /src | |
| parent | a1508e8d2db0003fafb53ae51ed1104ba957db6b (diff) | |
| download | emacs-11b0e33462fa7ebef142953010e25728543d1be8.tar.gz emacs-11b0e33462fa7ebef142953010e25728543d1be8.zip | |
Document image transforms
* doc/lispref/display.texi (Image Descriptors): Document :crop and
update :rotation.
* src/image.c: Describe the image transform matrix layout.
* test/manual/image-transforms-tests.el: New file.
Diffstat (limited to 'src')
| -rw-r--r-- | src/image.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/src/image.c b/src/image.c index 86f8e8f4bb7..a3747cfa6b7 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1967,6 +1967,87 @@ 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 | ||
| 1971 | image_set_transform use affine transformation matrices to perform | ||
| 1972 | various transforms on the image. The matrix is a 2D array of | ||
| 1973 | doubles. It is laid out like this: | ||
| 1974 | |||
| 1975 | m[0][0] = m11 | m[1][0] = m12 | m[2][0] = tx | ||
| 1976 | --------------+---------------+------------- | ||
| 1977 | m[0][1] = m21 | m[1][1] = m22 | m[2][1] = ty | ||
| 1978 | --------------+---------------+------------- | ||
| 1979 | m[0][2] = 0 | m[1][2] = 0 | m[2][2] = 1 | ||
| 1980 | |||
| 1981 | tx and ty represent translations, m11 and m22 represent scaling | ||
| 1982 | transforms and m21 and m12 represent shear transforms. Most | ||
| 1983 | graphics toolkits don't require the third row, however it is | ||
| 1984 | necessary for multiplication. | ||
| 1985 | |||
| 1986 | Transforms are done by creating a matrix for each action we wish to | ||
| 1987 | take, then multiplying the transformation matrix by each of those | ||
| 1988 | matrices in order (matrix multiplication is not commutative). | ||
| 1989 | After we’ve done that we can use our modified transformation matrix | ||
| 1990 | to transform points. We take the x and y coordinates and convert | ||
| 1991 | them into a 3x1 matrix and multiply that by the transformation | ||
| 1992 | matrix and it gives us a new, transformed, set of coordinates: | ||
| 1993 | |||
| 1994 | [m11 m12 tx] [x] [m11*x+m12*y+tx*1] [x'] | ||
| 1995 | [m21 m22 ty] X [y] = [m21*x+m22*y+ty*1] = [y'] | ||
| 1996 | [ 0 0 1] [1] [ 0*x+0*y+1*1] [ 1] | ||
| 1997 | |||
| 1998 | We don’t have to worry about the last step as the graphics toolkit | ||
| 1999 | will do it for us. | ||
| 2000 | |||
| 2001 | The three transforms we are concerned with are translation, scaling | ||
| 2002 | and rotation. The translation matrix looks like this: | ||
| 2003 | |||
| 2004 | [1 0 tx] | ||
| 2005 | [0 1 ty] | ||
| 2006 | [0 0 1] | ||
| 2007 | |||
| 2008 | Where tx and ty are the amount to translate the origin in the x and | ||
| 2009 | y coordinates, respectively. Since we are translating the origin | ||
| 2010 | and not the image data itself, it can appear backwards in use, for | ||
| 2011 | example to move the image 10 pixels to the right, you would set tx | ||
| 2012 | to -10. | ||
| 2013 | |||
| 2014 | To scale we use: | ||
| 2015 | |||
| 2016 | [x 0 0] | ||
| 2017 | [0 y 0] | ||
| 2018 | [0 0 1] | ||
| 2019 | |||
| 2020 | Where x and y are the amounts to scale in the x and y dimensions. | ||
| 2021 | Values smaller than 1 make the image larger, values larger than 1 | ||
| 2022 | make it smaller. Negative values flip the image. For example to | ||
| 2023 | double the image size set x and y to 0.5. | ||
| 2024 | |||
| 2025 | To rotate we use: | ||
| 2026 | |||
| 2027 | [ cos(r) sin(r) 0] | ||
| 2028 | [-sin(r) cos(r) 0] | ||
| 2029 | [ 0 0 1] | ||
| 2030 | |||
| 2031 | Where r is the angle of rotation required. Rotation occurs around | ||
| 2032 | the origin, not the centre of the image. Note that this is | ||
| 2033 | normally considered a counter-clockwise rotation, however because | ||
| 2034 | our y axis is reversed, (0, 0) at the top left, it works as a | ||
| 2035 | clockwise rotation. | ||
| 2036 | |||
| 2037 | The full process of rotating an image is to move the origin to the | ||
| 2038 | centre of the image (width/2, height/2), perform the rotation, and | ||
| 2039 | finally move the origin back to the top left of the image, which | ||
| 2040 | may now be a different corner. | ||
| 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 | |||
| 2046 | It's possible to pre-calculate the matrix multiplications and just | ||
| 2047 | 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 | ||
| 2049 | and I thought it was better to perform the steps separately. */ | ||
| 2050 | |||
| 1970 | typedef double matrix3x3[3][3]; | 2051 | typedef double matrix3x3[3][3]; |
| 1971 | 2052 | ||
| 1972 | static void | 2053 | static void |