1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <osl/endian.h>
23 #include <tools/stream.hxx>
26 maOrientation(exif::TOP_LEFT
),
30 void Exif::setOrientation(exif::Orientation aOrientation
) {
31 maOrientation
= aOrientation
;
34 exif::Orientation
Exif::convertToOrientation(sal_Int32 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
;
46 return exif::TOP_LEFT
;
49 Degree10
Exif::getRotation() const
51 switch(maOrientation
) {
54 case exif::BOTTOM_RIGHT
:
58 case exif::LEFT_BOTTOM
:
66 bool Exif::read(SvStream
& rStream
)
68 sal_uInt64 nStreamPosition
= rStream
.Tell();
69 bool result
= processJpeg(rStream
, false);
70 rStream
.Seek( nStreamPosition
);
75 void Exif::write(SvStream
& rStream
)
77 sal_uInt64 nStreamPosition
= rStream
.Tell();
78 processJpeg(rStream
, true);
79 rStream
.Seek( nStreamPosition
);
82 bool Exif::processJpeg(SvStream
& rStream
, bool bSetValue
)
87 sal_uInt64 aSize
= rStream
.TellEnd();
88 rStream
.Seek(STREAM_SEEK_TO_BEGIN
);
90 rStream
.SetEndian( SvStreamEndian::BIG
);
91 rStream
.ReadUInt16( aMagic16
);
93 // Compare JPEG magic bytes
94 if( 0xFFD8 != aMagic16
)
99 sal_uInt32 aPreviousPosition
= STREAM_SEEK_TO_BEGIN
;
103 sal_uInt8 aMarker
= 0xD9;
106 for (aCount
= 0; aCount
< 7; aCount
++)
108 rStream
.ReadUChar( aMarker
);
119 rStream
.ReadUInt16( aLength
);
121 if (aLength
< 8 || aLength
> rStream
.remainingSize())
128 return processExif(rStream
, aLength
, bSetValue
);
130 else if (aMarker
== 0xD9)
136 sal_uInt64 aCurrentPosition
= rStream
.SeekRel(aLength
-1);
137 if (aCurrentPosition
== aPreviousPosition
|| aCurrentPosition
> aSize
)
141 aPreviousPosition
= aCurrentPosition
;
149 sal_uInt16
read16(sal_uInt8
const (& data
)[2], bool littleEndian
) {
151 return data
[0] | (sal_uInt16(data
[1]) << 8);
153 return data
[1] | (sal_uInt16(data
[0]) << 8);
157 void write16(sal_uInt16 value
, sal_uInt8 (& data
)[2], bool littleEndian
) {
159 data
[0] = value
& 0xFF;
160 data
[1] = value
>> 8;
162 data
[1] = value
& 0xFF;
163 data
[0] = value
>> 8;
167 void write32(sal_uInt32 value
, sal_uInt8 (& data
)[4], bool littleEndian
) {
169 data
[0] = value
& 0xFF;
170 data
[1] = (value
>> 8) & 0xFF;
171 data
[2] = (value
>> 16) & 0xFF;
172 data
[3] = value
>> 24;
174 data
[3] = value
& 0xFF;
175 data
[2] = (value
>> 8) & 0xFF;
176 data
[1] = (value
>> 16) & 0xFF;
177 data
[0] = value
>> 24;
183 void Exif::processIFD(sal_uInt8
* pExifData
, sal_uInt16 aLength
, sal_uInt16 aOffset
, sal_uInt16 aNumberOfTags
, bool bSetValue
, bool littleEndian
)
185 ExifIFD
* ifd
= nullptr;
187 while (aOffset
<= aLength
- 12 && aNumberOfTags
> 0)
189 ifd
= reinterpret_cast<ExifIFD
*>(&pExifData
[aOffset
]);
190 sal_uInt16 tag
= read16(ifd
->tag
, littleEndian
);
192 if (tag
== ORIENTATION
)
196 write16(3, ifd
->type
, littleEndian
);
197 write32(1, ifd
->count
, littleEndian
);
199 maOrientation
, reinterpret_cast<sal_uInt8 (&)[2]>(ifd
->offset
), littleEndian
);
203 sal_uInt16 nIfdOffset
= read16(
204 reinterpret_cast<sal_uInt8 (&)[2]>(ifd
->offset
), littleEndian
);
205 maOrientation
= convertToOrientation(nIfdOffset
);
214 bool Exif::processExif(SvStream
& rStream
, sal_uInt16 aSectionLength
, bool bSetValue
)
219 rStream
.ReadUInt32( aMagic32
);
220 rStream
.ReadUInt16( aMagic16
);
222 // Compare EXIF magic bytes
223 if( 0x45786966 != aMagic32
|| 0x0000 != aMagic16
)
228 sal_uInt16 aLength
= aSectionLength
- 6; // Length = Section - Header
230 std::unique_ptr
<sal_uInt8
[]> aExifData(new sal_uInt8
[aLength
]);
231 sal_uInt64 aExifDataBeginPosition
= rStream
.Tell();
233 rStream
.ReadBytes(aExifData
.get(), aLength
);
236 mbExifPresent
= true;
238 TiffHeader
* aTiffHeader
= reinterpret_cast<TiffHeader
*>(&aExifData
[0]);
240 bool bIntel
= aTiffHeader
->byteOrder
== 0x4949; //little-endian
241 bool bMotorola
= aTiffHeader
->byteOrder
== 0x4D4D; //big-endian
243 if (!bIntel
&& !bMotorola
)
260 aTiffHeader
->tagAlign
= OSL_SWAPWORD(aTiffHeader
->tagAlign
);
261 aTiffHeader
->offset
= OSL_SWAPDWORD(aTiffHeader
->offset
);
264 if (aTiffHeader
->tagAlign
!= 0x002A) // TIFF tag
269 sal_uInt16 aOffset
= aTiffHeader
->offset
;
271 sal_uInt16 aNumberOfTags
= aExifData
[aOffset
];
274 aNumberOfTags
= ((aExifData
[aOffset
] << 8) | aExifData
[aOffset
+1]);
277 processIFD(aExifData
.get(), aLength
, aOffset
+2, aNumberOfTags
, bSetValue
, bIntel
);
281 rStream
.Seek(aExifDataBeginPosition
);
282 rStream
.WriteBytes(aExifData
.get(), aLength
);
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */