source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/Ricoh.pm@ 34921

Last change on this file since 34921 was 34921, checked in by anupama, 3 years ago

Committing the improvements to EmbeddedMetaPlugin's processing of Keywords vs other metadata fields. Keywords were literally stored as arrays of words rather than phrases in PDFs (at least in Diego's sample PDF), whereas other meta fields like Subjects and Creators stored them as arrays of phrases. To get both to work, Kathy updated EXIF to a newer version, to retrieve the actual EXIF values stored in the PDF. And Kathy and Dr Bainbridge came up with a new option that I added called apply_join_before_split_to_metafields that's a regex which can list the metadata fields to apply the join_before_split to and whcih previously always got applied to all metadata fields. Now it's applied to any *Keywords metafields by default, as that's the metafield we have experience of that behaves differently to the others, as it stores by word instead of phrases. Tested on Diego's sample PDF. Diego has double-checked it to works on his sample PDF too, setting the split char to ; and turning on the join_before_split and leaving apply_join_before_split_to_metafields at its default of .*Keywords. File changes are strings.properties for the tooltip, the plugin introducing the option and working with it and Kathy's EXIF updates affecting cpan/File and cpan/Image.

File size: 37.2 KB
Line 
1#------------------------------------------------------------------------------
2# File: Ricoh.pm
3#
4# Description: Ricoh EXIF maker notes tags
5#
6# Revisions: 03/28/2005 - P. Harvey Created
7#
8# References: 1) http://www.ozhiker.com/electronics/pjmt/jpeg_info/ricoh_mn.html
9# 2) http://homepage3.nifty.com/kamisaka/makernote/makernote_ricoh.htm
10# 3) Tim Gray private communication (GR)
11# 4) https://github.com/atotto/ricoh-theta-tools/
12# IB) Iliah Borg private communication (LibRaw)
13#------------------------------------------------------------------------------
14
15package Image::ExifTool::Ricoh;
16
17use strict;
18use vars qw($VERSION);
19use Image::ExifTool qw(:DataAccess :Utils);
20use Image::ExifTool::Exif;
21
22$VERSION = '1.35';
23
24sub ProcessRicohText($$$);
25sub ProcessRicohRMETA($$$);
26
27# lens types for Ricoh GXR
28my %ricohLensIDs = (
29 Notes => q{
30 Lens units available for the GXR, used by the Ricoh Composite LensID tag. Note
31 that unlike lenses for all other makes of cameras, the focal lengths in these
32 model names have already been scaled to include the 35mm crop factor.
33 },
34 # (the exact lens model names used by Ricoh, except for a change in case)
35 'RL1' => 'GR Lens A12 50mm F2.5 Macro',
36 'RL2' => 'Ricoh Lens S10 24-70mm F2.5-4.4 VC',
37 'RL3' => 'Ricoh Lens P10 28-300mm F3.5-5.6 VC',
38 'RL5' => 'GR Lens A12 28mm F2.5',
39 'RL8' => 'Mount A12',
40 'RL6' => 'Ricoh Lens A16 24-85mm F3.5-5.5',
41);
42
43%Image::ExifTool::Ricoh::Main = (
44 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
45 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
46 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
47 WRITABLE => 1,
48 0x0001 => { Name => 'MakerNoteType', Writable => 'string' },
49 0x0002 => { #PH
50 Name => 'FirmwareVersion',
51 Writable => 'string',
52 # eg. "Rev0113" is firmware version 1.13
53 PrintConv => '$val=~/^Rev(\d+)$/ ? sprintf("%.2f",$1/100) : $val',
54 PrintConvInv => '$val=~/^(\d+)\.(\d+)$/ ? sprintf("Rev%.2d%.2d",$1,$2) : $val',
55 },
56 0x0005 => [ #PH
57 {
58 Condition => '$$valPt =~ /^[-\w ]+$/',
59 Name => 'SerialNumber', # (verified for GXR)
60 Writable => 'undef',
61 Count => 16,
62 Notes => q{
63 the serial number stamped on the camera begins with 2 model-specific letters
64 followed by the last 8 digits of this value. For the GXR, this is the
65 serial number of the lens unit
66 },
67 PrintConv => '$val=~s/^(.*)(.{8})$/($1)$2/; $val',
68 PrintConvInv => '$val=~tr/()//d; $val',
69 },{
70 Name => 'InternalSerialNumber',
71 Writable => 'undef',
72 Count => 16,
73 ValueConv => 'unpack("H*", $val)',
74 ValueConvInv => 'pack("H*", $val)',
75 },
76 ],
77 0x0e00 => {
78 Name => 'PrintIM',
79 Writable => 0,
80 Description => 'Print Image Matching',
81 SubDirectory => { TagTable => 'Image::ExifTool::PrintIM::Main' },
82 },
83 0x1000 => { #3
84 Name => 'RecordingFormat',
85 Writable => 'int16u',
86 PrintConv => {
87 2 => 'JPEG',
88 3 => 'DNG',
89 },
90 },
91 0x1001 => [{
92 Name => 'ImageInfo',
93 Condition => '$format ne "int16u"',
94 SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::ImageInfo' },
95 },{ #3
96 Name => 'ExposureProgram',
97 Writable => 'int16u',
98 Notes => 'GR',
99 PrintConv => {
100 1 => 'Auto',
101 2 => 'Program AE',
102 3 => 'Aperture-priority AE',
103 4 => 'Shutter speed priority AE',
104 5 => 'Shutter/aperture priority AE', # TAv
105 6 => 'Manual',
106 7 => 'Movie', #PH
107 },
108 }],
109 0x1002 => { #3
110 Name => 'DriveMode',
111 Condition => '$format eq "int16u"',
112 Notes => 'valid only for some models',
113 Writable => 'int16u',
114 PrintConv => {
115 0 => 'Single-frame',
116 1 => 'Continuous',
117 8 => 'AF-priority Continuous',
118 },
119 },
120 0x1003 => [{
121 Name => 'Sharpness',
122 Condition => '$format ne "int16u"',
123 Writable => 'int32u',
124 PrintConv => {
125 0 => 'Sharp',
126 1 => 'Normal',
127 2 => 'Soft',
128 },
129 },{ #3
130 Name => 'WhiteBalance',
131 Writable => 'int16u',
132 Notes => 'GR',
133 PrintConv => {
134 0 => 'Auto',
135 1 => 'Multi-P Auto',
136 2 => 'Daylight',
137 3 => 'Cloudy',
138 4 => 'Incandescent 1',
139 5 => 'Incandescent 2',
140 6 => 'Daylight Fluorescent',
141 7 => 'Neutral White Fluorescent',
142 8 => 'Cool White Fluorescent',
143 9 => 'Warm White Fluorescent',
144 10 => 'Manual',
145 11 => 'Kelvin',
146 12 => 'Shade', #IB
147 },
148 }],
149 0x1004 => { #3
150 Name => 'WhiteBalanceFineTune',
151 Condition => '$format eq "int16u"',
152 Format => 'int16s',
153 Writable => 'int16u',
154 Notes => q{
155 2 numbers: amount of adjustment towards Amber and Green. Not valid for all
156 models
157 },
158 },
159 # 0x1005 int16u - 5
160 0x1006 => { #3
161 Name => 'FocusMode',
162 Writable => 'int16u',
163 PrintConv => {
164 1 => 'Manual',
165 2 => 'Multi AF',
166 3 => 'Spot AF',
167 4 => 'Snap',
168 5 => 'Infinity',
169 7 => 'Face Detect', #PH
170 8 => 'Subject Tracking',
171 9 => 'Pinpoint AF',
172 10 => 'Movie', #PH
173 },
174 },
175 0x1007 => { #3
176 Name => 'AutoBracketing',
177 Writable => 'int16u',
178 PrintConv => {
179 0 => 'Off',
180 9 => 'AE',
181 11 => 'WB',
182 16 => 'DR', # (dynamic range)
183 17 => 'Contrast',
184 18 => 'WB2', # (selects two different WB presets besides normal)
185 19 => 'Effect',
186 },
187 },
188 0x1009 => { #3
189 Name => 'MacroMode',
190 Writable => 'int16u',
191 PrintConv => { 0 => 'Off', 1 => 'On' },
192 },
193 0x100a => { #3
194 Name => 'FlashMode',
195 Writable => 'int16u',
196 PrintConv => {
197 0 => 'Off',
198 1 => 'Auto, Fired',
199 2 => 'On',
200 3 => 'Auto, Fired, Red-eye reduction',
201 4 => 'Slow Sync',
202 5 => 'Manual',
203 6 => 'On, Red-eye reduction',
204 7 => 'Synchro, Red-eye reduction',
205 8 => 'Auto, Did not fire',
206 },
207 },
208 0x100b => { #3
209 Name => 'FlashExposureComp',
210 Writable => 'rational64s',
211 PrintConv => '$val ? sprintf("%+.1f",$val) : 0',
212 PrintConvInv => '$val',
213 },
214 0x100c => { #3
215 Name => 'ManualFlashOutput',
216 Writable => 'rational64s',
217 PrintConv => {
218 0 => 'Full',
219 -24 => '1/1.4',
220 -48 => '1/2',
221 -72 => '1/2.8',
222 -96 => '1/4',
223 -120 => '1/5.6',
224 -144 => '1/8',
225 -168 => '1/11',
226 -192 => '1/16',
227 -216 => '1/22',
228 -240 => '1/32',
229 -288 => '1/64',
230 },
231 },
232 0x100d => { #3
233 Name => 'FullPressSnap',
234 Writable => 'int16u',
235 PrintConv => { 0 => 'Off', 1 => 'On' },
236 },
237 0x100e => { #3
238 Name => 'DynamicRangeExpansion',
239 Writable => 'int16u',
240 PrintConv => {
241 0 => 'Off',
242 3 => 'Weak',
243 4 => 'Medium',
244 5 => 'Strong',
245 },
246 },
247 0x100f => { #3
248 Name => 'NoiseReduction',
249 Writable => 'int16u',
250 PrintConv => {
251 0 => 'Off',
252 1 => 'Weak',
253 2 => 'Medium',
254 3 => 'Strong',
255 },
256 },
257 0x1010 => { #3
258 Name => 'ImageEffects',
259 Writable => 'int16u',
260 PrintConv => {
261 0 => 'Standard',
262 1 => 'Vivid',
263 3 => 'Black & White',
264 5 => 'B&W Toning Effect',
265 6 => 'Setting 1',
266 7 => 'Setting 2',
267 9 => 'High-contrast B&W',
268 10 => 'Cross Process',
269 11 => 'Positive Film',
270 12 => 'Bleach Bypass',
271 13 => 'Retro',
272 15 => 'Miniature',
273 17 => 'High Key',
274 },
275 },
276 0x1011 => { #3
277 Name => 'Vignetting',
278 Writable => 'int16u',
279 PrintConv => {
280 0 => 'Off',
281 1 => 'Low',
282 2 => 'Medium',
283 3 => 'High',
284 },
285 },
286 0x1012 => { #PH
287 Name => 'Contrast',
288 Writable => 'int32u',
289 Format => 'int32s', #3 (high-contrast B&W also has -1 and -2 settings)
290 PrintConv => {
291 OTHER => sub { shift },
292 2147483647 => 'MAX', #3 (high-contrast B&W effect MAX setting)
293 },
294 },
295 0x1013 => { Name => 'Saturation', Writable => 'int32u' }, #PH
296 0x1014 => { Name => 'Sharpness', Writable => 'int32u' }, #3
297 0x1015 => { #3
298 Name => 'ToningEffect',
299 Writable => 'int16u',
300 PrintConv => {
301 0 => 'Off',
302 1 => 'Sepia',
303 2 => 'Red',
304 3 => 'Green',
305 4 => 'Blue',
306 5 => 'Purple',
307 6 => 'B&W',
308 7 => 'Color',
309 },
310 },
311 0x1016 => { #3
312 Name => 'HueAdjust',
313 Writable => 'int16u',
314 PrintConv => {
315 0 => 'Off',
316 1 => 'Basic',
317 2 => 'Magenta',
318 3 => 'Yellow',
319 4 => 'Normal',
320 5 => 'Warm',
321 6 => 'Cool',
322 },
323 },
324 0x1017 => { #3
325 Name => 'WideAdapter',
326 Writable => 'int16u',
327 PrintConv => {
328 0 => 'Not Attached',
329 2 => 'Attached', # (21mm)
330 },
331 },
332 0x1018 => { #3
333 Name => 'CropMode',
334 Writable => 'int16u',
335 PrintConv => {
336 0 => 'Off',
337 1 => 'On (35mm)',
338 2 => 'On (47mm)', #IB
339 },
340 },
341 0x1019 => { #3
342 Name => 'NDFilter',
343 Writable => 'int16u',
344 PrintConv => { 0 => 'Off', 1 => 'On' },
345 },
346 0x101a => { Name => 'WBBracketShotNumber', Writable => 'int16u' }, #3
347 # 0x1100 - related to DR correction (ref 3)
348 0x1307 => { Name => 'ColorTempKelvin', Writable => 'int32u' }, #3
349 0x1308 => { Name => 'ColorTemperature', Writable => 'int32u' }, #3
350 0x1500 => { #3
351 Name => 'FocalLength',
352 Writable => 'rational64u',
353 PrintConv => 'sprintf("%.1f mm",$val)',
354 PrintConvInv => '$val=~s/\s*mm$//;$val',
355 },
356 0x1200 => { #3
357 Name => 'AFStatus',
358 Writable => 'int16u',
359 PrintConv => {
360 0 => 'Out of Focus',
361 1 => 'In Focus',
362 },
363 },
364 # 0x1201-0x1204 - related to focus points (ref 3)
365 0x1201 => { #PH (NC)
366 Name => 'AFAreaXPosition1',
367 Writable => 'int32u',
368 Notes => 'manual AF area position in a 1280x864 image',
369 },
370 0x1202 => { Name => 'AFAreaYPosition1', Writable => 'int32u' }, #PH (NC)
371 0x1203 => { #PH (NC)
372 Name => 'AFAreaXPosition',
373 Writable => 'int32u',
374 Notes => 'manual AF area position in the full image',
375 # (coordinates change to correspond with smaller image
376 # when recording reduced-size JPEG)
377 },
378 0x1204 => { Name => 'AFAreaYPosition', Writable => 'int32u' }, #PH (NC)
379 0x1205 => { #3
380 Name => 'AFAreaMode',
381 Writable => 'int16u',
382 PrintConv => {
383 0 => 'Auto',
384 2 => 'Manual',
385 },
386 },
387 0x1601 => { Name => 'SensorWidth', Writable => 'int32u' }, #3
388 0x1602 => { Name => 'SensorHeight', Writable => 'int32u' }, #3
389 0x1603 => { Name => 'CroppedImageWidth', Writable => 'int32u' }, #3
390 0x1604 => { Name => 'CroppedImageHeight', Writable => 'int32u' }, #3
391 # 0x1700 - Composite? (0=normal image, 1=interval composite, 2=multi-exposure composite) (ref 3)
392 # 0x1703 - 0=normal, 1=final composite (ref 3)
393 # 0x1704 - 0=normal, 2=final composite (ref 3)
394 0x2001 => [
395 {
396 Name => 'RicohSubdir',
397 Condition => q{
398 $self->{Model} !~ /^Caplio RR1\b/ and
399 ($format ne 'int32u' or $count != 1)
400 },
401 SubDirectory => {
402 Validate => '$val =~ /^\[Ricoh Camera Info\]/',
403 TagTable => 'Image::ExifTool::Ricoh::Subdir',
404 Start => '$valuePtr + 20',
405 ByteOrder => 'BigEndian',
406 },
407 },
408 {
409 Name => 'RicohSubdirIFD',
410 # the CX6 and GR Digital 4 write an int32u pointer in AVI videos -- doh!
411 Condition => '$self->{Model} !~ /^Caplio RR1\b/',
412 Flags => 'SubIFD',
413 SubDirectory => {
414 TagTable => 'Image::ExifTool::Ricoh::Subdir',
415 Start => '$val + 20', # (skip over "[Ricoh Camera Info]\0" header)
416 ByteOrder => 'BigEndian',
417 },
418 },
419 {
420 Name => 'RicohRR1Subdir',
421 SubDirectory => {
422 Validate => '$val =~ /^\[Ricoh Camera Info\]/',
423 TagTable => 'Image::ExifTool::Ricoh::Subdir',
424 Start => '$valuePtr + 20',
425 ByteOrder => 'BigEndian',
426 # the Caplio RR1 uses a different base address -- doh!
427 Base => '$start-20',
428 },
429 },
430 ],
431 0x4001 => {
432 Name => 'ThetaSubdir',
433 Groups => { 1 => 'MakerNotes' }, # SubIFD needs group 1 set
434 Flags => 'SubIFD',
435 SubDirectory => {
436 TagTable => 'Image::ExifTool::Ricoh::ThetaSubdir',
437 Start => '$val',
438 },
439 },
440);
441
442# Ricoh type 2 maker notes (ref PH)
443# (similar to Kodak::Type11 and GE::Main)
444%Image::ExifTool::Ricoh::Type2 = (
445 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
446 NOTES => q{
447 Tags written by models such as the Ricoh HZ15 and the Pentax XG-1. These
448 are not writable due to numerous formatting errors as written by these
449 cameras.
450 },
451 # 0x104 - int32u: 1
452 # 0x200 - int32u[3]: 0 0 0
453 # 0x202 - int16u: 0 (GE Macro?)
454 # 0x203 - int16u: 0,3 (Kodak PictureEffect?)
455 # 0x204 - rational64u: 0/10
456 # 0x205 - rational64u: 150/1
457 # 0x206 - float[6]: (not really float because size should be 2 bytes)
458 0x207 => {
459 Name => 'RicohModel',
460 Writable => 'string',
461 },
462 0x300 => {
463 # brutal. There are lots of errors in the XG-1 maker notes. For the XG-1,
464 # 0x300 has a value of "XG-1Pentax". The "XG-1" part is likely an improperly
465 # stored 0x207 RicohModel, resulting in an erroneous 4-byte offset for this tag
466 Name => 'RicohMake',
467 Writable => 'undef',
468 ValueConv => '$val =~ s/ *$//; $val',
469 },
470 # 0x306 - int16u: 1
471 # 0x500 - int16u: 0,1
472 # 0x501 - int16u: 0
473 # 0x502 - int16u: 0
474 # 0x9c9c - int8u[6]: ?
475 # 0xadad - int8u[20480]: ?
476);
477
478# Ricoh image info (ref 2)
479%Image::ExifTool::Ricoh::ImageInfo = (
480 GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
481 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
482 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
483 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
484 WRITABLE => 1,
485 PRIORITY => 0,
486 FORMAT => 'int8u',
487 FIRST_ENTRY => 0,
488 IS_OFFSET => [ 28 ], # tag 28 is 'IsOffset'
489 0 => {
490 Name => 'RicohImageWidth',
491 Format => 'int16u',
492 },
493 2 => {
494 Name => 'RicohImageHeight',
495 Format => 'int16u',
496 },
497 6 => {
498 Name => 'RicohDate',
499 Groups => { 2 => 'Time' },
500 Format => 'int8u[7]',
501 # (what an insane way to encode the date)
502 ValueConv => q{
503 sprintf("%.2x%.2x:%.2x:%.2x %.2x:%.2x:%.2x",
504 split(' ', $val));
505 },
506 ValueConvInv => q{
507 my @vals = ($val =~ /(\d{1,2})/g);
508 push @vals, 0 if @vals < 7;
509 join(' ', map(hex, @vals));
510 },
511 },
512 28 => {
513 Name => 'PreviewImageStart',
514 Format => 'int16u', # ha! (only the lower 16 bits, even if > 0xffff)
515 Flags => 'IsOffset',
516 OffsetPair => 30, # associated byte count tagID
517 DataTag => 'PreviewImage',
518 Protected => 2,
519 WriteGroup => 'MakerNotes',
520 # prevent preview from being written to MakerNotes of DNG images
521 RawConvInv => q{
522 return $val if $$self{FILE_TYPE} eq "JPEG";
523 warn "\n"; # suppress warning
524 return undef;
525 },
526 },
527 30 => {
528 Name => 'PreviewImageLength',
529 Format => 'int16u',
530 OffsetPair => 28, # point to associated offset
531 DataTag => 'PreviewImage',
532 Protected => 2,
533 WriteGroup => 'MakerNotes',
534 RawConvInv => q{
535 return $val if $$self{FILE_TYPE} eq "JPEG";
536 warn "\n"; # suppress warning
537 return undef;
538 },
539 },
540 32 => {
541 Name => 'FlashMode',
542 PrintConv => {
543 0 => 'Off',
544 1 => 'Auto', #PH
545 2 => 'On',
546 },
547 },
548 33 => {
549 Name => 'Macro',
550 PrintConv => { 0 => 'Off', 1 => 'On' },
551 },
552 34 => {
553 Name => 'Sharpness',
554 PrintConv => {
555 0 => 'Sharp',
556 1 => 'Normal',
557 2 => 'Soft',
558 },
559 },
560 38 => {
561 Name => 'WhiteBalance',
562 PrintConv => {
563 0 => 'Auto',
564 1 => 'Daylight',
565 2 => 'Cloudy',
566 3 => 'Tungsten',
567 4 => 'Fluorescent',
568 5 => 'Manual', #PH (GXR)
569 7 => 'Detail',
570 9 => 'Multi-pattern Auto', #PH (GXR)
571 },
572 },
573 39 => {
574 Name => 'ISOSetting',
575 PrintConv => {
576 0 => 'Auto',
577 1 => 64,
578 2 => 100,
579 4 => 200,
580 6 => 400,
581 7 => 800,
582 8 => 1600,
583 9 => 'Auto', #PH (? CX3)
584 10 => 3200, #PH (A16)
585 11 => '100 (Low)', #PH (A16)
586 },
587 },
588 40 => {
589 Name => 'Saturation',
590 PrintConv => {
591 0 => 'High',
592 1 => 'Normal',
593 2 => 'Low',
594 3 => 'B&W',
595 6 => 'Toning Effect', #PH (GXR Sepia,Red,Green,Blue,Purple)
596 9 => 'Vivid', #PH (GXR)
597 10 => 'Natural', #PH (GXR)
598 },
599 },
600);
601
602# Ricoh subdirectory tags (ref PH)
603# NOTE: this subdir is currently not writable because the offsets would require
604# special code to handle the funny start location and base offset
605%Image::ExifTool::Ricoh::Subdir = (
606 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
607 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
608 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
609 # the significance of the following 2 dates is not known. They are usually
610 # within a month of each other, but I have seen differences of nearly a year.
611 # Sometimes the first is more recent, and sometimes the second.
612 # 0x0003 - int32u[1]
613 0x0004 => { # (NC)
614 Name => 'ManufactureDate1',
615 Groups => { 2 => 'Time' },
616 Writable => 'string',
617 Count => 20,
618 },
619 0x0005 => { # (NC)
620 Name => 'ManufactureDate2',
621 Groups => { 2 => 'Time' },
622 Writable => 'string',
623 Count => 20,
624 },
625 # 0x0006 - undef[16] ?
626 # 0x0007 - int32u[1] ?
627 # 0x000c - int32u[2] 1st number is a counter (file number? shutter count?) - PH
628 # 0x0014 - int8u[338] could contain some data related to face detection? - PH
629 # 0x0015 - int8u[2]: related to noise reduction?
630 0x001a => { #PH
631 Name => 'FaceInfo',
632 SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::FaceInfo' },
633 },
634 0x0029 => {
635 Name => 'FirmwareInfo',
636 SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::FirmwareInfo' },
637 },
638 0x002a => {
639 Name => 'NoiseReduction',
640 # this is the applied value if NR is set to "Auto"
641 Writable => 'int32u',
642 PrintConv => {
643 0 => 'Off',
644 1 => 'Weak',
645 2 => 'Strong',
646 3 => 'Max',
647 },
648 },
649 0x002c => { # (GXR)
650 Name => 'SerialInfo',
651 SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::SerialInfo' },
652 }
653 # 0x000E ProductionNumber? (ref 2) [no. zero for most models - PH]
654);
655
656# Ricoh Theta subdirectory tags - Contains orientation information (ref 4)
657%Image::ExifTool::Ricoh::ThetaSubdir = (
658 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
659 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
660 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
661 # 0x0001 - int16u[1] ?
662 # 0x0002 - int16u[1] ?
663 0x0003 => {
664 Name => 'Accelerometer',
665 Writable => 'rational64s',
666 Count => 2,
667 },
668 0x0004 => {
669 Name => 'Compass',
670 Writable => 'rational64u',
671 },
672 # 0x0005 - int16u[1] ?
673 # 0x0006 - int16u[1] ?
674 # 0x0007 - int16u[1] ?
675 # 0x0008 - int16u[1] ?
676 # 0x0009 - int16u[1] ?
677 0x000a => {
678 Name => 'TimeZone',
679 Writable => 'string',
680 },
681 # 0x0101 - int16u[4] ISO (why 4 values?)
682 # 0x0102 - rational64s[2] FNumber (why 2 values?)
683 # 0x0103 - rational64u[2] ExposureTime (why 2 values?)
684 # 0x0104 - string[9] SerialNumber?
685 # 0x0105 - string[9] SerialNumber?
686);
687
688# face detection information (ref PH, CX4)
689%Image::ExifTool::Ricoh::FaceInfo = (
690 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
691 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
692 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
693 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
694 WRITABLE => 1,
695 FIRST_ENTRY => 0,
696 DATAMEMBER => [ 181 ],
697 0xb5 => { # (should be int16u at 0xb4?)
698 Name => 'FacesDetected',
699 DataMember => 'FacesDetected',
700 RawConv => '$$self{FacesDetected} = $val',
701 },
702 0xb6 => {
703 Name => 'FaceDetectFrameSize',
704 Format => 'int16u[2]',
705 },
706 0xbc => {
707 Name => 'Face1Position',
708 Condition => '$$self{FacesDetected} >= 1',
709 Format => 'int16u[4]',
710 Notes => q{
711 left, top, width and height of detected face in coordinates of
712 FaceDetectFrameSize with increasing Y downwards
713 },
714 },
715 0xc8 => {
716 Name => 'Face2Position',
717 Condition => '$$self{FacesDetected} >= 2',
718 Format => 'int16u[4]',
719 },
720 0xd4 => {
721 Name => 'Face3Position',
722 Condition => '$$self{FacesDetected} >= 3',
723 Format => 'int16u[4]',
724 },
725 0xe0 => {
726 Name => 'Face4Position',
727 Condition => '$$self{FacesDetected} >= 4',
728 Format => 'int16u[4]',
729 },
730 0xec => {
731 Name => 'Face5Position',
732 Condition => '$$self{FacesDetected} >= 5',
733 Format => 'int16u[4]',
734 },
735 0xf8 => {
736 Name => 'Face6Position',
737 Condition => '$$self{FacesDetected} >= 6',
738 Format => 'int16u[4]',
739 },
740 0x104 => {
741 Name => 'Face7Position',
742 Condition => '$$self{FacesDetected} >= 7',
743 Format => 'int16u[4]',
744 },
745 0x110 => {
746 Name => 'Face8Position',
747 Condition => '$$self{FacesDetected} >= 8',
748 Format => 'int16u[4]',
749 },
750);
751
752# firmware version information (ref PH)
753%Image::ExifTool::Ricoh::FirmwareInfo = (
754 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
755 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
756 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
757 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
758 WRITABLE => 1,
759 0x00 => {
760 Name => 'FirmwareRevision',
761 Format => 'string[12]',
762 },
763 0x0c => {
764 Name => 'FirmwareRevision2',
765 Format => 'string[12]',
766 },
767);
768
769# serial/version number information written by GXR (ref PH)
770%Image::ExifTool::Ricoh::SerialInfo = (
771 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
772 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
773 WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
774 CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
775 WRITABLE => 1,
776 NOTES => 'This information is found in images from the GXR.',
777 0 => {
778 Name => 'BodyFirmware', #(NC)
779 Format => 'string[16]',
780 # observed: "RS1 :V00560000" --> FirmwareVersion "Rev0056"
781 # "RS1 :V01020200" --> FirmwareVersion "Rev0102"
782 },
783 16 => {
784 Name => 'BodySerialNumber',
785 Format => 'string[16]',
786 # observed: "SID:00100056" --> "WD00100056" on plate
787 },
788 32 => {
789 Name => 'LensFirmware', #(NC)
790 Format => 'string[16]',
791 # observed: "RL1 :V00560000", "RL1 :V01020200" - A12 50mm F2.5 Macro
792 # "RL2 :V00560000", "RL2 :V01020300" - S10 24-70mm F2.5-4.4 VC
793 # --> used in a Composite tag to determine LensType
794 },
795 48 => {
796 Name => 'LensSerialNumber',
797 Format => 'string[16]',
798 # observed: (S10) "LID:00010024" --> "WF00010024" on plate
799 # (A12) "LID:00010054" --> "WE00010029" on plate??
800 },
801);
802
803# Ricoh text-type maker notes (PH)
804%Image::ExifTool::Ricoh::Text = (
805 GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
806 PROCESS_PROC => \&ProcessRicohText,
807 NOTES => q{
808 Some Ricoh DC and RDC models use a text-based format for their maker notes
809 instead of the IFD format used by the Caplio models. Below is a list of known
810 tags in this information.
811 },
812 Rev => {
813 Name => 'FirmwareVersion',
814 PrintConv => '$val=~/^\d+$/ ? sprintf("%.2f",$val/100) : $val',
815 PrintConvInv => '$val=~/^(\d+)\.(\d+)$/ ? sprintf("%.2d%.2d",$1,$2) : $val',
816 },
817 Rv => {
818 Name => 'FirmwareVersion',
819 PrintConv => '$val=~/^\d+$/ ? sprintf("%.2f",$val/100) : $val',
820 PrintConvInv => '$val=~/^(\d+)\.(\d+)$/ ? sprintf("%.2d%.2d",$1,$2) : $val',
821 },
822 Rg => 'RedGain',
823 Gg => 'GreenGain',
824 Bg => 'BlueGain',
825);
826
827%Image::ExifTool::Ricoh::RMETA = (
828 GROUPS => { 0 => 'APP5', 1 => 'RMETA', 2 => 'Image' },
829 PROCESS_PROC => \&Image::ExifTool::Ricoh::ProcessRicohRMETA,
830 NOTES => q{
831 The Ricoh Caplio Pro G3 has the ability to add custom fields to the APP5
832 "RMETA" segment of JPEG images. While only a few observed tags have been
833 defined below, ExifTool will extract any information found here.
834 },
835 'Sign type' => { Name => 'SignType', PrintConv => {
836 1 => 'Directional',
837 2 => 'Warning',
838 3 => 'Information',
839 } },
840 Location => { PrintConv => {
841 1 => 'Verge',
842 2 => 'Gantry',
843 3 => 'Central reservation',
844 4 => 'Roundabout',
845 } },
846 Lit => { PrintConv => {
847 1 => 'Yes',
848 2 => 'No',
849 } },
850 Condition => { PrintConv => {
851 1 => 'Good',
852 2 => 'Fair',
853 3 => 'Poor',
854 4 => 'Damaged',
855 } },
856 Azimuth => { PrintConv => {
857 1 => 'N',
858 2 => 'NNE',
859 3 => 'NE',
860 4 => 'ENE',
861 5 => 'E',
862 6 => 'ESE',
863 7 => 'SE',
864 8 => 'SSE',
865 9 => 'S',
866 10 => 'SSW',
867 11 => 'SW',
868 12 => 'WSW',
869 13 => 'W',
870 14 => 'WNW',
871 15 => 'NW',
872 16 => 'NNW',
873 } },
874 _audio => {
875 Name => 'SoundFile',
876 Notes => 'audio data recorded in JPEG images by the G700SE',
877 },
878 _barcode => { Name => 'Barcodes', List => 1 },
879);
880
881# information stored in Ricoh AVI images (ref PH)
882%Image::ExifTool::Ricoh::AVI = (
883 GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
884 ucmt => {
885 Name => 'Comment',
886 # Ricoh writes a "Unicode" header even when text is ASCII (spaces anyway)
887 ValueConv => '$_=$val; s/^(Unicode\0|ASCII\0\0\0)//; tr/\0//d; s/\s+$//; $_',
888 },
889 mnrt => {
890 Name => 'MakerNoteRicoh',
891 SubDirectory => {
892 TagTable => 'Image::ExifTool::Ricoh::Main',
893 Start => '$valuePtr + 8',
894 ByteOrder => 'BigEndian',
895 Base => '8',
896 },
897 },
898 rdc2 => {
899 Name => 'RicohRDC2',
900 Unknown => 1,
901 ValueConv => 'unpack("H*",$val)',
902 # have seen values like 0a000444 and 00000000 - PH
903 },
904 thum => {
905 Name => 'ThumbnailImage',
906 Groups => { 2 => 'Preview' },
907 Binary => 1,
908 },
909);
910
911# Ricoh composite tags
912%Image::ExifTool::Ricoh::Composite = (
913 GROUPS => { 2 => 'Camera' },
914 LensID => {
915 SeparateTable => 'Ricoh LensID',
916 Require => 'Ricoh:LensFirmware',
917 RawConv => '$val[0] ? $val[0] : undef',
918 ValueConv => '$val=~s/\s*:.*//; $val',
919 PrintConv => \%ricohLensIDs,
920 },
921 RicohPitch => {
922 Require => 'Ricoh:Accelerometer',
923 ValueConv => 'my @v = split(" ",$val); $v[1]',
924 },
925 RicohRoll => {
926 Require => 'Ricoh:Accelerometer',
927 ValueConv => 'my @v = split(" ",$val); $v[0] <= 180 ? $v[0] : $v[0] - 360',
928 },
929);
930
931# add our composite tags
932Image::ExifTool::AddCompositeTags('Image::ExifTool::Ricoh');
933
934
935#------------------------------------------------------------------------------
936# Process Ricoh text-based maker notes
937# Inputs: 0) ExifTool object reference
938# 1) Reference to directory information hash
939# 2) Pointer to tag table for this directory
940# Returns: 1 on success, otherwise returns 0 and sets a Warning
941sub ProcessRicohText($$$)
942{
943 my ($et, $dirInfo, $tagTablePtr) = @_;
944 my $dataPt = $$dirInfo{DataPt};
945 my $dataLen = $$dirInfo{DataLen};
946 my $dirStart = $$dirInfo{DirStart} || 0;
947 my $dirLen = $$dirInfo{DirLen} || $dataLen - $dirStart;
948 my $verbose = $et->Options('Verbose');
949
950 my $data = substr($$dataPt, $dirStart, $dirLen);
951 return 1 if $data =~ /^\0/; # blank Ricoh maker notes
952 # validate text maker notes
953 unless ($data =~ /^(Rev|Rv)/) {
954 $et->Warn('Bad Ricoh maker notes');
955 return 0;
956 }
957 while ($data =~ m/([A-Z][a-z]{1,2})([0-9A-F]+);/sg) {
958 my $tag = $1;
959 my $val = $2;
960 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
961 if ($verbose) {
962 $et->VerboseInfo($tag, $tagInfo,
963 Table => $tagTablePtr,
964 Value => $val,
965 );
966 }
967 unless ($tagInfo) {
968 next unless $$et{OPTIONS}{Unknown};
969 $tagInfo = {
970 Name => "Ricoh_Text_$tag",
971 Unknown => 1,
972 PrintConv => 'length($val) > 60 ? substr($val,0,55) . "[...]" : $val',
973 };
974 # add tag information to table
975 AddTagToTable($tagTablePtr, $tag, $tagInfo);
976 }
977 $et->FoundTag($tagInfo, $val);
978 }
979 return 1;
980}
981
982#------------------------------------------------------------------------------
983# Process Ricoh APP5 RMETA information
984# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
985# Returns: 1 on success, otherwise returns 0 and sets a Warning
986sub ProcessRicohRMETA($$$)
987{
988 my ($et, $dirInfo, $tagTablePtr) = @_;
989 my $dataPt = $$dirInfo{DataPt};
990 my $dirStart = $$dirInfo{DirStart};
991 my $dataLen = length($$dataPt);
992 my $dirLen = $dataLen - $dirStart;
993 my $verbose = $et->Options('Verbose');
994
995 $et->VerboseDir('Ricoh RMETA') if $verbose;
996 $dirLen < 20 and $et->Warn('Truncated Ricoh RMETA data', 1), return 0;
997 my $byteOrder = substr($$dataPt, $dirStart, 2);
998 $byteOrder = GetByteOrder() if $byteOrder eq "\0\0"; # (same order as container)
999 SetByteOrder($byteOrder) or $et->Warn('Bad Ricoh RMETA data', 1), return 0;
1000 # get the RMETA segment number
1001 my $rmetaNum = Get16u($dataPt, $dirStart+4);
1002 if ($rmetaNum != 0) {
1003 # not sure how to recognize audio, so do it by checking for "RIFF" header
1004 # and assume all subsequent RMETA segments are part of the audio data
1005 # (but it looks like the int16u at $dirStart+6 is the next block number
1006 # if the data is continued, or 0 for the last block)
1007 $dirLen < 14 and $et->Warn('Short Ricoh RMETA block', 1), return 0;
1008 if ($$dataPt =~ /^.{20}BARCODE/s) {
1009 my $val = substr($$dataPt, 20);
1010 $val =~ s/\0.*//s;
1011 $val =~ s/^BARCODE\w+,\d{2},//;
1012 my @codes;
1013 for (;;) {
1014 $val =~ s/(\d+),// and length $val >= $1 or last;
1015 push @codes, substr($val, 0, $1);
1016 last unless length $val > $1;
1017 $val = substr($val, $1+1);
1018 }
1019 $et->HandleTag($tagTablePtr, '_barcode', \@codes) if @codes;
1020 return 1;
1021 } elsif ($$dataPt =~ /^.{18}ASCII/s) {
1022 # (ignore barcode tag names for now)
1023 return 1;
1024 }
1025 my $audioLen = Get16u($dataPt, $dirStart+12);
1026 $audioLen + 14 > $dirLen and $et->Warn('Truncated Ricoh RMETA audio data', 1), return 0;
1027 my $buff = substr($$dataPt, $dirStart + 14, $audioLen);
1028 if ($audioLen >= 4 and substr($buff, 0, 4) eq 'RIFF') {
1029 $et->HandleTag($tagTablePtr, '_audio', \$buff);
1030 } elsif ($$et{VALUE}{SoundFile}) {
1031 ${$$et{VALUE}{SoundFile}} .= $buff;
1032 } else {
1033 $et->Warn('Unknown Ricoh RMETA type', 1);
1034 return 0;
1035 }
1036 return 1;
1037 }
1038 # decode standard RMETA tag directory
1039 my (@tags, @vals, @nums, $valPos, $numPos);
1040 my $pos = $dirStart + Get16u($dataPt, $dirStart+8);
1041 my $numEntries = Get16u($dataPt, $pos);
1042 $numEntries > 100 and $et->Warn('Bad RMETA entry count'), return 0;
1043 $pos += 10; # start of first RMETA section
1044 # loop through RMETA sections
1045 while ($pos <= $dataLen - 4) {
1046 my $type = Get16u($dataPt, $pos);
1047 my $size = Get16u($dataPt, $pos + 2);
1048 last unless $size;
1049 $pos += 4;
1050 $size -= 2;
1051 if ($size < 0 or $pos + $size > $dataLen) {
1052 $et->Warn('Corrupted Ricoh RMETA data', 1);
1053 last;
1054 }
1055 my $dat = substr($$dataPt, $pos, $size);
1056 if ($verbose) {
1057 $et->VPrint(2, "$$et{INDENT}RMETA section type=$type size=$size\n");
1058 $et->VerboseDump(\$dat, Addr => $$dirInfo{DataPos} + $pos);
1059 }
1060 if ($type == 1) { # section 1: tag names
1061 # save the tag names
1062 @tags = split /\0/, $dat, $numEntries+1;
1063 } elsif ($type == 2 || $type == 18) { # section 2/18: string values (G800 uses type 18)
1064 # save the tag values (assume "ASCII\0" encoding since others never seen)
1065 @vals = split /\0/, $dat, $numEntries+1;
1066 $valPos = $pos; # save position of first string value
1067 } elsif ($type == 3) { # section 3: numerical values
1068 if ($size < $numEntries * 2) {
1069 $et->Warn('Truncated RMETA section 3');
1070 } else {
1071 # save the numerical tag values
1072 # (0=empty, 0xffff=text input, otherwise menu item number)
1073 @nums = unpack(($byteOrder eq 'MM' ? 'n' : 'v').$numEntries, $dat);
1074 $numPos = $pos; # save position of numerical values
1075 }
1076 } elsif ($type != 16) {
1077 $et->Warn("Unrecognized RMETA section (type $type, len $size)");
1078 }
1079 $pos += $size;
1080 }
1081 return 1 unless @tags or @vals;
1082 $valPos or $valPos = 0; # (just in case there was no value section)
1083 # find next tag in null-delimited list
1084 # unpack numerical values from block of int16u values
1085 my ($i, $name);
1086 for ($i=0; $i<$numEntries; ++$i) {
1087 my $tag = $tags[$i];
1088 my $val = $vals[$i];
1089 $val = '' unless defined $val;
1090 unless (defined $tag and length $tag) {
1091 length $val or ++$valPos, next; # (skip empty entries)
1092 $tag = '';
1093 }
1094 ($name = $tag) =~ s/\b([a-z])/\U$1/gs; # capitalize all words
1095 $name =~ s/ (\w)/\U$1/g; # remove special characters
1096 $name = 'RMETA_Unknown' unless length($name);
1097 my $num = $nums[$i];
1098 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1099 if ($tagInfo) {
1100 # make sure print conversion is defined
1101 $$tagInfo{PrintConv} = { } unless ref $$tagInfo{PrintConv} eq 'HASH';
1102 } else {
1103 # create tagInfo hash
1104 $tagInfo = { Name => $name, PrintConv => { } };
1105 AddTagToTable($tagTablePtr, $tag, $tagInfo);
1106 }
1107 # use string value directly if no numerical value
1108 $num = $val unless defined $num;
1109 # add conversion for this value (replacing any existing entry)
1110 $tagInfo->{PrintConv}->{$num} = length $val ? $val : $num;
1111 if ($verbose) {
1112 my %datParms;
1113 if (length $val) {
1114 %datParms = ( Start => $valPos, Size => length($val), Format => 'string' );
1115 } elsif ($numPos) {
1116 %datParms = ( Start => $numPos + $i * 2, Size => 2, Format => 'int16u' );
1117 }
1118 %datParms and $datParms{DataPt} = $dataPt, $datParms{DataPos} = $$dirInfo{DataPos};
1119 $et->VerboseInfo($tag, $tagInfo, Table=>$tagTablePtr, Value=>$num, %datParms);
1120 }
1121 $et->FoundTag($tagInfo, $num);
1122 $valPos += length($val) + 1;
1123 }
1124 return 1;
1125}
1126
11271; # end
1128
1129__END__
1130
1131=head1 NAME
1132
1133Image::ExifTool::Ricoh - Ricoh EXIF maker notes tags
1134
1135=head1 SYNOPSIS
1136
1137This module is loaded automatically by Image::ExifTool when required.
1138
1139=head1 DESCRIPTION
1140
1141This module contains definitions required by Image::ExifTool to
1142interpret Ricoh maker notes EXIF meta information.
1143
1144=head1 AUTHOR
1145
1146Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
1147
1148This library is free software; you can redistribute it and/or modify it
1149under the same terms as Perl itself.
1150
1151=head1 REFERENCES
1152
1153=over 4
1154
1155=item L<http://www.ozhiker.com/electronics/pjmt/jpeg_info/ricoh_mn.html>
1156
1157=back
1158
1159=head1 ACKNOWLEDGEMENTS
1160
1161Thanks to Tim Gray for his help decoding a number of tags for the Ricoh GR.
1162
1163=head1 SEE ALSO
1164
1165L<Image::ExifTool::TagNames/Ricoh Tags>,
1166L<Image::ExifTool(3pm)|Image::ExifTool>
1167
1168=cut
Note: See TracBrowser for help on using the repository browser.