1
/** ===========================================================
4
* This file is a part of digiKam project
5
* <a href="http://www.digikam.org">http://www.digikam.org</a>
8
* @brief Tools for combining rotation operations
10
* @author Copyright (C) 2006-2011 by Gilles Caulier
11
* <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a>
12
* @author Copyright (C) 2004-2011 by Marcel Wiesweg
13
* <a href="mailto:marcel dot wiesweg at gmx dot de">marcel dot wiesweg at gmx dot de</a>
15
* This program is free software; you can redistribute it
16
* and/or modify it under the terms of the GNU General
17
* Public License as published by the Free Software Foundation;
18
* either version 2, or (at your option)
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU General Public License for more details.
26
* ============================================================ */
28
#include "rotationmatrix.h"
42
If the picture is displayed according to the exif orientation tag,
43
the user will request rotating operations relative to what he sees,
44
and that is the picture rotated according to the EXIF tag.
45
So the operation requested and the given EXIF angle must be combined.
46
E.g. if orientation is "6" (rotate 90 clockwiseto show correctly)
47
and the user selects 180 clockwise, the operation is 270.
48
If the user selected 270, the operation would be None (and clearing the exif tag).
50
This requires to describe the transformations in a model which
51
cares for both composing (180+90=270) and eliminating (180+180=no action),
52
as well as the non-commutative nature of the operations (vflip+90 is not 90+vflip)
54
All 2D transformations can be described by a 2x3 matrix, see QWRotationMatrix.
55
All transformations needed here - rotate 90, 180, 270, flipV, flipH -
56
can be described in a 2x2 matrix with the values 0,1,-1
57
(because flipping is expressed by changing the sign only,
58
and sine and cosine of 90, 180 and 270 are either 0,1 or -1).
63
Moreover, all combinations of these rotate/flip operations result in one of the eight
64
matrices defined below.
65
(I did not proof that mathematically, but empirically)
67
static const RotationMatrix identity; //( 1, 0, 0, 1)
68
static const RotationMatrix rotate90; //( 0, -1, 1, 0)
69
static const RotationMatrix rotate180; //(-1, 0, 0, -1)
70
static const RotationMatrix rotate270; //( 0, 1, -1, 0)
71
static const RotationMatrix flipHorizontal; //(-1, 0, 0, 1)
72
static const RotationMatrix flipVertical; //( 1, 0, 0, -1)
73
static const RotationMatrix rotate90flipHorizontal; //( 0, 1, 1, 0), first rotate, then flip
74
static const RotationMatrix rotate90flipVertical; //( 0, -1, -1, 0), first rotate, then flip
81
static const RotationMatrix identity ( 1, 0, 0, 1);
82
static const RotationMatrix rotate90 ( 0, -1, 1, 0);
83
static const RotationMatrix rotate180 (-1, 0, 0, -1);
84
static const RotationMatrix rotate270 ( 0, 1, -1, 0);
85
static const RotationMatrix flipHorizontal (-1, 0, 0, 1);
86
static const RotationMatrix flipVertical ( 1, 0, 0, -1);
87
static const RotationMatrix rotate90flipHorizontal ( 0, 1, 1, 0);
88
static const RotationMatrix rotate90flipVertical ( 0, -1, -1, 0);
90
RotationMatrix matrix(RotationMatrix::TransformationAction action)
94
case RotationMatrix::NoTransformation:
96
case RotationMatrix::FlipHorizontal:
97
return flipHorizontal;
98
case RotationMatrix::FlipVertical:
100
case RotationMatrix::Rotate90:
102
case RotationMatrix::Rotate180:
104
case RotationMatrix::Rotate270:
110
RotationMatrix matrix(KExiv2::ImageOrientation exifOrientation)
112
switch (exifOrientation)
114
case KExiv2::ORIENTATION_NORMAL:
116
case KExiv2::ORIENTATION_HFLIP:
117
return flipHorizontal;
118
case KExiv2::ORIENTATION_ROT_180:
120
case KExiv2::ORIENTATION_VFLIP:
122
case KExiv2::ORIENTATION_ROT_90_HFLIP:
123
return rotate90flipHorizontal;
124
case KExiv2::ORIENTATION_ROT_90:
126
case KExiv2::ORIENTATION_ROT_90_VFLIP:
127
return rotate90flipVertical;
128
case KExiv2::ORIENTATION_ROT_270:
130
case KExiv2::ORIENTATION_UNSPECIFIED:
137
} // namespace Matrix
139
RotationMatrix::RotationMatrix()
144
RotationMatrix::RotationMatrix(TransformationAction action)
146
*this = Matrix::matrix(action);
149
RotationMatrix::RotationMatrix(KExiv2::ImageOrientation exifOrientation)
151
*this = Matrix::matrix(exifOrientation);
154
RotationMatrix::RotationMatrix(int m11, int m12, int m21, int m22)
156
set(m11, m12, m21, m22);
159
void RotationMatrix::set(int m11, int m12, int m21, int m22)
167
bool RotationMatrix::isNoTransform() const
169
return *this == Matrix::identity;
172
RotationMatrix& RotationMatrix::operator*=(const RotationMatrix& ma)
174
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],
175
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] );
179
bool RotationMatrix::operator==(const RotationMatrix& ma) const
181
return m[0][0]==ma.m[0][0] &&
182
m[0][1]==ma.m[0][1] &&
183
m[1][0]==ma.m[1][0] &&
187
bool RotationMatrix::operator!=(const RotationMatrix& ma) const
192
RotationMatrix& RotationMatrix::operator*=(TransformationAction action)
194
return (*this *= Matrix::matrix(action));
197
RotationMatrix& RotationMatrix::operator*=(QList<TransformationAction> actions)
199
foreach (const TransformationAction& action, actions)
201
*this *= Matrix::matrix(action);
207
RotationMatrix& RotationMatrix::operator*=(KExiv2::ImageOrientation exifOrientation)
209
return (*this *= Matrix::matrix(exifOrientation));
212
/** Converts the mathematically correct description
213
into the primitive operations that can be carried out losslessly.
215
QList<RotationMatrix::TransformationAction> RotationMatrix::transformations() const
217
QList<TransformationAction> transforms;
219
if (*this == Matrix::rotate90)
221
transforms << Rotate90;
223
else if (*this == Matrix::rotate180)
225
transforms << Rotate180;
227
else if (*this == Matrix::rotate270)
229
transforms << Rotate270;
231
else if (*this == Matrix::flipHorizontal)
233
transforms << FlipHorizontal;
235
else if (*this == Matrix::flipVertical)
237
transforms << FlipVertical;
239
else if (*this == Matrix::rotate90flipHorizontal)
241
//first rotate, then flip!
242
transforms << Rotate90;
243
transforms << FlipHorizontal;
245
else if (*this == Matrix::rotate90flipVertical)
247
//first rotate, then flip!
248
transforms << Rotate90;
249
transforms << FlipVertical;
254
KExiv2::ImageOrientation RotationMatrix::exifOrientation() const
256
if (*this == Matrix::identity)
258
return KExiv2::ORIENTATION_NORMAL;
260
if (*this == Matrix::rotate90)
262
return KExiv2::ORIENTATION_ROT_90;
264
else if (*this == Matrix::rotate180)
266
return KExiv2::ORIENTATION_ROT_180;
268
else if (*this == Matrix::rotate270)
270
return KExiv2::ORIENTATION_ROT_270;
272
else if (*this == Matrix::flipHorizontal)
274
return KExiv2::ORIENTATION_HFLIP;
276
else if (*this == Matrix::flipVertical)
278
return KExiv2::ORIENTATION_VFLIP;
280
else if (*this == Matrix::rotate90flipHorizontal)
282
return KExiv2::ORIENTATION_ROT_90_HFLIP;
284
else if (*this == Matrix::rotate90flipVertical)
286
return KExiv2::ORIENTATION_ROT_90_VFLIP;
288
return KExiv2::ORIENTATION_UNSPECIFIED;
291
QMatrix RotationMatrix::toMatrix() const
293
return toMatrix(exifOrientation());
296
QMatrix RotationMatrix::toMatrix(KExiv2::ImageOrientation orientation)
302
case KExiv2::ORIENTATION_NORMAL:
303
case KExiv2::ORIENTATION_UNSPECIFIED:
306
case KExiv2::ORIENTATION_HFLIP:
310
case KExiv2::ORIENTATION_ROT_180:
314
case KExiv2::ORIENTATION_VFLIP:
318
case KExiv2::ORIENTATION_ROT_90_HFLIP:
323
case KExiv2::ORIENTATION_ROT_90:
327
case KExiv2::ORIENTATION_ROT_90_VFLIP:
332
case KExiv2::ORIENTATION_ROT_270:
340
} // namespace KExiv2Iface