use strict; use warnings; use Image::MetaData::JPEG; use Image::MetaData::JPEG::Record; use Image::MetaData::JPEG::data::Tables qw(:JPEGgrammar :Endianness :RecordTypes); #read the image filname from the command line arguments my $image = new Image::MetaData::JPEG($ARGV[0]); # This would be the correct procedure for adding records at low level # if the APP2 update routine existed at all (but it isn't implemented) # 1) create an empty APP2 segment # my $segref = # new Image::MetaData::JPEG::Segment('APP2', undef, 'NOPARSE'); # 2) store a record with a given key and value # my $head = "MPF0"; # $segref->store_record('MP_HEADER', $ASCII, \$head); # 3) IMPORTANT: update the binary block from the in memory # representation (this was the step you were missing) # $segref->update(); # But APP2 can "currently" only be parsed if it contains Flashpix # conversion information ("FPXR") or ICC profiles data. And there is # no update routine at all. So, either you extend the package or # create the entire binary block by hand in a local variable: # you skip parsing and just create the segment. my $buffer = "MPF0\0"; my $segref = new Image::MetaData::JPEG::Segment('APP2', \$buffer, 'NOPARSE'); # then insert it into the image $image->insert_segments($segref); # the segment is there, albeit without description, since unparsed foreach my $s ($image->get_segments('APP')) { print $s->get_description(); } # you can save to file nonetheless, unparsable segments aren't dropped my $new_file_name = 'tmp1.jpg'; $image->save($new_file_name); print "---------------------------------\n"; # now open the new file and check that APP2 is there (I avoid trying # to parse it, since parsing would fail with "Invalid APP2 segment" # in this case) my $new_image = new Image::MetaData::JPEG($new_file_name, 'APP[^2]'); foreach my $s ($new_image->get_segments('APP')) { print $s->get_description(); } print "---------------------------------\n"; # have a look at what's really inside your file: the APP2 segment # should be in the very first lines, unless your APP1 is huge. use Data::HexDump; my $hexdumper = new Data::HexDump; $hexdumper->file($new_file_name); $hexdumper->block_size(1024); print while $_ = $hexdumper->dump; #### FF E1 SOI ("Start of image") FF E0 APP0 segment starts here 00 10 length of APP0 (16, i.e., 14 to follow) ......... 14 data bytes in the APP0 segment FF E2 APP2 segment starts here 00 07 length of APP2 (7, i.e., 5 to follow) 4D 50 46 30 00 "MPF0\000" FF FE COM segment starts here 00 13 length of COM (19, i.e. 17 to follow) ......... "Created with GIMP", and so on