source: gs2-extensions/parallel-building/trunk/src/perllib/cpan/Image/ExifTool/PanasonicRaw.pm@ 24626

Last change on this file since 24626 was 24626, checked in by jmt12, 13 years ago

An (almost) complete copy of the perllib directory from a (circa SEP2011) head checkout from Greenstone 2 trunk - in order to try and make merging in this extension a little easier later on (as there have been some major changes to buildcol.pl commited in the main trunk but not in the x64 branch)

  • Property svn:executable set to *
File size: 13.1 KB
Line 
1#------------------------------------------------------------------------------
2# File: PanasonicRaw.pm
3#
4# Description: Read/write Panasonic/Leica RAW/RW2/RWL meta information
5#
6# Revisions: 2009/03/24 - P. Harvey Created
7# 2009/05/12 - PH Added RWL file type (same format as RW2)
8#
9# References: 1) CPAN forum post by 'hardloaf' (http://www.cpanforum.com/threads/2183)
10# 2) http://www.cybercom.net/~dcoffin/dcraw/
11# JD) Jens Duttke private communication (TZ3,FZ30,FZ50)
12#------------------------------------------------------------------------------
13
14package Image::ExifTool::PanasonicRaw;
15
16use strict;
17use vars qw($VERSION);
18use Image::ExifTool qw(:DataAccess :Utils);
19use Image::ExifTool::Exif;
20
21$VERSION = '1.02';
22
23sub ProcessJpgFromRaw($$$);
24sub WriteJpgFromRaw($$$);
25
26my %jpgFromRawMap = (
27 IFD1 => 'IFD0',
28 EXIF => 'IFD0', # to write EXIF as a block
29 ExifIFD => 'IFD0',
30 GPS => 'IFD0',
31 SubIFD => 'IFD0',
32 GlobParamIFD => 'IFD0',
33 PrintIM => 'IFD0',
34 InteropIFD => 'ExifIFD',
35 MakerNotes => 'ExifIFD',
36 IFD0 => 'APP1',
37 MakerNotes => 'ExifIFD',
38 Comment => 'COM',
39);
40
41# Tags found in Panasonic RAW/RW2/RWL images (ref PH)
42%Image::ExifTool::PanasonicRaw::Main = (
43 GROUPS => { 0 => 'EXIF', 1 => 'IFD0', 2 => 'Image'},
44 WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
45 CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
46 WRITE_GROUP => 'IFD0', # default write group
47 NOTES => 'These tags are found in IFD0 of Panasonic/Leica RAW, RW2 and RWL images.',
48 0x01 => {
49 Name => 'PanasonicRawVersion',
50 Writable => 'undef',
51 },
52 0x02 => 'SensorWidth', #1/PH
53 0x03 => 'SensorHeight', #1/PH
54 0x04 => 'SensorTopBorder', #JD
55 0x05 => 'SensorLeftBorder', #JD
56 0x06 => 'ImageHeight', #1/PH
57 0x07 => 'ImageWidth', #1/PH
58 # observed values for unknown tags - PH
59 # 0x08: 1
60 # 0x09: 1,3,4
61 # 0x0a: 12
62 # 0x0b: 0x860c,0x880a,0x880c
63 # 0x0c: 2 (only Leica Digilux 2)
64 # 0x0d: 0,1
65 # 0x0e,0x0f,0x10: 4095
66 # 0x18,0x19,0x1a,0x1c,0x1d,0x1e: 0
67 # 0x1b,0x27,0x29,0x2a,0x2b,0x2c: [binary data]
68 # 0x2d: 2,3
69 0x11 => { #JD
70 Name => 'RedBalance',
71 Writable => 'int16u',
72 ValueConv => '$val / 256',
73 ValueConvInv => 'int($val * 256 + 0.5)',
74 Notes => 'found in Digilux 2 RAW images',
75 },
76 0x12 => { #JD
77 Name => 'BlueBalance',
78 Writable => 'int16u',
79 ValueConv => '$val / 256',
80 ValueConvInv => 'int($val * 256 + 0.5)',
81 },
82 0x17 => { #1
83 Name => 'ISO',
84 Writable => 'int16u',
85 },
86 0x24 => { #2
87 Name => 'WBRedLevel',
88 Writable => 'int16u',
89 },
90 0x25 => { #2
91 Name => 'WBGreenLevel',
92 Writable => 'int16u',
93 },
94 0x26 => { #2
95 Name => 'WBBlueLevel',
96 Writable => 'int16u',
97 },
98 0x2e => { #JD
99 Name => 'JpgFromRaw', # (writable directory!)
100 Writable => 'undef',
101 # protect this tag because it contains all the metadata
102 Flags => [ 'Binary', 'Protected', 'NestedHtmlDump', 'BlockExtract' ],
103 Notes => 'processed as an embedded document because it contains full EXIF',
104 WriteCheck => '$val eq "none" ? undef : $self->CheckImage(\$val)',
105 DataTag => 'JpgFromRaw',
106 RawConv => '$self->ValidateImage(\$val,$tag)',
107 SubDirectory => {
108 # extract information from embedded image since it is metadata-rich,
109 # unless HtmlDump option set (note that the offsets will be relative,
110 # not absolute like they should be in verbose mode)
111 TagTable => 'Image::ExifTool::JPEG::Main',
112 WriteProc => \&WriteJpgFromRaw,
113 ProcessProc => \&ProcessJpgFromRaw,
114 },
115 },
116 0x10f => {
117 Name => 'Make',
118 Groups => { 2 => 'Camera' },
119 Writable => 'string',
120 DataMember => 'Make',
121 # save this value as an ExifTool member variable
122 RawConv => '$self->{Make} = $val',
123 },
124 0x110 => {
125 Name => 'Model',
126 Description => 'Camera Model Name',
127 Groups => { 2 => 'Camera' },
128 Writable => 'string',
129 DataMember => 'Model',
130 # save this value as an ExifTool member variable
131 RawConv => '$self->{Model} = $val',
132 },
133 0x111 => {
134 Name => 'StripOffsets',
135 # (this value is 0xffffffff for some models, and RawDataOffset must be used)
136 Flags => [ 'IsOffset', 'PanasonicHack' ],
137 OffsetPair => 0x117, # point to associated byte counts
138 ValueConv => 'length($val) > 32 ? \$val : $val',
139 },
140 0x112 => {
141 Name => 'Orientation',
142 Writable => 'int16u',
143 PrintConv => \%Image::ExifTool::Exif::orientation,
144 Priority => 0, # so IFD1 doesn't take precedence
145 },
146 0x116 => {
147 Name => 'RowsPerStrip',
148 Priority => 0,
149 },
150 0x117 => {
151 Name => 'StripByteCounts',
152 # (note that this value may represent something like uncompressed byte count
153 # for RAW/RW2/RWL images from some models, and is zero for some other models)
154 OffsetPair => 0x111, # point to associated offset
155 ValueConv => 'length($val) > 32 ? \$val : $val',
156 },
157 0x118 => {
158 Name => 'RawDataOffset', #PH (RW2/RWL)
159 IsOffset => '$$exifTool{TIFF_TYPE} =~ /^(RW2|RWL)$/', # (invalid in DNG-converted files)
160 PanasonicHack => 1,
161 OffsetPair => 0x117, # (use StripByteCounts as the offset pair)
162 },
163 # 0x119 undef[32] - lens distortion data? (http://thinkfat.blogspot.com/2009/02/dissecting-panasonic-rw2-files.html)
164 0x2bc => { # PH Extension!!
165 Name => 'ApplicationNotes',
166 Writable => 'int8u', # (writable directory!)
167 Format => 'undef',
168 Flags => [ 'Binary', 'Protected' ],
169 SubDirectory => {
170 DirName => 'XMP',
171 TagTable => 'Image::ExifTool::XMP::Main',
172 },
173 },
174 0x83bb => { # PH Extension!!
175 Name => 'IPTC-NAA', # (writable directory!)
176 Format => 'undef', # convert binary values as undef
177 Writable => 'int32u', # but write int32u format code in IFD
178 WriteGroup => 'IFD0',
179 Flags => [ 'Binary', 'Protected' ],
180 SubDirectory => {
181 DirName => 'IPTC',
182 TagTable => 'Image::ExifTool::IPTC::Main',
183 },
184 },
185 0x8769 => {
186 Name => 'ExifOffset',
187 Groups => { 1 => 'ExifIFD' },
188 Flags => 'SubIFD',
189 SubDirectory => {
190 TagTable => 'Image::ExifTool::Exif::Main',
191 DirName => 'ExifIFD',
192 Start => '$val',
193 },
194 },
195 0x8825 => {
196 Name => 'GPSInfo',
197 Groups => { 1 => 'GPS' },
198 Flags => 'SubIFD',
199 SubDirectory => {
200 DirName => 'GPS',
201 TagTable => 'Image::ExifTool::GPS::Main',
202 Start => '$val',
203 },
204 },
205);
206
207#------------------------------------------------------------------------------
208# Patch for writing non-standard Panasonic RAW/RW2/RWL raw data
209# Inputs: 0) offset info ref, 1) raf ref, 2) IFD number
210# Returns: error string, or undef on success
211# OffsetInfo is a hash by tag ID of lists with the following elements:
212# 0 - tag info ref
213# 1 - pointer to int32u offset in IFD or value data
214# 2 - value count
215# 3 - reference to list of original offset values
216# 4 - IFD format number
217sub PatchRawDataOffset($$$)
218{
219 my ($offsetInfo, $raf, $ifd) = @_;
220 my $stripOffsets = $$offsetInfo{0x111};
221 my $stripByteCounts = $$offsetInfo{0x117};
222 my $rawDataOffset = $$offsetInfo{0x118};
223 my $err;
224 $err = 1 unless $ifd == 0;
225 $err = 1 unless $stripOffsets and $stripByteCounts and $$stripOffsets[2] == 1;
226 if ($rawDataOffset) {
227 $err = 1 unless $$rawDataOffset[2] == 1;
228 $err = 1 unless $$stripOffsets[3][0] == 0xffffffff or $$stripByteCounts[3][0] == 0;
229 }
230 $err and return 'Unsupported Panasonic/Leica RAW variant';
231 if ($rawDataOffset) {
232 # update StripOffsets along with this tag if it contains a reasonable value
233 unless ($$stripOffsets[3][0] == 0xffffffff) {
234 # save pointer to StripOffsets value for updating later
235 push @$rawDataOffset, $$stripOffsets[1];
236 }
237 # handle via RawDataOffset instead of StripOffsets
238 $stripOffsets = $$offsetInfo{0x111} = $rawDataOffset;
239 delete $$offsetInfo{0x118};
240 }
241 # determine the length of the raw data
242 my $pos = $raf->Tell();
243 $raf->Seek(0, 2) or $err = 1; # seek to end of file
244 my $len = $raf->Tell() - $$stripOffsets[3][0];
245 $raf->Seek($pos, 0);
246 # quick check to be sure the raw data length isn't unreasonable
247 # (the 22-byte length is for '<Dummy raw image data>' in our tests)
248 $err = 1 if ($len < 1000 and $len != 22) or $len & 0x80000000;
249 $err and return 'Error reading Panasonic raw data';
250 # update StripByteCounts info with raw data length
251 # (note that the original value is maintained in the file)
252 $$stripByteCounts[3][0] = $len;
253
254 return undef;
255}
256
257#------------------------------------------------------------------------------
258# Write meta information to Panasonic JpgFromRaw in RAW/RW2/RWL image
259# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
260# Returns: updated image data, or undef if nothing changed
261sub WriteJpgFromRaw($$$)
262{
263 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
264 my $dataPt = $$dirInfo{DataPt};
265 my $byteOrder = GetByteOrder();
266 my $fileType = $$exifTool{FILE_TYPE}; # RAW, RW2 or RWL
267 my $dirStart = $$dirInfo{DirStart};
268 if ($dirStart) { # DirStart is non-zero in DNG-converted RW2/RWL
269 my $dirLen = $$dirInfo{DirLen} | length($$dataPt) - $dirStart;
270 my $buff = substr($$dataPt, $dirStart, $dirLen);
271 $dataPt = \$buff;
272 }
273 my $raf = new File::RandomAccess($dataPt);
274 my $outbuff;
275 my %dirInfo = (
276 RAF => $raf,
277 OutFile => \$outbuff,
278 );
279 $$exifTool{BASE} = $$dirInfo{DataPos};
280 $$exifTool{FILE_TYPE} = $$exifTool{TIFF_TYPE} = 'JPEG';
281 # use a specialized map so we don't write XMP or IPTC (or other junk) into the JPEG
282 my $editDirs = $$exifTool{EDIT_DIRS};
283 my $addDirs = $$exifTool{ADD_DIRS};
284 $exifTool->InitWriteDirs(\%jpgFromRawMap);
285 # don't add XMP segment (IPTC won't get added because it is in Photoshop record)
286 delete $$exifTool{ADD_DIRS}{XMP};
287 my $result = $exifTool->WriteJPEG(\%dirInfo);
288 # restore variables we changed
289 $$exifTool{BASE} = 0;
290 $$exifTool{FILE_TYPE} = 'TIFF';
291 $$exifTool{TIFF_TYPE} = $fileType;
292 $$exifTool{EDIT_DIRS} = $editDirs;
293 $$exifTool{ADD_DIRS} = $addDirs;
294 SetByteOrder($byteOrder);
295 return $result > 0 ? $outbuff : $$dataPt;
296}
297
298#------------------------------------------------------------------------------
299# Extract meta information from an Panasonic JpgFromRaw
300# Inputs: 0) ExifTool object reference, 1) dirInfo reference
301# Returns: 1 on success, 0 if this wasn't a valid JpgFromRaw image
302sub ProcessJpgFromRaw($$$)
303{
304 my ($exifTool, $dirInfo, $tagTablePtr) = @_;
305 my $dataPt = $$dirInfo{DataPt};
306 my $byteOrder = GetByteOrder();
307 my $fileType = $$exifTool{FILE_TYPE}; # RAW, RW2 or RWL
308 my $tagInfo = $$dirInfo{TagInfo};
309 my $verbose = $exifTool->Options('Verbose');
310 my ($indent, $out);
311 $tagInfo or $exifTool->Warn('No tag info for Panasonic JpgFromRaw'), return 0;
312 my $dirStart = $$dirInfo{DirStart};
313 if ($dirStart) { # DirStart is non-zero in DNG-converted RW2/RWL
314 my $dirLen = $$dirInfo{DirLen} | length($$dataPt) - $dirStart;
315 my $buff = substr($$dataPt, $dirStart, $dirLen);
316 $dataPt = \$buff;
317 }
318 $$exifTool{BASE} = $$dirInfo{DataPos} + ($dirStart || 0);
319 $$exifTool{FILE_TYPE} = $$exifTool{TIFF_TYPE} = 'JPEG';
320 $$exifTool{DOC_NUM} = 1;
321 # extract information from embedded JPEG
322 my %dirInfo = (
323 Parent => 'RAF',
324 RAF => new File::RandomAccess($dataPt),
325 );
326 if ($verbose) {
327 my $indent = $$exifTool{INDENT};
328 $$exifTool{INDENT} = ' ';
329 $out = $exifTool->Options('TextOut');
330 print $out '--- DOC1:JpgFromRaw ',('-'x56),"\n";
331 }
332 my $rtnVal = $exifTool->ProcessJPEG(\%dirInfo);
333 # restore necessary variables for continued RW2/RWL processing
334 $$exifTool{BASE} = 0;
335 $$exifTool{FILE_TYPE} = 'TIFF';
336 $$exifTool{TIFF_TYPE} = $fileType;
337 delete $$exifTool{DOC_NUM};
338 SetByteOrder($byteOrder);
339 if ($verbose) {
340 $$exifTool{INDENT} = $indent;
341 print $out ('-'x76),"\n";
342 }
343 return $rtnVal;
344}
345
3461; # end
347
348__END__
349
350=head1 NAME
351
352Image::ExifTool::PanasonicRaw - Read/write Panasonic/Leica RAW/RW2/RWL meta information
353
354=head1 SYNOPSIS
355
356This module is loaded automatically by Image::ExifTool when required.
357
358=head1 DESCRIPTION
359
360This module contains definitions required by Image::ExifTool to read and
361write meta information in Panasonic/Leica RAW, RW2 and RWL images.
362
363=head1 AUTHOR
364
365Copyright 2003-2011, Phil Harvey (phil at owl.phy.queensu.ca)
366
367This library is free software; you can redistribute it and/or modify it
368under the same terms as Perl itself.
369
370=head1 REFERENCES
371
372=over 4
373
374=item L<http://www.cybercom.net/~dcoffin/dcraw/>
375
376=back
377
378=head1 SEE ALSO
379
380L<Image::ExifTool::TagNames/PanasonicRaw Tags>,
381L<Image::ExifTool(3pm)|Image::ExifTool>
382
383=cut
Note: See TracBrowser for help on using the repository browser.