Diffstat (limited to 'libopie2/opiemm/opieexif.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie2/opiemm/opieexif.cpp | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/libopie2/opiemm/opieexif.cpp b/libopie2/opiemm/opieexif.cpp index de49937..653216c 100644 --- a/libopie2/opiemm/opieexif.cpp +++ b/libopie2/opiemm/opieexif.cpp | |||
@@ -160,97 +160,97 @@ int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode) | |||
160 | 160 | ||
161 | if (a >= 6){ | 161 | if (a >= 6){ |
162 | 162 | ||
163 | owarn << "too many padding bytes" << oendl; | 163 | owarn << "too many padding bytes" << oendl; |
164 | return false; | 164 | return false; |
165 | 165 | ||
166 | } | 166 | } |
167 | } | 167 | } |
168 | 168 | ||
169 | if (marker == 0xff){ | 169 | if (marker == 0xff){ |
170 | // 0xff is legal padding, but if we get that many, something's wrong. | 170 | // 0xff is legal padding, but if we get that many, something's wrong. |
171 | return false; | 171 | return false; |
172 | } | 172 | } |
173 | 173 | ||
174 | Sections[SectionsRead].Type = marker; | 174 | Sections[SectionsRead].Type = marker; |
175 | 175 | ||
176 | // Read the length of the section. | 176 | // Read the length of the section. |
177 | lh = (uchar) infile.getch(); | 177 | lh = (uchar) infile.getch(); |
178 | ll = (uchar) infile.getch(); | 178 | ll = (uchar) infile.getch(); |
179 | 179 | ||
180 | itemlen = (lh << 8) | ll; | 180 | itemlen = (lh << 8) | ll; |
181 | 181 | ||
182 | if (itemlen < 2) { | 182 | if (itemlen < 2) { |
183 | return false;; | 183 | return false;; |
184 | } | 184 | } |
185 | 185 | ||
186 | Sections[SectionsRead].Size = itemlen; | 186 | Sections[SectionsRead].Size = itemlen; |
187 | 187 | ||
188 | Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end. | 188 | Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end. |
189 | Sections[SectionsRead].Data = Data; | 189 | Sections[SectionsRead].Data = Data; |
190 | 190 | ||
191 | // Store first two pre-read bytes. | 191 | // Store first two pre-read bytes. |
192 | Data[0] = (uchar)lh; | 192 | Data[0] = (uchar)lh; |
193 | Data[1] = (uchar)ll; | 193 | Data[1] = (uchar)ll; |
194 | 194 | ||
195 | got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section. | 195 | got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section. |
196 | if (( unsigned ) got != itemlen-2){ | 196 | if (( unsigned ) got != itemlen-2){ |
197 | return false; | 197 | return false; |
198 | } | 198 | } |
199 | SectionsRead++; | 199 | SectionsRead++; |
200 | 200 | ||
201 | switch(marker){ | 201 | switch(marker){ |
202 | 202 | ||
203 | case M_SOS: // stop before hitting compressed data | 203 | case M_SOS: // stop before hitting compressed data |
204 | // If reading entire image is requested, read the rest of the data. | 204 | // If reading entire image is requested, read the rest of the data. |
205 | if (ReadMode & READ_IMAGE){ | 205 | if (ReadMode & READ_IMAGE){ |
206 | unsigned long size; | 206 | unsigned long size; |
207 | 207 | ||
208 | size = QMAX( 0ul, infile.size()-infile.at() ); | 208 | size = infile.size()-infile.at(); |
209 | Data = (uchar *)malloc(size); | 209 | Data = (uchar *)malloc(size); |
210 | if (Data == NULL){ | 210 | if (Data == NULL){ |
211 | return false; | 211 | return false; |
212 | } | 212 | } |
213 | 213 | ||
214 | got = infile.readBlock((char*)Data, size); | 214 | got = infile.readBlock((char*)Data, size); |
215 | if (( unsigned ) got != size){ | 215 | if (( unsigned ) got != size){ |
216 | return false; | 216 | return false; |
217 | } | 217 | } |
218 | 218 | ||
219 | Sections[SectionsRead].Data = Data; | 219 | Sections[SectionsRead].Data = Data; |
220 | Sections[SectionsRead].Size = size; | 220 | Sections[SectionsRead].Size = size; |
221 | Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; | 221 | Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; |
222 | SectionsRead ++; | 222 | SectionsRead ++; |
223 | //HaveAll = 1; | 223 | //HaveAll = 1; |
224 | } | 224 | } |
225 | return true; | 225 | return true; |
226 | 226 | ||
227 | case M_EOI: // in case it's a tables-only JPEG stream | 227 | case M_EOI: // in case it's a tables-only JPEG stream |
228 | owarn << "No image in jpeg!" << oendl; | 228 | owarn << "No image in jpeg!" << oendl; |
229 | return false; | 229 | return false; |
230 | 230 | ||
231 | case M_COM: // Comment section | 231 | case M_COM: // Comment section |
232 | // pieczy 2002-02-12 | 232 | // pieczy 2002-02-12 |
233 | // now the User comment goes to UserComment | 233 | // now the User comment goes to UserComment |
234 | // so we can store a Comment section also in READ_EXIF mode | 234 | // so we can store a Comment section also in READ_EXIF mode |
235 | process_COM(Data, itemlen); | 235 | process_COM(Data, itemlen); |
236 | break; | 236 | break; |
237 | 237 | ||
238 | case M_JFIF: | 238 | case M_JFIF: |
239 | // Regular jpegs always have this tag, exif images have the exif | 239 | // Regular jpegs always have this tag, exif images have the exif |
240 | // marker instead, althogh ACDsee will write images with both markers. | 240 | // marker instead, althogh ACDsee will write images with both markers. |
241 | // this program will re-create this marker on absence of exif marker. | 241 | // this program will re-create this marker on absence of exif marker. |
242 | // hence no need to keep the copy from the file. | 242 | // hence no need to keep the copy from the file. |
243 | free(Sections[--SectionsRead].Data); | 243 | free(Sections[--SectionsRead].Data); |
244 | break; | 244 | break; |
245 | 245 | ||
246 | case M_EXIF: | 246 | case M_EXIF: |
247 | // Seen files from some 'U-lead' software with Vivitar scanner | 247 | // Seen files from some 'U-lead' software with Vivitar scanner |
248 | // that uses marker 31 for non exif stuff. Thus make sure | 248 | // that uses marker 31 for non exif stuff. Thus make sure |
249 | // it says 'Exif' in the section before treating it as exif. | 249 | // it says 'Exif' in the section before treating it as exif. |
250 | if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ | 250 | if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ |
251 | process_EXIF((uchar *)Data, itemlen); | 251 | process_EXIF((uchar *)Data, itemlen); |
252 | }else{ | 252 | }else{ |
253 | // Discard this section. | 253 | // Discard this section. |
254 | free(Sections[--SectionsRead].Data); | 254 | free(Sections[--SectionsRead].Data); |
255 | } | 255 | } |
256 | break; | 256 | break; |
@@ -764,97 +764,101 @@ int ExifData::Exif2tm(struct ::tm * timeptr, char * ExifTime) | |||
764 | 764 | ||
765 | if (a == 6){ | 765 | if (a == 6){ |
766 | timeptr->tm_isdst = -1; | 766 | timeptr->tm_isdst = -1; |
767 | timeptr->tm_mon -= 1; // Adjust for unix zero-based months | 767 | timeptr->tm_mon -= 1; // Adjust for unix zero-based months |
768 | timeptr->tm_year -= 1900; // Adjust for year starting at 1900 | 768 | timeptr->tm_year -= 1900; // Adjust for year starting at 1900 |
769 | return true; // worked. | 769 | return true; // worked. |
770 | } | 770 | } |
771 | 771 | ||
772 | return false; // Wasn't in Exif date format. | 772 | return false; // Wasn't in Exif date format. |
773 | } | 773 | } |
774 | 774 | ||
775 | //-------------------------------------------------------------------------- | 775 | //-------------------------------------------------------------------------- |
776 | // Contructor for initialising | 776 | // Contructor for initialising |
777 | //-------------------------------------------------------------------------- | 777 | //-------------------------------------------------------------------------- |
778 | ExifData::ExifData() | 778 | ExifData::ExifData() |
779 | { | 779 | { |
780 | ExifData::Whitebalance = -1; | 780 | ExifData::Whitebalance = -1; |
781 | ExifData::MeteringMode = -1; | 781 | ExifData::MeteringMode = -1; |
782 | ExifData::FlashUsed = -1; | 782 | ExifData::FlashUsed = -1; |
783 | Orientation = 0; | 783 | Orientation = 0; |
784 | Height = 0; | 784 | Height = 0; |
785 | Width = 0; | 785 | Width = 0; |
786 | IsColor = 0; | 786 | IsColor = 0; |
787 | Process = 0; | 787 | Process = 0; |
788 | FocalLength = 0; | 788 | FocalLength = 0; |
789 | ExposureTime = 0; | 789 | ExposureTime = 0; |
790 | ApertureFNumber = 0; | 790 | ApertureFNumber = 0; |
791 | Distance = 0; | 791 | Distance = 0; |
792 | CCDWidth = 0; | 792 | CCDWidth = 0; |
793 | ExposureBias = 0; | 793 | ExposureBias = 0; |
794 | ExposureProgram = 0; | 794 | ExposureProgram = 0; |
795 | ISOequivalent = 0; | 795 | ISOequivalent = 0; |
796 | CompressionLevel = 0; | 796 | CompressionLevel = 0; |
797 | MotorolaOrder = 0; | 797 | MotorolaOrder = 0; |
798 | } | 798 | } |
799 | 799 | ||
800 | ExifData::~ExifData() | 800 | ExifData::~ExifData() |
801 | { | 801 | { |
802 | } | 802 | } |
803 | 803 | ||
804 | //-------------------------------------------------------------------------- | 804 | //-------------------------------------------------------------------------- |
805 | // process a EXIF jpeg file | 805 | // process a EXIF jpeg file |
806 | //-------------------------------------------------------------------------- | 806 | //-------------------------------------------------------------------------- |
807 | bool ExifData::scan(const QString & path) | 807 | bool ExifData::scan(const QString & path) |
808 | { | 808 | { |
809 | int ret; | 809 | int ret; |
810 | 810 | ||
811 | QFile f(path); | 811 | QFile f(path); |
812 | f.open(IO_ReadOnly); | 812 | if ( !f.open(IO_ReadOnly) ) { |
813 | owarn << "Unable to open file " << f.name() << " readonly" << oendl; | ||
814 | DiscardData(); | ||
815 | return false; | ||
816 | } | ||
813 | 817 | ||
814 | // Scan the JPEG headers. | 818 | // Scan the JPEG headers. |
815 | ret = ReadJpegSections(f, READ_EXIF); | 819 | ret = ReadJpegSections(f, READ_EXIF); |
816 | 820 | ||
817 | if (ret == false){ | 821 | if (ret == false){ |
818 | owarn << "Not JPEG file!" << oendl; | 822 | owarn << "Not JPEG file!" << oendl; |
819 | DiscardData(); | 823 | DiscardData(); |
820 | f.close(); | 824 | f.close(); |
821 | return false; | 825 | return false; |
822 | } | 826 | } |
823 | f.close(); | 827 | f.close(); |
824 | DiscardData(); | 828 | DiscardData(); |
825 | 829 | ||
826 | //now make the strings clean, | 830 | //now make the strings clean, |
827 | // for exmaple my Casio is a "QV-4000 " | 831 | // for exmaple my Casio is a "QV-4000 " |
828 | CameraMake = CameraMake.stripWhiteSpace(); | 832 | CameraMake = CameraMake.stripWhiteSpace(); |
829 | CameraModel = CameraModel.stripWhiteSpace(); | 833 | CameraModel = CameraModel.stripWhiteSpace(); |
830 | UserComment = UserComment.stripWhiteSpace(); | 834 | UserComment = UserComment.stripWhiteSpace(); |
831 | Comment = Comment.stripWhiteSpace(); | 835 | Comment = Comment.stripWhiteSpace(); |
832 | return true; | 836 | return true; |
833 | } | 837 | } |
834 | 838 | ||
835 | //-------------------------------------------------------------------------- | 839 | //-------------------------------------------------------------------------- |
836 | // Does the embedded thumbnail match the jpeg image? | 840 | // Does the embedded thumbnail match the jpeg image? |
837 | //-------------------------------------------------------------------------- | 841 | //-------------------------------------------------------------------------- |
838 | #ifndef JPEG_TOL | 842 | #ifndef JPEG_TOL |
839 | #define JPEG_TOL 0.02 | 843 | #define JPEG_TOL 0.02 |
840 | #endif | 844 | #endif |
841 | bool ExifData::isThumbnailSane() { | 845 | bool ExifData::isThumbnailSane() { |
842 | if (Thumbnail.isNull()) return false; | 846 | if (Thumbnail.isNull()) return false; |
843 | 847 | ||
844 | // check whether thumbnail dimensions match the image | 848 | // check whether thumbnail dimensions match the image |
845 | // not foolproof, but catches some altered images (jpegtran -rotate) | 849 | // not foolproof, but catches some altered images (jpegtran -rotate) |
846 | if (ExifImageLength != 0 && ExifImageLength != Height) return false; | 850 | if (ExifImageLength != 0 && ExifImageLength != Height) return false; |
847 | if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; | 851 | if (ExifImageWidth != 0 && ExifImageWidth != Width) return false; |
848 | if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; | 852 | if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false; |
849 | if (Height == 0 || Width == 0) return false; | 853 | if (Height == 0 || Width == 0) return false; |
850 | double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); | 854 | double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height(); |
851 | return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); | 855 | return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL); |
852 | } | 856 | } |
853 | 857 | ||
854 | 858 | ||
855 | 859 | ||
856 | static QImage flip_image( const QImage& img ); | 860 | static QImage flip_image( const QImage& img ); |
857 | static QImage rotate_90( const QImage& img ); | 861 | static QImage rotate_90( const QImage& img ); |
858 | static QImage rotate_180( const QImage& ); | 862 | static QImage rotate_180( const QImage& ); |
859 | static QImage rotate_270( const QImage& ); | 863 | static QImage rotate_270( const QImage& ); |
860 | 864 | ||