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 |
|
---|
15 | package Image::ExifTool::Ricoh;
|
---|
16 |
|
---|
17 | use strict;
|
---|
18 | use vars qw($VERSION);
|
---|
19 | use Image::ExifTool qw(:DataAccess :Utils);
|
---|
20 | use Image::ExifTool::Exif;
|
---|
21 |
|
---|
22 | $VERSION = '1.35';
|
---|
23 |
|
---|
24 | sub ProcessRicohText($$$);
|
---|
25 | sub ProcessRicohRMETA($$$);
|
---|
26 |
|
---|
27 | # lens types for Ricoh GXR
|
---|
28 | my %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
|
---|
932 | Image::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
|
---|
941 | sub 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
|
---|
986 | sub 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 |
|
---|
1127 | 1; # end
|
---|
1128 |
|
---|
1129 | __END__
|
---|
1130 |
|
---|
1131 | =head1 NAME
|
---|
1132 |
|
---|
1133 | Image::ExifTool::Ricoh - Ricoh EXIF maker notes tags
|
---|
1134 |
|
---|
1135 | =head1 SYNOPSIS
|
---|
1136 |
|
---|
1137 | This module is loaded automatically by Image::ExifTool when required.
|
---|
1138 |
|
---|
1139 | =head1 DESCRIPTION
|
---|
1140 |
|
---|
1141 | This module contains definitions required by Image::ExifTool to
|
---|
1142 | interpret Ricoh maker notes EXIF meta information.
|
---|
1143 |
|
---|
1144 | =head1 AUTHOR
|
---|
1145 |
|
---|
1146 | Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
|
---|
1147 |
|
---|
1148 | This library is free software; you can redistribute it and/or modify it
|
---|
1149 | under 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 |
|
---|
1161 | Thanks to Tim Gray for his help decoding a number of tags for the Ricoh GR.
|
---|
1162 |
|
---|
1163 | =head1 SEE ALSO
|
---|
1164 |
|
---|
1165 | L<Image::ExifTool::TagNames/Ricoh Tags>,
|
---|
1166 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
1167 |
|
---|
1168 | =cut
|
---|