Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I want to convert my music from flac to ogg, and currently oggenc does that perfectly except for album art. Metaflac can output album art, however there seems to be no command line tool to embed album art into ogg. MP3Tag and EasyTag are able to do it, and there is a specification for it here which calls for the image to be base64 encoded. However so far I have been unsuccessful in being able to take an image file, converting it to base64 and embedding it into an ogg file.

If I take a base64 encoded image from an ogg file that already has the image embedded, I can easily embed it into another image using vorbiscomment:

vorbiscomment -l withimage.ogg > textfile
vorbiscomment -c textfile noimage.ogg

My problem is taking something like a jpeg and converting it to base64. Currently I have:

base64 --wrap=0 ./image.jpg

Which gives me the image file converted to base64, using vorbiscomment and following the tagging rules, I can embed that into an ogg file like so:

echo "METADATA_BLOCK_PICTURE=$(base64 --wrap=0 ./image.jpg)" > ./folder.txt
vorbiscomment -c textfile noimage.ogg

However this gives me an ogg whose image does not work properly. I noticed when comparing the base64 strings that all properly embedding pictures have a header line but all the base64 strings I generate are lacking this header. Further analysis of the header:

od -c header.txt
0000000  \0  \0  \0 003  \0  \0  \0  \n   i   m   a   g   e   /   j   p
0000020   e   g  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040  \0  \0  \0  \0  \0  \0  \0  \0 035 332
0000052

Which follows the spec given above. Notice 003 corresponds to front cover and image/jpeg is the mime type.

So finally, my question is, how can I base64 encode a file and generate this header along with it for embedding into an ogg file?

share|improve this question
add comment

3 Answers 3

up vote 2 down vote accepted

i've just written a script that export / import images from OGG/Vorbis files using vorbiscomment. It is part of a music library conversion tool.

The revelent script is in the 'mussync-tools-transfert_images' function of this tool:

https://github.com/biapy/howto.biapy.com/blob/master/various/mussync-tools

Basically, i've written a reader and a writer for the metadata_block_picture format.

The code is quite complex:

      OUTPUT_FILE="/path/to/my-ogg-file.ogg"
      IMAGE_PATH="/path/to/my-cover-art.jpg"
      IMAGE_MIME_TYPE="image/jpeg"
      # Export existing comments to file.
      local COMMENTS_PATH="$(command mktemp -t "tmp.XXXXXXXXXX")"
      command vorbiscomment --list --raw "${OUTPUT_FILE}" > "${COMMENTS_PATH}"

      # Remove existing images.
      command sed -i -e '/^metadata_block_picture/d' "${COMMENTS_PATH}"

      # Insert cover image from file.

      # metadata_block_picture format.
      # See: https://xiph.org/flac/format.html#metadata_block_picture

      local IMAGE_WITH_HEADER="$(command mktemp -t "tmp.XXXXXXXXXX")"
      local DESCRIPTION=""

      # Reset cache file.
      echo -n "" > "${IMAGE_WITH_HEADER}"

      # Picture type <32>.
      command printf "0: %.8x" 3 | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Mime type length <32>.
      command printf "0: %.8x" $(echo -n "${IMAGE_MIME_TYPE}" | command wc -c) \
                | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Mime type (n * 8)
      echo -n "${IMAGE_MIME_TYPE}" >> "${IMAGE_WITH_HEADER}"
      # Description length <32>.
      command printf "0: %.8x" $(echo -n "${DESCRIPTION}" | command wc -c) \
                | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Description (n * 8)
      echo -n "${DESCRIPTION}" >> "${IMAGE_WITH_HEADER}"
      # Picture with <32>.
      command printf "0: %.8x" 0 | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Picture height <32>.
      command printf "0: %.8x" 0 | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Picture color depth <32>.
      command printf "0: %.8x" 0 | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Picture color count <32>.
      command printf "0: %.8x" 0 | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Image file size <32>.
      command printf "0: %.8x" $(command wc -c "${IMAGE_PATH}" \
                | command cut --delimiter=' ' --fields=1) \
                | command xxd -r -g0 \
              >> "${IMAGE_WITH_HEADER}"
      # Image file.
      command cat "${IMAGE_PATH}" >> "${IMAGE_WITH_HEADER}"

      echo "metadata_block_picture=$(command base64 --wrap=0 < "${IMAGE_WITH_HEADER}")" >> "${COMMENTS_PATH}"

      # Update vorbis file comments.
      command vorbiscomment --write --raw --commentfile "${COMMENTS_PATH}" "${OUTPUT_FILE}"

      # Delete cache file.
      command rm "${IMAGE_WITH_HEADER}"
      # Delete comments file.
      command rm "${COMMENTS_PATH}"
share|improve this answer
add comment

Here's my solution for the /usr/bin/vorbiscomment: Argument list too long problem. I created a script and named it oggart. Just run it from the command line like this:

oggart /path/to/music_file.ogg /path/to/image_file

This tags your ogg file with METADATA_BLOCK_PICTURE field. Easytag uses the old way of doing this with COVERART field instead of METADATA_BLOCK_PICTURE. If you want Easytag compatibility then you can run the script like this:

oggart /path/to/music_file.ogg /path/to/image_file -e

Here's the script:

#!/bin/sh

FILE1="`basename \"$1\"`"
EXT1=${FILE1##*.}
EXTTYPE1=`echo $EXT1 | tr '[:upper:]' '[:lower:]'`

FILE2="`basename \"$2\"`"
EXT2=${FILE2##*.}
EXTTYPE2=`echo $EXT2 | tr '[:upper:]' '[:lower:]'`

OGG=""
if [ "$EXTTYPE1" = ogg ]; then
OGG="$1"
elif [ "$EXTTYPE2" = ogg ]; then
OGG="$2"
fi
if [ "$OGG" = "" ]; then
echo no ogg file selected
exit 0
fi

PIC=""
array=(jpeg jpg png)
for item in ${array[*]}
do
if [ "$item" = "$EXTTYPE1" ]; then
PIC="$1"
elif [ "$item" = "$EXTTYPE2" ]; then
PIC="$2"
fi
done
if [ "$PIC" = "" ]; then
echo no jpg or png file selected
exit 0
fi

if [ "$3" = -e ]; then
EASYTAG=Y
else
EASYTAG=N
fi

DESC=`basename "$PIC"`
APIC=`base64 --wrap=0 "$PIC"`
if [ "`which exiv2`" != "" ]; then
MIME=`exiv2 "$PIC" | grep 'MIME type ' | sed 's/: /|/' | cut -f 2 -d '|' | tail -n 1`
fi
if [ "$MIME" = "" ]; then
MIME="image/jpeg"
fi

vorbiscomment -l "$OGG" | grep -v '^COVERART=' | grep -v '^COVERARTDESCRIPTION=' | grep -v '^COVERARTMIME=' | grep -v 'METADATA_BLOCK_PICTURE=' > "$OGG".tags

if [ "$EASYTAG" = N ]; then
echo METADATA_BLOCK_PICTURE="$APIC" > "$OGG".tags2
else
echo COVERART="$APIC" > "$OGG".tags2
fi
vorbiscomment -w -R -c "$OGG".tags2 "$OGG"
vorbiscomment -a -R -t COVERARTDESCRIPTION="$DESC" "$OGG"
vorbiscomment -a -R -t COVERARTMIME="$MIME" "$OGG"
vorbiscomment -a -R -c "$OGG".tags "$OGG"

rm -f "$OGG".tags
rm -f "$OGG".tags2
share|improve this answer
    
The script posted funny here. You can download oggart.tar.gz @ murga-linux.com/puppy/viewtopic.php?mode=attach&id=44270 –  Jason Aug 4 '11 at 16:49
    
    
I fixed the script formatting in the post. –  8088 Aug 4 '11 at 16:53
1  
If you get a "Syntax error: "(" unexpected" in Ubuntu it's probably something to do with the shell being used to run. I changed the first line to #!/bin/bash and it worked. –  Dan Gravell Aug 23 '12 at 11:41
1  
this script is not working for me. As I can see it only uses base64 of the image but there needs to be a special header before it –  Sergey Aug 24 '13 at 18:01
add comment

I'm not aware of anything that does it automatically by just pointing to the image.

However vorbiscomment can embed arbitrary tags, you just need to encode the image in base64 and then construct the tag in the correct format.

e.g vorbiscomment -a -t 'METADATA_BLOCK_PICTURE=...' file.ogg newfile.ogg

you'll have to hack these steps into a script of some kind for it to be useful.

share|improve this answer
    
This would be doable, but sadly if the picture is over 64kb then vorbiscomments returns "/usr/bin/vorbiscomment: Argument list too long ". Any idea how to get around this? –  dmikalova Jul 29 '10 at 6:31
    
what is your system, and what is the output of getconf ARG_MAX? Unfortunately there is no way around this limit without recompiling the kernel. Here on 64-bit 2.6.32-24, I have 2 MB. –  sml Jul 29 '10 at 17:14
    
I'm running arch linux 64-bit 2.6.34.1-1 and I have 2mb as well. Would it be possible to put in a marker e.g. vorbiscomment -a -t 'METADATA_BLOCK_PICTURE=marker' file.ogg newfile.ogg, then have something read the ogg file and replace the marker with the base64 image? –  dmikalova Jul 29 '10 at 17:16
    
Absolutely. If you see the tag format spec I linked, you could use vorbiscomment to insert a temporary (small) image, and then directly write to the file updating the last two parts of the tag - data length, and the data itself. Obviously you'll have to hack something together yourself, however. –  sml Jul 30 '10 at 4:00
    
I'm trying out mutagen, a low level python library for audio tagging and my preliminary looks seem like it can do what I need. I'll report back when I figure things out in it. –  dmikalova Jul 30 '10 at 5:07
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.