【问题标题】:Why is BitmapFactory.decodeByteArray returning Null?为什么 BitmapFactory.decodeByteArray 返回 Null?
【发布时间】:2015-05-19 09:06:44
【问题描述】:

Bitmap.Factory 不会将带有 png 图像数据的字节数组解码为位图。 png 数据是从 mp3 的 id3 标签中收集的。

     byte[] imageBytes = getImageFrameData("APIC", imageType, _id3TagByteArray);
    //!convert frame data bytes to image
    if(imageBytes != null) {
        image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    }

我做错了吗?位图工厂总是返回 null。

getImageFrameData

     private byte[] getImageFrameData(String frameID, byte imageType, byte[] ID3tag){
    /////////////////
     /*
    variable position is initialized to 10 in order to skip ID3 header
    (this must be improved in order to account for potential extended id3 header)
     */
    //!check for extended id3 header (to be implemented)
    final int FRAME_ID_LENGTH = 4;
    final int DATA_LENGTH = 4;
    final int FLAG_LENGTH = 2;
    final int HEADER_LENGTH = FRAME_ID_LENGTH + DATA_LENGTH + FLAG_LENGTH;
    final int TEXT_ENC_LENGTH = 1;
    final int PICT_TYPE_LENGTH = 1;
    List<Byte> fMimeType = new ArrayList<Byte>();


    int position = 10;
    int fInfoPos = position;
    byte[]frame = null;

    while(true){//!loop for seeking frames

        //!Get Frame Id of current frame in loop
        byte[] fID = getBytesInRange(ID3tag, fInfoPos, FRAME_ID_LENGTH);//^search start skips ten bytes

        //!Get Size of Frame Data
        byte[] fSize = getBytesInRange(ID3tag, fInfoPos+=fID.length, DATA_LENGTH);
        int frameDataSize = decodeSynchsafe(fSize);

        //!Get Frame Header Flags (to be implemented)
        byte[] fFlags = getBytesInRange(ID3tag, fInfoPos+=fSize.length, FLAG_LENGTH);

        try {
            if (frameID.equals(new String(fID, "UTF-8"))) {
                //!process image frame
                //!!get additional information data from image frame
                //!!!get text encoding
                byte[] fTextEnc = getBytesInRange(ID3tag, fInfoPos+=fFlags.length, TEXT_ENC_LENGTH);

                //!!!get MIME type
                for(int i = fInfoPos+=fTextEnc.length; i < ID3tag.length - 1; i++){
                    if(ID3tag[i] != 0){
                        fMimeType.add(ID3tag[i]);
                    }else{
                        fInfoPos += fMimeType.size() + 1;
                        break;
                    }
                }
                ////////////////
                byte[]mimeTypeData = new byte[fMimeType.size()];
                for(int i = 0; i < mimeTypeData.length; i++){
                    mimeTypeData[i] = fMimeType.get(i);
                }
                String mime = new String(mimeTypeData);
                ///////////////

                //!!!get image type
                byte[] imgType = getBytesInRange(ID3tag, fInfoPos, PICT_TYPE_LENGTH);

                //!!!get Description
                List<Byte>fDescList = new ArrayList<>();
                for(int i = fInfoPos+=imgType.length; i < ID3tag.length - 1; i++){
                    if(ID3tag[i] != 0){
                        fDescList.add(ID3tag[i]);
                    }else{
                        fInfoPos += fDescList.size() + 1;//+1
                        break;
                    }
                }

                //?if picture type is that of query

                if(imgType[0] == imageType ){
                    //!get image Frame
                    imageFrame = getBytesInRange(ID3tag, position, frameDataSize + 10);
                }

                //!Get Data from Image Frame
                int start = fInfoPos - position;/////////HERE
                //int end = (frameDataSize) - (fInfoPos - position);
                int end = (HEADER_LENGTH + frameDataSize) - start;
                byte[] image = getBytesInRange(imageFrame, start, end);
                String stop = "stop";
                return image;
            }else{
                //!skip to next frame
                position += frameDataSize + HEADER_LENGTH;
                fInfoPos = position;
            }
        }catch(Exception ex){

        }

        /*
        The frame header flags could have important information
         which can determine how the frame is to be processed.
         */
        /////////////////
        //No Frame Exists for the current tag
        // (The id3 tag has been scanned and the tag of query doesn't exist
        //!break
        if(frameDataSize == 0){
            break;
        }
        /////////////////
    }
    return null;
    ////////////////
}   

【问题讨论】:

  • 显示你的getImageFrameData()函数。
  • 好的,我添加了信息。
  • 我想字节数组已损坏。但是,我知道数组的前八个字节包含 png 文件的开头。 w3.org/TR/PNG-Structure.html
  • 我刚刚读到 png 文件有一个块,表示文件的结尾。所以我会确保完整的数据包含在字节数组中,尽管我很确定它应该是。

标签: android image mp3 bitmapfactory id3


【解决方案1】:

问题解决了。对于那些可能希望创建一个程序来处理 mp3 id3tag 信息的人来说,解决方案很重要。

问题在于图像数据字节数组中的图像数据不完整。 id3图像帧中存储的id3帧大小数据不正确是原因。

每个 id3 帧都有一个 10 字节的标头。第 4-8 个字节表示帧中数据的大小(不包括头的大小)。在我用于测试的 mp3 中,图像帧的解码大小很容易损坏。当实际数据大小为 85867 时,它给出的帧数据字节大小为 26350。

问题已通过在 id3tag 字节数组中搜索 PNG 文件结束标记来解决。标记的 8 个字节是文件的结尾。为了得到png文件的大小,在id3字节数组中搜索到找到png文件结束标记的字节数,减去图像帧数据开始前的字节数,然后加上8。 我知道这听起来很复杂,但我认为这可能会对某人有所帮助。 此外,一个 id3 标签可以包含两种图像 mime 类型,PNG 和 JPG。必须修改先前的解决方案以也处理 JPG。

                ///////////// Calculate size of PNG file /////////////
                int[]chunk_id_IEND = {73,69,78,68};
                int pngSize = 0;
                int counter = 0;
                for(int i = 0; i < _id3TagByteArray.length; i++){
                    if(_id3TagByteArray[i] == chunk_id_IEND[0]){
                        for(int j = 0; j < 4; j++ ){
                            if(_id3TagByteArray[i + j] == chunk_id_IEND[j]){
                                ++counter;
                            }else{
                                break;
                            }
                        }
                    }
                    if(counter == 4){
                        pngSize = (i - fInfoPos) + 8;
                        break;
                    }else{
                        counter = 0;
                    }
                }
                /////////////////////////////////////////////////////

【讨论】:

  • 我认为标题大小损坏的问题与一些使用同步安全整数的 MP3 文件有关。去谷歌上查询。但无论如何,搜索图像格式比依赖元数据设置要好。带 JPG 的 MP3 可能会损坏,有时它的正负 1 个字节会导致图像为空,
  • 啊。这就说得通了。这正是代码中计算错误大小的位置。起初我以为我的 Sync Safe Integer 代码是错误的,但它在大多数情况下都有效。确实不是。感谢 VC.One 提供的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-26
相关资源
最近更新 更多