source: liacs/MIR2010/SourceCode/cximage/ximaexif.cpp@ 97

Last change on this file since 97 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 30.6 KB
Line 
1/*
2 * File: ximaexif.cpp
3 * Purpose: EXIF reader
4 * 18/Aug/2002 Davide Pizzolato - www.xdp.it
5 * CxImage version 6.0.0 02/Feb/2008
6 * based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>
7 */
8
9#include "ximajpg.h"
10
11#if CXIMAGEJPG_SUPPORT_EXIF
12
13////////////////////////////////////////////////////////////////////////////////
14CxImageJPG::CxExifInfo::CxExifInfo(EXIFINFO* info)
15{
16 if (info) {
17 m_exifinfo = info;
18 freeinfo = false;
19 } else {
20 m_exifinfo = new EXIFINFO;
21 memset(m_exifinfo,0,sizeof(EXIFINFO));
22 freeinfo = true;
23 }
24
25 m_szLastError[0]='\0';
26 ExifImageWidth = MotorolaOrder = 0;
27 SectionsRead=0;
28 memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));
29}
30////////////////////////////////////////////////////////////////////////////////
31CxImageJPG::CxExifInfo::~CxExifInfo()
32{
33 for(int i=0;i<MAX_SECTIONS;i++) if(Sections[i].Data) free(Sections[i].Data);
34 if (freeinfo) delete m_exifinfo;
35}
36////////////////////////////////////////////////////////////////////////////////
37bool CxImageJPG::CxExifInfo::DecodeExif(CxFile * hFile, int nReadMode)
38{
39 int a;
40 int HaveCom = FALSE;
41
42 a = hFile->GetC();
43
44 if (a != 0xff || hFile->GetC() != M_SOI){
45 return FALSE;
46 }
47
48 for(;;){
49 int itemlen;
50 int marker = 0;
51 int ll,lh, got;
52 BYTE * Data;
53
54 if (SectionsRead >= MAX_SECTIONS){
55 strcpy(m_szLastError,"Too many sections in jpg file");
56 return false;
57 }
58
59 for (a=0;a<7;a++){
60 marker = hFile->GetC();
61 if (marker != 0xff) break;
62
63 if (a >= 6){
64 printf("too many padding bytes\n");
65 return false;
66 }
67 }
68
69 if (marker == 0xff){
70 // 0xff is legal padding, but if we get that many, something's wrong.
71 strcpy(m_szLastError,"too many padding bytes!");
72 return false;
73 }
74
75 Sections[SectionsRead].Type = marker;
76
77 // Read the length of the section.
78 lh = hFile->GetC();
79 ll = hFile->GetC();
80
81 itemlen = (lh << 8) | ll;
82
83 if (itemlen < 2){
84 strcpy(m_szLastError,"invalid marker");
85 return false;
86 }
87
88 Sections[SectionsRead].Size = itemlen;
89
90 Data = (BYTE *)malloc(itemlen);
91 if (Data == NULL){
92 strcpy(m_szLastError,"Could not allocate memory");
93 return false;
94 }
95 Sections[SectionsRead].Data = Data;
96
97 // Store first two pre-read bytes.
98 Data[0] = (BYTE)lh;
99 Data[1] = (BYTE)ll;
100
101 got = hFile->Read(Data+2, 1, itemlen-2); // Read the whole section.
102 if (got != itemlen-2){
103 strcpy(m_szLastError,"Premature end of file?");
104 return false;
105 }
106 SectionsRead += 1;
107
108 switch(marker){
109
110 case M_SOS: // stop before hitting compressed data
111 // If reading entire image is requested, read the rest of the data.
112 if (nReadMode & EXIF_READ_IMAGE){
113 int cp, ep, size;
114 // Determine how much file is left.
115 cp = hFile->Tell();
116 hFile->Seek(0, SEEK_END);
117 ep = hFile->Tell();
118 hFile->Seek(cp, SEEK_SET);
119
120 size = ep-cp;
121 Data = (BYTE *)malloc(size);
122 if (Data == NULL){
123 strcpy(m_szLastError,"could not allocate data for entire image");
124 return false;
125 }
126
127 got = hFile->Read(Data, 1, size);
128 if (got != size){
129 strcpy(m_szLastError,"could not read the rest of the image");
130 return false;
131 }
132
133 Sections[SectionsRead].Data = Data;
134 Sections[SectionsRead].Size = size;
135 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
136 SectionsRead ++;
137 }
138 return true;
139
140 case M_EOI: // in case it's a tables-only JPEG stream
141 printf("No image in jpeg!\n");
142 return FALSE;
143
144 case M_COM: // Comment section
145 if (HaveCom || ((nReadMode & EXIF_READ_EXIF) == 0)){
146 // Discard this section.
147 free(Sections[--SectionsRead].Data);
148 Sections[SectionsRead].Data=0;
149 }else{
150 process_COM(Data, itemlen);
151 HaveCom = TRUE;
152 }
153 break;
154
155 case M_JFIF:
156 // Regular jpegs always have this tag, exif images have the exif
157 // marker instead, althogh ACDsee will write images with both markers.
158 // this program will re-create this marker on absence of exif marker.
159 // hence no need to keep the copy from the file.
160 free(Sections[--SectionsRead].Data);
161 Sections[SectionsRead].Data=0;
162 break;
163
164 case M_EXIF:
165 // Seen files from some 'U-lead' software with Vivitar scanner
166 // that uses marker 31 for non exif stuff. Thus make sure
167 // it says 'Exif' in the section before treating it as exif.
168 if ((nReadMode & EXIF_READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
169 m_exifinfo->IsExif = process_EXIF((BYTE *)Data+2, itemlen);
170 }else{
171 // Discard this section.
172 free(Sections[--SectionsRead].Data);
173 Sections[SectionsRead].Data=0;
174 }
175 break;
176
177 case M_SOF0:
178 case M_SOF1:
179 case M_SOF2:
180 case M_SOF3:
181 case M_SOF5:
182 case M_SOF6:
183 case M_SOF7:
184 case M_SOF9:
185 case M_SOF10:
186 case M_SOF11:
187 case M_SOF13:
188 case M_SOF14:
189 case M_SOF15:
190 process_SOFn(Data, marker);
191 break;
192 default:
193 // Skip any other sections.
194 //if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
195 break;
196 }
197 }
198 return true;
199}
200////////////////////////////////////////////////////////////////////////////////
201/*--------------------------------------------------------------------------
202 Process a EXIF marker
203 Describes all the drivel that most digital cameras include...
204--------------------------------------------------------------------------*/
205bool CxImageJPG::CxExifInfo::process_EXIF(unsigned char * CharBuf, unsigned int length)
206{
207 m_exifinfo->FlashUsed = 0;
208 /* If it's from a digicam, and it used flash, it says so. */
209 m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */
210
211 ExifImageWidth = 0;
212
213 { /* Check the EXIF header component */
214 static const unsigned char ExifHeader[] = "Exif\0\0";
215 if (memcmp(CharBuf+0, ExifHeader,6)){
216 strcpy(m_szLastError,"Incorrect Exif header");
217 return false;
218 }
219 }
220
221 if (memcmp(CharBuf+6,"II",2) == 0){
222 MotorolaOrder = 0;
223 }else{
224 if (memcmp(CharBuf+6,"MM",2) == 0){
225 MotorolaOrder = 1;
226 }else{
227 strcpy(m_szLastError,"Invalid Exif alignment marker.");
228 return false;
229 }
230 }
231
232 /* Check the next two values for correctness. */
233 if (Get16u(CharBuf+8) != 0x2a){
234 strcpy(m_szLastError,"Invalid Exif start (1)");
235 return false;
236 }
237
238 int FirstOffset = Get32u(CharBuf+10);
239 /* <Richard Collins>
240 if (FirstOffset < 8 || FirstOffset > 16){
241 // I used to ensure this was set to 8 (website I used indicated its 8)
242 // but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002)
243 strcpy(m_szLastError,"Suspicious offset of first IFD value");
244 return false;
245 }*/
246
247 unsigned char * LastExifRefd = CharBuf;
248
249 /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */
250 if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))
251 return false;
252
253 /* <Richard Collins> give a chance for a second directory */
254 if (FirstOffset > 8) {
255 if (!ProcessExifDir(CharBuf+14+FirstOffset-8, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))
256 return false;
257 }
258
259 /* This is how far the interesting (non thumbnail) part of the exif went. */
260 // int ExifSettingsLength = LastExifRefd - CharBuf;
261
262 /* Compute the CCD width, in milimeters. */
263 if (m_exifinfo->FocalplaneXRes != 0){
264 m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);
265 }
266
267 return true;
268}
269//--------------------------------------------------------------------------
270// Get 16 bits motorola order (always) for jpeg header stuff.
271//--------------------------------------------------------------------------
272int CxImageJPG::CxExifInfo::Get16m(void * Short)
273{
274 return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
275}
276////////////////////////////////////////////////////////////////////////////////
277/*--------------------------------------------------------------------------
278 Convert a 16 bit unsigned value from file's native byte order
279--------------------------------------------------------------------------*/
280int CxImageJPG::CxExifInfo::Get16u(void * Short)
281{
282 if (MotorolaOrder){
283 return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
284 }else{
285 return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
286 }
287}
288////////////////////////////////////////////////////////////////////////////////
289/*--------------------------------------------------------------------------
290 Convert a 32 bit signed value from file's native byte order
291--------------------------------------------------------------------------*/
292long CxImageJPG::CxExifInfo::Get32s(void * Long)
293{
294 if (MotorolaOrder){
295 return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
296 | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
297 }else{
298 return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
299 | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
300 }
301}
302////////////////////////////////////////////////////////////////////////////////
303/*--------------------------------------------------------------------------
304 Convert a 32 bit unsigned value from file's native byte order
305--------------------------------------------------------------------------*/
306unsigned long CxImageJPG::CxExifInfo::Get32u(void * Long)
307{
308 return (unsigned long)Get32s(Long) & 0xffffffff;
309}
310////////////////////////////////////////////////////////////////////////////////
311
312/* Describes format descriptor */
313static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
314#define NUM_FORMATS 12
315
316#define FMT_BYTE 1
317#define FMT_STRING 2
318#define FMT_USHORT 3
319#define FMT_ULONG 4
320#define FMT_URATIONAL 5
321#define FMT_SBYTE 6
322#define FMT_UNDEFINED 7
323#define FMT_SSHORT 8
324#define FMT_SLONG 9
325#define FMT_SRATIONAL 10
326#define FMT_SINGLE 11
327#define FMT_DOUBLE 12
328
329/* Describes tag values */
330
331#define TAG_EXIF_VERSION 0x9000
332#define TAG_EXIF_OFFSET 0x8769
333#define TAG_INTEROP_OFFSET 0xa005
334
335#define TAG_MAKE 0x010F
336#define TAG_MODEL 0x0110
337
338#define TAG_ORIENTATION 0x0112
339#define TAG_XRESOLUTION 0x011A
340#define TAG_YRESOLUTION 0x011B
341#define TAG_RESOLUTIONUNIT 0x0128
342
343#define TAG_EXPOSURETIME 0x829A
344#define TAG_FNUMBER 0x829D
345
346#define TAG_SHUTTERSPEED 0x9201
347#define TAG_APERTURE 0x9202
348#define TAG_BRIGHTNESS 0x9203
349#define TAG_MAXAPERTURE 0x9205
350#define TAG_FOCALLENGTH 0x920A
351
352#define TAG_DATETIME_ORIGINAL 0x9003
353#define TAG_USERCOMMENT 0x9286
354
355#define TAG_SUBJECT_DISTANCE 0x9206
356#define TAG_FLASH 0x9209
357
358#define TAG_FOCALPLANEXRES 0xa20E
359#define TAG_FOCALPLANEYRES 0xa20F
360#define TAG_FOCALPLANEUNITS 0xa210
361#define TAG_EXIF_IMAGEWIDTH 0xA002
362#define TAG_EXIF_IMAGELENGTH 0xA003
363
364/* the following is added 05-jan-2001 vcs */
365#define TAG_EXPOSURE_BIAS 0x9204
366#define TAG_WHITEBALANCE 0x9208
367#define TAG_METERING_MODE 0x9207
368#define TAG_EXPOSURE_PROGRAM 0x8822
369#define TAG_ISO_EQUIVALENT 0x8827
370#define TAG_COMPRESSION_LEVEL 0x9102
371
372#define TAG_THUMBNAIL_OFFSET 0x0201
373#define TAG_THUMBNAIL_LENGTH 0x0202
374
375
376/*--------------------------------------------------------------------------
377 Process one of the nested EXIF directories.
378--------------------------------------------------------------------------*/
379bool CxImageJPG::CxExifInfo::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
380 EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP, int NestingLevel)
381{
382 int de;
383 int a;
384 int NumDirEntries;
385 unsigned ThumbnailOffset = 0;
386 unsigned ThumbnailSize = 0;
387
388 if (NestingLevel > 4){
389 strcpy(m_szLastError,"Maximum directory nesting exceeded (corrupt exif header)");
390 return false;
391 }
392
393 NumDirEntries = Get16u(DirStart);
394
395 if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){
396 strcpy(m_szLastError,"Illegally sized directory");
397 return false;
398 }
399
400 for (de=0;de<NumDirEntries;de++){
401 int Tag, Format, Components;
402 unsigned char * ValuePtr;
403 /* This actually can point to a variety of things; it must be
404 cast to other types when used. But we use it as a byte-by-byte
405 cursor, so we declare it as a pointer to a generic byte here.
406 */
407 int ByteCount;
408 unsigned char * DirEntry;
409 DirEntry = DirStart+2+12*de;
410
411 Tag = Get16u(DirEntry);
412 Format = Get16u(DirEntry+2);
413 Components = Get32u(DirEntry+4);
414
415 if ((Format-1) >= NUM_FORMATS) {
416 /* (-1) catches illegal zero case as unsigned underflows to positive large */
417 strcpy(m_szLastError,"Illegal format code in EXIF dir");
418 return false;
419 }
420
421 ByteCount = Components * BytesPerFormat[Format];
422
423 if (ByteCount > 4){
424 unsigned OffsetVal;
425 OffsetVal = Get32u(DirEntry+8);
426 /* If its bigger than 4 bytes, the dir entry contains an offset.*/
427 if (OffsetVal+ByteCount > ExifLength){
428 /* Bogus pointer offset and / or bytecount value */
429 strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");
430 return false;
431 }
432 ValuePtr = OffsetBase+OffsetVal;
433 }else{
434 /* 4 bytes or less and value is in the dir entry itself */
435 ValuePtr = DirEntry+8;
436 }
437
438 if (*LastExifRefdP < ValuePtr+ByteCount){
439 /* Keep track of last byte in the exif header that was
440 actually referenced. That way, we know where the
441 discardable thumbnail data begins.
442 */
443 *LastExifRefdP = ValuePtr+ByteCount;
444 }
445
446 /* Extract useful components of tag */
447 switch(Tag){
448
449 case TAG_MAKE:
450 strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);
451 break;
452
453 case TAG_MODEL:
454 strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);
455 break;
456
457 case TAG_EXIF_VERSION:
458 strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);
459 break;
460
461 case TAG_DATETIME_ORIGINAL:
462 strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);
463 break;
464
465 case TAG_USERCOMMENT:
466 // Olympus has this padded with trailing spaces. Remove these first.
467 for (a=ByteCount;;){
468 a--;
469 if (((char*)ValuePtr)[a] == ' '){
470 ((char*)ValuePtr)[a] = '\0';
471 }else{
472 break;
473 }
474 if (a == 0) break;
475 }
476
477 /* Copy the comment */
478 if (memcmp(ValuePtr, "ASCII",5) == 0){
479 for (a=5;a<10;a++){
480 char c;
481 c = ((char*)ValuePtr)[a];
482 if (c != '\0' && c != ' '){
483 strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);
484 break;
485 }
486 }
487
488 }else{
489 strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);
490 }
491 break;
492
493 case TAG_FNUMBER:
494 /* Simplest way of expressing aperture, so I trust it the most.
495 (overwrite previously computd value if there is one)
496 */
497 m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
498 break;
499
500 case TAG_APERTURE:
501 case TAG_MAXAPERTURE:
502 /* More relevant info always comes earlier, so only
503 use this field if we don't have appropriate aperture
504 information yet.
505 */
506 if (m_exifinfo->ApertureFNumber == 0){
507 m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)*0.5);
508 }
509 break;
510
511 case TAG_BRIGHTNESS:
512 m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);
513 break;
514
515 case TAG_FOCALLENGTH:
516 /* Nice digital cameras actually save the focal length
517 as a function of how farthey are zoomed in.
518 */
519
520 m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
521 break;
522
523 case TAG_SUBJECT_DISTANCE:
524 /* Inidcates the distacne the autofocus camera is focused to.
525 Tends to be less accurate as distance increases.
526 */
527 m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);
528 break;
529
530 case TAG_EXPOSURETIME:
531 /* Simplest way of expressing exposure time, so I
532 trust it most. (overwrite previously computd value
533 if there is one)
534 */
535 m_exifinfo->ExposureTime =
536 (float)ConvertAnyFormat(ValuePtr, Format);
537 break;
538
539 case TAG_SHUTTERSPEED:
540 /* More complicated way of expressing exposure time,
541 so only use this value if we don't already have it
542 from somewhere else.
543 */
544 if (m_exifinfo->ExposureTime == 0){
545 m_exifinfo->ExposureTime = (float)
546 (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)));
547 }
548 break;
549
550 case TAG_FLASH:
551 if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){
552 m_exifinfo->FlashUsed = 1;
553 }else{
554 m_exifinfo->FlashUsed = 0;
555 }
556 break;
557
558 case TAG_ORIENTATION:
559 m_exifinfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
560 if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){
561 strcpy(m_szLastError,"Undefined rotation value");
562 m_exifinfo->Orientation = 0;
563 }
564 break;
565
566 case TAG_EXIF_IMAGELENGTH:
567 case TAG_EXIF_IMAGEWIDTH:
568 /* Use largest of height and width to deal with images
569 that have been rotated to portrait format.
570 */
571 a = (int)ConvertAnyFormat(ValuePtr, Format);
572 if (ExifImageWidth < a) ExifImageWidth = a;
573 break;
574
575 case TAG_FOCALPLANEXRES:
576 m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);
577 break;
578
579 case TAG_FOCALPLANEYRES:
580 m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);
581 break;
582
583 case TAG_RESOLUTIONUNIT:
584 switch((int)ConvertAnyFormat(ValuePtr, Format)){
585 case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */
586 case 2: m_exifinfo->ResolutionUnit = 1.0f; break;
587 case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/
588 case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/
589 case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/
590 }
591 break;
592
593 case TAG_FOCALPLANEUNITS:
594 switch((int)ConvertAnyFormat(ValuePtr, Format)){
595 case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */
596 case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;
597 case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/
598 case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/
599 case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/
600 }
601 break;
602
603 // Remaining cases contributed by: Volker C. Schoech <schoech(at)gmx(dot)de>
604
605 case TAG_EXPOSURE_BIAS:
606 m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);
607 break;
608
609 case TAG_WHITEBALANCE:
610 m_exifinfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
611 break;
612
613 case TAG_METERING_MODE:
614 m_exifinfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
615 break;
616
617 case TAG_EXPOSURE_PROGRAM:
618 m_exifinfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
619 break;
620
621 case TAG_ISO_EQUIVALENT:
622 m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
623 if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200;
624 break;
625
626 case TAG_COMPRESSION_LEVEL:
627 m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
628 break;
629
630 case TAG_XRESOLUTION:
631 m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);
632 break;
633 case TAG_YRESOLUTION:
634 m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format);
635 break;
636
637 case TAG_THUMBNAIL_OFFSET:
638 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
639 break;
640
641 case TAG_THUMBNAIL_LENGTH:
642 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
643 break;
644
645 }
646
647 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
648 unsigned char * SubdirStart;
649 unsigned Offset = Get32u(ValuePtr);
650 if (Offset>8){
651 SubdirStart = OffsetBase + Offset;
652 if (SubdirStart < OffsetBase ||
653 SubdirStart > OffsetBase+ExifLength){
654 strcpy(m_szLastError,"Illegal subdirectory link");
655 return false;
656 }
657 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);
658 }
659 continue;
660 }
661 }
662
663
664 {
665 /* In addition to linking to subdirectories via exif tags,
666 there's also a potential link to another directory at the end
667 of each directory. This has got to be the result of a
668 committee!
669 */
670 unsigned char * SubdirStart;
671 unsigned Offset;
672 Offset = Get16u(DirStart+2+12*NumDirEntries);
673 if (Offset){
674 SubdirStart = OffsetBase + Offset;
675 if (SubdirStart < OffsetBase
676 || SubdirStart > OffsetBase+ExifLength){
677 strcpy(m_szLastError,"Illegal subdirectory link");
678 return false;
679 }
680 ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);
681 }
682 }
683
684
685 if (ThumbnailSize && ThumbnailOffset){
686 if (ThumbnailSize + ThumbnailOffset <= ExifLength){
687 /* The thumbnail pointer appears to be valid. Store it. */
688 m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset;
689 m_exifinfo->ThumbnailSize = ThumbnailSize;
690 }
691 }
692
693 return true;
694}
695////////////////////////////////////////////////////////////////////////////////
696/*--------------------------------------------------------------------------
697 Evaluate number, be it int, rational, or float from directory.
698--------------------------------------------------------------------------*/
699double CxImageJPG::CxExifInfo::ConvertAnyFormat(void * ValuePtr, int Format)
700{
701 double Value;
702 Value = 0;
703
704 switch(Format){
705 case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
706 case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break;
707
708 case FMT_USHORT: Value = Get16u(ValuePtr); break;
709 case FMT_ULONG: Value = Get32u(ValuePtr); break;
710
711 case FMT_URATIONAL:
712 case FMT_SRATIONAL:
713 {
714 int Num,Den;
715 Num = Get32s(ValuePtr);
716 Den = Get32s(4+(char *)ValuePtr);
717 if (Den == 0){
718 Value = 0;
719 }else{
720 Value = (double)Num/Den;
721 }
722 break;
723 }
724
725 case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
726 case FMT_SLONG: Value = Get32s(ValuePtr); break;
727
728 /* Not sure if this is correct (never seen float used in Exif format)
729 */
730 case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
731 case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
732 }
733 return Value;
734}
735////////////////////////////////////////////////////////////////////////////////
736void CxImageJPG::CxExifInfo::process_COM (const BYTE * Data, int length)
737{
738 int ch;
739 char Comment[MAX_COMMENT+1];
740 int nch;
741 int a;
742
743 nch = 0;
744
745 if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.
746
747 for (a=2;a<length;a++){
748 ch = Data[a];
749
750 if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.
751
752 if (isprint(ch) || ch == '\n' || ch == '\t'){
753 Comment[nch++] = (char)ch;
754 }else{
755 Comment[nch++] = '?';
756 }
757 }
758
759 Comment[nch] = '\0'; // Null terminate
760
761 //if (ShowTags) printf("COM marker comment: %s\n",Comment);
762
763 strcpy(m_exifinfo->Comments,Comment);
764}
765////////////////////////////////////////////////////////////////////////////////
766void CxImageJPG::CxExifInfo::process_SOFn (const BYTE * Data, int marker)
767{
768 int data_precision, num_components;
769
770 data_precision = Data[2];
771 m_exifinfo->Height = Get16m((void*)(Data+3));
772 m_exifinfo->Width = Get16m((void*)(Data+5));
773 num_components = Data[7];
774
775 if (num_components == 3){
776 m_exifinfo->IsColor = 1;
777 }else{
778 m_exifinfo->IsColor = 0;
779 }
780
781 m_exifinfo->Process = marker;
782
783 //if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
784 // ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
785}
786////////////////////////////////////////////////////////////////////////////////
787/**
788 * this will work only on a CxImageJPG object, if the image originally has valid EXIF data
789 \verbatim
790 CxImageJPG jpg;
791 CxIOFile in,out;
792 in.Open("D:\\exif_in.jpg","rb");
793 out.Open("D:\\exif_out.jpg","w+b");
794 jpg.Decode(&in);
795 if (jpg.IsValid()){
796 jpg.RotateLeft();
797 jpg.Encode(&out);
798 }
799 \endverbatim
800*/
801bool CxImageJPG::CxExifInfo::EncodeExif(CxFile * hFile)
802{
803 int a;
804
805 if (FindSection(M_SOS)==NULL){
806 strcpy(m_szLastError,"Can't write exif : didn't read all");
807 return false;
808 }
809
810 // Initial static jpeg marker.
811 hFile->PutC(0xff);
812 hFile->PutC(0xd8);
813
814 if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
815 // The image must start with an exif or jfif marker. If we threw those away, create one.
816 static BYTE JfifHead[18] = {
817 0xff, M_JFIF,
818 0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01,
819 0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00
820 };
821 hFile->Write(JfifHead, 18, 1);
822 }
823
824 // Write all the misc sections
825 for (a=0;a<SectionsRead-1;a++){
826 hFile->PutC(0xff);
827 hFile->PutC((unsigned char)(Sections[a].Type));
828 hFile->Write(Sections[a].Data, Sections[a].Size, 1);
829 }
830
831 // Write the remaining image data.
832 hFile->Write(Sections[a].Data, Sections[a].Size, 1);
833
834 return true;
835}
836////////////////////////////////////////////////////////////////////////////////
837void CxImageJPG::CxExifInfo::DiscardAllButExif()
838{
839 Section_t ExifKeeper;
840 Section_t CommentKeeper;
841 int a;
842
843 memset(&ExifKeeper, 0, sizeof(ExifKeeper));
844 memset(&CommentKeeper, 0, sizeof(ExifKeeper));
845
846 for (a=0;a<SectionsRead;a++){
847 if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
848 ExifKeeper = Sections[a];
849 }else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
850 CommentKeeper = Sections[a];
851 }else{
852 free(Sections[a].Data);
853 Sections[a].Data = 0;
854 }
855 }
856 SectionsRead = 0;
857 if (ExifKeeper.Type){
858 Sections[SectionsRead++] = ExifKeeper;
859 }
860 if (CommentKeeper.Type){
861 Sections[SectionsRead++] = CommentKeeper;
862 }
863}
864////////////////////////////////////////////////////////////////////////////////
865void* CxImageJPG::CxExifInfo::FindSection(int SectionType)
866{
867 int a;
868 for (a=0;a<SectionsRead-1;a++){
869 if (Sections[a].Type == SectionType){
870 return &Sections[a];
871 }
872 }
873 // Could not be found.
874 return NULL;
875}
876////////////////////////////////////////////////////////////////////////////////
877#endif // CXIMAGEJPG_SUPPORT_EXIF
878
Note: See TracBrowser for help on using the repository browser.