LibreOffice Module vcl (master) 1
Exif.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "Exif.hxx"
21#include <memory>
22#include <osl/endian.h>
23#include <tools/stream.hxx>
24
26 maOrientation(exif::TOP_LEFT),
27 mbExifPresent(false)
28{}
29
31 maOrientation = aOrientation;
32}
33
35{
36 switch(value) {
37 case 1: return exif::TOP_LEFT;
38 case 2: return exif::TOP_RIGHT;
39 case 3: return exif::BOTTOM_RIGHT;
40 case 4: return exif::BOTTOM_LEFT;
41 case 5: return exif::LEFT_TOP;
42 case 6: return exif::RIGHT_TOP;
43 case 7: return exif::RIGHT_BOTTOM;
44 case 8: return exif::LEFT_BOTTOM;
45 }
46 return exif::TOP_LEFT;
47}
48
50{
51 switch(maOrientation) {
52 case exif::TOP_LEFT:
53 return 0_deg10;
55 return 1800_deg10;
56 case exif::RIGHT_TOP:
57 return 2700_deg10;
59 return 900_deg10;
60 default:
61 break;
62 }
63 return 0_deg10;
64}
65
66bool Exif::read(SvStream& rStream)
67{
68 sal_Int32 nStreamPosition = rStream.Tell();
69 bool result = processJpeg(rStream, false);
70 rStream.Seek( nStreamPosition );
71
72 return result;
73}
74
75void Exif::write(SvStream& rStream)
76{
77 sal_Int32 nStreamPosition = rStream.Tell();
78 processJpeg(rStream, true);
79 rStream.Seek( nStreamPosition );
80}
81
82bool Exif::processJpeg(SvStream& rStream, bool bSetValue)
83{
84 sal_uInt16 aMagic16;
85 sal_uInt16 aLength;
86
87 sal_uInt32 aSize = rStream.TellEnd();
89
90 rStream.SetEndian( SvStreamEndian::BIG );
91 rStream.ReadUInt16( aMagic16 );
92
93 // Compare JPEG magic bytes
94 if( 0xFFD8 != aMagic16 )
95 {
96 return false;
97 }
98
99 sal_uInt32 aPreviousPosition = STREAM_SEEK_TO_BEGIN;
100
101 while(true)
102 {
103 sal_uInt8 aMarker = 0xD9;
104 sal_Int32 aCount;
105
106 for (aCount = 0; aCount < 7; aCount++)
107 {
108 rStream.ReadUChar( aMarker );
109 if (aMarker != 0xFF)
110 {
111 break;
112 }
113 if (aCount >= 6)
114 {
115 return false;
116 }
117 }
118
119 rStream.ReadUInt16( aLength );
120
121 if (aLength < 8 || aLength > rStream.remainingSize())
122 {
123 return false;
124 }
125
126 if (aMarker == 0xE1)
127 {
128 return processExif(rStream, aLength, bSetValue);
129 }
130 else if (aMarker == 0xD9)
131 {
132 return false;
133 }
134 else
135 {
136 sal_uInt32 aCurrentPosition = rStream.SeekRel(aLength-1);
137 if (aCurrentPosition == aPreviousPosition || aCurrentPosition > aSize)
138 {
139 return false;
140 }
141 aPreviousPosition = aCurrentPosition;
142 }
143 }
144 return false;
145}
146
147namespace {
148
149sal_uInt16 read16(sal_uInt8 const (& data)[2], bool littleEndian) {
150 if (littleEndian) {
151 return data[0] | (sal_uInt16(data[1]) << 8);
152 } else {
153 return data[1] | (sal_uInt16(data[0]) << 8);
154 }
155}
156
157void write16(sal_uInt16 value, sal_uInt8 (& data)[2], bool littleEndian) {
158 if (littleEndian) {
159 data[0] = value & 0xFF;
160 data[1] = value >> 8;
161 } else {
162 data[1] = value & 0xFF;
163 data[0] = value >> 8;
164 }
165}
166
167void write32(sal_uInt32 value, sal_uInt8 (& data)[4], bool littleEndian) {
168 if (littleEndian) {
169 data[0] = value & 0xFF;
170 data[1] = (value >> 8) & 0xFF;
171 data[2] = (value >> 16) & 0xFF;
172 data[3] = value >> 24;
173 } else {
174 data[3] = value & 0xFF;
175 data[2] = (value >> 8) & 0xFF;
176 data[1] = (value >> 16) & 0xFF;
177 data[0] = value >> 24;
178 }
179}
180
181}
182
183void Exif::processIFD(sal_uInt8* pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue, bool littleEndian)
184{
185 ExifIFD* ifd = nullptr;
186
187 while (aOffset <= aLength - 12 && aNumberOfTags > 0)
188 {
189 ifd = reinterpret_cast<ExifIFD*>(&pExifData[aOffset]);
190 sal_uInt16 tag = read16(ifd->tag, littleEndian);
191
192 if (tag == ORIENTATION)
193 {
194 if(bSetValue)
195 {
196 write16(3, ifd->type, littleEndian);
197 write32(1, ifd->count, littleEndian);
198 write16(
199 maOrientation, reinterpret_cast<sal_uInt8 (&)[2]>(ifd->offset), littleEndian);
200 }
201 else
202 {
203 sal_uInt16 nIfdOffset = read16(
204 reinterpret_cast<sal_uInt8 (&)[2]>(ifd->offset), littleEndian);
206 }
207 }
208
209 aNumberOfTags--;
210 aOffset += 12;
211 }
212}
213
214bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue)
215{
216 sal_uInt32 aMagic32;
217 sal_uInt16 aMagic16;
218
219 rStream.ReadUInt32( aMagic32 );
220 rStream.ReadUInt16( aMagic16 );
221
222 // Compare EXIF magic bytes
223 if( 0x45786966 != aMagic32 || 0x0000 != aMagic16)
224 {
225 return false;
226 }
227
228 sal_uInt16 aLength = aSectionLength - 6; // Length = Section - Header
229
230 std::unique_ptr<sal_uInt8[]> aExifData(new sal_uInt8[aLength]);
231 sal_uInt32 aExifDataBeginPosition = rStream.Tell();
232
233 rStream.ReadBytes(aExifData.get(), aLength);
234
235 // Exif detected
236 mbExifPresent = true;
237
238 TiffHeader* aTiffHeader = reinterpret_cast<TiffHeader*>(&aExifData[0]);
239
240 bool bIntel = aTiffHeader->byteOrder == 0x4949; //little-endian
241 bool bMotorola = aTiffHeader->byteOrder == 0x4D4D; //big-endian
242
243 if (!bIntel && !bMotorola)
244 {
245 return false;
246 }
247
248 bool bSwap = false;
249
250#ifdef OSL_BIGENDIAN
251 if (bIntel)
252 bSwap = true;
253#else
254 if (bMotorola)
255 bSwap = true;
256#endif
257
258 if (bSwap)
259 {
260 aTiffHeader->tagAlign = OSL_SWAPWORD(aTiffHeader->tagAlign);
261 aTiffHeader->offset = OSL_SWAPDWORD(aTiffHeader->offset);
262 }
263
264 if (aTiffHeader->tagAlign != 0x002A) // TIFF tag
265 {
266 return false;
267 }
268
269 sal_uInt16 aOffset = aTiffHeader->offset;
270
271 sal_uInt16 aNumberOfTags = aExifData[aOffset];
272 if (bSwap)
273 {
274 aNumberOfTags = ((aExifData[aOffset] << 8) | aExifData[aOffset+1]);
275 }
276
277 processIFD(aExifData.get(), aLength, aOffset+2, aNumberOfTags, bSetValue, bIntel);
278
279 if (bSetValue)
280 {
281 rStream.Seek(aExifDataBeginPosition);
282 rStream.WriteBytes(aExifData.get(), aLength);
283 }
284
285 return true;
286}
287
288/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool read(SvStream &rStream)
Definition: Exif.cxx:66
bool processExif(SvStream &rStream, sal_uInt16 aLength, bool bSetValue)
Definition: Exif.cxx:214
void setOrientation(exif::Orientation orientation)
Definition: Exif.cxx:30
exif::Orientation maOrientation
Definition: Exif.hxx:46
Exif()
Definition: Exif.cxx:25
void processIFD(sal_uInt8 *pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue, bool bLittleEndian)
Definition: Exif.cxx:183
bool mbExifPresent
Definition: Exif.hxx:47
static exif::Orientation convertToOrientation(sal_Int32 value)
Definition: Exif.cxx:34
Degree10 getRotation() const
Definition: Exif.cxx:49
bool processJpeg(SvStream &rStream, bool bSetValue)
Definition: Exif.cxx:82
void write(SvStream &rStream)
Definition: Exif.cxx:75
sal_uInt64 Tell() const
void SetEndian(SvStreamEndian SvStreamEndian)
virtual sal_uInt64 TellEnd()
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
sal_uInt64 SeekRel(sal_Int64 nPos)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_uInt64 remainingSize()
SvStream & ReadUChar(unsigned char &rChar)
Any value
Definition: Exif.hxx:25
Orientation
Definition: Exif.hxx:27
@ BOTTOM_LEFT
Definition: Exif.hxx:31
@ RIGHT_BOTTOM
Definition: Exif.hxx:34
@ LEFT_BOTTOM
Definition: Exif.hxx:35
@ BOTTOM_RIGHT
Definition: Exif.hxx:30
@ RIGHT_TOP
Definition: Exif.hxx:33
@ TOP_LEFT
Definition: Exif.hxx:28
@ TOP_RIGHT
Definition: Exif.hxx:29
@ LEFT_TOP
Definition: Exif.hxx:32
#define STREAM_SEEK_TO_BEGIN
sal_uInt8 count[4]
Definition: Exif.hxx:56
sal_uInt8 tag[2]
Definition: Exif.hxx:54
sal_uInt8 offset[4]
Definition: Exif.hxx:57
sal_uInt8 type[2]
Definition: Exif.hxx:55
sal_uInt32 offset
Definition: Exif.hxx:63
sal_uInt16 tagAlign
Definition: Exif.hxx:62
sal_uInt16 byteOrder
Definition: Exif.hxx:61
unsigned char sal_uInt8
Any result