summaryrefslogtreecommitdiff
authoralwin <alwin>2004-11-01 13:33:51 (UTC)
committer alwin <alwin>2004-11-01 13:33:51 (UTC)
commit915af02212ea80e43da5bcc24415e3e48778bea9 (patch) (unidiff)
treeeff6dbcc2f1e62dfbb8f6ababe183306fe2077e1
parentb3153506a1be76a386f23a3af44f84042d148111 (diff)
downloadopie-915af02212ea80e43da5bcc24415e3e48778bea9.zip
opie-915af02212ea80e43da5bcc24415e3e48778bea9.tar.gz
opie-915af02212ea80e43da5bcc24415e3e48778bea9.tar.bz2
when jpeg image is smaller than requested thumbsize it will not use
scaled loading
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/graphics/opie-eye/slave/jpeg_slave.cpp52
1 files changed, 30 insertions, 22 deletions
diff --git a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
index fb7d5de..1bb81d9 100644
--- a/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
+++ b/noncore/graphics/opie-eye/slave/jpeg_slave.cpp
@@ -1,40 +1,40 @@
1#include "jpeg_slave.h" 1#include "jpeg_slave.h"
2#include "thumbnailtool.h" 2#include "thumbnailtool.h"
3 3
4PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave ) 4PHUNK_VIEW_INTERFACE( "JPEG", JpegSlave )
5 5
6/* OPIE */ 6/* OPIE */
7#include <opie2/odebug.h> 7#include <opie2/odebug.h>
8#include <qpe/timestring.h> 8#include <qpe/timestring.h>
9using namespace Opie::Core; 9using namespace Opie::Core;
10 10
11/* QT */ 11/* QT */
12#include <qobject.h> 12#include <qobject.h>
13#include <qimage.h> 13#include <qimage.h>
14 14
15/** 15/**
16 exif.h 16 exif.h
17*/ 17*/
18 18
19#include <stdio.h> 19#include <stdio.h>
20#include <stdlib.h> 20#include <stdlib.h>
21#include <math.h> 21#include <math.h>
22#include <time.h> 22#include <time.h>
23 23
24#include <qstring.h> 24#include <qstring.h>
25#include <qfile.h> 25#include <qfile.h>
26#include <qimage.h> 26#include <qimage.h>
27 27
28typedef enum { 28typedef enum {
29 READ_EXIF = 1, 29 READ_EXIF = 1,
30 READ_IMAGE = 2, 30 READ_IMAGE = 2,
31 READ_ALL = 3 31 READ_ALL = 3
32}ReadMode_t; 32}ReadMode_t;
33 33
34//-------------------------------------------------------------------------- 34//--------------------------------------------------------------------------
35// This structure is used to store jpeg file sections in memory. 35// This structure is used to store jpeg file sections in memory.
36typedef struct { 36typedef struct {
37 uchar * Data; 37 uchar * Data;
38 int Type; 38 int Type;
39 unsigned Size; 39 unsigned Size;
40}Section_t; 40}Section_t;
@@ -245,49 +245,49 @@ static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
245//-------------------------------------------------------------------------- 245//--------------------------------------------------------------------------
246int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) 246int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
247{ 247{
248 int a; 248 int a;
249 249
250 a = infile.getch(); 250 a = infile.getch();
251 251
252 if (a != 0xff || infile.getch() != M_SOI) { 252 if (a != 0xff || infile.getch() != M_SOI) {
253 SectionsRead = 0; 253 SectionsRead = 0;
254 return false; 254 return false;
255 } 255 }
256 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){ 256 for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){
257 int marker = 0; 257 int marker = 0;
258 int got; 258 int got;
259 unsigned int ll,lh; 259 unsigned int ll,lh;
260 unsigned int itemlen; 260 unsigned int itemlen;
261 uchar * Data; 261 uchar * Data;
262 262
263 for (a=0;a<7;a++){ 263 for (a=0;a<7;a++){
264 marker = infile.getch(); 264 marker = infile.getch();
265 if (marker != 0xff) break; 265 if (marker != 0xff) break;
266 266
267 if (a >= 6){ 267 if (a >= 6){
268 268
269 owarn << "too many padding bytes" << oendl; 269 owarn << "too many padding bytes" << oendl;
270 return false; 270 return false;
271 271
272 } 272 }
273 } 273 }
274 274
275 if (marker == 0xff){ 275 if (marker == 0xff){
276 // 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.
277 return false; 277 return false;
278 } 278 }
279 279
280 Sections[SectionsRead].Type = marker; 280 Sections[SectionsRead].Type = marker;
281 281
282 // Read the length of the section. 282 // Read the length of the section.
283 lh = (uchar) infile.getch(); 283 lh = (uchar) infile.getch();
284 ll = (uchar) infile.getch(); 284 ll = (uchar) infile.getch();
285 285
286 itemlen = (lh << 8) | ll; 286 itemlen = (lh << 8) | ll;
287 287
288 if (itemlen < 2) { 288 if (itemlen < 2) {
289 return false;; 289 return false;;
290 } 290 }
291 291
292 Sections[SectionsRead].Size = itemlen; 292 Sections[SectionsRead].Size = itemlen;
293 293
@@ -310,56 +310,56 @@ int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
310 // 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.
311 if (ReadMode & READ_IMAGE){ 311 if (ReadMode & READ_IMAGE){
312 unsigned long size; 312 unsigned long size;
313 313
314 size = QMAX( 0ul, infile.size()-infile.at() ); 314 size = QMAX( 0ul, infile.size()-infile.at() );
315 Data = (uchar *)malloc(size); 315 Data = (uchar *)malloc(size);
316 if (Data == NULL){ 316 if (Data == NULL){
317 return false; 317 return false;
318 } 318 }
319 319
320 got = infile.readBlock((char*)Data, size); 320 got = infile.readBlock((char*)Data, size);
321 if (( unsigned ) got != size){ 321 if (( unsigned ) got != size){
322 return false; 322 return false;
323 } 323 }
324 324
325 Sections[SectionsRead].Data = Data; 325 Sections[SectionsRead].Data = Data;
326 Sections[SectionsRead].Size = size; 326 Sections[SectionsRead].Size = size;
327 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; 327 Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
328 SectionsRead ++; 328 SectionsRead ++;
329 //HaveAll = 1; 329 //HaveAll = 1;
330 } 330 }
331 return true; 331 return true;
332 332
333 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
334 owarn << "No image in jpeg!" << oendl; 334 owarn << "No image in jpeg!" << oendl;
335 return false; 335 return false;
336 336
337 case M_COM: // Comment section 337 case M_COM: // Comment section
338 // pieczy 2002-02-12 338 // pieczy 2002-02-12
339 // now the User comment goes to UserComment 339 // now the User comment goes to UserComment
340 // 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
341 process_COM(Data, itemlen); 341 process_COM(Data, itemlen);
342 break; 342 break;
343 343
344 case M_JFIF: 344 case M_JFIF:
345 // Regular jpegs always have this tag, exif images have the exif 345 // Regular jpegs always have this tag, exif images have the exif
346 // marker instead, althogh ACDsee will write images with both markers. 346 // marker instead, althogh ACDsee will write images with both markers.
347 // 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.
348 // hence no need to keep the copy from the file. 348 // hence no need to keep the copy from the file.
349 free(Sections[--SectionsRead].Data); 349 free(Sections[--SectionsRead].Data);
350 break; 350 break;
351 351
352 case M_EXIF: 352 case M_EXIF:
353 // Seen files from some 'U-lead' software with Vivitar scanner 353 // Seen files from some 'U-lead' software with Vivitar scanner
354 // that uses marker 31 for non exif stuff. Thus make sure 354 // that uses marker 31 for non exif stuff. Thus make sure
355 // it says 'Exif' in the section before treating it as exif. 355 // it says 'Exif' in the section before treating it as exif.
356 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ 356 if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
357 process_EXIF((uchar *)Data, itemlen); 357 process_EXIF((uchar *)Data, itemlen);
358 }else{ 358 }else{
359 // Discard this section. 359 // Discard this section.
360 free(Sections[--SectionsRead].Data); 360 free(Sections[--SectionsRead].Data);
361 } 361 }
362 break; 362 break;
363 363
364 case M_SOF0: 364 case M_SOF0:
365 case M_SOF1: 365 case M_SOF1:
@@ -526,91 +526,91 @@ void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBa
526 526
527 return; 527 return;
528 } 528 }
529 ValuePtr = OffsetBase+OffsetVal; 529 ValuePtr = OffsetBase+OffsetVal;
530 }else{ 530 }else{
531 // 4 bytes or less and value is in the dir entry itself 531 // 4 bytes or less and value is in the dir entry itself
532 ValuePtr = (unsigned char *)DirEntry+8; 532 ValuePtr = (unsigned char *)DirEntry+8;
533 } 533 }
534 534
535 if (LastExifRefd < ValuePtr+ByteCount){ 535 if (LastExifRefd < ValuePtr+ByteCount){
536 // Keep track of last byte in the exif header that was actually referenced. 536 // Keep track of last byte in the exif header that was actually referenced.
537 // That way, we know where the discardable thumbnail data begins. 537 // That way, we know where the discardable thumbnail data begins.
538 LastExifRefd = ValuePtr+ByteCount; 538 LastExifRefd = ValuePtr+ByteCount;
539 } 539 }
540 540
541 // Extract useful components of tag 541 // Extract useful components of tag
542 switch(Tag){ 542 switch(Tag){
543 543
544 case TAG_MAKE: 544 case TAG_MAKE:
545 ExifData::CameraMake = QString((char*)ValuePtr); 545 ExifData::CameraMake = QString((char*)ValuePtr);
546 break; 546 break;
547 547
548 case TAG_MODEL: 548 case TAG_MODEL:
549 ExifData::CameraModel = QString((char*)ValuePtr); 549 ExifData::CameraModel = QString((char*)ValuePtr);
550 break; 550 break;
551 551
552 case TAG_ORIENTATION: 552 case TAG_ORIENTATION:
553 Orientation = (int)ConvertAnyFormat(ValuePtr, Format); 553 Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
554 break; 554 break;
555 555
556 case TAG_DATETIME_ORIGINAL: 556 case TAG_DATETIME_ORIGINAL:
557 DateTime = QString((char*)ValuePtr); 557 DateTime = QString((char*)ValuePtr);
558 break; 558 break;
559 559
560 case TAG_USERCOMMENT: 560 case TAG_USERCOMMENT:
561 // Olympus has this padded with trailing spaces. Remove these first. 561 // Olympus has this padded with trailing spaces. Remove these first.
562 for (a=ByteCount;;){ 562 for (a=ByteCount;;){
563 a--; 563 a--;
564 if ((ValuePtr)[a] == ' '){ 564 if ((ValuePtr)[a] == ' '){
565 (ValuePtr)[a] = '\0'; 565 (ValuePtr)[a] = '\0';
566 }else{ 566 }else{
567 break; 567 break;
568 } 568 }
569 if (a == 0) break; 569 if (a == 0) break;
570 } 570 }
571 571
572 // Copy the comment 572 // Copy the comment
573 if (memcmp(ValuePtr, "ASCII",5) == 0){ 573 if (memcmp(ValuePtr, "ASCII",5) == 0){
574 for (a=5;a<10;a++){ 574 for (a=5;a<10;a++){
575 int c; 575 int c;
576 c = (ValuePtr)[a]; 576 c = (ValuePtr)[a];
577 if (c != '\0' && c != ' '){ 577 if (c != '\0' && c != ' '){
578 //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199); 578 //strncpy(ImageInfo.Comments, (const char*)(a+ValuePtr), 199);
579 UserComment.sprintf("%s", (const char*)(a+ValuePtr)); 579 UserComment.sprintf("%s", (const char*)(a+ValuePtr));
580 break; 580 break;
581 } 581 }
582 } 582 }
583 }else{ 583 }else{
584 //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199); 584 //strncpy(ImageInfo.Comments, (const char*)ValuePtr, 199);
585 UserComment.sprintf("%s", (const char*)ValuePtr); 585 UserComment.sprintf("%s", (const char*)ValuePtr);
586 } 586 }
587 break; 587 break;
588 588
589 case TAG_FNUMBER: 589 case TAG_FNUMBER:
590 // Simplest way of expressing aperture, so I trust it the most. 590 // Simplest way of expressing aperture, so I trust it the most.
591 // (overwrite previously computd value if there is one) 591 // (overwrite previously computd value if there is one)
592 ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); 592 ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
593 break; 593 break;
594 594
595 case TAG_APERTURE: 595 case TAG_APERTURE:
596 case TAG_MAXAPERTURE: 596 case TAG_MAXAPERTURE:
597 // More relevant info always comes earlier, so only use this field if we don't 597 // More relevant info always comes earlier, so only use this field if we don't
598 // have appropriate aperture information yet. 598 // have appropriate aperture information yet.
599 if (ExifData::ApertureFNumber == 0){ 599 if (ExifData::ApertureFNumber == 0){
600 ExifData::ApertureFNumber 600 ExifData::ApertureFNumber
601 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5); 601 = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
602 } 602 }
603 break; 603 break;
604 604
605 case TAG_FOCALLENGTH: 605 case TAG_FOCALLENGTH:
606 // Nice digital cameras actually save the focal length as a function 606 // Nice digital cameras actually save the focal length as a function
607 // of how farthey are zoomed in. 607 // of how farthey are zoomed in.
608 ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); 608 ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
609 break; 609 break;
610 610
611 case TAG_SUBJECT_DISTANCE: 611 case TAG_SUBJECT_DISTANCE:
612 // Inidcates the distacne the autofocus camera is focused to. 612 // Inidcates the distacne the autofocus camera is focused to.
613 // Tends to be less accurate as distance increases. 613 // Tends to be less accurate as distance increases.
614 ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format); 614 ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format);
615 break; 615 break;
616 616
@@ -645,131 +645,131 @@ void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBa
645 645
646 case TAG_FOCALPLANEXRES: 646 case TAG_FOCALPLANEXRES:
647 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); 647 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
648 break; 648 break;
649 649
650 case TAG_FOCALPLANEUNITS: 650 case TAG_FOCALPLANEUNITS:
651 switch((int)ConvertAnyFormat(ValuePtr, Format)){ 651 switch((int)ConvertAnyFormat(ValuePtr, Format)){
652 case 1: FocalplaneUnits = 25.4; break; // inch 652 case 1: FocalplaneUnits = 25.4; break; // inch
653 case 2: 653 case 2:
654 // According to the information I was using, 2 means meters. 654 // According to the information I was using, 2 means meters.
655 // But looking at the Cannon powershot's files, inches is the only 655 // But looking at the Cannon powershot's files, inches is the only
656 // sensible value. 656 // sensible value.
657 FocalplaneUnits = 25.4; 657 FocalplaneUnits = 25.4;
658 break; 658 break;
659 659
660 case 3: FocalplaneUnits = 10; break; // centimeter 660 case 3: FocalplaneUnits = 10; break; // centimeter
661 case 4: FocalplaneUnits = 1; break; // milimeter 661 case 4: FocalplaneUnits = 1; break; // milimeter
662 case 5: FocalplaneUnits = .001; break; // micrometer 662 case 5: FocalplaneUnits = .001; break; // micrometer
663 } 663 }
664 break; 664 break;
665 665
666 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de) 666 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
667 667
668 case TAG_EXPOSURE_BIAS: 668 case TAG_EXPOSURE_BIAS:
669 ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); 669 ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
670 break; 670 break;
671 671
672 case TAG_WHITEBALANCE: 672 case TAG_WHITEBALANCE:
673 ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); 673 ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
674 break; 674 break;
675 675
676 case TAG_METERING_MODE: 676 case TAG_METERING_MODE:
677 ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); 677 ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
678 break; 678 break;
679 679
680 case TAG_EXPOSURE_PROGRAM: 680 case TAG_EXPOSURE_PROGRAM:
681 ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); 681 ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
682 break; 682 break;
683 683
684 case TAG_ISO_EQUIVALENT: 684 case TAG_ISO_EQUIVALENT:
685 ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); 685 ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
686 if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200; 686 if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200;
687 break; 687 break;
688 688
689 case TAG_COMPRESSION_LEVEL: 689 case TAG_COMPRESSION_LEVEL:
690 ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); 690 ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
691 break; 691 break;
692 692
693 case TAG_THUMBNAIL_OFFSET: 693 case TAG_THUMBNAIL_OFFSET:
694 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); 694 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
695 break; 695 break;
696 696
697 case TAG_THUMBNAIL_LENGTH: 697 case TAG_THUMBNAIL_LENGTH:
698 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); 698 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
699 break; 699 break;
700 700
701 } 701 }
702 702
703 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ 703 if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
704 unsigned char * SubdirStart; 704 unsigned char * SubdirStart;
705 SubdirStart = OffsetBase + Get32u(ValuePtr); 705 SubdirStart = OffsetBase + Get32u(ValuePtr);
706 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){ 706 if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
707 return; 707 return;
708 } 708 }
709 ProcessExifDir(SubdirStart, OffsetBase, ExifLength); 709 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
710 continue; 710 continue;
711 } 711 }
712 } 712 }
713 713
714 { 714 {
715 // In addition to linking to subdirectories via exif tags, 715 // In addition to linking to subdirectories via exif tags,
716 // 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
717 // directory. this has got to be the result of a comitee! 717 // directory. this has got to be the result of a comitee!
718 unsigned char * SubdirStart; 718 unsigned char * SubdirStart;
719 unsigned Offset; 719 unsigned Offset;
720 720
721 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ 721 if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
722 Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries)); 722 Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries));
723 // 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.
724 // 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.
725 // See http://bugs.kde.org/show_bug.cgi?id=54542 725 // See http://bugs.kde.org/show_bug.cgi?id=54542
726 if (Offset && Offset < ExifLength){ 726 if (Offset && Offset < ExifLength){
727 SubdirStart = OffsetBase + Offset; 727 SubdirStart = OffsetBase + Offset;
728 if (SubdirStart > OffsetBase+ExifLength){ 728 if (SubdirStart > OffsetBase+ExifLength){
729 if (SubdirStart < OffsetBase+ExifLength+20){ 729 if (SubdirStart < OffsetBase+ExifLength+20){
730 // Jhead 1.3 or earlier would crop the whole directory! 730 // Jhead 1.3 or earlier would crop the whole directory!
731 // As Jhead produces this form of format incorrectness, 731 // As Jhead produces this form of format incorrectness,
732 // I'll just let it pass silently 732 // I'll just let it pass silently
733 owarn << "Thumbnail removed with Jhead 1.3 or earlier" << oendl; 733 owarn << "Thumbnail removed with Jhead 1.3 or earlier" << oendl;
734 }else{ 734 }else{
735 return; 735 return;
736 } 736 }
737 }else{ 737 }else{
738 if (SubdirStart <= OffsetBase+ExifLength){ 738 if (SubdirStart <= OffsetBase+ExifLength){
739 ProcessExifDir(SubdirStart, OffsetBase, ExifLength); 739 ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
740 } 740 }
741 } 741 }
742 } 742 }
743 }else{ 743 }else{
744 // The exif header ends before the last next directory pointer. 744 // The exif header ends before the last next directory pointer.
745 } 745 }
746 } 746 }
747 747
748 if (ThumbnailSize && ThumbnailOffset){ 748 if (ThumbnailSize && ThumbnailOffset){
749 if (ThumbnailSize + ThumbnailOffset <= ExifLength){ 749 if (ThumbnailSize + ThumbnailOffset <= ExifLength){
750 // The thumbnail pointer appears to be valid. Store it. 750 // The thumbnail pointer appears to be valid. Store it.
751 Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG"); 751 Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
752 } 752 }
753 } 753 }
754} 754}
755 755
756//-------------------------------------------------------------------------- 756//--------------------------------------------------------------------------
757// 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
758// progam that displays this text may decide to remove blanks, convert 758// progam that displays this text may decide to remove blanks, convert
759// newlines, or otherwise modify the text. In particular we want to be 759// newlines, or otherwise modify the text. In particular we want to be
760// safe for passing utf-8 text. 760// safe for passing utf-8 text.
761//-------------------------------------------------------------------------- 761//--------------------------------------------------------------------------
762void ExifData::process_COM (const uchar * Data, int length) 762void ExifData::process_COM (const uchar * Data, int length)
763{ 763{
764 QChar ch; 764 QChar ch;
765 int a; 765 int a;
766 766
767 for (a=2;a<length;a++){ 767 for (a=2;a<length;a++){
768 ch = Data[a]; 768 ch = Data[a];
769 if (ch == '\000') continue; // Remove nulls 769 if (ch == '\000') continue; // Remove nulls
770 Comment.append(ch); 770 Comment.append(ch);
771 } 771 }
772} 772}
773 773
774 774
775//-------------------------------------------------------------------------- 775//--------------------------------------------------------------------------
@@ -896,49 +896,49 @@ ExifData::ExifData()
896 ExposureTime = 0; 896 ExposureTime = 0;
897 ApertureFNumber = 0; 897 ApertureFNumber = 0;
898 Distance = 0; 898 Distance = 0;
899 CCDWidth = 0; 899 CCDWidth = 0;
900 ExposureBias = 0; 900 ExposureBias = 0;
901 ExposureProgram = 0; 901 ExposureProgram = 0;
902 ISOequivalent = 0; 902 ISOequivalent = 0;
903 CompressionLevel = 0; 903 CompressionLevel = 0;
904} 904}
905 905
906//-------------------------------------------------------------------------- 906//--------------------------------------------------------------------------
907// process a EXIF jpeg file 907// process a EXIF jpeg file
908//-------------------------------------------------------------------------- 908//--------------------------------------------------------------------------
909bool ExifData::scan(const QString & path) 909bool ExifData::scan(const QString & path)
910{ 910{
911 int ret; 911 int ret;
912 912
913 QFile f(path); 913 QFile f(path);
914 f.open(IO_ReadOnly); 914 f.open(IO_ReadOnly);
915 915
916 // Scan the JPEG headers. 916 // Scan the JPEG headers.
917 ret = ReadJpegSections(f, READ_EXIF); 917 ret = ReadJpegSections(f, READ_EXIF);
918 918
919 if (ret == false){ 919 if (ret == false){
920 owarn << "Not JPEG file!" << oendl; 920 owarn << "Not JPEG file!" << oendl;
921 DiscardData(); 921 DiscardData();
922 f.close(); 922 f.close();
923 return false; 923 return false;
924 } 924 }
925 f.close(); 925 f.close();
926 DiscardData(); 926 DiscardData();
927 927
928 //now make the strings clean, 928 //now make the strings clean,
929 // for exmaple my Casio is a "QV-4000 " 929 // for exmaple my Casio is a "QV-4000 "
930 CameraMake = CameraMake.stripWhiteSpace(); 930 CameraMake = CameraMake.stripWhiteSpace();
931 CameraModel = CameraModel.stripWhiteSpace(); 931 CameraModel = CameraModel.stripWhiteSpace();
932 UserComment = UserComment.stripWhiteSpace(); 932 UserComment = UserComment.stripWhiteSpace();
933 Comment = Comment.stripWhiteSpace(); 933 Comment = Comment.stripWhiteSpace();
934 return true; 934 return true;
935} 935}
936 936
937//-------------------------------------------------------------------------- 937//--------------------------------------------------------------------------
938// Does the embedded thumbnail match the jpeg image? 938// Does the embedded thumbnail match the jpeg image?
939//-------------------------------------------------------------------------- 939//--------------------------------------------------------------------------
940#ifndef JPEG_TOL 940#ifndef JPEG_TOL
941#define JPEG_TOL 0.02 941#define JPEG_TOL 0.02
942#endif 942#endif
943bool ExifData::isThumbnailSane() { 943bool ExifData::isThumbnailSane() {
944 if (Thumbnail.isNull()) return false; 944 if (Thumbnail.isNull()) return false;
@@ -1394,36 +1394,44 @@ QString JpegSlave::fullImageInfo( const QString& path) {
1394 tag += white_balance_string( ImageInfo.getWhitebalance() ); 1394 tag += white_balance_string( ImageInfo.getWhitebalance() );
1395 1395
1396 1396
1397 if( ImageInfo.getMeteringMode() != -1 ) 1397 if( ImageInfo.getMeteringMode() != -1 )
1398 tag += metering_mode( ImageInfo.getMeteringMode() ); 1398 tag += metering_mode( ImageInfo.getMeteringMode() );
1399 1399
1400 if ( ImageInfo.getExposureProgram() ) 1400 if ( ImageInfo.getExposureProgram() )
1401 tag += exposure_program( ImageInfo.getExposureProgram() ); 1401 tag += exposure_program( ImageInfo.getExposureProgram() );
1402 if ( ImageInfo.getISOequivalent() ) 1402 if ( ImageInfo.getISOequivalent() )
1403 tag += QObject::tr( "ISO equivalent: %1\n" ).arg( QString().sprintf("%2d", ImageInfo.getISOequivalent() ) ); 1403 tag += QObject::tr( "ISO equivalent: %1\n" ).arg( QString().sprintf("%2d", ImageInfo.getISOequivalent() ) );
1404 1404
1405 tmp = ImageInfo.getUserComment(); 1405 tmp = ImageInfo.getUserComment();
1406 if ( tmp.length() ) 1406 if ( tmp.length() )
1407 tag += QObject::tr( "EXIF comment: %1" ).arg( tmp ); 1407 tag += QObject::tr( "EXIF comment: %1" ).arg( tmp );
1408 1408
1409 tag += QObject::tr( "</qt>" ); 1409 tag += QObject::tr( "</qt>" );
1410 1410
1411 1411
1412 1412
1413 return tag; 1413 return tag;
1414} 1414}
1415 1415
1416QPixmap JpegSlave::pixmap( const QString& path, int wid, int hei) { 1416QPixmap JpegSlave::pixmap( const QString& path, int wid, int hei) {
1417 ExifData ImageInfo; 1417 ExifData ImageInfo;
1418 /*
1419 */
1418 if ( !ImageInfo.scan( path ) || ImageInfo.isNullThumbnail() ) { 1420 if ( !ImageInfo.scan( path ) || ImageInfo.isNullThumbnail() ) {
1419 QImage img; 1421 QImage img;
1420 QImageIO iio( path, 0l ); 1422 QImageIO iio( path, 0l );
1421 QString str = QString( "Fast Shrink( 4 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei ); 1423 if (wid < ImageInfo.getWidth() || hei<ImageInfo.getHeight()) {
1422 iio.setParameters( str.latin1() );// will be strdupped anyway 1424 odebug << "Scaling "<<ImageInfo.getWidth()<<"x"<<ImageInfo.getHeight()
1425 << " to "<<wid<<"x"<<hei<< " ("<<path<<")"<<oendl;
1426 QString str = QString( "Fast Shrink( 4 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei );
1427 iio.setParameters( str.latin1() );// will be strdupped anyway
1428 } else {
1429 odebug << "Not scaling "<<ImageInfo.getWidth()<<"x"<<ImageInfo.getHeight()<< " ("<<path<<")"<<oendl;
1430 }
1423 img = iio.read() ? iio.image() : QImage(); 1431 img = iio.read() ? iio.image() : QImage();
1424 return ThumbNailTool::scaleImage( img, wid,hei ); 1432 return ThumbNailTool::scaleImage( img, wid,hei );
1425 }else{ 1433 }else{
1426 QImage img = ImageInfo.getThumbnail(); 1434 QImage img = ImageInfo.getThumbnail();
1427 return ThumbNailTool::scaleImage( img, wid,hei ); 1435 return ThumbNailTool::scaleImage( img, wid,hei );
1428 } 1436 }
1429} 1437}