<?xml version="1.0" encoding="windows-1252"?>
<node id="896405" title="Re: I need help about MP3::Tag and perl script." created="2011-03-30 09:03:06" updated="2011-03-30 09:03:06">
<type id="11">
note</type>
<author id="186342">
hawtin</author>
<data>
<field name="doctext">
&lt;p&gt;
Oh, and cover art is a whole different challenge.  Here's 
how I do it (for ID3v2 and jpg images).&lt;/p&gt;
&lt;readmore&gt;
&lt;code&gt;
use constant COVERART_LOCATOR =&gt; "coverart";
use constant PICTURE_TYPE =&gt; "Cover (front)";
use constant PICTURE_COMMENT =&gt; "Cover Image";
use constant APIC =&gt; "APIC";

sub attach
  {
    # Find a suitable image and attach it to the suggested mp3 file
    my($track,$mp3_file,$image_file) = @_;

    return undef
         if(!defined $image_file);

    if(!-w $mp3_file)
      {
        # This shouldn't happen but...
        chmod 0755,$mp3_file;
      }
    if(!-w $mp3_file)
      {
        carp("Cannot write to $mp3_file");
        return undef;
      }
    my $mp3 = MP3::Tag-&gt;new($mp3_file);

    if(!defined $mp3)
      {
        carp("Cannot read tags from $mp3_file");
        return undef;
      }

    # Attempt to read the tags
    $mp3-&gt;get_tags();
    if(!defined $mp3-&gt;{ID3v2})
      {
        # Need to create a new set of tags
        $mp3-&gt;new_tag("ID3v2");
      }

    if(!defined $mp3-&gt;{ID3v2})
      {
        carp("Cannot create ID3v2 tags in $mp3_file");
        return undef;
      }

    my($mime_type,$image_data) = read_image($image_file);
    return undef if(!defined $mime_type);

    my $encoding = 0;
    my @apic_parts = ($encoding, $mime_type,
             picture_type_idx(PICTURE_TYPE),
             PICTURE_COMMENT, $image_data);

    if(defined $mp3-&gt;{ID3v2}-&gt;get_frame(APIC))
      {
        # Modifying an existing image
        $mp3-&gt;{ID3v2}-&gt;change_frame(APIC,@apic_parts);
      }
    else
      {
        # Create a new frame
        $mp3-&gt;{ID3v2}-&gt;add_frame(APIC,@apic_parts);
      }
    $mp3-&gt;{ID3v2}-&gt;write_tag();
    return $image_file;
  }

sub read_image
  {
    # Read the image file
    my($file_name) = @_;

    my $image_type;
    my $image_data;

    if(!-f $file_name)
      {
        error("Cannot read file \"$file_name\"");
        return;
      }

    if($file_name =~ /\.jpg$/i)
      {
        $image_type = "jpg";
        my $ifh = IO::File-&gt;new($file_name);
        if(!defined $ifh)
          {
            error("Failed to open \"$file_name\"");
            return;
          }
        binmode $ifh;

        $image_data = "";

        # This reads the data in 16k chunks, but the images should be small anyway

        while(!$ifh-&gt;eof())
          {
            my $c = $ifh-&gt;read($image_data,1024*16,length($image_data));
          }
        $ifh = undef;
      }

    if(!defined $image_type)
      {
        error("Does not yet support file type for \"$file_name\"");
        return;
      }
    if(!defined $image_data)
      {
        error("Cannot extract $image_type data from \"$file_name\"");
        return;
      }

    return("image/$image_type",$image_data);
  }

sub picture_type_idx
  {
    # Given a picture type string convert it into a number suitable
    # for MP3::Tag
    my($picture_type) = @_;

    # The picture types that are currently understood (from MP3::Tag::ID3v2):
    my @picture_types =
         ("Other", "32x32 pixels 'file icon' (PNG only)", "Other file icon",
           "Cover (front)", "Cover (back)", "Leaflet page",
           "Media (e.g. lable side of CD)", "Lead artist/lead performer/soloist"
,
           "Artist/performer", "Conductor", "Band/Orchestra", "Composer",
           "Lyricist/text writer", "Recording Location", "During recording",
           "During performance", "Movie/video screen capture",
           "A bright coloured fish", "Illustration", "Band/artist logotype",
           "Publisher/Studio logotype");

    # This approach is easy to understand
    for(my $i=0;$i&lt;=$#picture_types;$i++)
      {
        if(lc($picture_type) eq lc($picture_types[$i]))
          {
            return chr($i);
          }
      }
    error("The picture type \"$picture_type\" is not valid");
    return chr(3);
  }

&lt;/code&gt;
&lt;/readmore&gt;
&lt;p&gt;
&lt;b&gt;Update:&lt;/b&gt; 
This defines a new subroutine called attach().  The first parameter has 
no affect (its important in my script but for your purposes you can ignore 
it).  Suppose you want to attach a file &amp;quot;foo/cool.jpg&amp;quot; to an mp3 
file called &amp;quot;1.mp3&amp;quot; as the front cover, you would just do (untested)&lt;/p&gt;
&lt;code&gt;
    attach("","1.mp3","foo/cool.jpg");
&lt;/code&gt;
&lt;p&gt;
This, of course, requires that you add the appropriate packages and 
copy the definition of the subroutine somewhere into your script.
&lt;/p&gt;</field>
<field name="root_node">
896303</field>
<field name="parent_node">
896303</field>
</data>
</node>
