1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /* EXIFPROBE - TIFF/JPEG/EXIF image file probe */
3 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
4 /* Copyright (C) 2002,2005 by Duane H. Hesser. All rights reserved. */
5 /* */
6 /* See the file LICENSE.EXIFPROBE for terms of use. */
7 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
8
9 #ifndef lint
10 static char *ModuleId = "@(#) $Id: maker_epson.c,v 1.22 2005/07/24 22:56:26 alex Exp $";
11 #endif
12
13 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
14 /* Epson camera maker-specific routines */
15 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
16 /* This is currently a near-duplicate of the Olympus, based upon the */
17 /* similarity of tag numbers, the appearance of sample images taken */
18 /* from the Web, and reports that some Olympus, Epson, Minolta and */
19 /* Sanyo models use similar firmware. */
20 /* The "photopc" site at soucrceforge provides some insight: */
21 /* http://photopc.sourceforge.net/cameras.html */
22 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include "defs.h"
28 #include "datadefs.h"
29 #include "maker_datadefs.h"
30 #include "summary.h"
31 #include "maker.h"
32 #include "misc.h"
33 #include "tags.h"
34 #include "maker_extern.h"
35 #include "extern.h"
36
37 extern struct camera_id epson_model_id[];
38
39 /* Find the identifying number assigned to known Epson camera models. */
40 /* This number is used to dispatch appropriate print and interpret */
41 /* routines approopriate to the current image. */
42
43 int
epson_model_number(char * model,char * software)44 epson_model_number(char *model,char *software)
45 {
46 struct camera_id *model_id;
47 int number = NO_MODEL;
48
49 for(model_id = &epson_model_id[0]; model_id && model_id->name; ++model_id)
50 {
51 if(strncasecmp(model,model_id->name,model_id->namelen) == 0)
52 {
53 number = model_id->id;
54 setnoteversion(model_id->noteversion);
55 setnotetagset(model_id->notetagset); /* info only */
56 break;
57 }
58 }
59 return(number);
60 }
61
62
63 /* Dispatch a print routine for direct IFD values in Epson */
64 /* MakerNotes, based upon model */
65
66 void
print_epson_makervalue(struct ifd_entry * entry_ptr,int make,int model,char * prefix)67 print_epson_makervalue(struct ifd_entry *entry_ptr,int make, int model,
68 char *prefix)
69 {
70 int noteversion = 0;
71
72 noteversion = getnoteversion();
73
74 if(entry_ptr && (PRINT_VALUE))
75 {
76 switch(noteversion)
77 {
78 case 1 :
79 print_epson1_makervalue(entry_ptr,make,model,prefix);
80 epson1_interpret_value(entry_ptr);
81 break;
82 default:
83 print_value(entry_ptr,PREFIX);
84 break;
85 }
86 }
87 }
88
89 /* Model-specific print routine for Epson cameras. This routine is */
90 /* responsible for picking off any direct entry tags which are */
91 /* peculiar and will not be handled properly by print_value() */
92 /* (usually UNDEFINED values which fit in the 4-byte entry value). If */
93 /* there are no such entries, this function simply calls */
94 /* print_value(). */
95
96 void
print_epson1_makervalue(struct ifd_entry * entry_ptr,int make,int model,char * prefix)97 print_epson1_makervalue(struct ifd_entry *entry_ptr,int make, int model,
98 char *prefix)
99 {
100 if(entry_ptr && (PRINT_VALUE))
101 {
102 switch(entry_ptr->tag)
103 {
104 default:
105 print_value(entry_ptr,PREFIX);
106 break;
107 }
108 }
109 }
110
111 /* Dispatch a routine to decode and print offset values in MakerNotes */
112 /* from Epson cameras. */
113
114 void
print_epson_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base,struct image_summary * summary_entry,char * parent_name,char * prefix,int indent,int make,int model,int at_offset)115 print_epson_offset_makervalue(FILE *inptr,unsigned short byteorder,
116 struct ifd_entry *entry_ptr,unsigned long fileoffset_base,
117 struct image_summary *summary_entry,char *parent_name,char*prefix,
118 int indent,int make,int model,int at_offset)
119 {
120 int noteversion = 0;
121
122 noteversion = getnoteversion();
123
124 if(entry_ptr)
125 {
126 switch(noteversion)
127 {
128 case 1 :
129 epson1_offset_makervalue(inptr,byteorder,entry_ptr,
130 fileoffset_base,summary_entry,
131 parent_name,prefix,indent,
132 make,model,at_offset);
133 epson1_interpret_offset_makervalue(inptr,byteorder,
134 entry_ptr,fileoffset_base);
135 break;
136 default:
137 print_generic_offset_makervalue(inptr,byteorder,entry_ptr,
138 fileoffset_base,parent_name,prefix,
139 indent,make,model,at_offset);
140 break;
141 }
142 }
143 }
144
145 /* Model-specific routine to print UNDEFINED values found at offsets */
146 /* in epson makernotes. */
147
148 void
epson1_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base,struct image_summary * summary_entry,char * parent_name,char * prefix,int indent,int make,int model,int at_offset)149 epson1_offset_makervalue(FILE *inptr,unsigned short byteorder,
150 struct ifd_entry *entry_ptr,unsigned long fileoffset_base,
151 struct image_summary *summary_entry,char *parent_name,char*prefix,
152 int indent,int make,int model,int at_offset)
153 {
154 unsigned long value_offset,count;
155 unsigned long dumplength;
156 unsigned long max_offset = 0;
157 unsigned short marker;
158 char *nameoftag;
159 char *fulldirname = NULL;
160 int status = 0;
161 int chpr = 0;
162
163 if(entry_ptr)
164 {
165 nameoftag = maker_tagname(entry_ptr->tag,make,model);
166 fulldirname = splice(parent_name,".",nameoftag);
167 value_offset = fileoffset_base + entry_ptr->value;
168 count = entry_ptr->count;
169
170 switch(entry_ptr->tag)
171 {
172 case 0x020a: /* MakerNote version of UserComment */
173 if(at_offset)
174 {
175 print_tag_address(ENTRY,value_offset,indent,prefix);
176 print_makertagid(entry_ptr,23," = ",make,model);
177 }
178 if((PRINT_VALUE))
179 {
180 if((PRINT_OFFSET) && !at_offset)
181 chpr += chpr += printf(" = ");
182 print_user_comment(inptr,entry_ptr->count,value_offset,byteorder);
183 }
184 break;
185 case 0x0209: /* CameraId */
186 if(at_offset)
187 {
188 print_tag_address(ENTRY,value_offset,indent,prefix);
189 print_makertagid(entry_ptr,23," = ",make,model);
190 }
191 if((PRINT_VALUE))
192 {
193 if((PRINT_OFFSET) && !at_offset)
194 chpr += chpr += printf(" = ");
195 print_ascii(inptr,entry_ptr->count,value_offset);
196 }
197 break;
198 case 0x0301:
199 /* This is an odd one. Overwrite the values for */
200 /* offset and length, then fall through and display */
201 /* the thumbnail. */
202 /* Why didn't they just do this as an UNDEFINED */
203 /* section? */
204 value_offset = read_ulong(inptr,byteorder,value_offset);
205 count = read_ulong(inptr,byteorder,HERE);
206 if(at_offset && (PRINT_SECTION))
207 {
208 print_tag_address(SECTION,fileoffset_base + entry_ptr->value,
209 indent,prefix);
210 print_makertagid(entry_ptr,23," = ",make,model);
211 if((PRINT_VALUE))
212 chpr += printf("@%lu:%lu",value_offset,count);
213 chpr = newline(chpr);
214 }
215 else if((LIST_MODE) && !at_offset)
216 {
217 if((PRINT_VALUE))
218 {
219 if(!(PRINT_OFFSET))
220 chpr += printf("@%lu",fileoffset_base + entry_ptr->value);
221 }
222 chpr = newline(chpr);
223 /* In list mode, when SECTIONS are not printed, */
224 /* provide these items as "pseudotags". */
225 print_tag_address(ENTRY,value_offset,indent,prefix);
226 if((PRINT_TAGINFO))
227 {
228 if((PRINT_LONGNAMES))
229 chpr += printf("%s.",fulldirname);
230 chpr += printf("%-*.*s",9,9,"Offset");
231 }
232 if((PRINT_VALUE))
233 {
234 if((PRINT_OFFSET))
235 {
236 if(PRINT_BOTH_OFFSET)
237 chpr += printf(" = @%#lx=%lu",value_offset,value_offset);
238 else if(PRINT_HEX_OFFSET)
239 chpr += printf(" = @%#lx",value_offset);
240 else if(PRINT_DEC_OFFSET)
241 chpr += printf(" = @%lu",value_offset);
242 }
243 else
244 chpr += printf(" = @%lu",value_offset);
245 }
246
247 chpr = newline(chpr);
248 print_tag_address(ENTRY,value_offset,indent,prefix);
249 if((PRINT_TAGINFO))
250 {
251 if((PRINT_LONGNAMES))
252 chpr += printf("%s.",fulldirname);
253 chpr += printf("%-*.*s",9,9,"Length");
254 }
255 if((PRINT_VALUE))
256 chpr += printf(" = %lu",count);
257 }
258 /* fall through and process the thumbnail */
259 case 0x0100: /* Jpeg Thumbnail */
260 if(at_offset && (PRINT_SECTION))
261 {
262 print_tag_address(VALUE_AT_OFFSET,value_offset,indent,prefix);
263 chpr += printf("# Start of JPEG Thumbnail from MakerNote");
264 chpr += printf(" length %ld",count);
265 }
266 else if(!at_offset && (PRINT_VALUE) && (entry_ptr->tag == 0x0100))
267 {
268 if(!(PRINT_OFFSET))
269 chpr += printf("@%lu:%lu",value_offset,entry_ptr->count);
270 else
271 chpr = printf("length %lu", entry_ptr->count);
272 }
273 if((PRINT_SECTION) || (PRINT_SEGMENT))
274 chpr = newline(chpr);
275 marker = read_ushort(inptr,TIFF_MOTOROLA,value_offset);
276 max_offset = process_jpeg_segments(inptr,value_offset,marker,
277 count,summary_entry,fulldirname,
278 prefix,indent+SMALLINDENT);
279 if(at_offset)
280 {
281 if((PRINT_SECTION))
282 {
283 if((status = jpeg_status(0) == JPEG_EARLY_EOI))
284 chpr = newline(chpr);
285 jpeg_status(status);
286 print_tag_address(VALUE_AT_OFFSET,value_offset + count - 1,
287 indent,prefix);
288 chpr += printf("# End of JPEG Thumbnail from MakerNote");
289 if((PRINT_ENTRY) && !(PRINT_VALUE))
290 chpr = newline(chpr);
291 }
292 }
293 print_jpeg_status();
294 if(marker && summary_entry)
295 {
296 /* The new one is on the end of the chain */
297 if((summary_entry = last_summary_entry(summary_entry)))
298 {
299 summary_entry->filesubformat |= FILESUBFMT_MNOTE;
300 summary_entry->datatype = MAKER_IFD;
301 summary_entry->subfiletype = THUMBNAIL_TYPE;
302 }
303 }
304 /* make certain we're at the end */
305 clearerr(inptr);
306 fseek(inptr,value_offset + count,0);
307 break;
308 case 0x0e00: /* PrintIM (Epson Print Image matching) */
309 if(!at_offset && (PRINT_VALUE))
310 {
311 if(!(PRINT_OFFSET))
312 {
313 chpr += printf("@%lu:%lu",value_offset,count);
314 chpr = newline(chpr);
315 }
316 }
317 process_pim(inptr,byteorder,entry_ptr->value,fileoffset_base,
318 count,nameoftag,parent_name,prefix,indent);
319 break;
320 case 0x0f00: /* Data */
321 if(at_offset && (PRINT_ENTRY))
322 {
323 print_tag_address(ENTRY,value_offset,indent,prefix);
324 print_makertagid(entry_ptr,23," : ",make,model);
325 chpr += printf("length %lu", count);
326 if(Max_undefined == 0)
327 {
328 if(chpr)
329 printred(" (not dumped, use -U)");
330 }
331 else
332 {
333 if((Max_undefined == DUMPALL) || (Max_undefined > count))
334 dumplength = count;
335 else
336 dumplength = Max_undefined;
337 chpr = newline(chpr);
338 hexdump(inptr,value_offset,count,dumplength,12,
339 indent,SUBINDENT);
340 chpr = newline(1);
341 }
342 }
343 else if(!at_offset && (PRINT_VALUE))
344 {
345 if(!(PRINT_OFFSET))
346 chpr += printf("@%lu:%lu",value_offset,entry_ptr->count);
347 else
348 chpr = printf("length %lu", entry_ptr->count);
349 if(!(PRINT_VALUE_AT_OFFSET))
350 chpr += printf(" # UNDEFINED");
351 }
352 /* make certain we're at the end */
353 fseek(inptr,value_offset + count,0);
354 break;
355 default:
356 print_generic_offset_makervalue(inptr,byteorder,entry_ptr,
357 fileoffset_base,fulldirname,prefix,indent,
358 make,model,at_offset);
359 break;
360 }
361 if(fulldirname)
362 free(fulldirname);
363 }
364 setcharsprinted(chpr);
365 }
366
367 /* Epson-specific tagnames for makernotes. */
368
369 char *
maker_epson_tagname(unsigned short tag,int model)370 maker_epson_tagname(unsigned short tag,int model)
371 {
372 char *tagname = CNULL;
373 int noteversion = 0;
374
375 /* Should have to do this only once, and only for unrecognized */
376 /* models. If the model is recognized (or the user has forced a */
377 /* noteversion) noteversion will already be set. */
378 if((noteversion = getnoteversion()) == 0)
379 {
380 noteversion = 1;
381 setnoteversion(1);
382 }
383
384 switch(noteversion)
385 {
386 case 1 :
387 tagname = maker_epson1_tagname(tag,model);
388 break;
389 default:
390 break;
391 }
392
393 if(tagname == NULL)
394 {
395 switch(tag)
396 {
397 case 0x0e00: tagname = "PrintIM"; break;
398 case 0x0100: tagname = "JpegThumbnail"; break;
399 default: break;
400 }
401 }
402 return(tagname);
403 }
404
405 char *
maker_epson1_tagname(unsigned short tag,int model)406 maker_epson1_tagname(unsigned short tag,int model)
407 {
408 char *tagname = CNULL;
409
410 /* These are the Olympus tags; try them ###%%% ??? */
411 /* Update: the SoftwareRelease tag on Olympus is 0x0207; here it */
412 /* is 0x020d. One Epson model sports a hidden thumbnail (0x0301) */
413 switch(tag)
414 {
415 case 0x0200: tagname = "SpecialMode"; break;
416 case 0x0201: tagname = "CompressionMode"; break;
417 case 0x0202: tagname = "Macro"; break;
418 case 0x0204: tagname = "DigitalZoom"; break;
419 case 0x0208: tagname = "PictureInfo"; break;
420 case 0x0209: tagname = "CameraID"; break;
421 case 0x020a: tagname = "MakerUserComment"; break;
422 case 0x020b: tagname = "ImageWidth"; break;
423 case 0x020c: tagname = "ImageHeight"; break;
424 case 0x020d: tagname = "SoftwareRelease"; break;
425 case 0x0301: tagname = "JpegThumbnailData"; break;
426 case 0x0e00: tagname = "PrintIM"; break;
427 case 0x0f00: tagname = "Data"; break;
428 default: break;
429 }
430 setnotetagset(1);
431 return(tagname);
432 }
433
434
435 /* This arbitrarily assumes that the Epsons use firmware similar to */
436 /* that of the Olympus. I have seen no information on the web from */
437 /* Epson owners who have decoded notes from their cameras. The */
438 /* following seems to be correct based upon Epson PhotoPC 3000Z */
439 /* images downloaded from "dpreview" and "imaging resources". */
440
441 void
epson1_interpret_value(struct ifd_entry * entry_ptr)442 epson1_interpret_value(struct ifd_entry *entry_ptr)
443 {
444 int chpr = 0;
445
446 if(entry_ptr && (PRINT_VALUE))
447 {
448 switch(entry_ptr->tag)
449 {
450 case 0x0201: /* Compression Mode */
451 print_startvalue();
452 /* 'Quality' is a mix of this and image size. */
453 /* Interestingly, 'HyPict' (2544x1904) interpolated */
454 /* images are marked '34' (same as uncompressed 'tiff') */
455 /* but are in JPEG format with CompressedBitsPerPixel=1. */
456 /* The value '33' is used by Olympus cameras, which */
457 /* appear to use similar software. Of course, the Minolta */
458 /* F100 looks a lot like this too, but uses '4' for */
459 /* uncompressed. */
460 switch(entry_ptr->value)
461 {
462 case 1: chpr += printf("SQ"); break;
463 case 2: chpr += printf("HQ"); break;
464 case 3: chpr += printf("SHQ"); break;
465 case 33: chpr += printf("not compressed"); break;
466 case 34: chpr += printf("not compressed"); break;
467 default: printred("undefined"); break;
468 }
469 print_endvalue();
470 break;
471 case 0x0202: /* Macro */
472 print_startvalue();
473 switch(entry_ptr->value)
474 {
475 case 0: chpr += printf("Normal"); break;
476 case 1: chpr += printf("Macro"); break;
477 default: printred("undefined"); break;
478 }
479 print_endvalue();
480 break;
481 default:
482 break;
483 }
484 }
485 setcharsprinted(chpr);
486 }
487
488 /* Report the "meaning" of tag values found at offsets in an Epson */
489 /* MakerNote IFD entry (not at an offset). */
490
491 void
epson1_interpret_offset_makervalue(FILE * inptr,unsigned short byteorder,struct ifd_entry * entry_ptr,unsigned long fileoffset_base)492 epson1_interpret_offset_makervalue(FILE *inptr,unsigned short byteorder,
493 struct ifd_entry *entry_ptr,unsigned long fileoffset_base)
494 {
495 unsigned long offset,value;
496 int chpr = 0;
497
498 if(entry_ptr && (PRINT_VALUE))
499 {
500 offset = entry_ptr->value + fileoffset_base;
501 switch(entry_ptr->tag)
502 {
503 case 0x0200: /* SpecialMode */
504 value = read_ulong(inptr,byteorder,offset);
505 print_startvalue();
506 /* Don't know what the last 2 values might mean for */
507 /* "normal" or "fast". */
508 switch(value)
509 {
510 case 0: chpr += printf("Normal"); break;
511 case 1: chpr += printf("Unkown"); break;
512 case 2: chpr += printf("Fast"); break;
513 case 3: chpr += printf("Panorama,");
514 value = read_ulong(inptr,byteorder,HERE);
515 chpr += printf("#%lu,",value);
516 value = read_ulong(inptr,byteorder,HERE);
517 switch(value)
518 {
519 case 1: chpr += printf(" Left to Right"); break;
520 case 2: chpr += printf(" Right to Left"); break;
521 case 3: chpr += printf(" Bottom to Top"); break;
522 case 4: chpr += printf(" Top to Bottom"); break;
523 default: printred(" undefined"); break;
524 }
525 break;
526 default: printred("undefined"); break;
527 }
528 print_endvalue();
529 break;
530 default:
531 break;
532 }
533 }
534 setcharsprinted(chpr);
535 }
536