Back to project page Mpo_File_Parser_Example.
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.
/*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; } }