KExiv2

rotationmatrix.cpp
1 /*
2  SPDX-FileCopyrightText: 2006-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
3  SPDX-FileCopyrightText: 2004-2012 Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
4 
5  SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 // Local includes
9 
10 #include "rotationmatrix.h"
11 
12 namespace KExiv2Iface
13 {
14 
15 /**
16  If the picture is displayed according to the exif orientation tag,
17  the user will request rotating operations relative to what he sees,
18  and that is the picture rotated according to the EXIF tag.
19  So the operation requested and the given EXIF angle must be combined.
20  E.g. if orientation is "6" (rotate 90 clockwiseto show correctly)
21  and the user selects 180 clockwise, the operation is 270.
22  If the user selected 270, the operation would be None (and clearing the exif tag).
23 
24  This requires to describe the transformations in a model which
25  cares for both composing (180+90=270) and eliminating (180+180=no action),
26  as well as the non-commutative nature of the operations (vflip+90 is not 90+vflip)
27 
28  All 2D transformations can be described by a 2x3 matrix, see QWRotationMatrix.
29  All transformations needed here - rotate 90, 180, 270, flipV, flipH -
30  can be described in a 2x2 matrix with the values 0,1,-1
31  (because flipping is expressed by changing the sign only,
32  and sine and cosine of 90, 180 and 270 are either 0,1 or -1).
33 
34  x' = m11 x + m12 y
35  y' = m21 x + m22 y
36 
37  Moreover, all combinations of these rotate/flip operations result in one of the eight
38  matrices defined below.
39  (I did not proof that mathematically, but empirically)
40 
41  static const RotationMatrix identity; //( 1, 0, 0, 1)
42  static const RotationMatrix rotate90; //( 0, 1, -1, 0)
43  static const RotationMatrix rotate180; //(-1, 0, 0, -1)
44  static const RotationMatrix rotate270; //( 0, -1, 1, 0)
45  static const RotationMatrix flipHorizontal; //(-1, 0, 0, 1)
46  static const RotationMatrix flipVertical; //( 1, 0, 0, -1)
47  static const RotationMatrix rotate90flipHorizontal; //( 0, 1, 1, 0), first rotate, then flip
48  static const RotationMatrix rotate90flipVertical; //( 0, -1, -1, 0), first rotate, then flip
49 
50 */
51 
52 namespace Matrix
53 {
54 
55 static const RotationMatrix identity ( 1, 0, 0, 1);
56 static const RotationMatrix rotate90 ( 0, 1, -1, 0);
57 static const RotationMatrix rotate180 (-1, 0, 0, -1);
58 static const RotationMatrix rotate270 ( 0, -1, 1, 0);
59 static const RotationMatrix flipHorizontal (-1, 0, 0, 1);
60 static const RotationMatrix flipVertical ( 1, 0, 0, -1);
61 static const RotationMatrix rotate90flipHorizontal ( 0, 1, 1, 0);
62 static const RotationMatrix rotate90flipVertical ( 0, -1, -1, 0);
63 
65 {
66  switch (action)
67  {
68  case RotationMatrix::NoTransformation:
69  return identity;
71  return flipHorizontal;
73  return flipVertical;
75  return rotate90;
77  return rotate180;
79  return rotate270;
80  }
81 
82  return identity;
83 }
84 
85 RotationMatrix matrix(KExiv2::ImageOrientation exifOrientation)
86 {
87  switch (exifOrientation)
88  {
89  case KExiv2::ORIENTATION_NORMAL:
90  return identity;
91  case KExiv2::ORIENTATION_HFLIP:
92  return flipHorizontal;
93  case KExiv2::ORIENTATION_ROT_180:
94  return rotate180;
95  case KExiv2::ORIENTATION_VFLIP:
96  return flipVertical;
97  case KExiv2::ORIENTATION_ROT_90_HFLIP:
98  return rotate90flipHorizontal;
99  case KExiv2::ORIENTATION_ROT_90:
100  return rotate90;
101  case KExiv2::ORIENTATION_ROT_90_VFLIP:
102  return rotate90flipVertical;
103  case KExiv2::ORIENTATION_ROT_270:
104  return rotate270;
105  case KExiv2::ORIENTATION_UNSPECIFIED:
106  return identity;
107  }
108 
109  return identity;
110 }
111 
112 } // namespace Matrix
113 
115 {
116  set( 1, 0, 0, 1 );
117 }
118 
120 {
121  *this = Matrix::matrix(action);
122 }
123 
125 {
126  *this = Matrix::matrix(exifOrientation);
127 }
128 
129 RotationMatrix::RotationMatrix(int m11, int m12, int m21, int m22)
130 {
131  set(m11, m12, m21, m22);
132 }
133 
134 void RotationMatrix::set(int m11, int m12, int m21, int m22)
135 {
136  m[0][0]=m11;
137  m[0][1]=m12;
138  m[1][0]=m21;
139  m[1][1]=m22;
140 }
141 
143 {
144  return (*this == Matrix::identity);
145 }
146 
147 RotationMatrix& RotationMatrix::operator*=(const RotationMatrix& ma)
148 {
149  set( ma.m[0][0]*m[0][0] + ma.m[0][1]*m[1][0], ma.m[0][0]*m[0][1] + ma.m[0][1]*m[1][1],
150  ma.m[1][0]*m[0][0] + ma.m[1][1]*m[1][0], ma.m[1][0]*m[0][1] + ma.m[1][1]*m[1][1] );
151 
152  return *this;
153 }
154 
155 bool RotationMatrix::operator==(const RotationMatrix& ma) const
156 {
157  return m[0][0]==ma.m[0][0] &&
158  m[0][1]==ma.m[0][1] &&
159  m[1][0]==ma.m[1][0] &&
160  m[1][1]==ma.m[1][1];
161 }
162 
163 bool RotationMatrix::operator!=(const RotationMatrix& ma) const
164 {
165  return !(*this==ma);
166 }
167 
168 RotationMatrix& RotationMatrix::operator*=(TransformationAction action)
169 {
170  return (*this *= Matrix::matrix(action));
171 }
172 
173 RotationMatrix& RotationMatrix::operator*=(QList<TransformationAction> actions)
174 {
175  for (const TransformationAction& action : qAsConst(actions))
176  {
177  *this *= Matrix::matrix(action);
178  }
179 
180  return *this;
181 }
182 
183 RotationMatrix& RotationMatrix::operator*=(KExiv2::ImageOrientation exifOrientation)
184 {
185  return (*this *= Matrix::matrix(exifOrientation));
186 }
187 
188 /** Converts the mathematically correct description
189  into the primitive operations that can be carried out losslessly.
190 */
192 {
193  QList<TransformationAction> transforms;
194 
195  if (*this == Matrix::rotate90)
196  {
197  transforms << Rotate90;
198  }
199  else if (*this == Matrix::rotate180)
200  {
201  transforms << Rotate180;
202  }
203  else if (*this == Matrix::rotate270)
204  {
205  transforms << Rotate270;
206  }
207  else if (*this == Matrix::flipHorizontal)
208  {
209  transforms << FlipHorizontal;
210  }
211  else if (*this == Matrix::flipVertical)
212  {
213  transforms << FlipVertical;
214  }
215  else if (*this == Matrix::rotate90flipHorizontal)
216  {
217  //first rotate, then flip!
218  transforms << Rotate90;
219  transforms << FlipHorizontal;
220  }
221  else if (*this == Matrix::rotate90flipVertical)
222  {
223  //first rotate, then flip!
224  transforms << Rotate90;
225  transforms << FlipVertical;
226  }
227 
228  return transforms;
229 }
230 
232 {
233  if (*this == Matrix::identity)
234  {
235  return KExiv2::ORIENTATION_NORMAL;
236  }
237 
238  if (*this == Matrix::rotate90)
239  {
240  return KExiv2::ORIENTATION_ROT_90;
241  }
242  else if (*this == Matrix::rotate180)
243  {
244  return KExiv2::ORIENTATION_ROT_180;
245  }
246  else if (*this == Matrix::rotate270)
247  {
248  return KExiv2::ORIENTATION_ROT_270;
249  }
250  else if (*this == Matrix::flipHorizontal)
251  {
252  return KExiv2::ORIENTATION_HFLIP;
253  }
254  else if (*this == Matrix::flipVertical)
255  {
256  return KExiv2::ORIENTATION_VFLIP;
257  }
258  else if (*this == Matrix::rotate90flipHorizontal)
259  {
260  return KExiv2::ORIENTATION_ROT_90_HFLIP;
261  }
262  else if (*this == Matrix::rotate90flipVertical)
263  {
264  return KExiv2::ORIENTATION_ROT_90_VFLIP;
265  }
266 
267  return KExiv2::ORIENTATION_UNSPECIFIED;
268 }
269 
271 {
272  return toMatrix(exifOrientation());
273 }
274 
276 {
277  QMatrix matrix;
278 
279  switch (orientation)
280  {
281  case KExiv2::ORIENTATION_NORMAL:
282  case KExiv2::ORIENTATION_UNSPECIFIED:
283  break;
284 
285  case KExiv2::ORIENTATION_HFLIP:
286  matrix.scale(-1, 1);
287  break;
288 
289  case KExiv2::ORIENTATION_ROT_180:
290  matrix.rotate(180);
291  break;
292 
293  case KExiv2::ORIENTATION_VFLIP:
294  matrix.scale(1, -1);
295  break;
296 
297  case KExiv2::ORIENTATION_ROT_90_HFLIP:
298  matrix.scale(-1, 1);
299  matrix.rotate(90);
300  break;
301 
302  case KExiv2::ORIENTATION_ROT_90:
303  matrix.rotate(90);
304  break;
305 
306  case KExiv2::ORIENTATION_ROT_90_VFLIP:
307  matrix.scale(1, -1);
308  matrix.rotate(90);
309  break;
310 
311  case KExiv2::ORIENTATION_ROT_270:
312  matrix.rotate(270);
313  break;
314  }
315 
316  return matrix;
317 }
318 
319 } // namespace KExiv2Iface
KExiv2Iface - Exiv2 library interface.
Definition: kexiv2.cpp:16
ImageOrientation
The image orientation values given by Exif metadata.
Definition: kexiv2.h:86
KExiv2::ImageOrientation exifOrientation() const
Returns the Exif orienation flag describing this matrix.
90-degree clockwise rotation
TransformationAction
This describes single transform primitives.
QMatrix & rotate(qreal degrees)
QList< TransformationAction > transformations() const
Returns the actions described by this matrix.
bool isNoTransform() const
Returns true of this matrix describes no transformation (is the identity matrix)
RotationMatrix()
Constructs the identity matrix (the matrix describing no transformation)
QMatrix toMatrix() const
Returns a QMatrix representing this matrix.
QMatrix & scale(qreal sx, qreal sy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Dec 6 2021 22:32:32 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.