package com.wistron.WiViewer; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.StreamCorruptedException; import com.tridef.converter.DDD; import com.wistron.StreamHelper.MPOExifInterface; import com.wistron.StreamHelper.MPOFileStreamParser; import com.wistron.StreamHelper.MPOHexTAG; import Utilities.CSStaticData; import Utilities.FileTypeHelper; import android.R.integer; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.BitmapFactory.Options; import android.graphics.Matrix; import android.media.ExifInterface; import android.media.ThumbnailUtils; import android.net.Uri; import android.provider.MediaStore; import android.provider.MediaStore.Images.ImageColumns; import android.provider.MediaStore.MediaColumns; import android.provider.MediaStore.Images.Thumbnails; import android.util.Log; public class OperateBitmaps { static int screenwidth=TDStaticData.SCREEN_WIDTH; static int scrennheight=TDStaticData.SCREEN_HEIGHT; static int screenwidth_org=TDStaticData.SCREEN_WIDTH_ORG; static int scrennheight_org=TDStaticData.SCREEN_HEIGHT_ORG; static String TAG="OperateBitmaps"; String m_error=""; Context context; static int mOritationType=0;//0代表正常根据图片tag显示,1为不读图片tag static int mOrientation; private int mSceneDepth=255; private boolean isConvert2DTo3D=true; DDD m3DConverter=null; public void setConvertAuto(boolean isconvert) { isConvert2DTo3D=isconvert; } public void setSceneDepth(int SceneDepth) { mSceneDepth=SceneDepth; m3DConverter.setSceneDepth(mSceneDepth); } public void setOrientationType(int type ) { mOritationType=type; } //private int mOrientation=0; public OperateBitmaps( Context context) { this.context= context; m3DConverter=new DDD(); m3DConverter.setSceneDepth(mSceneDepth); } public void setOrientation(int degree) { mOrientation=degree; } /** * 解码图片,得到适当大小的图片数组。 *【0】为原图(2D为原图,3D为左图),【1】为左右图压缩一半后的合成图 * @param filepath * @return */ public Bitmap[] decodeBitmap(String filepath) { try { if(CSStaticData.DEBUG) Log.e(TAG, "decodeBitmap---------------1"); boolean isVideo = isVideo(filepath); boolean is3DSource = is3DSource(filepath); if (isVideo) { // 解码视频得到缩略图,因为视频缩图一般比较小,所以不用调整大小(调整大小主要是为了防止内存溢出) Bitmap srcBitmap = ThumbnailUtils.createVideoThumbnail(filepath, Thumbnails.FULL_SCREEN_KIND); return genFinalBitmaps(seperateBitmap(srcBitmap,is3DSource,0), is3DSource,false); } else { //先解码(用到option可以压缩图片),根据是否为3D及图片尺寸来决定压缩比率。 return decodeImage(filepath,is3DSource); } } catch (OutOfMemoryError e) { // TODO: handle exception if(CSStaticData.DEBUG) Log.e(TAG, "decodeBitmap------[OutOfMemoryError]"); return null; } } public void updateOrientation(String filepath,int changeangle) { int rotate= ImageInfo.getImageOrientationForRotate(filepath); int orientation=(rotate+changeangle+720)%360; if(orientation==0) orientation=360; try { ExifInterface m_exif=new ExifInterface(filepath); int aString= ImageInfo.genNewOrientation(orientation); m_exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(aString)); m_exif.saveAttributes(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public int lookUpOrientation(String filepath ) { int a=ImageInfo.getImageOrientationForRotate(filepath); if(CSStaticData.DEBUG) { Log.e(TAG, "[lookUpOrientation]="+a); } return a; } public Bitmap Rotate2DBitmap(Bitmap bitmap, int orientation ) { if(bitmap!=null) { int width=bitmap.getWidth(); int height=bitmap.getHeight(); if(width*height==0) return null; if(!(orientation==90||orientation==180||orientation==270)) { return bitmap; } else { Matrix matrix=new Matrix(); matrix.postRotate(orientation,width/2, height/2); Bitmap mBitmap=Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); if(mBitmap!=bitmap) recycleSBitmap(bitmap); return mBitmap; } } return null; } /** * 将输入图片居中分割为左右图和旋转,并将输入图片回收。如果图片为2D,则直接返回,数组第二元素为第一元素 * @param bitmap * @return */ public static Bitmap[] seperateBitmap(Bitmap bitmap,boolean is3D,int orientation) { if(CSStaticData.DEBUG) Log.e(TAG, "seperateBitmap---------------3"); if(bitmap==null||bitmap.getWidth()==0||bitmap.getHeight()==0) return null; int width=bitmap.getWidth(); int height=bitmap.getHeight(); Bitmap[] mBitmaps=new Bitmap[2]; if(mOritationType==0) { //根据图片tag信息修改旋转角 if(is3D) { Matrix matrix=new Matrix(); if(orientation==90||orientation==180||orientation==270) matrix.postRotate(orientation,width/4, height/2); mBitmaps[0]=Bitmap.createBitmap(bitmap, 0, 0, width/2, height, matrix, false); mBitmaps[1]=Bitmap.createBitmap(bitmap, width/2, 0, width/2, height, matrix, false); recycleSBitmap(bitmap); } else { if(!(orientation==90||orientation==180||orientation==270)) { mBitmaps[0]=bitmap; } else { Matrix matrix=new Matrix(); matrix.postRotate(orientation,width/2, height/2); mBitmaps[0]=Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); if(mBitmaps[0]!=bitmap) recycleSBitmap(bitmap); } mBitmaps[1]=null; } } else if(mOritationType==1) { int tempangle=0; if(orientation!=0&&orientation!=-1) { //查询不出错 tempangle= getDegreeToShow(orientation); } tempangle=0; if(is3D) { Matrix matrix=new Matrix(); if(tempangle!=0&&tempangle!=360) matrix.postRotate(tempangle,width/4, height/2); mBitmaps[0]=Bitmap.createBitmap(bitmap, 0, 0, width/2, height, matrix, false); mBitmaps[1]=Bitmap.createBitmap(bitmap, width/2, 0, width/2, height, matrix, false); recycleSBitmap(bitmap); } else { if(CSStaticData.DEBUG) Log.e(TAG, " 进入非tag模式,获取的temangle为:"+tempangle); if(tempangle==0||tempangle==360) { mBitmaps[0]=bitmap; } else { Matrix matrix=new Matrix(); matrix.postRotate(tempangle,width/2, height/2); mBitmaps[0]=Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); if(mBitmaps[0]!=bitmap) recycleSBitmap(bitmap); } mBitmaps[1]=null; } } return mBitmaps; } public static int getDegreeToShow(int orientation) { return orientation-mOrientation; // if(mOrientation==360) // { // return mOrientation; // } // else if(mOrientation==180) // { // return mOrientation-180; // // } // else if (mOrientation==90) { // return mOrientation-90; // // } // else { // return mOrientation-270; // } } /** * 需要将图片调整为适应屏幕大小,计算option的压缩比 * * @param width * 图片的长( 真实长度,3D模式下左图长度) * @param height * 图片宽 * @param is3D * 是否为3D * @return 压缩的比例 */ public static int getDecodeRate(float width, float height, boolean is3D,int orientation) { float rateScreen =0; float rateImage =0; int rate=0; if(orientation==90||orientation==270) { rateImage = height / width; } else { rateImage = width / height; } boolean flag; if (is3D) { rateScreen= ((float) screenwidth_org) / ((float) scrennheight_org); if((rateImage / 2f) - rateScreen > 0) { flag=true; } else { flag=false; } if (width > 2 * screenwidth || height > scrennheight) { if (flag) { rate= (int) (width / 2) / screenwidth; } else { rate= (int) height / scrennheight; } } else { rate= 1; } } else { rateScreen= ((float) screenwidth) / ((float) scrennheight); if(rateImage - rateScreen > 0) { flag=true; } else { flag=false; } if (width > screenwidth || height > scrennheight) { if (flag) { rate= (int) (width) / screenwidth; } else { rate= (int) height / scrennheight; } } else { rate= 1; } } if(CSStaticData.DEBUG) Log.e(TAG, "压缩比例为"+rate); return rate; } /** * 判断是否为3D资源,无论是3D影片还是图片 * @param filepath * @return */ public static boolean is3DSource(String filepath) { return FileTypeHelper.isStereoImageFile(filepath)||FileTypeHelper.isStereoImageFile(filepath); } /** * 判断是否为影片 * @param filepath * @return */ public static boolean isVideo(String filepath) { return FileTypeHelper.isVideoFile(filepath); } /** * 判断是否为mpo文件 * @param filepath * @return */ public static boolean isMpo(String filepath) { String mString=filepath.toLowerCase(); return mString.endsWith("mpo"); } // public void setOrientation(int orientation) // { // mOrientation=orientation; // Log.e(TAG, "当前operateBitmap中的mOrientation="+mOrientation); // } /** * 解码图片,定义解压比例,返回图片数组,生成图片数组 【0】为原图(2D为原图,3D为左图),【1】为左右图压缩一半后的合成图 * @param filepath * @return */ public Bitmap[] decodeImage(String filepath,boolean is3DSource) { if(CSStaticData.DEBUG) Log.e(TAG, "decodeImage---------------2"); boolean ismpo=isMpo(filepath); if(ismpo) { Bitmap[] res =null; try { Bitmap[] mpoBitmaps =decodeMpoBitmap(filepath, screenwidth, scrennheight); res= genFinalBitmaps(mpoBitmaps,true,false); } catch (OutOfMemoryError e) { if(CSStaticData.DEBUG) Log.e(TAG, "解码mpo文件失败,内存不足"); } return res; } else { //为jps和jpg等 BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; options.inPurgeable = true; options.inInputShareable = true; options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filepath, options); int srcWidth = options.outWidth; int srcHeight = options.outHeight; if (srcWidth * srcHeight != 0) { int orientation=lookUpOrientation(filepath); int rate=getDecodeRate(srcWidth, srcHeight, is3DSource,orientation); options.inJustDecodeBounds=false; options.inSampleSize=rate; Bitmap mBitmap=BitmapFactory.decodeFile(filepath, options); if(isConvert2DTo3D&&!filepath.toLowerCase().endsWith("jps")) { Bitmap rotatebitmap=Rotate2DBitmap(mBitmap,orientation); if(rotatebitmap!=null) { int width=rotatebitmap.getWidth(); int height=rotatebitmap.getHeight(); if(width!=0&&height!=0) { float r=((float)height)/((float)width); //如果比例超过2.4则不适用2D转3D if(r>2.4) { return genFinalBitmaps(seperateBitmap(rotatebitmap, is3DSource,0), is3DSource,false); } else { Bitmap temp=fitScreenSize(rotatebitmap, TDStaticData.SCREEN_WIDTH_ORG, TDStaticData.SCREEN_HEIGHT_ORG); Bitmap tempBitmaps= m3DConverter.genrenteTriDefBitmap(temp, false); Bitmap[] resBitmaps=new Bitmap[2]; resBitmaps[0]=temp; resBitmaps[1]=tempBitmaps; return resBitmaps; } } } } else { return genFinalBitmaps(seperateBitmap(mBitmap, is3DSource,orientation), is3DSource,false); } } } return null; } /** * 用于解码图片,并旋转(orientation)。 * @return */ /** * 回收bitmap数组 */ public static void recycleDBitmap(Bitmap[] bitmaps) { if (bitmaps != null) { for (int i = 0; i < bitmaps.length; i++) { if(bitmaps[i]!=null) { if (!bitmaps[i].isRecycled()) bitmaps[i].recycle(); } } bitmaps=null; } } public static void recycleSBitmap(Bitmap bitmap) { if (bitmap != null) { if (!bitmap.isRecycled()) bitmap.recycle(); bitmap=null; } } //通过给定的屏幕大小生成一张完整的图片,包括mpo(拼成一张),并且读取了旋转信息 public Bitmap decodeMpotoSingle(String filepath,int Swidth,int Sheight) { Bitmap[] mBitmaps =decodeMpoBitmap(filepath, Swidth/2, Sheight); Bitmap res=null; if(mBitmaps!=null&&mBitmaps[0]!=null) { int singlewidth=mBitmaps[0].getWidth(); int singleheight=mBitmaps[0].getHeight(); Bitmap mbitmap = Bitmap.createBitmap(singlewidth * 2, singleheight, Config.ARGB_8888); Canvas mCanvas = new Canvas(mbitmap); mCanvas.drawBitmap(mBitmaps[0], 0, 0, null); if(mBitmaps[1]!=null) mCanvas.drawBitmap(mBitmaps[1], singlewidth, 0, null); res = mbitmap; } return fitScreenSize(res,Swidth,Sheight); } /** * 生成jpg和jps适应屏幕的图片 */ public Bitmap decodeNomalBitmaptoSingle(String filepath,int Swidth,int Sheight) { Bitmap mRetrunBitmap=null; BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_8888; options.inPurgeable = true; options.inInputShareable = true; options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filepath, options); int srcWidth = options.outWidth; int srcHeight = options.outHeight; if (srcWidth * srcHeight != 0) { int orientation=lookUpOrientation(filepath); int sampleSize = Math.max(srcWidth / Swidth, srcHeight / Sheight); sampleSize = Math.min(sampleSize, Math.max(srcWidth / Sheight,srcHeight / Swidth)); options.inSampleSize = Math.max(sampleSize, 2); options.inJustDecodeBounds=false; Bitmap mBitmap=BitmapFactory.decodeFile(filepath, options); int width=mBitmap.getWidth(); int height=mBitmap.getHeight(); //特殊处理,处理编码方式 if(mBitmap.getConfig()!=Config.ARGB_8888) { Bitmap temp= Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas tempcanvas=new Canvas(temp); tempcanvas.drawBitmap(mBitmap, 0, 0, null); if(mBitmap!=temp) { mBitmap.recycle(); mBitmap=temp; } else { temp.recycle(); } } if(!(orientation==90||orientation==180||orientation==270)) { mRetrunBitmap=mBitmap; } else { Matrix matrix=new Matrix(); matrix.postRotate(orientation,width/2, height/2); mRetrunBitmap=Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, false); if(mRetrunBitmap!=mBitmap) recycleSBitmap(mBitmap); } } return fitScreenSize(mRetrunBitmap,Swidth,Sheight); } public static Bitmap fitScreenSize(Bitmap bitmap,int swidth,int sheight) { Bitmap res=null; if(bitmap!=null) { int width=bitmap.getWidth(); int height=bitmap.getHeight(); if(width*height!=0) { if(width<=swidth&&height<=sheight) { return bitmap; } else { //按比例压缩大小 float rate_src=((float)width)/((float)height); float rate_screen=((float)swidth)/((float)sheight); Bitmap temp=null; if(rate_src<=rate_screen) { temp=Bitmap.createScaledBitmap(bitmap, (int) (sheight*rate_src), sheight, false); } else { temp=Bitmap.createScaledBitmap(bitmap,swidth, (int) (swidth/rate_src), false); } if(temp!=bitmap) { bitmap.recycle(); res=temp; } } } } return res; } /** * 压缩mpo到屏幕大小,并调整大小,然后旋转,生成正常比例的左右图的图片数组 * @param filepath * @param Swidth * @param Sheight * @return */ public Bitmap[] decodeMpoBitmap(String filepath,int Swidth,int Sheight) { if(CSStaticData.DEBUG) Log.e(TAG, "decodeMpoBitmap"); Bitmap [] mReturnBitmaps=new Bitmap[2]; int orientation=lookUpOrientation( filepath); int decodeRate=1; Options mOptions=new Options(); mOptions.inPreferredConfig=Config.RGB_565; try { ExifInterface exf=new ExifInterface(filepath); int width=Integer.valueOf(exf.getAttribute(ExifInterface.TAG_IMAGE_WIDTH)); int height=Integer.valueOf(exf.getAttribute(ExifInterface.TAG_IMAGE_LENGTH)); if(width>0&&height>0) { decodeRate= getDecodeRate(width*2, height,true , orientation); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mOptions.inSampleSize=decodeRate; if(CSStaticData.DEBUG) Log.e(TAG, "[decodeMpoBitmap]-------------------------------------------->inSampleSize="+decodeRate); Bitmap[] mBitmaps=MPOFileStreamParser.decodeFile(filepath,mOptions); if(mBitmaps==null) return null; //调整大小 for (int i = 0; i < mBitmaps.length; i++) { if(i<2) { //mReturnBitmaps[i]=mBitmaps[i]; mReturnBitmaps[i]=reSizeBitmap(mBitmaps[i], Swidth, Sheight); } else { if(mBitmaps[i]!=null) mBitmaps[i].recycle(); } } //调整左右图大小一致,这里偷工减料了,不保证为原比例 if(mReturnBitmaps[0]!=null&&mReturnBitmaps[1]!=null) { int width=mReturnBitmaps[0].getWidth(); int height=mReturnBitmaps[0].getHeight(); if(width!=mReturnBitmaps[1].getWidth()||height!=mReturnBitmaps[1].getHeight()) { //ruguo if(width*height!=0) { Bitmap tmpBitmap=Bitmap.createScaledBitmap(mReturnBitmaps[1], width, height, false); if(tmpBitmap!=mReturnBitmaps[1]) mReturnBitmaps[1].recycle(); mReturnBitmaps[1]=tmpBitmap; } } } //orientation旋转 //同普通图片方式一致,测试 if(orientation==90||orientation==180||orientation==270) { Bitmap[] temp=new Bitmap[2]; Matrix matrix=new Matrix(); if(mReturnBitmaps[0]!=null) { if(mReturnBitmaps[0].getWidth()*mReturnBitmaps[0].getHeight()!=0) { matrix.setRotate(orientation,mReturnBitmaps[0].getWidth()/2, mReturnBitmaps[0].getHeight()/2); temp[0]=Bitmap.createBitmap(mReturnBitmaps[0], 0, 0, mReturnBitmaps[0].getWidth(), mReturnBitmaps[0].getHeight(), matrix, false); } } if(mReturnBitmaps[1]!=null) { if(mReturnBitmaps[1].getWidth()*mReturnBitmaps[1].getHeight()!=0) { matrix.setRotate(orientation,mReturnBitmaps[1].getWidth()/2, mReturnBitmaps[1].getHeight()/2); temp[1]=Bitmap.createBitmap(mReturnBitmaps[1], 0, 0, mReturnBitmaps[1].getWidth(), mReturnBitmaps[1].getHeight(), matrix, false); } } recycleDBitmap(mReturnBitmaps); mReturnBitmaps=temp; } //返回图片 return mReturnBitmaps; } /** * 将两张图片合成一张图片,如果为3D,则左右压缩后合成一张,如果为2D,则将图片压缩一半后画两遍 * @param bitmaps * @param is3d * @param isrecycleleft * @return */ public Bitmap conbineImages2OneInhalf(Bitmap[] bitmaps,boolean is3d,boolean isrecycleleft) { if(CSStaticData.DEBUG) Log.e(TAG, "conbineImages2OneInhalf---------------5"); if(bitmaps!=null&&bitmaps[0]!=null) { int width=bitmaps[0].getWidth(); int height=bitmaps[0].getHeight(); if(width*height!=0) { Bitmap res=Bitmap.createBitmap(width, height, Config.RGB_565); Canvas mCanvas=new Canvas(res); Rect src=new Rect(0, 0, width, height); Rect dst1=new Rect(0, 0, width/2, height); Rect dst2=new Rect(width/2, 0, width, height); if(is3d) { mCanvas.drawBitmap(bitmaps[0], src, dst1, null); if(bitmaps[1]!=null) { mCanvas.drawBitmap(bitmaps[1], src, dst2, null); bitmaps[1].recycle(); } } else { mCanvas.drawBitmap(bitmaps[0], src, dst1, null); mCanvas.drawBitmap(bitmaps[0], src, dst2, null); } if(isrecycleleft) { bitmaps[0].recycle(); } return res; } else { return null; } } else { return null; } } /** * 生成图片数组 【0】为原图(2D为原图,3D为左图),【1】为左右图压缩一半后的合成图 * @param bitmaps * @param is3D * @param isrecycleleft * @return */ public Bitmap[] genFinalBitmaps(Bitmap[] bitmaps,boolean is3D,boolean isrecycleleft) { if(CSStaticData.DEBUG) Log.e(TAG, "genFinalBitmaps---------------4"); if(bitmaps==null||bitmaps[0]==null) { return null; } Bitmap[] res=new Bitmap[2]; res[0]=bitmaps[0]; res[1]=conbineImages2OneInhalf(bitmaps, is3D,isrecycleleft); return res; } public Bitmap reSizeBitmap(Bitmap bitmap ,int width,int height ) { Bitmap mBitmap=null; if(bitmap!=null) { int srcwidth=bitmap.getWidth(); int srcheight=bitmap.getHeight(); if(srcwidth*srcheight!=0) { if(srcwidth<=width&&srcheight<=height) { mBitmap=bitmap; } else { float rate_src=((float)srcwidth)/((float)srcheight); float rate_screen=((float)width)/((float)height); if(rate_src>rate_screen) { mBitmap=Bitmap.createScaledBitmap(bitmap, width, (int) (width/rate_src), false); } else { mBitmap=Bitmap.createScaledBitmap(bitmap, (int) (height*rate_src), height, false); } if(bitmap!=mBitmap) bitmap.recycle(); } } } return mBitmap; } }