diff options
author | Tomaž Vajngerl <quikee@gmail.com> | 2013-04-21 14:08:42 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2013-04-21 21:55:47 +0200 |
commit | 4f3bc8cf69bedb831d81d716274427191319fef0 (patch) | |
tree | ca6ddf3a7f60cb1b127a04a515648e9de37b6398 /vcl | |
parent | df155415d8f46d884ba18e370e8028d020ba6f3b (diff) |
More correct reading of Exif metadata.
Change-Id: Id9e7754cfcbd1d7e8b512eb1c1a3384df2db149f
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/source/filter/jpeg/Exif.cxx | 118 | ||||
-rw-r--r-- | vcl/source/filter/jpeg/Exif.hxx | 22 |
2 files changed, 107 insertions, 33 deletions
diff --git a/vcl/source/filter/jpeg/Exif.cxx b/vcl/source/filter/jpeg/Exif.cxx index f0b1970d175f..be054dc6076a 100644 --- a/vcl/source/filter/jpeg/Exif.cxx +++ b/vcl/source/filter/jpeg/Exif.cxx @@ -20,7 +20,8 @@ #include "Exif.hxx" Exif::Exif() : - maOrientation(TOP_LEFT) + maOrientation(TOP_LEFT), + mbExifPresent(false) {} Exif::~Exif() @@ -66,10 +67,15 @@ sal_Int32 Exif::getRotation() return 0; } +bool Exif::hasExif() +{ + return mbExifPresent; +} + bool Exif::read(SvStream& rStream) { sal_Int32 nStreamPosition = rStream.Tell(); - bool result = processJpegStream(rStream, false); + bool result = processJpeg(rStream, false); rStream.Seek( nStreamPosition ); return result; @@ -78,33 +84,81 @@ bool Exif::read(SvStream& rStream) bool Exif::write(SvStream& rStream) { sal_Int32 nStreamPosition = rStream.Tell(); - bool result = processJpegStream(rStream, true); + bool result = processJpeg(rStream, true); rStream.Seek( nStreamPosition ); return result; } -bool Exif::processJpegStream(SvStream& rStream, bool bSetValue) +bool Exif::processJpeg(SvStream& rStream, bool bSetValue) { - sal_uInt32 aMagic32; sal_uInt16 aMagic16; + sal_uInt8 aMarker; sal_uInt16 aLength; + rStream.Seek(STREAM_SEEK_TO_END); + sal_uInt32 aSize = rStream.Tell(); + rStream.Seek(STREAM_SEEK_TO_BEGIN); + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); - rStream >> aMagic32; + rStream >> aMagic16; // Compare JPEG magic bytes - if( 0xffd8ff00 != ( aMagic32 & 0xffffff00 ) ) + if( 0xFFD8 != aMagic16 ) { return false; } - rStream >> aLength; - if (aLength < 8) + sal_uInt32 aPreviousPosition = STREAM_SEEK_TO_BEGIN; + + while(true) { - return false; + sal_Int32 aCount; + for (aCount = 0; aCount < 7; aCount++) + { + rStream >> aMarker; + if (aMarker != 0xFF) + { + break; + } + if (aCount >= 6) + { + return false; + } + } + + rStream >> aLength; + + if (aLength < 8) + { + return false; + } + + if (aMarker == 0xE1) + { + return processExif(rStream, aLength, bSetValue); + } + else if (aMarker == 0xD9) + { + return false; + } + else + { + sal_uInt32 aCurrentPosition = rStream.SeekRel(aLength-1); + if (aCurrentPosition == aPreviousPosition || aCurrentPosition > aSize) + { + return false; + } + aPreviousPosition = aCurrentPosition; + } } - aLength -= 8; + return false; +} + +bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue) +{ + sal_uInt32 aMagic32; + sal_uInt16 aMagic16; rStream >> aMagic32; rStream >> aMagic16; @@ -115,26 +169,36 @@ bool Exif::processJpegStream(SvStream& rStream, bool bSetValue) return false; } - sal_uInt8* exifData = new sal_uInt8[aLength]; + sal_uInt16 aLength = aSectionLength - 6; // Length = Section - Header + + sal_uInt8* aExifData = new sal_uInt8[aLength]; sal_uInt32 aExifDataBeginPosition = rStream.Tell(); - rStream.Read(exifData, aLength); - sal_uInt16 offset; - offset = exifData[5]; - offset <<= 8; - offset += exifData[4]; + rStream.Read(aExifData, aLength); + + // Exif detected + mbExifPresent = true; + + TiffHeader* aTiffHeader = (TiffHeader*) &aExifData[0]; + + if( 0x4949 != aTiffHeader->byteOrder || 0x002A != aTiffHeader->tagAlign ) + { + return false; + } + + sal_uInt16 aOffset = aTiffHeader->offset; - sal_uInt16 numberOfTags; - numberOfTags = exifData[offset+1]; - numberOfTags <<= 8; - numberOfTags += exifData[offset]; + sal_uInt16 aNumberOfTags = aExifData[aOffset]; + aNumberOfTags = aExifData[aOffset + 1]; + aNumberOfTags <<= 8; + aNumberOfTags += aExifData[aOffset]; - offset += 2; + aOffset += 2; ExifIFD* ifd = NULL; - while (offset <= aLength - 12 && numberOfTags > 0) { - ifd = (ExifIFD*) &exifData[offset]; + while (aOffset <= aLength - 12 && aNumberOfTags > 0) { + ifd = (ExifIFD*) &aExifData[aOffset]; if (ifd->tag == Tag::ORIENTATION) { @@ -151,14 +215,14 @@ bool Exif::processJpegStream(SvStream& rStream, bool bSetValue) } } - numberOfTags--; - offset += 12; + aNumberOfTags--; + aOffset += 12; } if (bSetValue) { rStream.Seek(aExifDataBeginPosition); - rStream.Write(exifData, aLength); + rStream.Write(aExifData, aLength); } return true; diff --git a/vcl/source/filter/jpeg/Exif.hxx b/vcl/source/filter/jpeg/Exif.hxx index cce6a63cfb96..eea8ada97534 100644 --- a/vcl/source/filter/jpeg/Exif.hxx +++ b/vcl/source/filter/jpeg/Exif.hxx @@ -38,11 +38,11 @@ enum Orientation { }; enum Tag { - IMAGE_WIDTH = 0x0100, - IMAGE_HEIGHT = 0x0101, - BITS_PER_SAMPLE = 0x0102, - COMPRESSION = 0x0103, - ORIENTATION = 0x0112 + ORIENTATION = 0x0112, + X_RESOLUTION = 0x011a, + Y_RESOLUTION = 0x011b, + EXIF_OFFSET = 0x8769, + INTEROP_OFFSET = 0xa005 }; class Exif @@ -50,8 +50,10 @@ class Exif private: Orientation maOrientation; sal_Int32 mnStreamPosition; + bool mbExifPresent; - bool processJpegStream(SvStream& rStream, bool bSetValue); + bool processJpeg(SvStream& rStream, bool bSetValue); + bool processExif(SvStream& rStream, sal_uInt16 aLength, bool bSetValue); struct ExifIFD { sal_uInt16 tag; @@ -60,12 +62,20 @@ private: sal_uInt32 offset; }; + struct TiffHeader { + sal_uInt16 byteOrder; + sal_uInt16 tagAlign; + sal_uInt32 offset; + }; + Orientation convertToOrientation(sal_Int32 value); public : Exif(); virtual ~Exif(); + bool hasExif(); + Orientation getOrientation(); sal_Int32 getRotation(); |