package com.wistron.StreamHelper;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.provider.MediaStore.Images.Thumbnails;
import android.util.Log;
/**
* MPO文件解析类
* @author WH1107028 Cocoonshu
* @commit 使用RandomAccessFile作为文件流读取类
* @Notice 为了减少内存的使用,buffer尽量使用全局的
*/
public class MPOFileStreamParser {
private static final boolean DEBUG = false;
protected Options mOpts = new Options();
protected long[] mAnchorInAPP2 = null; //偏移点列表
protected int mImageCount = 0; //MPO中包含的图片数量
protected long[] mImageSizes = null;
protected byte[] mBuffer = null;
protected String mFileName = null;
protected int mPointer = 0; //文件Buffer指针
protected RandomAccessFile mFin = null;
protected RandomAccessFile mFout = null;
protected int m0thImageLen = 0, //APP2段中记录0th图片的长度
m1thImageLen = 0, //APP2段中记录1th图片的长度
m0thImageOffset = -1, //APP2段中记录0th图片的偏移
m1thImageOffset = -1, //APP2段中记录1th图片的偏移
m0thAPP2IISOffset = -1, //APP2段中记录0th Individual Image Size 的位置
m1thAPP2IISOffset = -1, //APP2段中记录1th Individual Image Size 的位置
mAPP0LengthL = 0, //APP0左图段长
mAPP0LengthR = 0, //APP0右图段长
mAPP1LengthL = 0, //APP1左图段长
mAPP1LengthR = 0, //APP1右图段长
mAPP2LengthL = 0, //APP2左图段长
mAPP2LengthR = 0, //APP2右图段长
mLeftImageLength = 0, //左图段长
mRightImageLength = 0; //右图段长
protected List<Integer> mFFE1_list = null; //APP1
protected List<Integer> mFFE2_list = null; //APP2
protected List<Integer> mFFDB_list = null; //DQT
protected List<Integer> mFFD9_list = null; //EOI
/**
* 解码MPO文件
* @param filePath
* @return
*/
static public Bitmap[] decodeFile(String filePath){
MPOFileStreamParser parser = null;
Bitmap[] bmp = new Bitmap[2];
int imageCount = 0;
try {
parser = new MPOFileStreamParser(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
imageCount = parser.getImageCount();
bmp = new Bitmap[imageCount];
for(int i = 0; i < imageCount; i++){
bmp[i] = parser.seekIndividualImage(i);
}
parser.close();
return bmp;
}
/**
* 解码MPO文件
* @param filePath
* @return
*/
static public Bitmap[] decodeFile(String filePath, Options opt){
MPOFileStreamParser parser = null;
Bitmap[] bmp = new Bitmap[2];
int imageCount = 0;
try {
parser = new MPOFileStreamParser(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
try{
imageCount = parser.getImageCount();
bmp = new Bitmap[imageCount];
parser.setOption(opt);
for(int i = 0; i < imageCount; i++){
bmp[i] = parser.seekIndividualImage(i);
}
}catch (Exception exp) {
exp.printStackTrace();
bmp = null;
}
parser.close();
System.gc();
return bmp;
}
/**
* 编码MPO文件
* @param filePath
* @return
*/
static public boolean encodeFile(String filePath, byte[] JPEGImage){
MPOFileStreamParser parser = null;
boolean isDone = true;
byte[] APP0 = null,
APP1 = null,
IMGL = null,
IMGR = null,
JPEGImageL = null,
JPEGImageR = null;
byte[][] srcImage = new byte[2][];
if(JPEGImage != null && JPEGImage.length > 4){
//1.record APP0 APP1 APP2 block, we call it [imageTIFF]
//2.split Image
//3.merge APP0+APP1+APP2+LImage APP0+APP1+APP2+RImage
//4.call encodeFile(String, byte[], byte[])
parser = new MPOFileStreamParser();
parser.mFileName = filePath; // DEBUG!!
parser.setBuffer(JPEGImage);
APP0 = parser.pickAPP0(0);
APP1 = parser.pickAPP1(0);
srcImage = splitImage(JPEGImage);
parser.setBuffer(srcImage[0]);
IMGL = parser.pickCData(0);
parser.setBuffer(srcImage[1]);
IMGR = parser.pickCData(1);
JPEGImageL = new byte[APP0.length + APP1.length + IMGL.length];
JPEGImageR = new byte[APP0.length + APP1.length + IMGR.length];
System.arraycopy(MPOHexTAG.TAG_SOI, 0, JPEGImageL, 0, 2);
System.arraycopy(APP0, 0, JPEGImageL, 2, APP0.length);
System.arraycopy(APP1, 0, JPEGImageL, APP0.length, APP1.length);
System.arraycopy(IMGL, 0, JPEGImageL, APP0.length + APP1.length, IMGL.length);
IMGL = null;
System.gc();
System.arraycopy(MPOHexTAG.TAG_SOI, 0, JPEGImageR, 0, 2);
System.arraycopy(APP0, 0, JPEGImageR, 0, APP0.length);
System.arraycopy(APP1, 0, JPEGImageR, APP0.length, APP1.length);
System.arraycopy(IMGR, 0, JPEGImageR, APP0.length + APP1.length, IMGR.length);
IMGR = null;
System.gc();
isDone = encodeFile(filePath, JPEGImageL, JPEGImageR);
APP0 = null;
APP1 = null;
System.gc();
}else{
isDone = false;
}
return isDone;
}
/**
* 编码MPO文件
* @param filePath
* @return
*/
static public boolean encodeFile(String filePath, byte[] JPEGImageL, byte[] JPEGImageR){
MPOFileStreamParser parser = null;
boolean isDone = true;
int imageCount = 0;
String path = null;
File desFile = null,
desDir = null;
try{
if(JPEGImageL != null && JPEGImageR != null && JPEGImageL.length > 4 && JPEGImageR.length > 4){
//创建MPO文件
desFile = new File(filePath);
if(!desFile.getParentFile().exists()){
desFile.getParentFile().mkdirs();
}
if(!desFile.exists()){
try {
if(!desFile.createNewFile()){
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
//创建流
parser = new MPOFileStreamParser();
try {
parser.create(desFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
//处理左图并写入
parser.writeLeftImage(JPEGImageL);
JPEGImageL = null;
System.gc();
//处理右图并写入
parser.writeRightImage(JPEGImageR);
JPEGImageR = null;
System.gc();
parser.close();
}else{
return false;
}
}catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (NumberFormatException e) {
e.printStackTrace();
new File(filePath).delete();
return false;
} catch (IOException e) {
e.printStackTrace();
new File(filePath).delete();
return false;
}
System.gc();
return isDone;
}
/**
* 编码MPO文件
* @param filePath
* @return
*/
static public boolean encodeFile(String filePath, byte[] JPEGImage, OnMPOWrittenListener listener){
boolean result = false;
result = encodeFile(filePath, JPEGImage);
if(listener != null){
listener.OnMPOWrittenCompleted();
}
return result;
}
/**
* 编码MPO文件
* @param filePath
* @return
*/
static public boolean encodeFile(String filePath, byte[] JPEGImageL, byte[] JPEGImageR, OnMPOWrittenListener listener){
boolean result = false;
result = encodeFile(filePath, JPEGImageL, JPEGImageR);
if(listener != null){
listener.OnMPOWrittenCompleted();
}
return result;
}
/**
* 获取MPO文件的指定大小的缩略图
* @param filePath
* @param width
* @param height
* @return
*/
static public Bitmap[] getThumbnails(String filePath, int width, int height){//×
return null;
}
/**
* 获取MPO文件的预设打下的缩略图
* @param filePath
* @param thumbSize
* @return
*/
static public Bitmap[] getThumbnails(String filePath, int thumbSize){//×
switch (thumbSize) {
case Thumbnails.FULL_SCREEN_KIND:
break;
case Thumbnails.MINI_KIND:
break;
case Thumbnails.MICRO_KIND:
break;
default:
break;
}
return null;
}
/**
* 将图片分解为左右两张
* @param src
* @return
*/
static protected byte[][] splitImage(byte[] src){
byte[][] res = new byte[2][];
File tmpMPOL = null,
tmpMPOR = null;
FileOutputStream foutL = null,
foutR = null;
RandomAccessFile finL = null,
finR = null;
String str = null;
Bitmap bmp = null;
Bitmap[] desbmp = new Bitmap[2];
if(src == null || src.length < 4){
return null;
}
try {
bmp = BitmapFactory.decodeByteArray(src, 0, src.length);
str = System.currentTimeMillis() + "";
tmpMPOL = File.createTempFile("MPOencoder_" + str + "L", "tmp");
tmpMPOR = File.createTempFile("MPOencoder_" + str + "R", "tmp");
foutL = new FileOutputStream(tmpMPOL);
foutR = new FileOutputStream(tmpMPOR);
//获取左图
desbmp[0] = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth()/2, bmp.getHeight());
desbmp[0].compress(CompressFormat.JPEG, 80, foutL);
//获取右图
desbmp[1] = Bitmap.createBitmap(bmp, bmp.getWidth()/2, 0, bmp.getWidth()/2, bmp.getHeight());
desbmp[1].compress(CompressFormat.JPEG, 80, foutR);
bmp.recycle();
desbmp[0].recycle();
desbmp[1].recycle();
finL = new RandomAccessFile(tmpMPOL, "r");
finR = new RandomAccessFile(tmpMPOR, "r");
res[0] = new byte[(int) finL.length()];
res[1] = new byte[(int) finR.length()];
finL.read(res[0]);
finR.read(res[1]);
finL.close();
finR.close();
tmpMPOL.delete();
tmpMPOR.delete();
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (OutOfMemoryError e) {
e.printStackTrace();
Log.w("MPOencoder","[splitImage]OutOfMemoryError");
return null;
}
return res;
}
///////////////////////////////////
// @Don't call by outer
// Private functions
///////////////////////////////////
protected MPOFileStreamParser() {
}
protected MPOFileStreamParser(String filePath) throws FileNotFoundException{
mFileName = filePath;
if(filePath != null){
if(!open()){
throw new FileNotFoundException("Cannot open \"" + filePath + "\"");
}
}
mFFE1_list = new ArrayList<Integer>();
mFFE2_list = new ArrayList<Integer>();
mFFDB_list = new ArrayList<Integer>();
mFFD9_list = new ArrayList<Integer>();
if(mFin == null){
open();
}
getMarkerList(mFin);
}
private void create(File desFile) throws FileNotFoundException {
if(desFile == null){
throw new FileNotFoundException("File is null");
}
if(mFout != null){
mFout = null;
}
mFileName = desFile.getAbsolutePath();
mFout = new RandomAccessFile(desFile, "rw"); //要求同步写入时,可设定mFout的mode为"rws"
}
private void writeLeftImage(byte[] buffer) throws NumberFormatException, IOException {
if(mFout == null){
mFout = new RandomAccessFile(mFileName, "rw"); //要求同步写入时,可设定mFout的mode为"rws"
}
mPointer = 0;
mBuffer = buffer;
//写入文件SOI
mFout.write(new byte[]{(byte)0xFF, (byte)0xD8});
//写入APP0
mFout.write(pickAPP0(0));
//写入APP1
mFout.write(pickAPP1(0));
//写入APP2
mFout.write(pickAPP2(0));
//写入左图数据
mFout.write(pickCompData(0));
//修正偏移量
fixOffsetInAPP2();
/*******************************/
/*******************************/
/*******************************/
}
private void writeRightImage(byte[] buffer) throws NumberFormatException, IOException {
if(mFout == null){
mFout = new RandomAccessFile(mFileName, "rw"); //要求同步写入时,可设定mFout的mode为"rws"
}
mPointer = 0;
mBuffer = buffer;
//写入文件SOI
mFout.write(new byte[]{(byte)0xFF, (byte)0xD8});
//写入APP0
mFout.write(pickAPP0(1));
//写入APP1
// mFout.write(pickAPP1(1)); //可以不写入
pickAPP1(1); //运行一次,跳过APP1区
//写入APP2
mFout.write(pickAPP2(1));
//写入右图原始数据
mFout.write(pickCompData(1));
//修正偏移量
fixOffsetInAPP2();
/*******************************/
/*******************************/
/*******************************/
}
private void fixOffsetInAPP2() throws IOException {
long FDpointer = mFout.getFilePointer();
//修正APP2数据
if(m0thAPP2IISOffset >= 0){
mFout.seek(m0thAPP2IISOffset);
mFout.write(BaselineUtls.Int2Byte(m0thImageLen, 4));
mFout.write(BaselineUtls.Int2Byte(0, 4));
}
if(m1thAPP2IISOffset >= 0){
mFout.seek(m1thAPP2IISOffset);
mFout.write(BaselineUtls.Int2Byte(m1thImageLen, 4));
mFout.write(BaselineUtls.Int2Byte(2 + mAPP0LengthL + mAPP1LengthL + mAPP2LengthL + m0thImageLen, 4));
}
mFout.seek(FDpointer);
}
private byte[] pickAPP0(int index) throws ArrayIndexOutOfBoundsException{//为了减少内存的使用,buffer不传入,而使用全局的
byte[] resAPP0 = new byte[0];
int pos = 0,
len = 0;
if(mBuffer == null){
return resAPP0;
}
//查找APP0标签
for(int i = 0; i < mBuffer.length - 1; i++){
if(mBuffer[i] == MPOHexTAG.TAG_APP0[0] && mBuffer[i+1] == MPOHexTAG.TAG_APP0[1]){
pos = i;
len = BaselineUtls.Byte2UInt(new byte[]{mBuffer[i+2], mBuffer[i+3]}, MPOHexTAG.BIG_ENDIAN) + 2; //要加上FF E0 2个字节
break;
}
}
//开始拷贝
resAPP0 = new byte[len];
for(int i = 0; i < len; i++){ /**<=================>**/
resAPP0[i] = mBuffer[i + pos];
}
switch (index) {
case 0:
mAPP0LengthL = len;
break;
case 1:
mAPP0LengthR = len;
break;
default:
break;
}
if(pos == 0 && len == 0){
// mPointer = pos + len;
}else{
mPointer = pos + len - 2;
}
System.gc();
if(DEBUG){
Log.w("MPOEncoder", "[pickAPP0]pos = " + pos + ", len = " + len + ", mPointer = " + mPointer);
DEBUG_saveData(mFileName + ".APP0", resAPP0);
}
return resAPP0;
}
private byte[] pickAPP1(int index) {//为了减少内存的使用,buffer不传入,而使用全局的
byte[] resAPP1 = new byte[0];
int pos = 0,
len = 0;
if(mBuffer == null){
return resAPP1;
}
//查找APP1标签
//for(int i = mPointer; i < mBuffer.length - 1; i++){
for(int i = 0; i < mBuffer.length - 1; i++){
if(mBuffer[i] == MPOHexTAG.TAG_APP1[0] && mBuffer[i+1] == MPOHexTAG.TAG_APP1[1]){
pos = i;
len = BaselineUtls.Byte2UInt(new byte[]{mBuffer[i+2], mBuffer[i+3]}, MPOHexTAG.BIG_ENDIAN) + 2; //要加上FF E1 2个字节
break;
}
}
//开始拷贝
resAPP1 = new byte[len];
for(int i = 0; i < len; i++){
resAPP1[i] = mBuffer[i + pos];
}
switch (index) {
case 0:
mAPP1LengthL = len;
break;
case 1:
mAPP1LengthR = len;
default:
break;
}
if(pos == 0 && len == 0){
// mPointer = pos + len;
}else{
mPointer = pos + len - 2;
}
System.gc();
if(DEBUG){
Log.w("MPOEncoder", "[pickAPP1]pos = " + pos + ", len = " + len);
DEBUG_saveData(mFileName + ".APP1", resAPP1);
}
return resAPP1;
}
/**
*
* @param index 0 = 左图 1 = 右图
* @return
*/
private byte[] pickAPP2(int index) {
ByteBuffer res = ByteBuffer.allocate(160); //预定义APP2 Block Length = 0x5A
mAPP2LengthL = res.capacity();
//记录要修改的关键点
switch (index) {
case 0:
//生成APP2头部
res.put(MPOHexTAG.TAG_APP2); //APP2标签
res.put(BaselineUtls.Int2Byte(158, 2)); //APP2段长
res.put(new byte[]{(byte)0x4D, (byte)0x50, (byte)0x46, (byte)0x00}); //MP 标识
res.put(new byte[]{(byte)0x4D, (byte)0x4D, (byte)0x00, (byte)0x2A}); //字节序:默认为Big Endian
res.putInt(8); //偏移量
//生成MP Index IFD
res.put(BaselineUtls.Int2Byte(3, 2)); //节点数量
res.put(MPOHexTAG.TAG_MPFVER); //MP 格式版本
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_UNDEFINED, 2)); //节点的数据类型:未定义
res.put(BaselineUtls.Int2Byte(4, 4)); //节点大小:4
res.put(new byte[]{(byte)0x30, (byte)0x31, (byte)0x30, (byte)0x30}); //值:默认为“0100”,即v1.0.0
res.put(MPOHexTAG.TAG_MPIMGCOUNT); //图片数量
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(2, 4)); //值:2
res.put(MPOHexTAG.TAG_MPENTRY); //MP 节点偏移
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_UNDEFINED, 2)); //节点的数据类型:未定义
res.put(BaselineUtls.Int2Byte(2, 4)); //节点大小:2
res.put(BaselineUtls.Int2Byte(32, 4)); //值:32
res.putInt(82); //下个节点的偏移:0x52 = 82
res.put(new byte[]{(byte)0x20, (byte)0x02, (byte)0x00, (byte)0x02}); //图片属性:即100000000000100000000000000010 <========= 貌似Big Endian不是单纯的把字序换一下,而是重新按照bit的顺序计算
res.put(BaselineUtls.Int2Byte(0, 4)); //图片大小
res.put(BaselineUtls.Int2Byte(0, 4)); //图片偏移:0,第一张为0
res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片0的编号:没有时为0
res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片1的编号:没有时为0
res.put(new byte[]{(byte)0x00, (byte)0x02, (byte)0x00, (byte)0x02}); //图片属性:即000000000000100000000000000010 <========= 貌似Big Endian不是单纯的把字序换一下,而是重新按照bit的顺序计算
res.put(BaselineUtls.Int2Byte(0, 4)); //图片大小
res.put(BaselineUtls.Int2Byte(0, 4)); //图片偏移:JPEG Header length + APP0 Length + APP1 Length + APP2 Length
res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片0的编号:没有时为0
res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片1的编号:没有时为0
//生成MP Attribute IFD
res.put(BaselineUtls.Int2Byte(4, 2)); //节点数量
res.put(MPOHexTAG.TAG_MPIMGNUM); //MPIndividualNum
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(1, 4)); //值:2
res.put(MPOHexTAG.TAG_BASEVPNUM); //BaseViewPointNum
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(1, 4)); //值:2
res.put(MPOHexTAG.TAG_CONANGLE); //ConvergenceAngle
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_SRATIONAL, 2)); //节点的数据类型:SRational
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(138, 4)); //偏移:XXXXXXXXXXXXXXXXXXXXXXXXX
res.put(MPOHexTAG.TAG_BASELINELEN); //BaselineLength
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_RATIONAL, 2)); //节点的数据类型:Rational
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(146, 4)); //偏移:XXXXXXXXXXXXXXXXXXXXXXXXX
//生成MP Attribute Value
res.put(new byte[]{(byte)0x00, (byte)0x00}); //pad
res.put(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, //ConvergenceAngle 值:unknown
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
res.put(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}); //BaselineLength 值:unknown
res.putInt(0); //下个节点的偏移:0
m0thAPP2IISOffset = 2 + mAPP0LengthL + mAPP1LengthL + 62;
m1thAPP2IISOffset = 2 + mAPP0LengthL + mAPP1LengthL + 78;
break;
case 1:
//生成APP2头部
res.put(MPOHexTAG.TAG_APP2); //APP2标签
res.put(BaselineUtls.Int2Byte(88, 2)); //APP2段长
res.put(new byte[]{(byte)0x4D, (byte)0x50, (byte)0x46, (byte)0x00}); //MP 标识
res.put(new byte[]{(byte)0x4D, (byte)0x4D, (byte)0x00, (byte)0x2A}); //字节序:默认为Big Endian
res.putInt(8); //偏移量
//生成MP Index IFD
// res.put(BaselineUtls.Int2Byte(3, 2)); //节点数量
// res.put(MPOHexTAG.TAG_MPFVER); //MP 格式版本
// res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_UNDEFINED, 2)); //节点的数据类型:未定义
// res.put(BaselineUtls.Int2Byte(4, 2)); //节点大小:4
// res.put(new byte[]{(byte)0x30, (byte)0x31, (byte)0x30, (byte)0x30}); //值:默认为“0100”,即v1.0.0
// res.put(MPOHexTAG.TAG_MPIMGCOUNT); //图片数量
// res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
// res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
// res.put(BaselineUtls.Int2Byte(2, 4)); //值:2
// res.put(MPOHexTAG.TAG_MPENTRY); //MP 节点偏移
// res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_UNDEFINED, 2)); //节点的数据类型:未定义
// res.put(BaselineUtls.Int2Byte(2, 4)); //节点大小:2
// res.put(BaselineUtls.Int2Byte(32, 4)); //值:32
// res.put(BaselineUtls.Int2Byte(0, 4)); //下个节点的偏移
// res.put(new byte[]{(byte)0x20, (byte)0x02, (byte)0x00, (byte)0x02}); //图片属性:即100000000000100000000000000010
// res.put(BaselineUtls.Int2Byte(0, 4)); //图片大小
// res.put(BaselineUtls.Int2Byte(0, 4)); //图片偏移:0,第一张为0
// res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片0的编号:没有时为0
// res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片1的编号:没有时为0
// res.put(new byte[]{(byte)0x00, (byte)0x02, (byte)0x00, (byte)0x02}); //图片属性:即000000000000100000000000000010
// res.put(BaselineUtls.Int2Byte(0, 4)); //图片大小
// res.put(BaselineUtls.Int2Byte(0, 4)); //图片偏移:JPEG Header length + APP0 Length + APP1 Length + APP2 Length
// res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片0的编号:没有时为0
// res.put(BaselineUtls.Int2Byte(0, 2)); //附属图片1的编号:没有时为0
//生成MP Attribute IFD
res.put(BaselineUtls.Int2Byte(4, 2)); //节点数量
res.put(MPOHexTAG.TAG_MPIMGNUM); //MPIndividualNum
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(2, 4)); //值:2
res.put(MPOHexTAG.TAG_BASEVPNUM); //BaseViewPointNum
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_LONG, 2)); //节点的数据类型:Long
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(1, 4)); //值:2
res.put(MPOHexTAG.TAG_CONANGLE); //ConvergenceAngle
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_SRATIONAL, 2)); //节点的数据类型:SRational
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(68, 4)); //偏移:XXXXXXXXXXXXXXXXXXXXXXXXX
res.put(MPOHexTAG.TAG_BASELINELEN); //BaselineLength
res.put(BaselineUtls.Int2Byte(MPOHexTAG.TAG_RATIONAL, 2)); //节点的数据类型:Rational
res.put(BaselineUtls.Int2Byte(1, 4)); //节点大小:1
res.put(BaselineUtls.Int2Byte(76, 4)); //偏移:XXXXXXXXXXXXXXXXXXXXXXXXX
//生成MP Attribute Value
res.put(new byte[]{(byte)0x00, (byte)0x00}); //pad
res.put(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, //ConvergenceAngle 值:unknown
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
res.put(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}); //BaselineLength 值:unknown
res.putInt(0); //下个节点的偏移:0
// m0thAPP2IISOffset = 2 + mAPP0LengthL + mAPP1LengthL + mAPP2LengthL + m0thImageLen + 2 + mAPP0LengthR + mAPP1LengthR + 62;
// m1thAPP2IISOffset = 2 + mAPP0LengthL + mAPP1LengthL + mAPP2LengthL + m0thImageLen + 2 + mAPP0LengthR + mAPP1LengthR + 78;
m0thAPP2IISOffset = -1;
m1thAPP2IISOffset = -1;
break;
default:
break;
}
return res.array();
}
/**
* 获取jpeg中的图像数据,encodeFile(byte[] arg0)用
* @param index
* @return
*/
private byte[] pickCData(int index) {
byte[] resData = new byte[0];
int pos = 0,
len = 0;
boolean APP0_OK = false,
APP1_OK = false;
if(mBuffer == null){
return resData;
}
//跳过APPn
for(int i = 0; i < mBuffer.length - 2; i++){
if((!APP0_OK) && (mBuffer[i] == MPOHexTAG.TAG_APP0[0] && mBuffer[i+1] == MPOHexTAG.TAG_APP0[1])){//APP0
if(i + 3 <= mBuffer.length){//防越界
int jump = BaselineUtls.Byte2UInt(new byte[]{mBuffer[i+2], mBuffer[i+3]}, MPOHexTAG.BIG_ENDIAN);
if(jump >= mBuffer.length ){
return new byte[0];
}else{
i = jump;
pos = i;
}
}
APP0_OK = true;
}
if((!APP1_OK) && (mBuffer[i] == MPOHexTAG.TAG_APP1[0] && mBuffer[i+1] == MPOHexTAG.TAG_APP1[1])){//APP1
if(i + 3 <= mBuffer.length){//防越界
int jump = BaselineUtls.Byte2UInt(new byte[]{mBuffer[i+2], mBuffer[i+3]}, MPOHexTAG.BIG_ENDIAN);
if(jump >= mBuffer.length ){
return new byte[0];
}else{
i = jump;
pos = i;
}
}
APP1_OK = true;
}
}
//查找FF DB标签
for(int i = pos ; i < mBuffer.length - 1; i++){
if(mBuffer[i] == MPOHexTAG.TAG_DQT[0] && mBuffer[i+1] == MPOHexTAG.TAG_DQT[1]){
pos = i;
len = mBuffer.length - pos;
break;
}
}
resData = new byte[len]; //
for(int i = 0; i < len; i++){ //建议在这部分直接操作mFout来写入文件
resData[i] = mBuffer[i + pos]; //节约内存,提高速度
} //
if(len == 0){
resData = new byte[0];
System.gc();
}
if(DEBUG){
Log.w("MPOEncoder", "[pickCDATA" + index + "]pos = " + pos + ", len = " + len);
DEBUG_saveData(mFileName + ".CDATA" + index, resData);
}
return resData;
}
/**
* 获取jpeg中的图像数据,encodeFile(byte[] arg0, byte[] arg1)用
* @param index
* @return
* @throws ArrayIndexOutOfBoundsException
*/
private byte[] pickCompData(int index) throws ArrayIndexOutOfBoundsException{
byte[] resData = new byte[0];
int pos = 0,
len = 0;
if(mBuffer == null){
return resData;
}
if(DEBUG){
for(int i = 0; i < mBuffer.length - 1; i++){
if(mBuffer[i] == MPOHexTAG.TAG_DQT[0] && mBuffer[i+1] == MPOHexTAG.TAG_DQT[1]){
Log.w("MPOEncoder", "FF DB = " + i);
break;
}
}
DEBUG_saveData(mFileName + ".SCR" + index + ".jpg", mBuffer);
}
//查找FF DB标签
for(int i = (mPointer - 2 < 0 ? 0 : mPointer - 2); i < mBuffer.length - 1; i++){
if(mBuffer[i] == MPOHexTAG.TAG_DQT[0] && mBuffer[i+1] == MPOHexTAG.TAG_DQT[1]){
pos = i;
len = mBuffer.length - pos;
break;
}
}
resData = new byte[len]; //
for(int i = 0; i < len; i++){ //建议在这部分直接操作mFout来写入文件
resData[i] = mBuffer[i + pos]; //节约内存,提高速度
} //
if(len == 0){
resData = new byte[0];
System.gc();
}
switch (index) {
case 0:
m0thImageLen = len;
break;
case 1:
m1thImageLen = len;
break;
default:
break;
}
if(DEBUG){
Log.w("MPOEncoder", "[pickCOMDATA" + index + "]pos = " + pos + ", len = " + len);
DEBUG_saveData(mFileName + ".COMDATA" + index, resData);
}
return resData;
}
private void appendBytes(byte[] content) throws IOException {
if(mFout == null){
mFout = new RandomAccessFile(mFileName, "rw"); //要求同步写入时,可设定mFout的mode为"rws"
}
mFout.seek(mFout.length());
mFout.write(content);
mFout.seek(mFout.length());
}
private void setBuffer(byte[] buffer) {
mBuffer = null;
System.gc();
mBuffer = buffer;
mPointer = 0;
System.gc();
}
private byte[] getBuffer() {
return mBuffer;
}
/**
* 搜索图片
* @param imageIndex 第几幅图
* @return
*/
private Bitmap seekIndividualImage(int imageIndex){
Bitmap ans = null;
int start = 0,
end = 0;
if(mFin == null){
return null;
}
if(imageIndex >= mImageCount){
return null;
}
//开始搜索
for(int i = imageIndex; i < mFFDB_list.size(); i++){
if(mFFDB_list.get(i) >= mFFE2_list.get(imageIndex)){
start = mFFDB_list.get(i);
break;
}
}
for(int i = imageIndex; i < mFFD9_list.size(); i++){
if(mFFD9_list.get(i) >= mFFE2_list.get(imageIndex) && mFFD9_list.get(i) >= start){
end = mFFD9_list.get(i);
break;
}
}
//开始读取
if(mFFDB_list.size() >= imageIndex && mFFD9_list.size() >= imageIndex){
byte[] buffer = new byte[end - start + 4];
try {
mFin.seek(start);
mFin.read(buffer, 2, end - start);
mFin.seek(0);
buffer[0] = MPOHexTAG.TAG_SOI[0];
buffer[1] = MPOHexTAG.TAG_SOI[1];
buffer[buffer.length - 2] = MPOHexTAG.TAG_EOI[0];
buffer[buffer.length - 1] = MPOHexTAG.TAG_EOI[1];
ans = BitmapFactory.decodeByteArray(buffer, 0, buffer.length, mOpts);
buffer = null;
System.gc();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e){
e.printStackTrace();
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
return ans;
}
protected void setOption(Options opt) {
mOpts = opt;
}
protected int getImageCount(){
return mImageCount;
}
protected void getMarkerList(RandomAccessFile fin){
try{
if(fin == null){
return;
}
byte[] buffer = new byte[1024];
int loopCount = (int) (fin.length()/1024f);
int loopMod = (int) (fin.length()%1024f);
for(int i = 0; i < loopCount; i++){
//1024倍数文件块
fin.read(buffer, 0, 1024);
for(int j = 0; j < buffer.length - 1; j++){
//APP1
if(buffer[j] == MPOHexTAG.TAG_APP1[0] && buffer[j+1] == MPOHexTAG.TAG_APP1[1]){
mFFE1_list.add(i*buffer.length + j);
}
//APP2
if(buffer[j] == MPOHexTAG.TAG_APP2[0] && buffer[j+1] == MPOHexTAG.TAG_APP2[1]){
mFFE2_list.add(i*buffer.length + j);
}
//DQT
if(buffer[j] == MPOHexTAG.TAG_DQT[0] && buffer[j+1] == MPOHexTAG.TAG_DQT[1]){
mFFDB_list.add(i*buffer.length + j);
}
//EOI
if(buffer[j] == MPOHexTAG.TAG_EOI[0] && buffer[j+1] == MPOHexTAG.TAG_EOI[1]){
mFFD9_list.add(i*buffer.length + j);
}
}
}
if(loopMod > 0){
//1024余数文件块
fin.read(buffer, 0, loopMod);
for(int j = 0; j < 1024 - 1; j++){
//APP1
if(buffer[j] == MPOHexTAG.TAG_APP1[0] && buffer[j+1] == MPOHexTAG.TAG_APP1[1]){
mFFE1_list.add(loopCount*buffer.length + j);
}
//APP2
if(buffer[j] == MPOHexTAG.TAG_APP2[0] && buffer[j+1] == MPOHexTAG.TAG_APP2[1]){
mFFE2_list.add(loopCount*buffer.length + j);
}
//DQT
if(buffer[j] == MPOHexTAG.TAG_DQT[0] && buffer[j+1] == MPOHexTAG.TAG_DQT[1]){
mFFDB_list.add(loopCount*buffer.length + j);
}
//EOI
if(buffer[j] == MPOHexTAG.TAG_EOI[0] && buffer[j+1] == MPOHexTAG.TAG_EOI[1]){
mFFD9_list.add(loopCount*buffer.length + j);
}
}
}
fin.seek(0);
}catch(IOException exp){
exp.printStackTrace();
}
}
private boolean open(){
boolean result = true;
ArrayList<Long> anchors = new ArrayList<Long>();
byte[] buffer = new byte[1024];
if(mFin != null){
try {
mFin.close();
} catch (IOException e) {
e.printStackTrace();
mFin = null;
}
}
try {
/**
* 读取0xFFE2的个数,就能获取图片数量
*/
mFin = new RandomAccessFile(mFileName, "r");
//获取基本信息
mImageCount = 0;
int loopCount = (int) (mFin.length()/1024f);
int loopMod = (int) (mFin.length()%1024f);
for(int i = 0; i < loopCount; i++){
//1024倍数文件块
mFin.read(buffer, 0, 1024);
for(int j = 0; j < 1024 - 1; j++){
if(buffer[j] == MPOHexTAG.TAG_APP2[0] && buffer[j+1] == MPOHexTAG.TAG_APP2[1]){
mImageCount++;
anchors.add((long)(i*1024+j));
}
}
}
if(loopMod > 0){
//1024余数文件块
mFin.read(buffer, 0, loopMod);
for(int j = 0; j < 1024 - 1; j++){
if(buffer[j] == MPOHexTAG.TAG_APP2[0] && buffer[j+1] == MPOHexTAG.TAG_APP2[1]){
mImageCount++;
anchors.add((long)(loopCount*1024+j));
}
}
}
mFin.seek(0);
//记录偏移点
mAnchorInAPP2 = new long[mImageCount];
mImageSizes = new long[mImageCount];
for(int i = 0; i < mImageCount; i++){
mAnchorInAPP2[i] = anchors.get(i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return result;
}
private boolean close(){
if(mFin == null){
}else{
try {
mFin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(mFout == null){
}else{
try {
mFout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.gc();
return true;
}
public interface OnMPOWrittenListener{
public void OnMPOWrittenCompleted();
}
/////////////////////////////////////////////
private void DEBUG_saveData(String filePath, byte [] sdata) {
//创建MPO文件
File File = new File(filePath);
if(File.getParentFile() == null || !File.getParentFile().exists()){
File.getParentFile().mkdirs();
}
if(!File.exists()){
try {
if(!File.createNewFile()){
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
FileOutputStream fout = new FileOutputStream(File);
fout.write(sdata);
fout.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}