- Timestamp:
- 2021-02-26T19:39:51+13:00 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone2/perllib/cpan/Image/ExifTool/WritePNG.pl
r24107 r34921 14 14 #------------------------------------------------------------------------------ 15 15 # Calculate CRC or update running CRC (ref 1) 16 # Inputs: 0) data reference, 1) running crc to update (undef in tially)16 # Inputs: 0) data reference, 1) running crc to update (undef initially) 17 17 # 2) data position (undef for 0), 3) data length (undef for all data), 18 18 # Returns: updated CRC … … 61 61 62 62 #------------------------------------------------------------------------------ 63 # Write profile to tEXt or zTXt chunk (zTXtif Zlib is available)63 # Write profile chunk (possibly compressed if Zlib is available) 64 64 # Inputs: 0) outfile, 1) Raw profile type, 2) data ref 65 65 # 3) profile header type (undef if not a text profile) … … 69 69 my ($outfile, $rawType, $dataPt, $profile) = @_; 70 70 my ($buff, $prefix, $chunk, $deflate); 71 if ( eval 'require Compress::Zlib') {71 if ($rawType ne $stdCase{exif} and eval { require Compress::Zlib }) { 72 72 $deflate = Compress::Zlib::deflateInit(); 73 73 } 74 74 if (not defined $profile) { 75 75 # write ICC profile as compressed iCCP chunk if possible 76 return 0 unless $deflate; 77 $buff = $deflate->deflate($$dataPt); 78 return 0 unless defined $buff; 79 $buff .= $deflate->flush(); 80 my %rawTypeChunk = ( icm => 'iCCP' ); 81 $chunk = $rawTypeChunk{$rawType} or return 0; 82 $prefix = "$rawType\0\0"; 83 $dataPt = \$buff; 76 if ($rawType eq 'icm') { 77 return 0 unless $deflate; 78 $chunk = 'iCCP'; 79 $prefix = "$rawType\0\0"; 80 } else { 81 $chunk = $rawType; 82 if ($rawType eq $stdCase{zxif}) { 83 $prefix = "\0" . pack('N', length $$dataPt); # (proposed compressed EXIF) 84 } else { 85 $prefix = ''; # standard EXIF 86 } 87 } 88 if ($deflate) { 89 $buff = $deflate->deflate($$dataPt); 90 return 0 unless defined $buff; 91 $buff .= $deflate->flush(); 92 $dataPt = \$buff; 93 } 84 94 } else { 85 95 # write as ASCII-hex encoded profile in tEXt or zTXt chunk … … 107 117 108 118 #------------------------------------------------------------------------------ 109 # Add iCCP to the PNG image if necessary (must come before PLTE and IDAT)119 # Add iCCP chunk to the PNG image if necessary (must come before PLTE and IDAT) 110 120 # Inputs: 0) ExifTool object ref, 1) output file or scalar ref 111 121 # Returns: true on success 112 122 sub Add_iCCP($$) 113 123 { 114 my ($e xifTool, $outfile) = @_;115 if ($ exifTool->{ADD_DIRS}->{ICC_Profile}) {124 my ($et, $outfile) = @_; 125 if ($$et{ADD_DIRS}{ICC_Profile}) { 116 126 # write new ICC data 117 127 my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::ICC_Profile::Main'); 118 128 my %dirInfo = ( Parent => 'PNG', DirName => 'ICC_Profile' ); 119 my $buff = $e xifTool->WriteDirectory(\%dirInfo, $tagTablePtr);129 my $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); 120 130 if (defined $buff and length $buff and WriteProfile($outfile, 'icm', \$buff)) { 121 $e xifTool->VPrint(0, "Created ICC profile\n");122 delete $ exifTool->{ADD_DIRS}->{ICC_Profile}; # don't add it again131 $et->VPrint(0, "Created ICC profile\n"); 132 delete $$et{ADD_DIRS}{ICC_Profile}; # don't add it again 123 133 } 124 134 } 125 135 return 1; 136 } 137 138 #------------------------------------------------------------------------------ 139 # This routine is called after we edit an existing directory 140 # Inputs: 0) ExifTool ref, 1) dir name, 2) output data ref 141 # 3) flag set if location is non-standard (to update, but not create from scratch) 142 # - on return, $$outBuff is set to '' if the directory is to be deleted 143 sub DoneDir($$$;$) 144 { 145 my ($et, $dir, $outBuff, $nonStandard) = @_; 146 my $saveDir = $dir; 147 $dir = 'EXIF' if $dir eq 'IFD0'; 148 # don't add this directory again unless this is in a non-standard location 149 if (not $nonStandard) { 150 delete $$et{ADD_DIRS}{$dir}; 151 delete $$et{ADD_DIRS}{IFD0} if $dir eq 'EXIF'; 152 } elsif ($$et{DEL_GROUP}{$dir} or $$et{DEL_GROUP}{$saveDir}) { 153 $et->VPrint(0," Deleting non-standard $dir\n"); 154 $$outBuff = ''; 155 } 126 156 } 127 157 … … 133 163 sub BuildTextChunk($$$$$) 134 164 { 135 my ($e xifTool, $tag, $tagInfo, $val, $lang) = @_;165 my ($et, $tag, $tagInfo, $val, $lang) = @_; 136 166 my ($xtra, $compVal, $iTXt, $comp); 137 167 if ($$tagInfo{SubDirectory}) { … … 144 174 } else { 145 175 # compress if specified 146 $comp = 1 if $e xifTool->Options('Compress');176 $comp = 1 if $et->Options('Compress'); 147 177 if ($lang) { 148 178 $iTXt = 1; # write as iTXt if it has a language code 149 179 $tag =~ s/-$lang$//; # remove language code from tagID 150 } elsif ($$e xifTool{OPTIONS}{Charset} ne 'Latin' and $val =~ /[\x80-\xff]/) {180 } elsif ($$et{OPTIONS}{Charset} ne 'Latin' and $val =~ /[\x80-\xff]/) { 151 181 $iTXt = 1; # write as iTXt if it contains non-Latin special characters 152 182 } … … 154 184 if ($comp) { 155 185 my $warn; 156 if (eval 'require Compress::Zlib') {186 if (eval { require Compress::Zlib }) { 157 187 my $deflate = Compress::Zlib::deflateInit(); 158 188 $compVal = $deflate->deflate($val) if $deflate; … … 172 202 # warn if any user-specified compression fails 173 203 if ($warn and $comp == 1) { 174 $e xifTool->Warn("PNG:$$tagInfo{Name} not compressed ($warn)", 1);204 $et->Warn("PNG:$$tagInfo{Name} not compressed ($warn)", 1); 175 205 } 176 206 } 177 207 # decide whether to write as iTXt, zTXt or tEXt 178 208 if ($iTXt) { 179 $$e xifTool{TextChunkType} = 'iTXt';209 $$et{TextChunkType} = 'iTXt'; 180 210 $xtra = (defined $compVal ? "\x01\0" : "\0\0") . ($lang || '') . "\0\0"; 181 211 # iTXt is encoded as UTF-8 (but note that XMP is already UTF-8) 182 $val = $e xifTool->Encode($val, 'UTF8') if $iTXt == 1;212 $val = $et->Encode($val, 'UTF8') if $iTXt == 1; 183 213 } elsif (defined $compVal) { 184 $$e xifTool{TextChunkType} = 'zTXt';214 $$et{TextChunkType} = 'zTXt'; 185 215 $xtra = "\0"; 186 216 } else { 187 $$e xifTool{TextChunkType} = 'tEXt';217 $$et{TextChunkType} = 'tEXt'; 188 218 $xtra = ''; 189 219 } … … 194 224 # Add any outstanding new chunks to the PNG image 195 225 # Inputs: 0) ExifTool object ref, 1) output file or scalar ref 226 # 2-N) dirs to add (empty to add all except EXIF 'IFD0', including PNG tags) 196 227 # Returns: true on success 197 sub AddChunks($$) 198 { 199 my ($exifTool, $outfile) = @_; 228 sub AddChunks($$;@) 229 { 230 my ($et, $outfile, @add) = @_; 231 my ($addTags, $tag, $dir, $err, $tagTablePtr, $specified); 232 233 if (@add) { 234 $addTags = { }; # don't add any PNG tags 235 $specified = 1; 236 } else { 237 $addTags = $$et{ADD_PNG}; # add all PNG tags... 238 delete $$et{ADD_PNG}; # ...once 239 # add all directories 240 @add = sort keys %{$$et{ADD_DIRS}}; 241 } 200 242 # write any outstanding PNG tags 201 my $addTags = $exifTool->{ADD_PNG};202 delete $exifTool->{ADD_PNG};203 my ($tag, $dir, $err, $tagTablePtr);204 205 243 foreach $tag (sort keys %$addTags) { 206 244 my $tagInfo = $$addTags{$tag}; 207 my $nvHash = $e xifTool->GetNewValueHash($tagInfo);208 # ( always create native PNG information, so don't check IsCreating())209 next unless Image::ExifTool::IsOverwriting($nvHash) > 0;210 my $val = Image::ExifTool::GetNewValues($nvHash);245 my $nvHash = $et->GetNewValueHash($tagInfo); 246 # (native PNG information is always preferred, so don't check IsCreating) 247 next unless $et->IsOverwriting($nvHash); 248 my $val = $et->GetNewValue($nvHash); 211 249 if (defined $val) { 250 next if $$nvHash{EditOnly}; 212 251 my $data; 213 252 if ($$tagInfo{Table} eq \%Image::ExifTool::PNG::TextualData) { 214 $data = BuildTextChunk($e xifTool, $tag, $tagInfo, $val, $$tagInfo{LangCode});215 $data = $$e xifTool{TextChunkType} . $data;216 delete $$e xifTool{TextChunkType};253 $data = BuildTextChunk($et, $tag, $tagInfo, $val, $$tagInfo{LangCode}); 254 $data = $$et{TextChunkType} . $data; 255 delete $$et{TextChunkType}; 217 256 } else { 218 257 $data = "$tag$val"; … … 221 260 my $cbuf = pack('N', CalculateCRC(\$data, undef)); 222 261 Write($outfile, $hdr, $data, $cbuf) or $err = 1; 223 $exifTool->VerboseValue("+ PNG:$$tagInfo{Name}", $val); 224 ++$exifTool->{CHANGED}; 225 } 226 } 227 $addTags = { }; # prevent from adding tags again 262 $et->VerboseValue("+ PNG:$$tagInfo{Name}", $val); 263 ++$$et{CHANGED}; 264 } 265 } 228 266 # create any necessary directories 229 foreach $dir (sort keys %{$exifTool->{ADD_DIRS}}) { 267 foreach $dir (@add) { 268 next unless $$et{ADD_DIRS}{$dir}; # make sure we want to add it first 230 269 my $buff; 231 270 my %dirInfo = ( … … 234 273 ); 235 274 if ($dir eq 'IFD0') { 236 $exifTool->VPrint(0, "Creating EXIF profile:\n"); 237 $exifTool->{TIFF_TYPE} = 'APP1'; 275 next unless $specified; # wait until specifically asked to write EXIF 'IFD0' 276 my $chunk = $stdCase{exif}; 277 # (zxIf was not adopted) 278 #if ($et->Options('Compress')) { 279 # if (eval { require Compress::Zlib }) { 280 # $chunk = $stdCase{zxif}; 281 # } else { 282 # $et->Warn("Creating uncompressed $stdCase{exif} chunk (Compress::Zlib not available)"); 283 # } 284 #} 285 $et->VPrint(0, "Creating $chunk chunk:\n"); 286 $$et{TIFF_TYPE} = 'APP1'; 238 287 $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Exif::Main'); 239 $buff = $e xifTool->WriteDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::WriteTIFF);288 $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::WriteTIFF); 240 289 if (defined $buff and length $buff) { 241 $buff = $Image::ExifTool::exifAPP1hdr . $buff; 242 WriteProfile($outfile, 'APP1', \$buff, 'generic') or $err = 1; 290 WriteProfile($outfile, $chunk, \$buff) or $err = 1; 243 291 } 244 292 } elsif ($dir eq 'XMP') { 245 $e xifTool->VPrint(0, "Creating XMP iTXt chunk:\n");293 $et->VPrint(0, "Creating XMP iTXt chunk:\n"); 246 294 $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::XMP::Main'); 247 295 $dirInfo{ReadOnly} = 1; 248 $buff = $e xifTool->WriteDirectory(\%dirInfo, $tagTablePtr);296 $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); 249 297 if (defined $buff and length $buff and 250 298 # the packet is read-only (because of CRC) … … 261 309 } 262 310 } elsif ($dir eq 'IPTC') { 263 $exifTool->VPrint(0, "Creating IPTC profile:\n"); 264 # write new IPTC data 311 $et->Warn('Creating non-standard IPTC in PNG', 1); 312 $et->VPrint(0, "Creating IPTC profile:\n"); 313 # write new IPTC data (stored in a Photoshop directory) 314 $dirInfo{DirName} = 'Photoshop'; 265 315 $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Photoshop::Main'); 266 $buff = $e xifTool->WriteDirectory(\%dirInfo, $tagTablePtr);316 $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); 267 317 if (defined $buff and length $buff) { 268 318 WriteProfile($outfile, 'iptc', \$buff, 'IPTC') or $err = 1; 269 319 } 270 320 } elsif ($dir eq 'ICC_Profile') { 271 $e xifTool->VPrint(0, "Creating ICC profile:\n");321 $et->VPrint(0, "Creating ICC profile:\n"); 272 322 # write new ICC data (only done if we couldn't create iCCP chunk) 273 323 $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::ICC_Profile::Main'); 274 $buff = $e xifTool->WriteDirectory(\%dirInfo, $tagTablePtr);324 $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); 275 325 if (defined $buff and length $buff) { 276 326 WriteProfile($outfile, 'icm', \$buff, 'ICC') or $err = 1; 277 $exifTool->Warn('Wrote ICC as a raw profile (no Compress::Zlib)'); 278 } 279 } 280 } 281 $exifTool->{ADD_DIRS} = { }; # prevent from adding dirs again 327 $et->Warn('Wrote ICC as a raw profile (no Compress::Zlib)'); 328 } 329 } elsif ($dir eq 'PNG-pHYs') { 330 $et->VPrint(0, "Creating pHYs chunk (default 2834 pixels per meter):\n"); 331 $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::PNG::PhysicalPixel'); 332 my $blank = "\0\0\x0b\x12\0\0\x0b\x12\x01"; # 2834 pixels per meter (72 dpi) 333 $dirInfo{DataPt} = \$blank; 334 $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); 335 if (defined $buff and length $buff) { 336 $buff = 'pHYs' . $buff; # CRC includes chunk name 337 my $hdr = pack('N', length($buff) - 4); 338 my $cbuf = pack('N', CalculateCRC(\$buff, undef)); 339 Write($outfile, $hdr, $buff, $cbuf) or $err = 1; 340 } 341 } else { 342 next; 343 } 344 delete $$et{ADD_DIRS}{$dir}; # don't add again 345 } 282 346 return not $err; 283 347 } … … 305 369 306 370 Existing text tags are always rewritten in their original form (compressed 307 zTXt, uncompressed tEXt or internation iTXt), so pre-existing compressed371 zTXt, uncompressed tEXt or international iTXt), so pre-existing compressed 308 372 information can only be modified if Compress::Zlib is available. 309 373 … … 316 380 =head1 AUTHOR 317 381 318 Copyright 2003-20 11, Phil Harvey (phil at owl.phy.queensu.ca)382 Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 319 383 320 384 This library is free software; you can redistribute it and/or modify it
Note:
See TracChangeset
for help on using the changeset viewer.