use constant COVERART_LOCATOR => "coverart"; use constant PICTURE_TYPE => "Cover (front)"; use constant PICTURE_COMMENT => "Cover Image"; use constant APIC => "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->new($mp3_file); if(!defined $mp3) { carp("Cannot read tags from $mp3_file"); return undef; } # Attempt to read the tags $mp3->get_tags(); if(!defined $mp3->{ID3v2}) { # Need to create a new set of tags $mp3->new_tag("ID3v2"); } if(!defined $mp3->{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->{ID3v2}->get_frame(APIC)) { # Modifying an existing image $mp3->{ID3v2}->change_frame(APIC,@apic_parts); } else { # Create a new frame $mp3->{ID3v2}->add_frame(APIC,@apic_parts); } $mp3->{ID3v2}->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->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->eof()) { my $c = $ifh->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<=$#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); } #### attach("","1.mp3","foo/cool.jpg");