source: main/trunk/greenstone2/perllib/cpan/Image/ExifTool/Red.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: 10.8 KB
Line 
1#------------------------------------------------------------------------------
2# File: Red.pm
3#
4# Description: Read Redcode R3D video files
5#
6# Revisions: 2018-01-25 - P. Harvey Created
7#
8# References: 1) http://www.wikiwand.com/en/REDCODE
9#------------------------------------------------------------------------------
10
11package Image::ExifTool::Red;
12
13use strict;
14use vars qw($VERSION);
15use Image::ExifTool qw(:DataAccess :Utils);
16
17$VERSION = '1.01';
18
19sub ProcessR3D($$);
20
21# RED format codes (ref PH)
22my %redFormat = (
23 0 => 'int8u',
24 1 => 'string',
25 2 => 'float',
26 3 => 'int8u', # (how is this different than 0?)
27 4 => 'int16u',
28 5 => 'int8s', # (not sure about this)
29 6 => 'int32s',
30 7 => 'undef', # (mixed-format structure?)
31 8 => 'int32u', # (NC)
32 9 => 'undef', # ? (seen 256 bytes, all zero)
33);
34
35# error strings
36my $errTrunc = 'Truncated R3D file';
37
38# RED directory tags (ref PH)
39%Image::ExifTool::Red::Main = (
40 GROUPS => { 2 => 'Camera' },
41 NOTES => 'Tags extracted from Redcode R3D video files.',
42 VARS => { ALPHA_FIRST => 1 },
43
44 RED1 => { Name => 'Red1Header', SubDirectory => { TagTable => 'Image::ExifTool::Red::RED1' } },
45 RED2 => { Name => 'Red2Header', SubDirectory => { TagTable => 'Image::ExifTool::Red::RED2' } },
46
47 # (upper 4 bits of tag ID are the format code)
48 # ---- format 1 ----
49 0x1000 => 'StartEdgeCode', #1
50 0x1001 => { Name => 'StartTimecode', Groups => { 2 => 'Time' } }, #1
51 0x1002 => { #1
52 Name => 'OtherDate1',
53 Groups => { 2 => 'Time' },
54 # format is "YYYY_MM_DD[_TZ?]"
55 ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val',
56 },
57 0x1003 => { #1
58 Name => 'OtherDate2',
59 Groups => { 2 => 'Time' },
60 ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val',
61 },
62 0x1004 => { #1
63 Name => 'OtherDate3',
64 Groups => { 2 => 'Time' },
65 ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val',
66 },
67 0x1005 => { #1
68 Name => 'DateTimeOriginal',
69 Description => 'Date/Time Original',
70 Groups => { 2 => 'Time' },
71 ValueConv => '$val =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/$1:$2:$3 $4:$5:/; $val',
72 PrintConv => '$self->ConvertDateTime($val)',
73 },
74 0x1006 => 'SerialNumber', #1
75 0x1019 => 'CameraType', #1
76 0x101a => { Name => 'ReelNumber', Groups => { 2 => 'Video' } }, #1
77 0x101b => { Name => 'Take', Groups => { 2 => 'Video' } },
78 0x1023 => { #1
79 Name => 'DateCreated',
80 Groups => { 2 => 'Time' },
81 ValueConv => '$val =~ s/(\d{4})(\d{2})/$1:$2:/; $val',
82 },
83 0x1024 => { #1
84 Name => 'TimeCreated',
85 Groups => { 2 => 'Time' },
86 ValueConv => '$val =~ s/(\d{2})(\d{2})/$1:$2:/; $val',
87 },
88 0x1025 => 'FirmwareVersion', #1
89 0x1029 => { Name => 'ReelTimecode', Groups => { 2 => 'Time' } }, #1
90 0x102a => 'StorageType', #1
91 0x1030 => { #1
92 Name => 'StorageFormatDate',
93 Groups => { 2 => 'Time' },
94 ValueConv => '$val =~ s/(\d{4})(\d{2})/$1:$2:/; $val',
95 },
96 0x1031 => { #1
97 Name => 'StorageFormatTime',
98 Groups => { 2 => 'Time' },
99 ValueConv => '$val =~ s/(\d{2})(\d{2})/$1:$2:/; $val',
100 },
101 0x1032 => 'StorageSerialNumber', #1
102 0x1033 => 'StorageModel', #1
103 0x1036 => 'AspectRatio', #1
104 # 0x1041 - seen 'NA'
105 0x1042 => 'Revision', # ? (seen "TODO, rev EPIC-1.0" and "MYSTERIUM X, rev EPIC-1.0")
106 # 0x1051 - seen 'C', 'L'
107 0x1056 => 'OriginalFileName',
108 0x106e => 'LensMake',
109 0x106f => 'LensNumber', # (last 2 hex digits are LensType)
110 0x1070 => 'LensModel',
111 0x1071 => {
112 Name => 'Model',
113 Description => 'Camera Model Name',
114 },
115 0x107c => { Name => 'CameraOperator', Groups => { 2 => 'Author' } },
116 0x1086 => {
117 Name => 'VideoFormat',
118 Groups => { 2 => 'Video' },
119 },
120 0x1096 => 'Filter', # optical low-pass filter
121 0x10a0 => 'Brain',
122 0x10a1 => 'Sensor',
123 # ---- format 2 ----
124 0x200d => 'ColorTemperature',
125 # 0x200e - (sometimes this is frame rate)
126 # 0x2015 - seen '1 1 1' (RGBGain or RGBGamma?)
127 0x204b => 'RGBCurves', # (blackx/y,toex/y,midx/y,kneex/y,whitex/y)
128 0x2066 => {
129 Name => 'OriginalFrameRate',
130 Groups => { 2 => 'Video' },
131 PrintConv => 'int($val * 1000 + 0.5) / 1000',
132 },
133 # ---- format 4 ----
134 0x4037 => { Name => 'CropArea' }, # (NC)
135 0x403b => 'ISO',
136 # 0x404e - related to CropArea (or "0 0 0 0")
137 0x406a => { Name => 'FNumber', ValueConv => '$val / 10' },
138 0x406b => 'FocalLength',
139 # 0x4084 - related to ISO?
140 # 0x4087 - related to ISO?
141 # ---- format 6 ----
142 0x606c => { Name => 'FocusDistance', ValueConv => '$val/1000', PrintConv => '"$val m"' },
143);
144
145# RED1 file header (ref PH)
146%Image::ExifTool::Red::RED1 = (
147 GROUPS => { 2 => 'Video' },
148 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
149 NOTES => 'Redcode version 1 header.',
150 # 0x00 - int32u: length of header
151 # 0x04 - string: "RED1"
152 # 0x0a - string: "R1"
153 0x07 => { Name => 'RedcodeVersion', Format => 'string[1]' }, #1
154 # 0x0e - looks funny; my sample has a value of 43392 here
155 # 0x0e => { Name => 'AudioSampleRate', Format => 'int16u' }, #1
156 0x36 => { Name => 'ImageWidth', Format => 'int16u' }, #1
157 0x3a => { Name => 'ImageHeight', Format => 'int16u' }, #PH (ref 1 gave 0x3c)
158 0x3e => { #PH (ref 1 gave 0x42 for denom)
159 Name => 'FrameRate',
160 Format => 'rational32u',
161 PrintConv => 'int($val * 1000 + 0.5) / 1000',
162 },
163 0x43 => { Name => 'OriginalFileName', Format => 'string[32]' }, #1
164);
165
166# RED2 file header (ref PH)
167%Image::ExifTool::Red::RED2 = (
168 GROUPS => { 2 => 'Video' },
169 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
170 NOTES => 'Redcode version 2 header.',
171 # 0x00 - int32u: length of header
172 # 0x04 - string: "RED2"
173 0x07 => { Name => 'RedcodeVersion', Format => 'string[1]' },
174 # 0x08 - seen 0x05
175 # 0x09 - seen 0x0d,0x0f,0x10
176 # 0x0a - string: "R2"
177 # 0x0c - seen 0x04,0x05,0x07,0x08,0x0b,0x0c
178 # 0x0d - seen 0x01,0x08 (and 0x09 in block 1)
179 # 0x0e - int16u: seen 3072
180 # 0x10 - looks like some sort of 32-byte hash or something (same in other blocks)
181 # 0x30-0x3f - mostly 0x00's with a couple of 0x01's
182 # 0x40 - int8u: count of 0x18-byte "rdi" records
183 # 0x41-0x43 - seen "\0\0\x01"
184 # ---- rdi record: (0x18 bytes long) ----
185 # 0x44 - string: "rdi#" (where number is index of "rdi" record, starting at \x01)
186 0x4c => { Name => 'ImageWidth', Format => 'int32u' },
187 0x50 => { Name => 'ImageHeight', Format => 'int32u' },
188 # 0x54 - seen 0x11,0x13,0x15 (and 0x03 in "rdi\x02" record)
189 # 0x55 - seen 0x02
190 0x56 => {
191 Name => 'FrameRate',
192 Format => 'int16u[3]',
193 ValueConv => 'my @a = split " ",$val; ($a[1] * 0x10000 + $a[2]) / $a[0]',
194 PrintConv => 'int($val * 1000 + 0.5) / 1000',
195 },
196 # (immediately following last "rdi" record is a
197 # Red directory beginning with int16u size)
198);
199
200#------------------------------------------------------------------------------
201# Process metadata from a Redcode R3D video (ref PH)
202# Inputs: 0) ExifTool object reference, 1) dirInfo reference
203# Returns: 1 on success, 0 if this wasn't a valid R3D file
204sub ProcessR3D($$)
205{
206 my ($et, $dirInfo) = @_;
207 my $raf = $$dirInfo{RAF};
208 my ($buff, $buf2, $pos, $dirLen, $dirEnd);
209 my $verbose = $et->Options('Verbose');
210
211 # R3D file structure:
212 # - each block starts with int32u block size followed by 4-byte block type
213 # - first block type is either "RED1" (version 1) or "RED2" (version 2)
214 # - blocks begin on even 0x1000 byte boundaries for version 2 files
215
216 # validate the file header
217 return 0 unless $raf->Read($buff, 8) == 8 and $buff =~ /^\0\0..RED(1|2)/s;
218 my $ver = $1;
219 my $size = unpack('N', $buff);
220 return 0 if $size < 8;
221
222 $et->SetFileType();
223 SetByteOrder('MM');
224 my $tagTablePtr = GetTagTable('Image::ExifTool::Red::Main');
225 my $dataPos = 0;
226
227 # read the first block of the file
228 $raf->Read($buf2, $size - 8) == $size - 8 or return $et->Warn($errTrunc);
229 $buff .= $buf2;
230
231 # extract tags from the header
232 $et->HandleTag($tagTablePtr, "RED$ver", undef, DataPt => \$buff);
233
234 # read the second block from a version 1 file because
235 # the first block doesn't contain a Red directory
236 if ($ver eq '1') {
237 # (read more than we need)
238 $raf->Read($buff, 0x10000) or return $et->Warn($errTrunc);
239 $dataPos += $size;
240 $pos = 0x22; # directory starts at offset 0x22
241 } else {
242 # calculate position of Red directory start
243 length($buff) < 0x41 and return $et->Warn($errTrunc);
244 my $n = Get8u(\$buff, 0x40); # number of "rdi" records
245 $pos = 0x44 + $n * 0x18;
246 }
247 if ($pos + 8 > length $buff) {
248 $dirLen = 0; # find directory the hard way
249 } else {
250 $dirLen = Get16u(\$buff, $pos); # get length of Red directory
251 $pos += 2; # skip length word
252 }
253 # do sanity check on the directory size (in case our assumptions were wrong)
254 if ($dirLen < 300 or $dirLen >= 2048 or $pos + $dirLen > length $buff) {
255 # tag 0x1000 with length 0x000f should be near the directory start
256 $buff =~ /\0\x0f\x10\0/g or return $et->Warn("Can't find Red directory");
257 $pos = pos($buff) - 4;
258 $dirEnd = length $buff;
259 undef $dirLen;
260 $et->Warn('This R3D file is different. Please submit a sample for testing');
261 } else {
262 $dirEnd = $pos + $dirLen;
263 }
264 $$et{INDENT} .= '| ', $et->VerboseDir('Red', undef, $dirLen) if $verbose;
265
266 # process the first Red directory
267 while ($pos + 4 <= $dirEnd) {
268 my $len = Get16u(\$buff, $pos);
269 last if $len < 4 or $pos + $len > $dirEnd;
270 my $tag = Get16u(\$buff, $pos + 2);
271 my $fmt = $redFormat{$tag >> 12}; # format is top 4 bits of tag ID (ref PH)
272 $fmt or $dirLen && $et->Warn('Unknown format code'), last;
273 $et->HandleTag($tagTablePtr, $tag, undef,
274 DataPt => \$buff,
275 DataPos => $dataPos,
276 Start => $pos + 4,
277 Size => $len - 4,
278 Format => $fmt,
279 );
280 $pos += $len;
281 }
282 $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $verbose;
283
284 return 1;
285}
286
2871; # end
288
289__END__
290
291=head1 NAME
292
293Image::ExifTool::Red - Read Redcode R3D video files
294
295=head1 SYNOPSIS
296
297This module is used by Image::ExifTool
298
299=head1 DESCRIPTION
300
301This module contains routines required by Image::ExifTool to read metadata
302from Redcode R3D version 1 and 2 video files.
303
304=head1 AUTHOR
305
306Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
307
308This library is free software; you can redistribute it and/or modify it
309under the same terms as Perl itself.
310
311=head1 REFERENCES
312
313=over 4
314
315=item L<http://www.wikiwand.com/en/REDCODE>
316
317=back
318
319=head1 SEE ALSO
320
321L<Image::ExifTool::TagNames/Red Tags>,
322L<Image::ExifTool(3pm)|Image::ExifTool>
323
324=cut
325
Note: See TracBrowser for help on using the repository browser.