diff options
Diffstat (limited to 'src/gui/image/qjpeghandler.cpp')
-rw-r--r-- | src/gui/image/qjpeghandler.cpp | 122 |
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; } |