/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.imagepipeline.image;
import android.graphics.Bitmap;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.ResourceReleaser;
import com.facebook.imageutils.BitmapUtil;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
/**
* CloseableImage that contains one Bitmap.
*/
@ThreadSafe
public class CloseableStaticBitmap extends CloseableBitmap {
@GuardedBy("this")
private CloseableReference<Bitmap> mBitmapReference;
private volatile Bitmap mBitmap;
// quality info
private final QualityInfo mQualityInfo;
private final int mRotationAngle;
/**
* Creates a new instance of a CloseableStaticBitmap.
*
* @param bitmap the bitmap to wrap
* @param resourceReleaser ResourceReleaser to release the bitmap to
*/
public CloseableStaticBitmap(
Bitmap bitmap,
ResourceReleaser<Bitmap> resourceReleaser,
QualityInfo qualityInfo,
int rotationAngle) {
mBitmap = Preconditions.checkNotNull(bitmap);
mBitmapReference = CloseableReference.of(
mBitmap,
Preconditions.checkNotNull(resourceReleaser));
mQualityInfo = qualityInfo;
mRotationAngle = rotationAngle;
}
/**
* Creates a new instance of a CloseableStaticBitmap from an existing CloseableReference. The
* CloseableStaticBitmap will hold a reference to the Bitmap until it's closed.
*
* @param bitmapReference the bitmap reference.
*/
public CloseableStaticBitmap(
CloseableReference<Bitmap> bitmapReference,
QualityInfo qualityInfo,
int rotationAngle) {
mBitmapReference = Preconditions.checkNotNull(bitmapReference.cloneOrNull());
mBitmap = mBitmapReference.get();
mQualityInfo = qualityInfo;
mRotationAngle = rotationAngle;
}
/**
* Releases the bitmap to the pool.
*/
@Override
public void close() {
CloseableReference<Bitmap> reference = detachBitmapReference();
if (reference != null) {
reference.close();
}
}
private synchronized CloseableReference<Bitmap> detachBitmapReference() {
CloseableReference<Bitmap> reference = mBitmapReference;
mBitmapReference = null;
mBitmap = null;
return reference;
}
/**
* Convert this object to a CloseableReference<Bitmap>.
* <p>You cannot call this method on an object that has already been closed.
* <p>The reference count of the bitmap is preserved. After calling this method, this object
* can no longer be used and no longer points to the bitmap.
* <p>See {@link #cloneUnderlyingBitmapReference()} for an alternative that returns a cloned
* bitmap reference instead.
*
* @return the underlying bitmap reference after being detached from this instance
* @throws IllegalArgumentException if this object has already been closed.
*/
public synchronized CloseableReference<Bitmap> convertToBitmapReference() {
Preconditions.checkNotNull(mBitmapReference, "Cannot convert a closed static bitmap");
return detachBitmapReference();
}
/**
* Get a cloned bitmap reference for the underlying original CloseableReference<Bitmap>.
* <p>After calling this method, this object can still be used.
* See {@link #convertToBitmapReference()} for an alternative that detaches the original reference
* instead.
*
* @return the cloned bitmap reference without altering this instance or null if already closed
*/
@Nullable
public synchronized CloseableReference<Bitmap> cloneUnderlyingBitmapReference() {
return CloseableReference.cloneOrNull(mBitmapReference);
}
/**
* Returns whether this instance is closed.
*/
@Override
public synchronized boolean isClosed() {
return mBitmapReference == null;
}
/**
* Gets the underlying bitmap.
*
* @return the underlying bitmap
*/
@Override
public Bitmap getUnderlyingBitmap() {
return mBitmap;
}
/**
* @return size in bytes of the underlying bitmap
*/
@Override
public int getSizeInBytes() {
return BitmapUtil.getSizeInBytes(mBitmap);
}
/**
* @return width of the image
*/
@Override
public int getWidth() {
if (mRotationAngle == 90 || mRotationAngle == 270) {
return getBitmapHeight(mBitmap);
}
return getBitmapWidth(mBitmap);
}
/**
* @return height of the image
*/
@Override
public int getHeight() {
if (mRotationAngle == 90 || mRotationAngle == 270) {
return getBitmapWidth(mBitmap);
}
return getBitmapHeight(mBitmap);
}
private static int getBitmapWidth(@Nullable Bitmap bitmap) {
return (bitmap == null) ? 0 : bitmap.getWidth();
}
private static int getBitmapHeight(@Nullable Bitmap bitmap) {
return (bitmap == null) ? 0 : bitmap.getHeight();
}
/**
* @return the rotation angle of the image
*/
public int getRotationAngle() {
return mRotationAngle;
}
/**
* Returns quality information for the image.
*/
@Override
public QualityInfo getQualityInfo() {
return mQualityInfo;
}
}