Android Open Source - Mpo_File_Parser_Example Mpo File Parser






From Project

Back to project page Mpo_File_Parser_Example.

License

The source code is released under:

MIT License

If you think the Android project Mpo_File_Parser_Example listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*The MIT License (MIT)
*//  w  ww. ja  v a2 s . c om
*Copyright (c) 2014 Poming Chen
*
*Permission is hereby granted, free of charge, to any person obtaining a copy
*of this software and associated documentation files (the "Software"), to deal
*in the Software without restriction, including without limitation the rights
*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*copies of the Software, and to permit persons to whom the Software is
*furnished to do so, subject to the following conditions:
*
*The above copyright notice and this permission notice shall be included in all
*copies or substantial portions of the Software.
*
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*SOFTWARE.
*/

package tw.edu.nccu.cs.vipl.fun.mpo;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Point;
import android.media.ExifInterface;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class MpoFileParser {

    private final static short TAG_SOI = (short) 0xFFD8;
    private final static short TAG_EOI = (short) 0xFFD9;
    private final static short TAG_APP1 = (short) 0xFFE1;
    private final static short TAG_APP2 = (short) 0xFFE2;

    private final static short MARKER_DQT = (short) 0xFFDB;
    private final static short MARKER_DHT = (short) 0xFFC4;
    private final static short MARKER_DRI = (short) 0xFFDD;
    private final static short MARKER_SOF = (short) 0xFFC0;
    private final static short MARKER_SOS = (short) 0xFFDA;

    private final static short APP2_TAG_VERSION = (short) 0xB000;
    private final static short APP2_TAG_IMAGE_NUMBERS = (short) 0xB001;
    private final static short APP2_TAG_ENTRY = (short) 0xB002;
    private final static short APP2_TAG_UID_LISTS = (short) 0xB003;
    private final static short APP2_TAG_TOTAL_FRAME = (short) 0xB004;

    private final static String MPO_INDICATE = "MPF\0";

    private final static int MP_LITTLE_ENDIAN = 0x49492A00;
    private final static int MP_BIG_ENDIAN = 0x4D4D002A;

    private List<ImageIndex> mImageIndexList;
    private Bitmap mBitmap;
    private Options mOptions;

    private String mFileName;
    private boolean mLoaded = false;
    private int mOrientation = 0;
    private Point mImageSize = new Point();
    private String mFileDateTaken;
    private String mVersion;
    private int mNumberOfImages;
    private int mMpEntry;

    private int mImageUIDList;
    private int mTotalFrames;
    private String mSimpleName;

    private class ImageIndex {
        private int mHead = 0;
        private int mTail = 0;
        private byte[] rawDatas;

        public ImageIndex(int head, int tail, byte[] rawDatas) {
            this.mHead = head;
            this.mTail = tail;
            this.rawDatas = rawDatas;
        }

    }

    /**
     * @param fileName
     * @param autoLoad if true would parse file right away , it would cause heavy loading.
     * @throws FileNotFoundException
     * @throws IOException
     */
    public MpoFileParser(String fileName, boolean autoLoad) throws FileNotFoundException, IOException {
        mFileName = fileName;
        if (autoLoad) {
            init();
        }
    }

    /**
     * @return the number of images in the mpo file , don't call this method in main thread or may cause ANR
     * @throws IOException
     */
    public int init() throws IOException, FileNotFoundException {

        File file = new File(mFileName);
        mSimpleName = file.getName();
        mImageIndexList = new ArrayList<ImageIndex>();

        ExifInterface exifInterface = new ExifInterface(mFileName);
        if (exifInterface != null) {
            mOrientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

            switch (mOrientation) {
                case ExifInterface.ORIENTATION_NORMAL:
                    mOrientation = 0;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    mOrientation = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    mOrientation = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    mOrientation = 270;
                    break;

                default:
                    break;
            }

            mImageSize.x = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 100);
            mImageSize.y = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 100);
            mFileDateTaken = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
        }

        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
        FileChannelReader fileChannelReader = new FileChannelReader(randomAccessFile.getChannel());

        if (fileChannelReader.readShort() != TAG_SOI) {
            randomAccessFile.close();
            throw new IOException();
        }

        long position = fileChannelReader.position();
        long size = fileChannelReader.size();

        while (position < size) {

            short marker = fileChannelReader.readShort();
            int length = fileChannelReader.readShort() & 0xFFFF;

            if (marker != TAG_APP2) {
                if (position + length + 2 >= size) {
                    break;
                }
                fileChannelReader.position(position + length + 2);
                position = fileChannelReader.position();
                continue;
            }

            String indicate = fileChannelReader.readString();
            length -= 4;
            if (MPO_INDICATE.equals(indicate)) {

                int startOfOffset = (int) fileChannelReader.position();
                int mpEndian = fileChannelReader.readInt();
                boolean isLittleEndian = mpEndian == MP_LITTLE_ENDIAN;

                int offsetToFirstIFD = fileChannelReader.readInt(isLittleEndian);
                fileChannelReader.position(startOfOffset + offsetToFirstIFD);

                short tagCount = fileChannelReader.readShort(isLittleEndian);

                for (int i = 0; i < tagCount; i++)
                {
                    short tag = fileChannelReader.readShort(isLittleEndian);
                    short type = fileChannelReader.readShort(isLittleEndian);
                    int count2 = fileChannelReader.readInt(isLittleEndian);

                    switch (tag)
                    {

                        case APP2_TAG_VERSION:
                            mVersion = fileChannelReader.readString();
                            break;
                        case APP2_TAG_IMAGE_NUMBERS:
                            mNumberOfImages = fileChannelReader.readInt(isLittleEndian);
                            break;
                        case APP2_TAG_ENTRY:
                            mMpEntry = fileChannelReader.readInt(isLittleEndian);
                            break;
                        case APP2_TAG_UID_LISTS:
                            mImageUIDList = fileChannelReader.readInt(isLittleEndian);
                            break;
                        case APP2_TAG_TOTAL_FRAME:
                            mTotalFrames = fileChannelReader.readInt(isLittleEndian);
                            break;

                    }
                }

                int offsetNext = fileChannelReader.readInt(isLittleEndian);

                // Read the values of the MP Index IFD
                for (int i = 0; i < mNumberOfImages; i++)
                {
                    int iattr = fileChannelReader.readInt(isLittleEndian);
                    int imageSize = fileChannelReader.readInt(isLittleEndian);
                    int dataOffset = fileChannelReader.readInt(isLittleEndian);
                    short d1EntryNo = fileChannelReader.readShort(isLittleEndian);
                    short d2EntryNo = fileChannelReader.readShort(isLittleEndian);

                    // Calculate offset from beginning of file
                    long offset = i == 0 ? 0 : dataOffset + startOfOffset;
                    // store the current position
                    long currentPosition = fileChannelReader.position();
                    // read the image
                    fileChannelReader.position(offset);
                    ImageIndex imageIndex = new ImageIndex((int) offset, (int) (offset + imageSize), fileChannelReader.readBytes(imageSize));
                    fileChannelReader.position(currentPosition);
                    mImageIndexList.add(imageIndex);
                }

            }

            fileChannelReader.position(position + length + 2);
            position = fileChannelReader.position();

        }
        randomAccessFile.close();
        mLoaded = true;

        return mImageIndexList.size();
    }

    /**
     * 
     * @param index the index file need to decode
     * @return deocde bitmap if in mpo file or null
     */
    public Bitmap getBitmap(int index) {
        if (index >= mImageIndexList.size() || index < 0) {
            return null;
        }

        if (mOptions != null) {
            mOptions.requestCancelDecode();
        }

        mOptions = new Options();
        mOptions.inPreferredConfig = Config.RGB_565;
        mOptions.inPreferQualityOverSpeed = false;
        mOptions.inPurgeable = true;
        ImageIndex imageIndex = mImageIndexList.get(index);
        return BitmapFactory.decodeByteArray(imageIndex.rawDatas, 0, imageIndex.rawDatas.length, mOptions);

    }

    public int getOrientation() {
        return mOrientation;
    }

    public Point getImageSize() {
        return mImageSize;
    }

    public String getFileName() {
        return mFileName;
    }

    public String getSimpleName() {
        return mSimpleName;
    }

    public boolean isLoaded() {
        return mLoaded;
    }

    public String getFileDateTaken() {
        return mFileDateTaken;
    }

    public String getVersion() {
        return mVersion;
    }

    public int getNumberOfImages() {
        return mImageIndexList.size();
    }

    public int getMpEntry() {
        return mMpEntry;
    }

    public int getImageUIDList() {
        return mImageUIDList;
    }

    public int getTotalFrames() {
        return mTotalFrames;
    }

}




Java Source Code List

tw.edu.nccu.cs.vipl.fun.mpo.FileChannelReader.java
tw.edu.nccu.cs.vipl.fun.mpo.MainActivity.java
tw.edu.nccu.cs.vipl.fun.mpo.MpoFileParser.java
tw.edu.nccu.cs.vipl.task.BlockingLinkedList.java
tw.edu.nccu.cs.vipl.task.CancelableRunnable.java
tw.edu.nccu.cs.vipl.task.TaskManager.java