下面列出了android.graphics.BitmapRegionDecoder# recycle ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Reads and crops the bitmap.
* @param outOptions Bitmap options, useful to determine {@code outMimeType}.
*/
private Bitmap crop(BitmapFactory.Options outOptions) throws IOException {
InputStream inputStream = openBitmapInputStream();
// Effeciently crops image without loading full resolution into memory
// https://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(inputStream, false);
try {
Rect rect = new Rect(mX, mY, mX + mWidth, mY + mHeight);
return decoder.decodeRegion(rect, outOptions);
} finally {
if (inputStream != null) {
inputStream.close();
}
decoder.recycle();
}
}
/**
* Reads and crops the bitmap.
* @param outOptions Bitmap options, useful to determine {@code outMimeType}.
*/
private Bitmap crop(BitmapFactory.Options outOptions) throws IOException {
InputStream inputStream = openBitmapInputStream();
// Effeciently crops image without loading full resolution into memory
// https://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(inputStream, false);
try {
Rect rect = new Rect(mX, mY, mX + mWidth, mY + mHeight);
return decoder.decodeRegion(rect, outOptions);
} finally {
if (inputStream != null) {
inputStream.close();
}
decoder.recycle();
}
}
private Bitmap readBitmap (final int scalePercentage, final Rect cropRect) throws IOException {
if (100 % scalePercentage != 0) throw new IllegalArgumentException("scalePercentage " + scalePercentage + " is not a int ratio.");
final Options opts = new Options();
opts.inPurgeable = true;
opts.inInputShareable = true;
opts.inSampleSize = 100 / scalePercentage;
if (cropRect != null) {
final BitmapRegionDecoder dec = BitmapRegionDecoder.newInstance(openFileDescriptor().getFileDescriptor(), true);
try {
return dec.decodeRegion(cropRect, opts);
}
finally {
dec.recycle();
}
}
return BitmapFactory.decodeFileDescriptor(openFileDescriptor().getFileDescriptor(), null, opts);
}
private static byte[] transformByteArray(@NonNull byte[] data, @Nullable Rect cropRect, int rotation, boolean flip) throws IOException {
Stopwatch stopwatch = new Stopwatch("transform");
Bitmap in;
if (cropRect != null) {
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(data, 0, data.length, false);
in = decoder.decodeRegion(cropRect, new BitmapFactory.Options());
decoder.recycle();
stopwatch.split("crop");
} else {
in = BitmapFactory.decodeByteArray(data, 0, data.length);
}
Bitmap out = in;
if (rotation != 0 || flip) {
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
if (flip) {
matrix.postScale(-1, 1);
matrix.postTranslate(in.getWidth(), 0);
}
out = Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), matrix, true);
}
byte[] transformedData = toJpegBytes(out);
stopwatch.split("transcode");
in.recycle();
out.recycle();
stopwatch.stop(TAG);
return transformedData;
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
@TargetApi(Build.VERSION_CODES.N)
private Palette getHotseatPalette() {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
if (AndroidVersion.isAtLeastNougat) {
try (ParcelFileDescriptor fd = wallpaperManager
.getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
BitmapRegionDecoder decoder = BitmapRegionDecoder
.newInstance(fd.getFileDescriptor(), false);
int height = decoder.getHeight();
Rect decodeRegion = new Rect(0, (int) (height * (1f - HOTSEAT_FRACTION)),
decoder.getWidth(), height);
Bitmap bitmap = decoder.decodeRegion(decodeRegion, null);
decoder.recycle();
if (bitmap != null) {
return Palette.from(bitmap).clearFilters().generate();
}
} catch (IOException | NullPointerException e) {
e.printStackTrace();
}
}
Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
return Palette.from(wallpaper)
.setRegion(0, (int) (wallpaper.getHeight() * (1f - HOTSEAT_FRACTION)),
wallpaper.getWidth(), wallpaper.getHeight())
.clearFilters()
.generate();
}
@TargetApi(Build.VERSION_CODES.N)
private Palette getStatusBarPalette() {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
int statusBarHeight = getResources()
.getDimensionPixelSize(R.dimen.status_bar_height);
if (AndroidVersion.isAtLeastNougat) {
try (ParcelFileDescriptor fd = wallpaperManager
.getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
BitmapRegionDecoder decoder = BitmapRegionDecoder
.newInstance(fd.getFileDescriptor(), false);
Rect decodeRegion = new Rect(0, 0,
decoder.getWidth(), statusBarHeight);
Bitmap bitmap = decoder.decodeRegion(decodeRegion, null);
decoder.recycle();
if (bitmap != null) {
return Palette.from(bitmap).clearFilters().generate();
}
} catch (IOException | NullPointerException e) {
e.printStackTrace();
}
}
Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
return Palette.from(wallpaper)
.setRegion(0, 0, wallpaper.getWidth(), statusBarHeight)
.clearFilters()
.generate();
}
public static Bitmap loadBitmapRegion(Path path,int sampleSize,Rect regionRect) throws IOException
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
InputStream data = path.getFile().getInputStream();
try
{
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.GINGERBREAD_MR1)
{
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(data, true);
try
{
return decoder.decodeRegion(regionRect, options);
}
finally
{
decoder.recycle();
}
}
else
return BitmapFactory.decodeStream(data, null, options);
}
finally
{
data.close();
}
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
private Bitmap readBitmapInternal(BitmapFactory.Options options, boolean mayUseRegionDecoder,
boolean mayUseWebViewDecoder) {
ImageData imageData = getImageData();
if (imageData.type == ImageType.NOT_IMAGE) {
return null;
}
if (imageData.type != ImageType.IMAGE_SVG) {
Bitmap bitmap = readBitmapSimple(options);
if (bitmap != null) {
return bitmap;
}
if (mayUseRegionDecoder && isRegionDecoderSupported()) {
InputStream input = null;
BitmapRegionDecoder decoder = null;
try {
input = openInputStream();
decoder = BitmapRegionDecoder.newInstance(input, false);
return decoder.decodeRegion(new Rect(0, 0, decoder.getWidth(), decoder.getHeight()), options);
} catch (IOException e) {
Log.persistent().stack(e);
} finally {
IOUtils.close(input);
if (decoder != null) {
decoder.recycle();
}
}
}
}
if (mayUseWebViewDecoder) {
return WebViewBitmapDecoder.loadBitmap(this, options);
}
return null;
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
if (decoder != null) {
decoder.recycle();
decoders.remove(decoder);
}
}
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
@Override
protected Bitmap doInBackground (final Void... params) {
LOG.i("Generating preview: s=%s q=%s.", this.dlg.getScale(), this.dlg.getQuality());
try {
final Bitmap scaled = this.srcMetadata.getBitmap(this.dlg.getScale().getPercentage());
final ByteArrayOutputStream compOut = new ByteArrayOutputStream(512 * 1024);
if (scaled.compress(Bitmap.CompressFormat.JPEG, this.dlg.getQuality().getPercentage(), compOut)) {
this.summary
.append(this.srcMetadata.getWidth()).append(" x ").append(this.srcMetadata.getHeight())
.append(" (").append(IoHelper.readableFileSize(this.srcMetadata.getSize())).append(")")
.append(" --> ").append(scaled.getWidth()).append(" x ").append(scaled.getHeight())
.append(" (").append(IoHelper.readableFileSize(compOut.size())).append(")");
final BitmapRegionDecoder dec = BitmapRegionDecoder.newInstance(compOut.toBufferedInputStream(), true);
try {
final int srcW = dec.getWidth();
final int srcH = dec.getHeight();
final int tgtW = this.dlg.getRootView().getWidth(); // FIXME Workaround for ImageView width issue. Fix properly with something like FixedWidthImageView.
final int tgtH = this.imgPreview.getHeight();
final int left = srcW > tgtW ? (srcW - tgtW) / 2 : 0;
final int top = srcH > tgtH ? (srcH - tgtH) / 2 : 0;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inInputShareable = true;
return dec.decodeRegion(new Rect(left, top, left + tgtW, top + tgtH), options);
}
finally {
dec.recycle();
}
}
this.summary.append("Failed to compress image."); //ES
return null;
}
// XXX Many cases of OutOfMemoryError have been reported, particularly on low end hardware.
// Try not to upset the user too much by not dying completely if possible.
catch (final Throwable e) {
LOG.e("Failed to generate preview image.", e);
this.summary.append(e.toString());
return null;
}
}
/**
* While there are decoders in the map, wait until each is available before acquiring,
* recycling and removing it. After this is called, any call to {@link #acquire()} will
* block forever, so this call should happen within a write lock, and all calls to
* {@link #acquire()} should be made within a read lock so they cannot end up blocking on
* the semaphore when it has no permits.
*/
private synchronized void recycle() {
while (!decoders.isEmpty()) {
BitmapRegionDecoder decoder = acquire();
decoder.recycle();
decoders.remove(decoder);
}
}
private Bitmap createClippedBitmap() {
//if (mSampleSize <= 1) {
// TODO has problem, this method is not useful on some picture
// return mClipImageView.clip();
//}
final float[] matrixValues = mClipImageView.getClipMatrixValues();
final float scale = matrixValues[Matrix.MSCALE_X];
final float transX = matrixValues[Matrix.MTRANS_X];
final float transY = matrixValues[Matrix.MTRANS_Y];
final Rect border = mClipImageView.getClipBorder();
final float cropX = ((-transX + border.left) / scale) * mSampleSize;
final float cropY = ((-transY + border.top) / scale) * mSampleSize;
final float cropWidth = (border.width() / scale) * mSampleSize;
final float cropHeight = (border.height() / scale) * mSampleSize;
final RectF srcRect = new RectF(cropX, cropY, cropX + cropWidth, cropY + cropHeight);
final Rect clipRect = getRealRect(srcRect);
final BitmapFactory.Options ops = new BitmapFactory.Options();
final Matrix outputMatrix = new Matrix();
outputMatrix.setRotate(mDegree);
if (mMaxWidth > 0 && cropWidth > mMaxWidth) {
ops.inSampleSize = findBestSample((int) cropWidth, mMaxWidth);
final float outputScale = mMaxWidth / (cropWidth / ops.inSampleSize);
outputMatrix.postScale(outputScale, outputScale);
}
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(mInput, false);
final Bitmap source = decoder.decodeRegion(clipRect, ops);
recycleImageViewBitmap();
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
outputMatrix, false);
} catch (Exception e) {
return mClipImageView.clip();
} finally {
if (decoder != null && !decoder.isRecycled()) {
decoder.recycle();
}
}
}
private Bitmap createClippedBitmap() {
if (mSampleSize <= 1) {
return mClipImageView.clip();
}
// 获取缩放位移后的矩阵值
final float[] matrixValues = mClipImageView.getClipMatrixValues();
final float scale = matrixValues[Matrix.MSCALE_X];
final float transX = matrixValues[Matrix.MTRANS_X];
final float transY = matrixValues[Matrix.MTRANS_Y];
// 获取在显示的图片中裁剪的位置
final Rect border = mClipImageView.getClipBorder();
final float cropX = ((-transX + border.left) / scale) * mSampleSize;
final float cropY = ((-transY + border.top) / scale) * mSampleSize;
final float cropWidth = (border.width() / scale) * mSampleSize;
final float cropHeight = (border.height() / scale) * mSampleSize;
// 获取在旋转之前的裁剪位置
final RectF srcRect = new RectF(cropX, cropY, cropX + cropWidth, cropY + cropHeight);
final Rect clipRect = getRealRect(srcRect);
final BitmapFactory.Options ops = new BitmapFactory.Options();
final Matrix outputMatrix = new Matrix();
outputMatrix.setRotate(mDegree);
// 如果裁剪之后的图片宽高仍然太大,则进行缩小
if (mMaxWidth > 0 && cropWidth > mMaxWidth) {
ops.inSampleSize = findBestSample((int) cropWidth, mMaxWidth);
final float outputScale = mMaxWidth / (cropWidth / ops.inSampleSize);
outputMatrix.postScale(outputScale, outputScale);
}
// 裁剪
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(mInput, false);
final Bitmap source = decoder.decodeRegion(clipRect, ops);
recycleImageViewBitmap();
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), outputMatrix, false);
} catch (Exception e) {
return mClipImageView.clip();
} finally {
if (decoder != null && !decoder.isRecycled()) {
decoder.recycle();
}
}
}