Line data Source code
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 :
22 0 : Exif::Exif() :
23 : maOrientation(TOP_LEFT),
24 0 : mbExifPresent(false)
25 0 : {}
26 :
27 0 : Exif::~Exif()
28 0 : {}
29 :
30 0 : Orientation Exif::getOrientation() {
31 0 : return maOrientation;
32 : }
33 :
34 0 : void Exif::setOrientation(Orientation aOrientation) {
35 0 : maOrientation = aOrientation;
36 0 : }
37 :
38 0 : Orientation Exif::convertToOrientation(sal_Int32 value)
39 : {
40 0 : switch(value) {
41 0 : case 1: return TOP_LEFT;
42 0 : case 2: return TOP_RIGHT;
43 0 : case 3: return BOTTOM_RIGHT;
44 0 : case 4: return BOTTOM_LEFT;
45 0 : case 5: return LEFT_TOP;
46 0 : case 6: return RIGHT_TOP;
47 0 : case 7: return RIGHT_BOTTOM;
48 0 : case 8: return LEFT_BOTTOM;
49 : }
50 0 : return TOP_LEFT;
51 : }
52 :
53 0 : sal_Int32 Exif::getRotation()
54 : {
55 0 : switch(maOrientation) {
56 : case TOP_LEFT:
57 0 : return 0;
58 : case BOTTOM_RIGHT:
59 0 : return 1800;
60 : case RIGHT_TOP:
61 0 : return 2700;
62 : case LEFT_BOTTOM:
63 0 : return 900;
64 : default:
65 0 : break;
66 : }
67 0 : return 0;
68 : }
69 :
70 0 : bool Exif::hasExif()
71 : {
72 0 : return mbExifPresent;
73 : }
74 :
75 0 : bool Exif::read(SvStream& rStream)
76 : {
77 0 : sal_Int32 nStreamPosition = rStream.Tell();
78 0 : bool result = processJpeg(rStream, false);
79 0 : rStream.Seek( nStreamPosition );
80 :
81 0 : return result;
82 : }
83 :
84 0 : bool Exif::write(SvStream& rStream)
85 : {
86 0 : sal_Int32 nStreamPosition = rStream.Tell();
87 0 : bool result = processJpeg(rStream, true);
88 0 : rStream.Seek( nStreamPosition );
89 :
90 0 : return result;
91 : }
92 :
93 0 : bool Exif::processJpeg(SvStream& rStream, bool bSetValue)
94 : {
95 : sal_uInt16 aMagic16;
96 : sal_uInt16 aLength;
97 :
98 0 : rStream.Seek(STREAM_SEEK_TO_END);
99 0 : sal_uInt32 aSize = rStream.Tell();
100 0 : rStream.Seek(STREAM_SEEK_TO_BEGIN);
101 :
102 0 : rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
103 0 : rStream >> aMagic16;
104 :
105 : // Compare JPEG magic bytes
106 0 : if( 0xFFD8 != aMagic16 )
107 : {
108 0 : return false;
109 : }
110 :
111 0 : sal_uInt32 aPreviousPosition = STREAM_SEEK_TO_BEGIN;
112 :
113 : while(true)
114 : {
115 0 : sal_uInt8 aMarker = 0xD9;
116 : sal_Int32 aCount;
117 :
118 0 : for (aCount = 0; aCount < 7; aCount++)
119 : {
120 0 : rStream >> aMarker;
121 0 : if (aMarker != 0xFF)
122 : {
123 0 : break;
124 : }
125 0 : if (aCount >= 6)
126 : {
127 0 : return false;
128 : }
129 : }
130 :
131 0 : rStream >> aLength;
132 :
133 0 : if (aLength < 8)
134 : {
135 0 : return false;
136 : }
137 :
138 0 : if (aMarker == 0xE1)
139 : {
140 0 : return processExif(rStream, aLength, bSetValue);
141 : }
142 0 : else if (aMarker == 0xD9)
143 : {
144 0 : return false;
145 : }
146 : else
147 : {
148 0 : sal_uInt32 aCurrentPosition = rStream.SeekRel(aLength-1);
149 0 : if (aCurrentPosition == aPreviousPosition || aCurrentPosition > aSize)
150 : {
151 0 : return false;
152 : }
153 0 : aPreviousPosition = aCurrentPosition;
154 : }
155 : }
156 0 : return false;
157 : }
158 :
159 0 : bool Exif::processIFD(sal_uInt8* pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue)
160 : {
161 0 : ExifIFD* ifd = NULL;
162 :
163 0 : while (aOffset <= aLength - 12 && aNumberOfTags > 0)
164 : {
165 0 : ifd = (ExifIFD*) &pExifData[aOffset];
166 :
167 0 : if (ifd->tag == ORIENTATION)
168 : {
169 0 : if(bSetValue)
170 : {
171 0 : ifd->tag = ORIENTATION;
172 0 : ifd->type = 3;
173 0 : ifd->count = 1;
174 0 : ifd->offset = maOrientation;
175 : }
176 : else
177 : {
178 0 : maOrientation = convertToOrientation(ifd->offset);
179 : }
180 : }
181 :
182 0 : aNumberOfTags--;
183 0 : aOffset += 12;
184 : }
185 0 : return true;
186 : }
187 :
188 0 : bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue)
189 : {
190 : sal_uInt32 aMagic32;
191 : sal_uInt16 aMagic16;
192 :
193 0 : rStream >> aMagic32;
194 0 : rStream >> aMagic16;
195 :
196 : // Compare EXIF magic bytes
197 0 : if( 0x45786966 != aMagic32 || 0x0000 != aMagic16)
198 : {
199 0 : return false;
200 : }
201 :
202 0 : sal_uInt16 aLength = aSectionLength - 6; // Length = Section - Header
203 :
204 0 : sal_uInt8* aExifData = new sal_uInt8[aLength];
205 0 : sal_uInt32 aExifDataBeginPosition = rStream.Tell();
206 :
207 0 : rStream.Read(aExifData, aLength);
208 :
209 : // Exif detected
210 0 : mbExifPresent = true;
211 :
212 0 : TiffHeader* aTiffHeader = (TiffHeader*) &aExifData[0];
213 :
214 0 : if( 0x4949 != aTiffHeader->byteOrder || 0x002A != aTiffHeader->tagAlign )
215 : {
216 0 : delete[] aExifData;
217 0 : return false;
218 : }
219 :
220 0 : sal_uInt16 aOffset = aTiffHeader->offset;
221 :
222 0 : sal_uInt16 aNumberOfTags = aExifData[aOffset];
223 0 : aNumberOfTags = aExifData[aOffset + 1];
224 0 : aNumberOfTags <<= 8;
225 0 : aNumberOfTags += aExifData[aOffset];
226 :
227 0 : processIFD(aExifData, aLength, aOffset+2, aNumberOfTags, bSetValue);
228 :
229 0 : if (bSetValue)
230 : {
231 0 : rStream.Seek(aExifDataBeginPosition);
232 0 : rStream.Write(aExifData, aLength);
233 : }
234 :
235 0 : delete[] aExifData;
236 0 : return true;
237 465 : }
238 :
239 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|