summaryrefslogtreecommitdiff
path: root/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
Unidiff
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.cpp18
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
5PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave ) 4PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave )
6 5
7#include <qtopia/timestring.h> 6/* OPIE */
7#include <opie2/odebug.h>
8#include <qpe/timestring.h>
9using 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
24typedef enum { 28typedef 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
118class FatalError { 122class FatalError {
119 const char* ex; 123 const char* ex;
120public: 124public:
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
127static unsigned char * LastExifRefd; 131static unsigned char * LastExifRefd;
128static int ExifSettingsLength; 132static int ExifSettingsLength;
129static double FocalplaneXRes; 133static double FocalplaneXRes;
130static double FocalplaneUnits; 134static double FocalplaneUnits;
131static int MotorolaOrder = 0; 135static int MotorolaOrder = 0;
132static int SectionsRead; 136static 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//--------------------------------------------------------------------------
242int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) 246int 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//--------------------------------------------------------------------------
905bool ExifData::scan(const QString & path) 909bool 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
939bool ExifData::isThumbnailSane() { 943bool ExifData::isThumbnailSane() {
940 if (Thumbnail.isNull()) return false; 944 if (Thumbnail.isNull()) return false;