How to recover the art Image since an .mp3 file ID3

Hi all

Is it possible to recover images art ID3 of an audio file. I used successfully MetaDataControl API to retrieve other properties of file but I can't find the art inside picture specification.

OK, I was interested in how do you extract the image of myself, I gave you just a generalization of what to do. I wrote a 'fast' service and dirty. Fuction has many types of treaties even if not used and I have not tested on several types of images and MP3s so use at your own risk. It is not optimized and don't go back not the 'mime type' when the runction is returned because I finished creating a new string rather than edit an existing one.

Anyway, that this should work:

public static net.rim.device.api.system.EncodedImage getID3Image(java.io.InputStream fs, long fsPos, long fsLength, String mimeType)
        throws java.io.UnsupportedEncodingException, java.io.IOException
{
    /*---------------------------
     * ID3 v1 tags cannot contain images, so no need to process them.
     * ID3 v1 tags are also placed at the end of the MP3 so checking the beginning of the file won't do anything useful.
     *---------------------------
     */

    //Read the tags, searching for the album artwork
    byte[] imageData = null;
    boolean foundImage = false;
    mimeType = null;
    while (!foundImage)
    {
        byte[] buffer = new byte[10];
        fs.mark(10);
        if ((fs.read(buffer, 0, 10) != 10) || !(new String(buffer, 0, 3, "UTF-8").equals("ID3")))
        {
            fs.reset();
            break;
        }
        fsPos += 10;
        //Found a ID3 version 2 or greater tag

        //Now to actually parse a tag
        int majorVersion = buffer[3] & 0xFF;
        byte minorVersion = buffer[4];
        byte[] destinationArray = new byte[4];
        System.arraycopy(buffer, 6, destinationArray, 0, 4);
        //Read a 28bit int for size
        int size = (((((destinationArray[0] & 0xFF) << 0x15) | ((destinationArray[1] & 0xFF) << 14)) | ((destinationArray[2] & 0xFF) << 7)) | (destinationArray[3] & 0xFF));
        long end = fsPos + size;
        fs.mark((int)size);
        long dataLength = end - 11L;

        boolean ver2 = true;

        if (majorVersion == 2)
        {
            //ID3 v2.2
            ver2 = true;
        }
        else if (majorVersion == 3 || majorVersion == 4)
        {
            //ID3 v2.3/ID3 v2.4

            //Extra data seems might exist, go through
            boolean hasExtendedHeader = (buffer[5] & 0x40) == 0x40;
            if (hasExtendedHeader)
            {
                byte[] exHeadBuf = new byte[4];
                fs.read(exHeadBuf, 0, 4);
                fsPos += 4;
                int exHeadLength = (((((exHeadBuf[0] & 0xFF) << 0x18) | ((exHeadBuf[1] & 0xFF) << 0x10)) | ((exHeadBuf[2] & 0xFF) << 8)) | (exHeadBuf[3] & 0xFF));
                byte[] exHeadData = new byte[exHeadLength + 4];
                System.arraycopy(exHeadBuf, 0, exHeadData, 4, exHeadLength);
                fs.read(exHeadData, 4, exHeadLength);
                fsPos += exHeadLength;
                //No use for this data in the pic so just ignore it
            }
            ver2 = false;
        }

        for (boolean flag = true; (fsPos < dataLength) && flag; )
        {
            //Get the frame header and make sure that it is a valid frame.
            byte[] fBuf = new byte[ver2 ? 6 : 10];
            if ((fs.read(fBuf, 0, fBuf.length) != fBuf.length) || ((fBuf[0] & 0xFF) <= 0))
            {
                flag = false;
                continue;
            }
            fsPos += fBuf.length;
            String frameId = new String(fBuf, 0, ver2 ? 3 : 4, "UTF-8");
            destinationArray = new byte[ver2 ? 3 : 4];
            System.arraycopy(fBuf, destinationArray.length, destinationArray, 0, destinationArray.length);
            int frameCount = 0;
            switch (majorVersion)
            {
                case 2:
                    //24bit
                    frameCount = ((((destinationArray[0] & 0xFF) << 0x10) | ((destinationArray[1] & 0xFF) << 8)) | (destinationArray[2] & 0xFF));
                    break;
                case 3:
                    //32bit
                    frameCount = (((((destinationArray[0] & 0xFF) << 0x18) | ((destinationArray[1] & 0xFF) << 0x10)) | ((destinationArray[2] & 0xFF) << 8)) | (destinationArray[3] & 0xFF));
                    break;
                case 4:
                    //28bit
                    frameCount = (((((destinationArray[0] & 0xFF) << 0x15) | ((destinationArray[1] & 0xFF) << 14)) | ((destinationArray[2] & 0xFF) << 7)) | (destinationArray[3] & 0xFF));
                    break;
                default:
                    continue;
            }
            //Now read the data and check to see if it is a picture
            fBuf = new byte[frameCount];
            if (fs.read(fBuf, 0, frameCount) == frameCount)
            {
                fsPos += frameCount;
                if (frameId.equals("PIC") || frameId.equals("APIC"))
                {
                    //Got the frame data
                    int refPoint = 0;
                    //First we get the encoding type
                    int encType = (fBuf[refPoint++] & 0xFF); //0=ISO8859, 1=Unicode,2=UnicodeBE,3=UTF8
                    //Second we get the mime type
                    int indexPoint = refPoint;
                    while (fBuf[refPoint++] != 0)
                    {
                    }
                    int mimeLength = refPoint - indexPoint;
                    if (mimeLength > 1)
                    {
                        mimeType = new String(fBuf, indexPoint, mimeLength - 1, "ISO-8859-1");
                    }
                    //Third we get the picture type
                    int picType = (fBuf[refPoint++] & 0xFF);
                    //Fourth we load the picture description
                    byte[] desBuf;
                    switch (encType)
                    {
                        case 0:
                        case 3:
                            //8bit string
                            byte num;
                            net.rim.device.api.util.ByteVector list = new net.rim.device.api.util.ByteVector();
                            while ((refPoint < fBuf.length) && ((num = fBuf[refPoint++]) != 0))
                            {
                                list.addElement(num);
                            }
                            desBuf = list.toArray();
                            break;
                        case 1:
                        case 2:
                            //16bit string
                            list = new net.rim.device.api.util.ByteVector();
                            do
                            {
                                byte item = fBuf[refPoint++];
                                byte num2 = fBuf[refPoint++];
                                if ((item == 0) && (num2 == 0))
                                {
                                    break;
                                }
                                if (((item != 0xff) || (num2 != 0xfe)) || (encType != 1))
                                {
                                    list.addElement(item);
                                    list.addElement(num2);
                                }
                            }
                            while (refPoint < (fBuf.length - 1));
                            desBuf = list.toArray();
                            break;
                        default:
                            throw new java.io.UnsupportedEncodingException("Cannot get picture description. Frame Encoding is invalid.");
                    }
                    String description;
                    switch (encType)
                    {
                        case 0:
                            description = new String(desBuf, "ISO-8859-1");
                            break;
                        case 1:
                            description = new String(desBuf, "UTF-16");
                            break;
                        case 2:
                            description = new String(desBuf, "UTF-16BE");
                            break;
                        case 3:
                            description = new String(desBuf, "UTF-8");
                            break;
                    }
                    //Finally, THE MAIN EVENT, the image data
                    int imCount = fBuf.length - refPoint;
                    imageData = new byte[imCount];
                    System.arraycopy(fBuf, refPoint, imageData, 0, imCount);
                    foundImage = true;
                    break;
                }
            }
            continue;
        }
        fs.reset();
        continue;
    }
    if (imageData != null)
    {
        //We found the image
        if(mimeType != null && mimeType.length() > 0)
        {
            //Save some time in searching for image type
            return net.rim.device.api.system.EncodedImage.createEncodedImage(imageData, 0, imageData.length, mimeType);
        }
        else
        {
            return net.rim.device.api.system.EncodedImage.createEncodedImage(imageData, 0, imageData.length);
        }
    }
    //No image found
    mimeType = null;
    return null;
}

The sample code I used was:

try
{
    javax.microedition.io.file.FileConnection file = (javax.microedition.io.file.FileConnection)javax.microedition.io.Connector.open(path, javax.microedition.io.Connector.READ);
    if(file.exists())
    {
        java.io.InputStream fs = file.openInputStream();
        long pos = 0L;
        long length = file.fileSize();
        String mime = "";
        net.rim.device.api.system.EncodedImage image = getID3Image(fs, pos, length, mime);
        fs.close();
    }
    file.close();
}
catch(Exception e)
{
}

Just the value of 'path' and an image will be returned.

Edit: Added an if statement that changed value Boolean ver2. Also the length and the position probably don't matter, but it was just for safety, but I says that it can decode the description with UTF-16, the javadoc for 4.7.0 (the version I made and tested with) said that he supports of UTF-16 (Big Endian), but does not specify if Big Endian UTF-16 (not) is supported. Finally, a few points of optimization could be:

  • remove the descriptions (don't know not 100% if they determine if it is album art, the logo of the Publisher, etc.)
  • remove the image type (variable picType)
  • remove the minor version
  • change (if you decide to keep) "get byte" code description image so just realize that the bytes and let Java take care to get the bytes (as what the code for the type MIME)
  • replaceing the MIME parameter with a StringBuffer type so that you can get the MIME type when the function returns.
  • remove the "if(majorVersion == 2)" block because ver2 is set to true already and does not need to be redefined.

Edit 2: Fixed a quick Oops, also found this which sets the value type (variable picType) image:

  • X 00 other
  • x 01 32 x 32 pixels 'file icon' (PNG only)
  • x 02 other file icon
  • X 03 cover (front)
  • x 04 (back) cover
  • x 05 page of the brochure
  • x 06 Media (e.g. lable side of the CD)
  • x 07 lead artist/lead performer/soloist
  • x 08 artist/performer
  • x 09 conductor
  • X0A Band/Orchestra
  • x0B composer
  • lyricist/text writer x0C
  • Saving x0D location
  • X0E during recording
  • x0F during execution
  • x 10 screenshot of film/video
  • X 11 has light colored fish
  • X 12 illustration
  • X 13 logo group/artist
  • x 14 logo editor/Studio

From: http://www.id3.org/id3v2.3.0

Tags: BlackBerry Developers

Similar Questions

Maybe you are looking for

  • any upgrade program

    I am in iphone upgrade program, want to know what is the procedure for obtaining new iphone7 coming soon? Please notify.

  • Need help finding missing app

    I was reset certain features on my I 6 s and lost the Podcast app on my home screen. I can see it listed in the background App update in settings, but it is not in the list of research Spotlight. I am confused on how to get it back.

  • "inspect element" not able to be closed

    After the opening of the toolbar 'inspect element' right click menu is not able to be closed. I tried to click x toolbar, pushing the ESC and by again clicking 'inspect element' in the menu popup with nothing doesn't. The button (Q) also cause it to

  • Problems to make a call

    Hi I am new in Skype yesterday, I set up my Skype and make a calle to my family in Cuba, my home country but when I tal for 1 call of you minute was o worm unspectly and I need to unblock my account. Today, I try to do it again, but the same, I repea

  • DAQ Assistant as a selector of case

    Hello I'm reading an entry to my daq assistant digital camera, and then to hold for x number of seconds, up to that time. The entrance to the wizard matter not after the first entry. So, I used a switch case and started trying with a virtual switch.