android读取sd卡图片并进行缩放操作
Android 操作 进行 图片 读取 缩放 SD
2023-09-14 08:58:19 时间
在Android中对大图片进行缩放真的很不尽如人意,不知道是不是我的方法不对。下面我列出3种对图片缩放的方法,并给出相应速度。请高人指教。 br br
第一种是BitmapFactory和BitmapFactory.Options。 br
首先,BitmapFactory.Options有几个Fields很有用: br
inJustDecodeBounds:If set to
在Android中对大图片进行缩放真的很不尽如人意,不知道是不是我的方法不对。下面我列出3种对图片缩放的方法,并给出相应速度。请高人指教。
第一种是BitmapFactory和BitmapFactory.Options。
首先,BitmapFactory.Options有几个Fields很有用:
inJustDecodeBounds:If set to true, the decoder will return null (no bitmap), but the out...
也就是说,当inJustDecodeBounds设成true时,bitmap并不加载到内存,这样效率很高哦。而这时,你可以获得bitmap的高、宽等信息。
outHeight:The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.
outWidth:The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.
看到了吧,上面3个变量是相关联的哦。
inSampleSize : If set to a value 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
这就是用来做缩放比的。这里有个技巧:
inSampleSize=(outHeight/Height+outWidth/Width)/2
实践证明,这样缩放出来的图片还是很好的。
最后用BitmapFactory.decodeFile(path, options)生成。
由于只是对bitmap加载到内存一次,所以效率比较高。解析速度快。
第二种是使用Bitmap加Matrix来缩放。
?xml version="1.0" encoding="utf-8"? LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ImageView android:id="@+id/imageShow" android:layout_width="wrap_content" android:layout_height="wrap_content" / ImageView android:id="@+id/image2" android:layout_width="wrap_content" android:layout_height="wrap_content" / TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" / /LinearLayout
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.ThumbnailUtils; import android.os.Bundle; import android.util.Log; import android.widget.ImageView; import android.widget.TextView; public class ResolvePicture extends Activity { private static String tag="ResolvePicture"; Drawable bmImg; ImageView imView; ImageView imView2; TextView text; String theTime; long start, stop; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.text); imView=(ImageView) findViewById(R.id.imageShow); imView2=(ImageView) findViewById(R.id.image2); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic); start=System.currentTimeMillis(); // imView.setImageDrawable(resizeImage(bitmap, 300, 100)); imView2.setImageDrawable(resizeImage2("/sdcard/2.jpeg", 200, 100)); stop=System.currentTimeMillis(); String theTime= String.format("\n1 iterative: (%d msec)", stop - start); start=System.currentTimeMillis(); imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));//2.2才加进来的新类,简单易用 // imView.setImageDrawable(resizeImage(bitmap, 30, 30)); stop=System.currentTimeMillis(); theTime+= String.format("\n2 iterative: (%d msec)", stop - start); text.setText(theTime); } //使用Bitmap加Matrix来缩放 public static Drawable resizeImage(Bitmap bitmap, int w, int h) { Bitmap BitmapOrg = bitmap; int width = BitmapOrg.getWidth(); int height = BitmapOrg.getHeight(); int newWidth = w; int newHeight = h; float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); // if you want to rotate the Bitmap // matrix.postRotate(45); Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true); return new BitmapDrawable(resizedBitmap); } //使用BitmapFactory.Options的inSampleSize参数来缩放 public static Drawable resizeImage2(String path, int width,int height) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true;//不加载bitmap到内存中 BitmapFactory.decodeFile(path,options); int outWidth = options.outWidth; int outHeight = options.outHeight; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; options.inSampleSize = 1; if (outWidth != 0 outHeight != 0 width != 0 height != 0) { int sampleSize=(outWidth/width+outHeight/height)/2; Log.d(tag, "sampleSize = " + sampleSize); options.inSampleSize = sampleSize; } options.inJustDecodeBounds = false; return new BitmapDrawable(BitmapFactory.decodeFile(path, options)); } //图片保存 private void saveThePicture(Bitmap bitmap) { File file=new File("/sdcard/2.jpeg"); try { FileOutputStream fos=new FileOutputStream(file); if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)) { fos.flush(); fos.close(); } } catch(FileNotFoundException e1) { e1.printStackTrace(); } catch(IOException e2) { e2.printStackTrace(); } }
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.media.MediaMetadataRetriever; import android.media.MediaFile.MediaFileType; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.Thumbnails; import android.util.Log; import java.io.FileInputStream; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; * Thumbnail generation routines for media provider. */ public class ThumbnailUtils { private static final String TAG = "ThumbnailUtils"; /* Maximum pixels size for created bitmap. */ private static final int MAX_NUM_PIXELS_THUMBNAIL = 512 * 384; private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 128 * 128; private static final int UNCONSTRAINED = -1; /* Options used internally. */ private static final int OPTIONS_NONE = 0x0; private static final int OPTIONS_SCALE_UP = 0x1; /** * Constant used to indicate we should recycle the input in * {@link #extractThumbnail(Bitmap, int, int, int)} unless the output is the input. */ public static final int OPTIONS_RECYCLE_INPUT = 0x2; /** * Constant used to indicate the dimension of mini thumbnail. * @hide Only used by media framework and media provider internally. */ public static final int TARGET_SIZE_MINI_THUMBNAIL = 320; /** * Constant used to indicate the dimension of micro thumbnail. * @hide Only used by media framework and media provider internally. */ public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96; /** * This method first examines if the thumbnail embedded in EXIF is bigger than our target * size. If not, then itll create a thumbnail from original image. Due to efficiency * consideration, we want to let MediaThumbRequest avoid calling this method twice for * both kinds, so it only requests for MICRO_KIND and set saveImage to true. * * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. * * @param filePath the path of image file * @param kind could be MINI_KIND or MICRO_KIND * @return Bitmap * * @hide This method is only used by media framework and media provider internally. */ public static Bitmap createImageThumbnail(String filePath, int kind) { boolean wantMini = (kind == Images.Thumbnails.MINI_KIND); int targetSize = wantMini ? TARGET_SIZE_MINI_THUMBNAIL : TARGET_SIZE_MICRO_THUMBNAIL; int maxPixels = wantMini ? MAX_NUM_PIXELS_THUMBNAIL : MAX_NUM_PIXELS_MICRO_THUMBNAIL; SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); Bitmap bitmap = null; MediaFileType fileType = MediaFile.getFileType(filePath); if (fileType != null fileType.fileType == MediaFile.FILE_TYPE_JPEG) { createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); bitmap = sizedThumbnailBitmap.mBitmap; } if (bitmap == null) { try { FileDescriptor fd = new FileInputStream(filePath).getFD(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, targetSize, maxPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (IOException ex) { Log.e(TAG, "", ex); } } if (kind == Images.Thumbnails.MICRO_KIND) { // now we make it a "square thumbnail" for MICRO_KIND thumbnail bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; } /** * Create a video thumbnail for a video. May return null if the video is * corrupt or the format is not supported. * * @param filePath the path of video file * @param kind could be MINI_KIND or MICRO_KIND */ public static Bitmap createVideoThumbnail(String filePath, int kind) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); retriever.setDataSource(filePath); bitmap = retriever.captureFrame(); } catch (IllegalArgumentException ex) { // Assume this is a corrupt video file } catch (RuntimeException ex) { // Assume this is a corrupt video file. } finally { try { retriever.release(); } catch (RuntimeException ex) { // Ignore failures while cleaning up. } } if (kind == Images.Thumbnails.MICRO_KIND bitmap != null) { bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; } /** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height */ public static Bitmap extractThumbnail( Bitmap source, int width, int height) { return extractThumbnail(source, width, height, OPTIONS_NONE); } /** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height * @param options options used during thumbnail extraction */ public static Bitmap extractThumbnail( Bitmap source, int width, int height, int options) { if (source == null) { return null; } float scale; if (source.getWidth() source.getHeight()) { scale = width / (float) source.getWidth(); } else { scale = height / (float) source.getHeight(); } Matrix matrix = new Matrix(); matrix.setScale(scale, scale); Bitmap thumbnail = transform(matrix, source, width, height, OPTIONS_SCALE_UP | options); return thumbnail; } /* * Compute the sample size as a function of minSideLength * and maxNumOfPixels. * minSideLength is used to specify that minimal width or height of a * bitmap. * maxNumOfPixels is used to specify the maximal size in pixels that is * tolerable in terms of memory usage. * * The function returns a sample size based on the constraints. * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, * which indicates no care of the corresponding constraint. * The functions prefers returning a sample size that * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. * * Also, the function rounds up the sample size to a power of 2 or multiple * of 8 because BitmapFactory only honors sample size this way. * For example, BitmapFactory downsamples an image by 2 even though the * request is 3. So we round up the sample size to avoid OOM. */ private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize = 8 ) { roundedSize = 1; while (roundedSize initialSize) { roundedSize = 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == UNCONSTRAINED) (minSideLength == UNCONSTRAINED)) { return 1; } else if (minSideLength == UNCONSTRAINED) { return lowerBound; } else { return upperBound; } } /** * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. * The image data will be read from specified pfd if its not null, otherwise * a new input stream will be created using specified ContentResolver. * * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A * new BitmapFactory.Options will be created if options is null. */ private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, BitmapFactory.Options options) { Bitmap b = null; try { if (pfd == null) pfd = makeInputStream(uri, cr); if (pfd == null) return null; if (options == null) options = new BitmapFactory.Options(); FileDescriptor fd = pfd.getFileDescriptor(); options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, minSideLength, maxNumOfPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; b = BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (OutOfMemoryError ex) { Log.e(TAG, "Got oom exception ", ex); return null; } finally { closeSilently(pfd); } return b; } private static void closeSilently(ParcelFileDescriptor c) { if (c == null) return; try { c.close(); } catch (Throwable t) { // do nothing } } private static ParcelFileDescriptor makeInputStream( Uri uri, ContentResolver cr) { try { return cr.openFileDescriptor(uri, "r"); } catch (IOException ex) { return null; } } /** * Transform source Bitmap to targeted width and height. */ private static Bitmap transform(Matrix scaler, Bitmap source, int targetWidth, int targetHeight, int options) { boolean scaleUp = (options OPTIONS_SCALE_UP) != 0; boolean recycle = (options OPTIONS_RECYCLE_INPUT) != 0; int deltaX = source.getWidth() - targetWidth; int deltaY = source.getHeight() - targetHeight; if (!scaleUp (deltaX 0 || deltaY 0)) { /* * In this case the bitmap is smaller, at least in one dimension, * than the target. Transform it by placing as much of the image * as possible into the target and leaving the top/bottom or * left/right (or both) black. */ Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b2); int deltaXHalf = Math.max(0, deltaX / 2); int deltaYHalf = Math.max(0, deltaY / 2); Rect src = new Rect( deltaXHalf, deltaYHalf, deltaXHalf + Math.min(targetWidth, source.getWidth()), deltaYHalf + Math.min(targetHeight, source.getHeight())); int dstX = (targetWidth - src.width()) / 2; int dstY = (targetHeight - src.height()) / 2; Rect dst = new Rect( dstX, dstY, targetWidth - dstX, targetHeight - dstY); c.drawBitmap(source, src, dst, null); if (recycle) { source.recycle(); } return b2; } float bitmapWidthF = source.getWidth(); float bitmapHeightF = source.getHeight(); float bitmapAspect = bitmapWidthF / bitmapHeightF; float viewAspect = (float) targetWidth / targetHeight; if (bitmapAspect viewAspect) { float scale = targetHeight / bitmapHeightF; if (scale .9F || scale 1F) { scaler.setScale(scale, scale); } else { scaler = null; } } else { float scale = targetWidth / bitmapWidthF; if (scale .9F || scale 1F) { scaler.setScale(scale, scale); } else { scaler = null; } } Bitmap b1; if (scaler != null) { // this is used for minithumb and crop, so we want to filter here. b1 = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), scaler, true); } else { b1 = source; } if (recycle b1 != source) { source.recycle(); } int dx1 = Math.max(0, b1.getWidth() - targetWidth); int dy1 = Math.max(0, b1.getHeight() - targetHeight); Bitmap b2 = Bitmap.createBitmap( b1, dx1 / 2, dy1 / 2, targetWidth, targetHeight); if (b2 != b1) { if (recycle || b1 != source) { b1.recycle(); } } return b2; } /** * SizedThumbnailBitmap contains the bitmap, which is downsampled either from * the thumbnail in exif or the full image. * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail * is not null. * * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. */ private static class SizedThumbnailBitmap { public byte[] mThumbnailData; public Bitmap mBitmap; public int mThumbnailWidth; public int mThumbnailHeight; } /** * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. * The functions returns a SizedThumbnailBitmap, * which contains a downsampled bitmap and the thumbnail data in EXIF if exists. */ private static void createThumbnailFromEXIF(String filePath, int targetSize, int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) { if (filePath == null) return; ExifInterface exif = null; byte [] thumbData = null; try { exif = new ExifInterface(filePath); if (exif != null) { thumbData = exif.getThumbnail(); } } catch (IOException ex) { Log.w(TAG, ex); } BitmapFactory.Options fullOptions = new BitmapFactory.Options(); BitmapFactory.Options exifOptions = new BitmapFactory.Options(); int exifThumbWidth = 0; int fullThumbWidth = 0; // Compute exifThumbWidth. if (thumbData != null) { exifOptions.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions); exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels); exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize; } // Compute fullThumbWidth. fullOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, fullOptions); fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels); fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize; // Choose the larger thumbnail as the returning sizedThumbBitmap. if (thumbData != null exifThumbWidth = fullThumbWidth) { int width = exifOptions.outWidth; int height = exifOptions.outHeight; exifOptions.inJustDecodeBounds = false; sizedThumbBitmap.mBitmap = BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions); if (sizedThumbBitmap.mBitmap != null) { sizedThumbBitmap.mThumbnailData = thumbData; sizedThumbBitmap.mThumbnailWidth = width; sizedThumbBitmap.mThumbnailHeight = height; } } else { fullOptions.inJustDecodeBounds = false; sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions); } } }
在Android中对大图片进行缩放真的很不尽如人意,不知道是不是我的方法不对。下面我列出3种对图片缩放的方法,并给出相应速度。请高人指教。
第一种是BitmapFactory和BitmapFactory.Options。
首先,BitmapFactory.Options有几个Fields很有用:
inJustDecodeBounds:If set to true, the decoder will return null (no bitmap), but the out...
也就是说,当inJustDecodeBounds设成true时,bitmap并不加载到内存,这样效率很高哦。而这时,你可以获得bitmap的高、宽等信息。
outHeight:The resulting height of the bitmap, set independent of the state of inJustDecodeBounds.
outWidth:The resulting width of the bitmap, set independent of the state of inJustDecodeBounds.
看到了吧,上面3个变量是相关联的哦。
inSampleSize : If set to a value 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
这就是用来做缩放比的。这里有个技巧:
inSampleSize=(outHeight/Height+outWidth/Width)/2
实践证明,这样缩放出来的图片还是很好的。
最后用BitmapFactory.decodeFile(path, options)生成。
由于只是对bitmap加载到内存一次,所以效率比较高。解析速度快。
第二种是使用Bitmap加Matrix来缩放。
首先要获得原bitmap,再从原bitmap的基础上生成新图片。这样效率很低。
第三种是用2.2新加的类ThumbnailUtils来做。
让我们新看看这个类,从API中来看,此类就三个静态方法:createVideoThumbnail、extractThumbnail(Bitmap source, int width, int height, int options)、extractThumbnail(Bitmap source, int width, int height)。
我这里使用了第三个方法。再看看它的源码,下面会附上。是上面我们用到的BitmapFactory.Options和Matrix等经过人家一阵加工而成。
效率好像比第二种方法高一点点。
下面是我的例子:
?xml version="1.0" encoding="utf-8"? LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ImageView android:id="@+id/imageShow" android:layout_width="wrap_content" android:layout_height="wrap_content" / ImageView android:id="@+id/image2" android:layout_width="wrap_content" android:layout_height="wrap_content" / TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" / /LinearLayout
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.ThumbnailUtils; import android.os.Bundle; import android.util.Log; import android.widget.ImageView; import android.widget.TextView; public class ResolvePicture extends Activity { private static String tag="ResolvePicture"; Drawable bmImg; ImageView imView; ImageView imView2; TextView text; String theTime; long start, stop; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.text); imView=(ImageView) findViewById(R.id.imageShow); imView2=(ImageView) findViewById(R.id.image2); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic); start=System.currentTimeMillis(); // imView.setImageDrawable(resizeImage(bitmap, 300, 100)); imView2.setImageDrawable(resizeImage2("/sdcard/2.jpeg", 200, 100)); stop=System.currentTimeMillis(); String theTime= String.format("\n1 iterative: (%d msec)", stop - start); start=System.currentTimeMillis(); imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));//2.2才加进来的新类,简单易用 // imView.setImageDrawable(resizeImage(bitmap, 30, 30)); stop=System.currentTimeMillis(); theTime+= String.format("\n2 iterative: (%d msec)", stop - start); text.setText(theTime); } //使用Bitmap加Matrix来缩放 public static Drawable resizeImage(Bitmap bitmap, int w, int h) { Bitmap BitmapOrg = bitmap; int width = BitmapOrg.getWidth(); int height = BitmapOrg.getHeight(); int newWidth = w; int newHeight = h; float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); // if you want to rotate the Bitmap // matrix.postRotate(45); Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true); return new BitmapDrawable(resizedBitmap); } //使用BitmapFactory.Options的inSampleSize参数来缩放 public static Drawable resizeImage2(String path, int width,int height) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true;//不加载bitmap到内存中 BitmapFactory.decodeFile(path,options); int outWidth = options.outWidth; int outHeight = options.outHeight; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; options.inSampleSize = 1; if (outWidth != 0 outHeight != 0 width != 0 height != 0) { int sampleSize=(outWidth/width+outHeight/height)/2; Log.d(tag, "sampleSize = " + sampleSize); options.inSampleSize = sampleSize; } options.inJustDecodeBounds = false; return new BitmapDrawable(BitmapFactory.decodeFile(path, options)); } //图片保存 private void saveThePicture(Bitmap bitmap) { File file=new File("/sdcard/2.jpeg"); try { FileOutputStream fos=new FileOutputStream(file); if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)) { fos.flush(); fos.close(); } } catch(FileNotFoundException e1) { e1.printStackTrace(); } catch(IOException e2) { e2.printStackTrace(); } }
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.media.MediaMetadataRetriever; import android.media.MediaFile.MediaFileType; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.Thumbnails; import android.util.Log; import java.io.FileInputStream; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; * Thumbnail generation routines for media provider. */ public class ThumbnailUtils { private static final String TAG = "ThumbnailUtils"; /* Maximum pixels size for created bitmap. */ private static final int MAX_NUM_PIXELS_THUMBNAIL = 512 * 384; private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 128 * 128; private static final int UNCONSTRAINED = -1; /* Options used internally. */ private static final int OPTIONS_NONE = 0x0; private static final int OPTIONS_SCALE_UP = 0x1; /** * Constant used to indicate we should recycle the input in * {@link #extractThumbnail(Bitmap, int, int, int)} unless the output is the input. */ public static final int OPTIONS_RECYCLE_INPUT = 0x2; /** * Constant used to indicate the dimension of mini thumbnail. * @hide Only used by media framework and media provider internally. */ public static final int TARGET_SIZE_MINI_THUMBNAIL = 320; /** * Constant used to indicate the dimension of micro thumbnail. * @hide Only used by media framework and media provider internally. */ public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96; /** * This method first examines if the thumbnail embedded in EXIF is bigger than our target * size. If not, then itll create a thumbnail from original image. Due to efficiency * consideration, we want to let MediaThumbRequest avoid calling this method twice for * both kinds, so it only requests for MICRO_KIND and set saveImage to true. * * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. * * @param filePath the path of image file * @param kind could be MINI_KIND or MICRO_KIND * @return Bitmap * * @hide This method is only used by media framework and media provider internally. */ public static Bitmap createImageThumbnail(String filePath, int kind) { boolean wantMini = (kind == Images.Thumbnails.MINI_KIND); int targetSize = wantMini ? TARGET_SIZE_MINI_THUMBNAIL : TARGET_SIZE_MICRO_THUMBNAIL; int maxPixels = wantMini ? MAX_NUM_PIXELS_THUMBNAIL : MAX_NUM_PIXELS_MICRO_THUMBNAIL; SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); Bitmap bitmap = null; MediaFileType fileType = MediaFile.getFileType(filePath); if (fileType != null fileType.fileType == MediaFile.FILE_TYPE_JPEG) { createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); bitmap = sizedThumbnailBitmap.mBitmap; } if (bitmap == null) { try { FileDescriptor fd = new FileInputStream(filePath).getFD(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, targetSize, maxPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (IOException ex) { Log.e(TAG, "", ex); } } if (kind == Images.Thumbnails.MICRO_KIND) { // now we make it a "square thumbnail" for MICRO_KIND thumbnail bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; } /** * Create a video thumbnail for a video. May return null if the video is * corrupt or the format is not supported. * * @param filePath the path of video file * @param kind could be MINI_KIND or MICRO_KIND */ public static Bitmap createVideoThumbnail(String filePath, int kind) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); retriever.setDataSource(filePath); bitmap = retriever.captureFrame(); } catch (IllegalArgumentException ex) { // Assume this is a corrupt video file } catch (RuntimeException ex) { // Assume this is a corrupt video file. } finally { try { retriever.release(); } catch (RuntimeException ex) { // Ignore failures while cleaning up. } } if (kind == Images.Thumbnails.MICRO_KIND bitmap != null) { bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; } /** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height */ public static Bitmap extractThumbnail( Bitmap source, int width, int height) { return extractThumbnail(source, width, height, OPTIONS_NONE); } /** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height * @param options options used during thumbnail extraction */ public static Bitmap extractThumbnail( Bitmap source, int width, int height, int options) { if (source == null) { return null; } float scale; if (source.getWidth() source.getHeight()) { scale = width / (float) source.getWidth(); } else { scale = height / (float) source.getHeight(); } Matrix matrix = new Matrix(); matrix.setScale(scale, scale); Bitmap thumbnail = transform(matrix, source, width, height, OPTIONS_SCALE_UP | options); return thumbnail; } /* * Compute the sample size as a function of minSideLength * and maxNumOfPixels. * minSideLength is used to specify that minimal width or height of a * bitmap. * maxNumOfPixels is used to specify the maximal size in pixels that is * tolerable in terms of memory usage. * * The function returns a sample size based on the constraints. * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED, * which indicates no care of the corresponding constraint. * The functions prefers returning a sample size that * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED. * * Also, the function rounds up the sample size to a power of 2 or multiple * of 8 because BitmapFactory only honors sample size this way. * For example, BitmapFactory downsamples an image by 2 even though the * request is 3. So we round up the sample size to avoid OOM. */ private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); int roundedSize; if (initialSize = 8 ) { roundedSize = 1; while (roundedSize initialSize) { roundedSize = 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == UNCONSTRAINED) (minSideLength == UNCONSTRAINED)) { return 1; } else if (minSideLength == UNCONSTRAINED) { return lowerBound; } else { return upperBound; } } /** * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. * The image data will be read from specified pfd if its not null, otherwise * a new input stream will be created using specified ContentResolver. * * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A * new BitmapFactory.Options will be created if options is null. */ private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, BitmapFactory.Options options) { Bitmap b = null; try { if (pfd == null) pfd = makeInputStream(uri, cr); if (pfd == null) return null; if (options == null) options = new BitmapFactory.Options(); FileDescriptor fd = pfd.getFileDescriptor(); options.inSampleSize = 1; options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) { return null; } options.inSampleSize = computeSampleSize( options, minSideLength, maxNumOfPixels); options.inJustDecodeBounds = false; options.inDither = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; b = BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (OutOfMemoryError ex) { Log.e(TAG, "Got oom exception ", ex); return null; } finally { closeSilently(pfd); } return b; } private static void closeSilently(ParcelFileDescriptor c) { if (c == null) return; try { c.close(); } catch (Throwable t) { // do nothing } } private static ParcelFileDescriptor makeInputStream( Uri uri, ContentResolver cr) { try { return cr.openFileDescriptor(uri, "r"); } catch (IOException ex) { return null; } } /** * Transform source Bitmap to targeted width and height. */ private static Bitmap transform(Matrix scaler, Bitmap source, int targetWidth, int targetHeight, int options) { boolean scaleUp = (options OPTIONS_SCALE_UP) != 0; boolean recycle = (options OPTIONS_RECYCLE_INPUT) != 0; int deltaX = source.getWidth() - targetWidth; int deltaY = source.getHeight() - targetHeight; if (!scaleUp (deltaX 0 || deltaY 0)) { /* * In this case the bitmap is smaller, at least in one dimension, * than the target. Transform it by placing as much of the image * as possible into the target and leaving the top/bottom or * left/right (or both) black. */ Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b2); int deltaXHalf = Math.max(0, deltaX / 2); int deltaYHalf = Math.max(0, deltaY / 2); Rect src = new Rect( deltaXHalf, deltaYHalf, deltaXHalf + Math.min(targetWidth, source.getWidth()), deltaYHalf + Math.min(targetHeight, source.getHeight())); int dstX = (targetWidth - src.width()) / 2; int dstY = (targetHeight - src.height()) / 2; Rect dst = new Rect( dstX, dstY, targetWidth - dstX, targetHeight - dstY); c.drawBitmap(source, src, dst, null); if (recycle) { source.recycle(); } return b2; } float bitmapWidthF = source.getWidth(); float bitmapHeightF = source.getHeight(); float bitmapAspect = bitmapWidthF / bitmapHeightF; float viewAspect = (float) targetWidth / targetHeight; if (bitmapAspect viewAspect) { float scale = targetHeight / bitmapHeightF; if (scale .9F || scale 1F) { scaler.setScale(scale, scale); } else { scaler = null; } } else { float scale = targetWidth / bitmapWidthF; if (scale .9F || scale 1F) { scaler.setScale(scale, scale); } else { scaler = null; } } Bitmap b1; if (scaler != null) { // this is used for minithumb and crop, so we want to filter here. b1 = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), scaler, true); } else { b1 = source; } if (recycle b1 != source) { source.recycle(); } int dx1 = Math.max(0, b1.getWidth() - targetWidth); int dy1 = Math.max(0, b1.getHeight() - targetHeight); Bitmap b2 = Bitmap.createBitmap( b1, dx1 / 2, dy1 / 2, targetWidth, targetHeight); if (b2 != b1) { if (recycle || b1 != source) { b1.recycle(); } } return b2; } /** * SizedThumbnailBitmap contains the bitmap, which is downsampled either from * the thumbnail in exif or the full image. * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail * is not null. * * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. */ private static class SizedThumbnailBitmap { public byte[] mThumbnailData; public Bitmap mBitmap; public int mThumbnailWidth; public int mThumbnailHeight; } /** * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. * The functions returns a SizedThumbnailBitmap, * which contains a downsampled bitmap and the thumbnail data in EXIF if exists. */ private static void createThumbnailFromEXIF(String filePath, int targetSize, int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) { if (filePath == null) return; ExifInterface exif = null; byte [] thumbData = null; try { exif = new ExifInterface(filePath); if (exif != null) { thumbData = exif.getThumbnail(); } } catch (IOException ex) { Log.w(TAG, ex); } BitmapFactory.Options fullOptions = new BitmapFactory.Options(); BitmapFactory.Options exifOptions = new BitmapFactory.Options(); int exifThumbWidth = 0; int fullThumbWidth = 0; // Compute exifThumbWidth. if (thumbData != null) { exifOptions.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions); exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels); exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize; } // Compute fullThumbWidth. fullOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, fullOptions); fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels); fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize; // Choose the larger thumbnail as the returning sizedThumbBitmap. if (thumbData != null exifThumbWidth = fullThumbWidth) { int width = exifOptions.outWidth; int height = exifOptions.outHeight; exifOptions.inJustDecodeBounds = false; sizedThumbBitmap.mBitmap = BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions); if (sizedThumbBitmap.mBitmap != null) { sizedThumbBitmap.mThumbnailData = thumbData; sizedThumbBitmap.mThumbnailWidth = width; sizedThumbBitmap.mThumbnailHeight = height; } } else { fullOptions.inJustDecodeBounds = false; sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions); } } }
相关文章
- Android加密之全盘加密
- android 浏览器 开发,Android 浏览器的开发实例分享
- android图片资源加密,Android平台图像文件加密
- android activity自动跳转,Android activity跳转之finish()方法的作用
- android移动点餐系统内容和要求,基于Android云计算的移动点餐系统
- android activity singletask,Android Activity启动模式之singleTask实例详解
- Android 源码解析 之 setContentView「建议收藏」
- android跳转到相册需要权限,Android打开相册获取图片路径[通俗易懂]
- android线程间通信的几种方法_Android进程间和线程间通信方式
- mac下Android Studio 安装和使用adb
- android友盟统计分渠道打包
- 【Android】Pixel 2 解锁 Bootloader
- 【Android 性能优化】布局渲染优化 ( CPU 与 GPU 架构分析 | 安卓布局显示流程 | 视觉与帧率分析 | 渲染超时卡顿分析 | 渲染过程与优化 )
- 【Android 异步操作】线程池 ( 线程池作用 | 线程池种类 | 线程池工作机制 | 线程池任务调度源码解析 )
- 【Android FFMPEG 开发】Android 中使用 FFMPEG 对 MP3 文件进行混音操作
- 【字节码插桩】Android 打包流程 | Android 中的字节码操作方式 | AOP 面向切面编程 | APT 编译时技术
- 【ijkplayer】编译 Android 版本的 ijkplayer ③ ( 执行 compile-ffmpeg.sh clean 命令 | 下载并配置 android-ndk-r10e )
- 【Android 逆向】ART 函数抽取加壳 ④ ( 对 libc.so#execve 函数进行内联 HOOK 操作 )
- Android方法数methods超过65536详解手机开发
- Android-SQLite数据库操作详解手机开发
- [android] 手机卫士关闭自动更新详解手机开发
- android读取sd卡图片并进行缩放操作详解手机开发
- android Universal Image Loader for Android 说明文档 (1)详解手机开发
- Android系统与Linux之间的联系(android和linux)
- Android实现PHP连接MySQL进行数据交互(android通过php连接mysql)
- Android短信接收监听、自动回复短信操作例子
- Android中AutoCompleteTextView与MultiAutoCompleteTextView的用法
- Android对sdcard扩展卡文件操作实例详解
- Android显式启动与隐式启动Activity的区别介绍