summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorTomaž Vajngerl <quikee@gmail.com>2013-04-21 14:08:42 +0200
committerTomaž Vajngerl <quikee@gmail.com>2013-04-21 21:55:47 +0200
commit4f3bc8cf69bedb831d81d716274427191319fef0 (patch)
treeca6ddf3a7f60cb1b127a04a515648e9de37b6398 /vcl
parentdf155415d8f46d884ba18e370e8028d020ba6f3b (diff)
More correct reading of Exif metadata.
Change-Id: Id9e7754cfcbd1d7e8b512eb1c1a3384df2db149f
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/filter/jpeg/Exif.cxx118
-rw-r--r--vcl/source/filter/jpeg/Exif.hxx22
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();