update credits
[LibreOffice.git] / vcl / source / filter / jpeg / Exif.cxx
blobcf64f9b1e2099a2286fb9869c6815e799ee8dc28
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "Exif.hxx"
22 Exif::Exif() :
23 maOrientation(TOP_LEFT),
24 mbExifPresent(false)
27 Exif::~Exif()
30 Orientation Exif::getOrientation() {
31 return maOrientation;
34 void Exif::setOrientation(Orientation aOrientation) {
35 maOrientation = aOrientation;
38 Orientation Exif::convertToOrientation(sal_Int32 value)
40 switch(value) {
41 case 1: return TOP_LEFT;
42 case 2: return TOP_RIGHT;
43 case 3: return BOTTOM_RIGHT;
44 case 4: return BOTTOM_LEFT;
45 case 5: return LEFT_TOP;
46 case 6: return RIGHT_TOP;
47 case 7: return RIGHT_BOTTOM;
48 case 8: return LEFT_BOTTOM;
50 return TOP_LEFT;
53 sal_Int32 Exif::getRotation()
55 switch(maOrientation) {
56 case TOP_LEFT:
57 return 0;
58 case BOTTOM_RIGHT:
59 return 1800;
60 case RIGHT_TOP:
61 return 2700;
62 case LEFT_BOTTOM:
63 return 900;
64 default:
65 break;
67 return 0;
70 bool Exif::hasExif()
72 return mbExifPresent;
75 bool Exif::read(SvStream& rStream)
77 sal_Int32 nStreamPosition = rStream.Tell();
78 bool result = processJpeg(rStream, false);
79 rStream.Seek( nStreamPosition );
81 return result;
84 bool Exif::write(SvStream& rStream)
86 sal_Int32 nStreamPosition = rStream.Tell();
87 bool result = processJpeg(rStream, true);
88 rStream.Seek( nStreamPosition );
90 return result;
93 bool Exif::processJpeg(SvStream& rStream, bool bSetValue)
95 sal_uInt16 aMagic16;
96 sal_uInt16 aLength;
98 rStream.Seek(STREAM_SEEK_TO_END);
99 sal_uInt32 aSize = rStream.Tell();
100 rStream.Seek(STREAM_SEEK_TO_BEGIN);
102 rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
103 rStream >> aMagic16;
105 // Compare JPEG magic bytes
106 if( 0xFFD8 != aMagic16 )
108 return false;
111 sal_uInt32 aPreviousPosition = STREAM_SEEK_TO_BEGIN;
113 while(true)
115 sal_uInt8 aMarker = 0xD9;
116 sal_Int32 aCount;
118 for (aCount = 0; aCount < 7; aCount++)
120 rStream >> aMarker;
121 if (aMarker != 0xFF)
123 break;
125 if (aCount >= 6)
127 return false;
131 rStream >> aLength;
133 if (aLength < 8)
135 return false;
138 if (aMarker == 0xE1)
140 return processExif(rStream, aLength, bSetValue);
142 else if (aMarker == 0xD9)
144 return false;
146 else
148 sal_uInt32 aCurrentPosition = rStream.SeekRel(aLength-1);
149 if (aCurrentPosition == aPreviousPosition || aCurrentPosition > aSize)
151 return false;
153 aPreviousPosition = aCurrentPosition;
156 return false;
159 bool Exif::processIFD(sal_uInt8* pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue, bool bSwap)
161 ExifIFD* ifd = NULL;
163 while (aOffset <= aLength - 12 && aNumberOfTags > 0)
165 ifd = (ExifIFD*) &pExifData[aOffset];
166 sal_uInt16 tag = ifd->tag;
167 if (bSwap)
169 tag = OSL_SWAPWORD(ifd->tag);
172 if (tag == ORIENTATION)
174 if(bSetValue)
176 ifd->tag = ORIENTATION;
177 ifd->type = 3;
178 ifd->count = 1;
179 ifd->offset = maOrientation;
180 if (bSwap)
182 ifd->tag = OSL_SWAPWORD(ifd->tag);
183 ifd->offset = OSL_SWAPWORD(ifd->offset);
186 else
188 sal_uInt32 nIfdOffset = ifd->offset;
189 if (bSwap)
190 nIfdOffset = OSL_SWAPWORD(ifd->offset);
191 maOrientation = convertToOrientation(nIfdOffset);
195 aNumberOfTags--;
196 aOffset += 12;
198 return true;
201 bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue)
203 sal_uInt32 aMagic32;
204 sal_uInt16 aMagic16;
206 rStream >> aMagic32;
207 rStream >> aMagic16;
209 // Compare EXIF magic bytes
210 if( 0x45786966 != aMagic32 || 0x0000 != aMagic16)
212 return false;
215 sal_uInt16 aLength = aSectionLength - 6; // Length = Section - Header
217 sal_uInt8* aExifData = new sal_uInt8[aLength];
218 sal_uInt32 aExifDataBeginPosition = rStream.Tell();
220 rStream.Read(aExifData, aLength);
222 // Exif detected
223 mbExifPresent = true;
225 TiffHeader* aTiffHeader = (TiffHeader*) &aExifData[0];
227 bool bIntel = aTiffHeader->byteOrder == 0x4949; //big-endian
228 bool bMotorola = aTiffHeader->byteOrder == 0x4D4D; //little-endian
230 if (!bIntel && !bMotorola)
232 delete[] aExifData;
233 return false;
236 bool bSwap = false;
238 #ifdef OSL_BIGENDIAN
239 if (bIntel)
240 bSwap = true;
241 #else
242 if (bMotorola)
243 bSwap = true;
244 #endif
246 if (bSwap)
248 aTiffHeader->tagAlign = OSL_SWAPWORD(aTiffHeader->tagAlign);
249 aTiffHeader->offset = OSL_SWAPDWORD(aTiffHeader->offset);
252 if (aTiffHeader->tagAlign != 0x002A) // TIFF tag
254 delete[] aExifData;
255 return false;
258 sal_uInt16 aOffset = aTiffHeader->offset;
260 sal_uInt16 aNumberOfTags = aExifData[aOffset];
261 if (bSwap)
263 aNumberOfTags = ((aExifData[aOffset] << 8) | aExifData[aOffset+1]);
266 processIFD(aExifData, aLength, aOffset+2, aNumberOfTags, bSetValue, bSwap);
268 if (bSetValue)
270 rStream.Seek(aExifDataBeginPosition);
271 rStream.Write(aExifData, aLength);
274 delete[] aExifData;
275 return true;
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */