imageperlimage-processingiptcperlmagick

Adding data to IPTC field using Perl


I want to set custom text to the IPTC field "Special instructions" in Perl.

How can this be done without the usage of a modul?


Solution

  • Updated Again

    Ok, in the light of your new requirement to actually read, modify and then re-write the IPTC information, you could use the following to read the IPTC information until we find something better:

    print $image->Identify();
    

    which gives this:

    stuff ..
    ...
    Profiles:
      Profile-8bim: 44 bytes
      Profile-iptc: 32 bytes
        Special Instructions[2,40]: Handle with care.
        Credit[2,110]: Mark
    ...
    ...
    

    Mmm... it appears that that information gets written to stdout, and I don't know how to capture it. So I have investigated further and can get the IPTC information like this too:

    $profile=$image->Get('IPTC');
    

    which gives this:

    0000000      021c    0028    4811    6e61    6c64    2065    6977    6874
             034 002   (  \0 021   H   a   n   d   l   e       w   i   t   h
    0000020      6320    7261    2e65    021c    006e    4d04    7261    006b
                   c   a   r   e   . 034 002   n  \0 004   M   a   r   k  \0
    

    So it looks like individual IPTC fields are separated by:

    1c - a single byte marker
    byte - IPTC page
    byte - IPTC field number
    2 bytes - length of following field
    <FIELD> - the actual data
    

    So, you can read them and create your IPTC.txt file like this:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Image::Magick;
    
    my ($image,$x,$profile,$id);
    $image=Image::Magick->new(size=>'256x128');
    $image->ReadImage('out.jpg');
    
    $profile=$image->Get('IPTC');
    my @items=split /\x1c/,$profile;
    shift @items; # Discard emptiness before first separator
    foreach (@items) {
       my $page=ord(substr($_,0,1));
       my $field=ord(substr($_,1,1));
       my $value=substr($_,4); # rest
       print "$page#$field=\"$value\"\n";
    }
    

    With my test file I get the following output from this:

    2#110="CREDITCREDITCREDITCREDIT"
    2#5="OBJECT"
    2#115="SOURCE"
    2#116="COPYRIGHT"
    2#118="CONTACT"
    2#120="CAPTION"
    

    Then you can set IPTC data using the Perl API, as follows using the file IPTC.txt further down:

    $image->Mogrify("profile",'8BIMTEXT:IPTC.txt');
    

    The following is not a sensible, complete program in itself but it shows how to use the techniques I am suggesting:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Image::Magick;
    
    my ($image,$x,$profile);
    $image=Image::Magick->new(size=>'256x128');
    $image->ReadImage('out.jpg');
    print $image->Identify();                          # Get IPTC info - to screen but you can put it in a variable obviously
    $image->Mogrify("profile",'8BIMTEXT:IPTC.txt');    # Write IPTC info
    $image->Write('out.jpg');                          # Output image with new IPTC info
    

    Updated

    I have made a little progress... I can read the IPTC attributes from an image using the Perl API. For example, the following will read the IPTC Credit:

    $credit=$image->Get('IPTC:2:110');
    

    Original Answer

    I am working on this, but the following may be enough to get you started anyway before I finish!

    If I create a file like this, and call it IPTC.txt

    2#40#Special Instructions="Handle with care."
    2#110#Credit="Mark"
    

    and then use ImageMagick convert like this:

    convert out.jpg -profile 8BIMTEXT:IPTC.txt out.jpg
    

    I can insert the IPTC information. I can then test this using jhead as follows:

    jhead out.jpg
    File name    : out.jpg
    File size    : 18899 bytes
    File date    : 2014:09:24 11:41:23
    Resolution   : 1024 x 768
    Color/bw     : Black and white
    JPEG Quality : 86
    ======= IPTC data: =======
    Spec. Instr.  : Handle with care.
    Credit        : Mark
    

    I know you don't want to shell out, but this will hopefully get us started on how to do it using the CPAN module you have. Which one do you have, by the way?