Diffstat (limited to 'noncore/graphics/opie-eye/slave/jpeg_slave.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/graphics/opie-eye/slave/jpeg_slave.cpp | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp index 086b47f..fb7d5de 100644 --- a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp +++ b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp | |||
@@ -1,31 +1,35 @@ | |||
1 | #include "jpeg_slave.h" | 1 | #include "jpeg_slave.h" |
2 | |||
3 | #include "thumbnailtool.h" | 2 | #include "thumbnailtool.h" |
4 | 3 | ||
5 | PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave ) | 4 | PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave ) |
6 | 5 | ||
7 | #include <qtopia/timestring.h> | 6 | /* OPIE */ |
7 | #include <opie2/odebug.h> | ||
8 | #include <qpe/timestring.h> | ||
9 | using namespace Opie::Core; | ||
10 | |||
11 | /* QT */ | ||
8 | #include <qobject.h> | 12 | #include <qobject.h> |
9 | #include <qimage.h> | 13 | #include <qimage.h> |
10 | 14 | ||
11 | /** | 15 | /** |
12 | exif.h | 16 | exif.h |
13 | */ | 17 | */ |
14 | 18 | ||
15 | #include <stdio.h> | 19 | #include <stdio.h> |
16 | #include <stdlib.h> | 20 | #include <stdlib.h> |
17 | #include <math.h> | 21 | #include <math.h> |
18 | #include <time.h> | 22 | #include <time.h> |
19 | 23 | ||
20 | #include <qstring.h> | 24 | #include <qstring.h> |
21 | #include <qfile.h> | 25 | #include <qfile.h> |
22 | #include <qimage.h> | 26 | #include <qimage.h> |
23 | 27 | ||
24 | typedef enum { | 28 | typedef enum { |
25 | READ_EXIF = 1, | 29 | READ_EXIF = 1, |
26 | READ_IMAGE = 2, | 30 | READ_IMAGE = 2, |
27 | READ_ALL = 3 | 31 | READ_ALL = 3 |
28 | }ReadMode_t; | 32 | }ReadMode_t; |
29 | 33 | ||
30 | //-------------------------------------------------------------------------- | 34 | //-------------------------------------------------------------------------- |
31 | // This structure is used to store jpeg file sections in memory. | 35 | // This structure is used to store jpeg file sections in memory. |
@@ -98,49 +102,49 @@ public: | |||
98 | int getProcess() { return Process; } | 102 | int getProcess() { return Process; } |
99 | int getFlashUsed() { return FlashUsed; } | 103 | int getFlashUsed() { return FlashUsed; } |
100 | float getFocalLength() { return FocalLength; } | 104 | float getFocalLength() { return FocalLength; } |
101 | float getExposureTime() { return ExposureTime; } | 105 | float getExposureTime() { return ExposureTime; } |
102 | float getApertureFNumber() { return ApertureFNumber; } | 106 | float getApertureFNumber() { return ApertureFNumber; } |
103 | float getDistance() { return Distance; } | 107 | float getDistance() { return Distance; } |
104 | int getWhitebalance() { return Whitebalance; } | 108 | int getWhitebalance() { return Whitebalance; } |
105 | int getMeteringMode() { return MeteringMode; } | 109 | int getMeteringMode() { return MeteringMode; } |
106 | float getCCDWidth() { return CCDWidth; } | 110 | float getCCDWidth() { return CCDWidth; } |
107 | float getExposureBias() { return ExposureBias; } | 111 | float getExposureBias() { return ExposureBias; } |
108 | int getExposureProgram() { return ExposureProgram; } | 112 | int getExposureProgram() { return ExposureProgram; } |
109 | int getISOequivalent() { return ISOequivalent; } | 113 | int getISOequivalent() { return ISOequivalent; } |
110 | int getCompressionLevel() { return CompressionLevel; } | 114 | int getCompressionLevel() { return CompressionLevel; } |
111 | QString getUserComment() { return UserComment; } | 115 | QString getUserComment() { return UserComment; } |
112 | QString getComment() { return Comment; } | 116 | QString getComment() { return Comment; } |
113 | QImage getThumbnail(); | 117 | QImage getThumbnail(); |
114 | bool isThumbnailSane(); | 118 | bool isThumbnailSane(); |
115 | bool isNullThumbnail() { return !isThumbnailSane(); } | 119 | bool isNullThumbnail() { return !isThumbnailSane(); } |
116 | }; | 120 | }; |
117 | 121 | ||
118 | class FatalError { | 122 | class FatalError { |
119 | const char* ex; | 123 | const char* ex; |
120 | public: | 124 | public: |
121 | FatalError(const char* s) { ex = s; } | 125 | FatalError(const char* s) { ex = s; } |
122 | void debug_print() const { qWarning("exception: %s", ex ); } | 126 | void debug_print() const { owarn << "exception: " << ex << "" << oendl; } |
123 | }; | 127 | }; |
124 | 128 | ||
125 | 129 | ||
126 | 130 | ||
127 | static unsigned char * LastExifRefd; | 131 | static unsigned char * LastExifRefd; |
128 | static int ExifSettingsLength; | 132 | static int ExifSettingsLength; |
129 | static double FocalplaneXRes; | 133 | static double FocalplaneXRes; |
130 | static double FocalplaneUnits; | 134 | static double FocalplaneUnits; |
131 | static int MotorolaOrder = 0; | 135 | static int MotorolaOrder = 0; |
132 | static int SectionsRead; | 136 | static int SectionsRead; |
133 | //static int HaveAll; | 137 | //static int HaveAll; |
134 | 138 | ||
135 | //-------------------------------------------------------------------------- | 139 | //-------------------------------------------------------------------------- |
136 | // Table of Jpeg encoding process names | 140 | // Table of Jpeg encoding process names |
137 | 141 | ||
138 | #define M_SOF0 0xC0 // Start Of Frame N | 142 | #define M_SOF0 0xC0 // Start Of Frame N |
139 | #define M_SOF1 0xC1 // N indicates which compression process | 143 | #define M_SOF1 0xC1 // N indicates which compression process |
140 | #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use | 144 | #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use |
141 | #define M_SOF3 0xC3 | 145 | #define M_SOF3 0xC3 |
142 | #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers | 146 | #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers |
143 | #define M_SOF6 0xC6 | 147 | #define M_SOF6 0xC6 |
144 | #define M_SOF7 0xC7 | 148 | #define M_SOF7 0xC7 |
145 | #define M_SOF9 0xC9 | 149 | #define M_SOF9 0xC9 |
146 | #define M_SOF10 0xCA | 150 | #define M_SOF10 0xCA |
@@ -241,49 +245,49 @@ static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; | |||
241 | //-------------------------------------------------------------------------- | 245 | //-------------------------------------------------------------------------- |
242 | int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) | 246 | int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) |
243 | { | 247 | { |
244 | int a; | 248 | int a; |
245 | 249 | ||
246 | a = infile.getch(); | 250 | a = infile.getch(); |
247 | 251 | ||
248 | if (a != 0xff || infile.getch() != M_SOI) { | 252 | if (a != 0xff || infile.getch() != M_SOI) { |
249 | SectionsRead = 0; | 253 | SectionsRead = 0; |
250 | return false; | 254 | return false; |
251 | } | 255 | } |
252 | for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ | 256 | for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ |
253 | int marker = 0; | 257 | int marker = 0; |
254 | int got; | 258 | int got; |
255 | unsigned int ll,lh; | 259 | unsigned int ll,lh; |
256 | unsigned int itemlen; | 260 | unsigned int itemlen; |
257 | uchar * Data; | 261 | uchar * Data; |
258 | 262 | ||
259 | for (a=0;a<7;a++){ | 263 | for (a=0;a<7;a++){ |
260 | marker = infile.getch(); | 264 | marker = infile.getch(); |
261 | if (marker != 0xff) break; | 265 | if (marker != 0xff) break; |
262 | 266 | ||
263 | if (a >= 6){ | 267 | if (a >= 6){ |
264 | 268 | ||
265 | qWarning( "too many padding bytes" ); | 269 | owarn << "too many padding bytes" << oendl; |
266 | return false; | 270 | return false; |
267 | 271 | ||
268 | } | 272 | } |
269 | } | 273 | } |
270 | 274 | ||
271 | if (marker == 0xff){ | 275 | if (marker == 0xff){ |
272 | // 0xff is legal padding, but if we get that many, something's wrong. | 276 | // 0xff is legal padding, but if we get that many, something's wrong. |
273 | return false; | 277 | return false; |
274 | } | 278 | } |
275 | 279 | ||
276 | Sections[SectionsRead].Type = marker; | 280 | Sections[SectionsRead].Type = marker; |
277 | 281 | ||
278 | // Read the length of the section. | 282 | // Read the length of the section. |
279 | lh = (uchar) infile.getch(); | 283 | lh = (uchar) infile.getch(); |
280 | ll = (uchar) infile.getch(); | 284 | ll = (uchar) infile.getch(); |
281 | 285 | ||
282 | itemlen = (lh << 8) | ll; | 286 | itemlen = (lh << 8) | ll; |
283 | 287 | ||
284 | if (itemlen < 2) { | 288 | if (itemlen < 2) { |
285 | return false;; | 289 | return false;; |
286 | } | 290 | } |
287 | 291 | ||
288 | Sections[SectionsRead].Size = itemlen; | 292 | Sections[SectionsRead].Size = itemlen; |
289 | 293 | ||
@@ -306,49 +310,49 @@ int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) | |||
306 | // If reading entire image is requested, read the rest of the data. | 310 | // If reading entire image is requested, read the rest of the data. |
307 | if (ReadMode & READ_IMAGE){ | 311 | if (ReadMode & READ_IMAGE){ |
308 | unsigned long size; | 312 | unsigned long size; |
309 | 313 | ||
310 | size = QMAX( 0ul, infile.size()-infile.at() ); | 314 | size = QMAX( 0ul, infile.size()-infile.at() ); |
311 | Data = (uchar *)malloc(size); | 315 | Data = (uchar *)malloc(size); |
312 | if (Data == NULL){ | 316 | if (Data == NULL){ |
313 | return false; | 317 | return false; |
314 | } | 318 | } |
315 | 319 | ||
316 | got = infile.readBlock((char*)Data, size); | 320 | got = infile.readBlock((char*)Data, size); |
317 | if (( unsigned ) got != size){ | 321 | if (( unsigned ) got != size){ |
318 | return false; | 322 | return false; |
319 | } | 323 | } |
320 | 324 | ||
321 | Sections[SectionsRead].Data = Data; | 325 | Sections[SectionsRead].Data = Data; |
322 | Sections[SectionsRead].Size = size; | 326 | Sections[SectionsRead].Size = size; |
323 | Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; | 327 | Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; |
324 | SectionsRead ++; | 328 | SectionsRead ++; |
325 | //HaveAll = 1; | 329 | //HaveAll = 1; |
326 | } | 330 | } |
327 | return true; | 331 | return true; |
328 | 332 | ||
329 | case M_EOI: // in case it's a tables-only JPEG stream | 333 | case M_EOI: // in case it's a tables-only JPEG stream |
330 | qWarning( "No image in jpeg!" ); | 334 | owarn << "No image in jpeg!" << oendl; |
331 | return false; | 335 | return false; |
332 | 336 | ||
333 | case M_COM: // Comment section | 337 | case M_COM: // Comment section |
334 | // pieczy 2002-02-12 | 338 | // pieczy 2002-02-12 |
335 | // now the User comment goes to UserComment | 339 | // now the User comment goes to UserComment |
336 | // so we can store a Comment section also in READ_EXIF mode | 340 | // so we can store a Comment section also in READ_EXIF mode |
337 | process_COM(Data, itemlen); | 341 | process_COM(Data, itemlen); |
338 | break; | 342 | break; |
339 | 343 | ||
340 | case M_JFIF: | 344 | case M_JFIF: |
341 | // Regular jpegs always have this tag, exif images have the exif | 345 | // Regular jpegs always have this tag, exif images have the exif |
342 | // marker instead, althogh ACDsee will write images with both markers. | 346 | // marker instead, althogh ACDsee will write images with both markers. |
343 | // this program will re-create this marker on absence of exif marker. | 347 | // this program will re-create this marker on absence of exif marker. |
344 | // hence no need to keep the copy from the file. | 348 | // hence no need to keep the copy from the file. |
345 | free(Sections[--SectionsRead].Data); | 349 | free(Sections[--SectionsRead].Data); |
346 | break; | 350 | break; |
347 | 351 | ||
348 | case M_EXIF: | 352 | case M_EXIF: |
349 | // Seen files from some 'U-lead' software with Vivitar scanner | 353 | // Seen files from some 'U-lead' software with Vivitar scanner |
350 | // that uses marker 31 for non exif stuff. Thus make sure | 354 | // that uses marker 31 for non exif stuff. Thus make sure |
351 | // it says 'Exif' in the section before treating it as exif. | 355 | // it says 'Exif' in the section before treating it as exif. |
352 | if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ | 356 | if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ |
353 | process_EXIF((uchar *)Data, itemlen); | 357 | process_EXIF((uchar *)Data, itemlen); |
354 | }else{ | 358 | }else{ |
@@ -705,49 +709,49 @@ void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBa | |||
705 | ProcessExifDir(SubdirStart, OffsetBase, ExifLength); | 709 | ProcessExifDir(SubdirStart, OffsetBase, ExifLength); |
706 | continue; | 710 | continue; |
707 | } | 711 | } |
708 | } | 712 | } |
709 | 713 | ||
710 | { | 714 | { |
711 | // In addition to linking to subdirectories via exif tags, | 715 | // In addition to linking to subdirectories via exif tags, |
712 | // there's also a potential link to another directory at the end of each | 716 | // there's also a potential link to another directory at the end of each |
713 | // directory. this has got to be the result of a comitee! | 717 | // directory. this has got to be the result of a comitee! |
714 | unsigned char * SubdirStart; | 718 | unsigned char * SubdirStart; |
715 | unsigned Offset; | 719 | unsigned Offset; |
716 | 720 | ||
717 | if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ | 721 | if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ |
718 | Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); | 722 | Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); |
719 | // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. | 723 | // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT. |
720 | // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. | 724 | // Adding OffsetBase to it produces an overflow, so compare with ExifLength here. |
721 | // See http://bugs.kde.org/show_bug.cgi?id=54542 | 725 | // See http://bugs.kde.org/show_bug.cgi?id=54542 |
722 | if (Offset && Offset < ExifLength){ | 726 | if (Offset && Offset < ExifLength){ |
723 | SubdirStart = OffsetBase + Offset; | 727 | SubdirStart = OffsetBase + Offset; |
724 | if (SubdirStart > OffsetBase+ExifLength){ | 728 | if (SubdirStart > OffsetBase+ExifLength){ |
725 | if (SubdirStart < OffsetBase+ExifLength+20){ | 729 | if (SubdirStart < OffsetBase+ExifLength+20){ |
726 | // Jhead 1.3 or earlier would crop the whole directory! | 730 | // Jhead 1.3 or earlier would crop the whole directory! |
727 | // As Jhead produces this form of format incorrectness, | 731 | // As Jhead produces this form of format incorrectness, |
728 | // I'll just let it pass silently | 732 | // I'll just let it pass silently |
729 | qWarning( "Thumbnail removed with Jhead 1.3 or earlier" ); | 733 | owarn << "Thumbnail removed with Jhead 1.3 or earlier" << oendl; |
730 | }else{ | 734 | }else{ |
731 | return; | 735 | return; |
732 | } | 736 | } |
733 | }else{ | 737 | }else{ |
734 | if (SubdirStart <= OffsetBase+ExifLength){ | 738 | if (SubdirStart <= OffsetBase+ExifLength){ |
735 | ProcessExifDir(SubdirStart, OffsetBase, ExifLength); | 739 | ProcessExifDir(SubdirStart, OffsetBase, ExifLength); |
736 | } | 740 | } |
737 | } | 741 | } |
738 | } | 742 | } |
739 | }else{ | 743 | }else{ |
740 | // The exif header ends before the last next directory pointer. | 744 | // The exif header ends before the last next directory pointer. |
741 | } | 745 | } |
742 | } | 746 | } |
743 | 747 | ||
744 | if (ThumbnailSize && ThumbnailOffset){ | 748 | if (ThumbnailSize && ThumbnailOffset){ |
745 | if (ThumbnailSize + ThumbnailOffset <= ExifLength){ | 749 | if (ThumbnailSize + ThumbnailOffset <= ExifLength){ |
746 | // The thumbnail pointer appears to be valid. Store it. | 750 | // The thumbnail pointer appears to be valid. Store it. |
747 | Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); | 751 | Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); |
748 | } | 752 | } |
749 | } | 753 | } |
750 | } | 754 | } |
751 | 755 | ||
752 | //-------------------------------------------------------------------------- | 756 | //-------------------------------------------------------------------------- |
753 | // Process a COM marker. We want to leave the bytes unchanged. The | 757 | // Process a COM marker. We want to leave the bytes unchanged. The |
@@ -892,49 +896,49 @@ ExifData::ExifData() | |||
892 | ExposureTime = 0; | 896 | ExposureTime = 0; |
893 | ApertureFNumber = 0; | 897 | ApertureFNumber = 0; |
894 | Distance = 0; | 898 | Distance = 0; |
895 | CCDWidth = 0; | 899 | CCDWidth = 0; |
896 | ExposureBias = 0; | 900 | ExposureBias = 0; |
897 | ExposureProgram = 0; | 901 | ExposureProgram = 0; |
898 | ISOequivalent = 0; | 902 | ISOequivalent = 0; |
899 | CompressionLevel = 0; | 903 | CompressionLevel = 0; |
900 | } | 904 | } |
901 | 905 | ||
902 | //-------------------------------------------------------------------------- | 906 | //-------------------------------------------------------------------------- |
903 | // process a EXIF jpeg file | 907 | // process a EXIF jpeg file |
904 | //-------------------------------------------------------------------------- | 908 | //-------------------------------------------------------------------------- |
905 | bool ExifData::scan(const QString & path) | 909 | bool ExifData::scan(const QString & path) |
906 | { | 910 | { |
907 | int ret; | 911 | int ret; |
908 | 912 | ||
909 | QFile f(path); | 913 | QFile f(path); |
910 | f.open(IO_ReadOnly); | 914 | f.open(IO_ReadOnly); |
911 | 915 | ||
912 | // Scan the JPEG headers. | 916 | // Scan the JPEG headers. |
913 | ret = ReadJpegSections(f, READ_EXIF); | 917 | ret = ReadJpegSections(f, READ_EXIF); |
914 | 918 | ||
915 | if (ret == false){ | 919 | if (ret == false){ |
916 | qWarning( "Not JPEG file!" ); | 920 | owarn << "Not JPEG file!" << oendl; |
917 | DiscardData(); | 921 | DiscardData(); |
918 | f.close(); | 922 | f.close(); |
919 | return false; | 923 | return false; |
920 | } | 924 | } |
921 | f.close(); | 925 | f.close(); |
922 | DiscardData(); | 926 | DiscardData(); |
923 | 927 | ||
924 | //now make the strings clean, | 928 | //now make the strings clean, |
925 | // for exmaple my Casio is a "QV-4000 " | 929 | // for exmaple my Casio is a "QV-4000 " |
926 | CameraMake = CameraMake.stripWhiteSpace(); | 930 | CameraMake = CameraMake.stripWhiteSpace(); |
927 | CameraModel = CameraModel.stripWhiteSpace(); | 931 | CameraModel = CameraModel.stripWhiteSpace(); |
928 | UserComment = UserComment.stripWhiteSpace(); | 932 | UserComment = UserComment.stripWhiteSpace(); |
929 | Comment = Comment.stripWhiteSpace(); | 933 | Comment = Comment.stripWhiteSpace(); |
930 | return true; | 934 | return true; |
931 | } | 935 | } |
932 | 936 | ||
933 | //-------------------------------------------------------------------------- | 937 | //-------------------------------------------------------------------------- |
934 | // Does the embedded thumbnail match the jpeg image? | 938 | // Does the embedded thumbnail match the jpeg image? |
935 | //-------------------------------------------------------------------------- | 939 | //-------------------------------------------------------------------------- |
936 | #ifndef JPEG_TOL | 940 | #ifndef JPEG_TOL |
937 | #define JPEG_TOL 0.02 | 941 | #define JPEG_TOL 0.02 |
938 | #endif | 942 | #endif |
939 | bool ExifData::isThumbnailSane() { | 943 | bool ExifData::isThumbnailSane() { |
940 | if (Thumbnail.isNull()) return false; | 944 | if (Thumbnail.isNull()) return false; |