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

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?

  • FYI vorbiscomment doesn't work with OGG/Opus files, i.e. when the audio is encoded using the Opus codec rather than Vorbis. – pts Jan 28 at 0:37

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:


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

The code is quite complex:

      # 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}"

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:


FILE1="`basename \"$1\"`"
EXTTYPE1=`echo $EXT1 | tr '[:upper:]' '[:lower:]'`

FILE2="`basename \"$2\"`"
EXTTYPE2=`echo $EXT2 | tr '[:upper:]' '[:lower:]'`

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

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

if [ "$3" = -e ]; then

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`
if [ "$MIME" = "" ]; then

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

if [ "$EASYTAG" = N ]; then
echo COVERART="$APIC" > "$OGG".tags2
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
  • 1
    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. – Gaff 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
  • @Jason Congratulations for your script. BTW, maybe you could migrate it to gist.github.com just in case, over the years, your murga-linux page goes down. – SebMa Mar 22 at 21:05

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.

  • 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 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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