summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qjpeghandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image/qjpeghandler.cpp')
-rw-r--r--src/gui/image/qjpeghandler.cpp122
1 files changed, 61 insertions, 61 deletions
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
index 839f90f17c..4ff3917fe6 100644
--- a/src/gui/image/qjpeghandler.cpp
+++ b/src/gui/image/qjpeghandler.cpp
@@ -714,7 +714,7 @@ public:
};
QJpegHandlerPrivate(QJpegHandler *qq)
- : quality(75), exifOrientation(1), iod_src(0),
+ : quality(75), transformation(QImageIOHandler::TransformationNone), iod_src(0),
rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq)
{}
@@ -730,10 +730,9 @@ public:
bool readJpegHeader(QIODevice*);
bool read(QImage *image);
- void applyExifOrientation(QImage *image);
int quality;
- int exifOrientation;
+ QImageIOHandler::Transformations transformation;
QVariant size;
QImage::Format format;
QSize scaledSize;
@@ -761,9 +760,8 @@ static bool readExifHeader(QDataStream &stream)
char prefix[6];
if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix))
return false;
- if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0)
- return false;
- return true;
+ static const char exifMagic[6] = {'E', 'x', 'i', 'f', 0, 0};
+ return memcmp(prefix, exifMagic, 6) == 0;
}
/*
@@ -787,6 +785,7 @@ static int getExifOrientation(QByteArray &exifData)
quint16 val;
quint32 offset;
+ const qint64 headerStart = stream.device()->pos();
// read byte order marker
stream >> val;
@@ -803,20 +802,20 @@ static int getExifOrientation(QByteArray &exifData)
return -1;
stream >> offset;
- // we have already used 8 bytes of TIFF header
- offset -= 8;
// read IFD
while (!stream.atEnd()) {
quint16 numEntries;
// skip offset bytes to get the next IFD
- if (stream.skipRawData(offset) != (qint32)offset)
+ const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart);
+
+ if (stream.skipRawData(bytesToSkip) != bytesToSkip)
return -1;
stream >> numEntries;
- for (;numEntries > 0; --numEntries) {
+ for (; numEntries > 0; --numEntries) {
quint16 tag;
quint16 type;
quint32 components;
@@ -825,7 +824,7 @@ static int getExifOrientation(QByteArray &exifData)
stream >> tag >> type >> components >> value >> dummy;
if (tag == 0x0112) { // Tag Exif.Image.Orientation
- if (components !=1)
+ if (components != 1)
return -1;
if (type != 3) // we are expecting it to be an unsigned short
return -1;
@@ -847,6 +846,31 @@ static int getExifOrientation(QByteArray &exifData)
// No Exif orientation was found
return 0;
}
+
+static QImageIOHandler::Transformations exif2Qt(int exifOrientation)
+{
+ switch (exifOrientation) {
+ case 1: // normal
+ return QImageIOHandler::TransformationNone;
+ case 2: // mirror horizontal
+ return QImageIOHandler::TransformationMirror;
+ case 3: // rotate 180
+ return QImageIOHandler::TransformationRotate180;
+ case 4: // mirror vertical
+ return QImageIOHandler::TransformationFlip;
+ case 5: // mirror horizontal and rotate 270 CW
+ return QImageIOHandler::TransformationFlipAndRotate90;
+ case 6: // rotate 90 CW
+ return QImageIOHandler::TransformationRotate90;
+ case 7: // mirror horizontal and rotate 90 CW
+ return QImageIOHandler::TransformationMirrorAndRotate90;
+ case 8: // rotate 270 CW
+ return QImageIOHandler::TransformationRotate270;
+ }
+ qWarning("Invalid EXIF orientation");
+ return QImageIOHandler::TransformationNone;
+}
+
/*!
\internal
*/
@@ -866,7 +890,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
if (!setjmp(err.setjmp_buffer)) {
jpeg_save_markers(&info, JPEG_COM, 0xFFFF);
- jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker
+ jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker
(void) jpeg_read_header(&info, TRUE);
@@ -897,16 +921,18 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
description += key + QLatin1String(": ") + value.simplified();
readTexts.append(key);
readTexts.append(value);
- } else if (marker->marker == JPEG_APP0+1) {
+ } else if (marker->marker == JPEG_APP0 + 1) {
exifData.append((const char*)marker->data, marker->data_length);
}
}
- if (exifData.size()) {
+ if (!exifData.isEmpty()) {
// Exif data present
- int orientation = getExifOrientation(exifData);
- if (orientation > 0)
- exifOrientation = orientation;
+ int exifOrientation = getExifOrientation(exifData);
+ if (exifOrientation == -1)
+ return false;
+ if (exifOrientation > 0)
+ transformation = exif2Qt(exifOrientation);
}
state = ReadHeader;
@@ -922,48 +948,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
return true;
}
-void QJpegHandlerPrivate::applyExifOrientation(QImage *image)
-{
- // This is not an optimized implementation, but easiest to maintain
- QTransform transform;
-
- switch (exifOrientation) {
- case 1: // normal
- break;
- case 2: // mirror horizontal
- *image = image->mirrored(true, false);
- break;
- case 3: // rotate 180
- transform.rotate(180);
- *image = image->transformed(transform);
- break;
- case 4: // mirror vertical
- *image = image->mirrored(false, true);
- break;
- case 5: // mirror horizontal and rotate 270 CCW
- *image = image->mirrored(true, false);
- transform.rotate(270);
- *image = image->transformed(transform);
- break;
- case 6: // rotate 90 CW
- transform.rotate(90);
- *image = image->transformed(transform);
- break;
- case 7: // mirror horizontal and rotate 90 CW
- *image = image->mirrored(true, false);
- transform.rotate(90);
- *image = image->transformed(transform);
- break;
- case 8: // rotate 270 CW
- transform.rotate(-90);
- *image = image->transformed(transform);
- break;
- default:
- qWarning("This should never happen");
- }
- exifOrientation = 1;
-}
-
bool QJpegHandlerPrivate::read(QImage *image)
{
if(state == Ready)
@@ -975,7 +959,6 @@ bool QJpegHandlerPrivate::read(QImage *image)
if (success) {
for (int i = 0; i < readTexts.size()-1; i+=2)
image->setText(readTexts.at(i), readTexts.at(i+1));
- applyExifOrientation(image);
state = Ready;
return true;
@@ -1053,8 +1036,16 @@ bool QJpegHandler::read(QImage *image)
return d->read(image);
}
+extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient);
+
bool QJpegHandler::write(const QImage &image)
{
+ if (d->transformation != QImageIOHandler::TransformationNone) {
+ // We don't support writing EXIF headers so apply the transform to the data.
+ QImage img = image;
+ qt_imageTransform(img, d->transformation);
+ return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
+ }
return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
}
@@ -1068,7 +1059,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const
|| option == Size
|| option == ImageFormat
|| option == OptimizedWrite
- || option == ProgressiveScanWrite;
+ || option == ProgressiveScanWrite
+ || option == ImageTransformation;
}
QVariant QJpegHandler::option(ImageOption option) const
@@ -1095,6 +1087,9 @@ QVariant QJpegHandler::option(ImageOption option) const
return d->optimize;
case ProgressiveScanWrite:
return d->progressive;
+ case ImageTransformation:
+ d->readJpegHeader(device());
+ return int(d->transformation);
default:
break;
}
@@ -1126,6 +1121,11 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
case ProgressiveScanWrite:
d->progressive = value.toBool();
break;
+ case ImageTransformation: {
+ int transformation = value.toInt();
+ if (transformation > 0 && transformation < 8)
+ d->transformation = QImageIOHandler::Transformations(transformation);
+ }
default:
break;
}