ImageDecoder.java
/*
* Decompiled with CFR 0_132.
*
* Could not load the following classes:
* android.content.res.Resources
* android.graphics.Bitmap
* android.graphics.Bitmap$CompressFormat
* android.graphics.Bitmap$Config
* android.graphics.BitmapFactory
* android.graphics.BitmapFactory$Options
* android.graphics.Canvas
* android.graphics.Matrix
* android.graphics.Movie
* android.graphics.Paint
* android.graphics.PorterDuff
* android.graphics.PorterDuff$Mode
* android.graphics.PorterDuffXfermode
* android.graphics.RectF
* android.graphics.Xfermode
* android.graphics.drawable.Drawable
* android.media.ExifInterface
* android.os.Build
* android.os.Build$VERSION
* android.widget.ImageView
*/
package org.xutils.image;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Movie;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.os.Build;
import android.widget.ImageView;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import org.xutils.cache.DiskCacheEntity;
import org.xutils.cache.DiskCacheFile;
import org.xutils.cache.LruDiskCache;
import org.xutils.common.Callback;
import org.xutils.common.task.PriorityExecutor;
import org.xutils.common.util.IOUtil;
import org.xutils.common.util.LogUtil;
import org.xutils.image.GifDrawable;
import org.xutils.image.ImageOptions;
import org.xutils.image.ReusableBitmapDrawable;
import org.xutils.x;
public final class ImageDecoder {
private static final int BITMAP_DECODE_MAX_WORKER;
private static final AtomicInteger bitmapDecodeWorker;
private static final Object bitmapDecodeLock;
private static final Object gifDecodeLock;
private static final byte[] GIF_HEADER;
private static final Executor THUMB_CACHE_EXECUTOR;
private static final LruDiskCache THUMB_CACHE;
private static final boolean supportWebP;
private ImageDecoder() {
}
static void clearCacheFiles() {
THUMB_CACHE.clearCacheFiles();
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
static Drawable decodeFileWithLock(final File file, final ImageOptions options, Callback.Cancelable cancelable) throws IOException {
if (file == null || !file.exists() || file.length() < 1L) {
return null;
}
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
Object result = null;
if (!options.isIgnoreGif() && ImageDecoder.isGif(file)) {
Movie movie = null;
Object object = gifDecodeLock;
synchronized (object) {
movie = ImageDecoder.decodeGif(file, options, cancelable);
}
if (movie != null) {
result = new GifDrawable(movie, (int)file.length());
}
} else {
Bitmap bitmap;
Object finalBitmap;
bitmap = null;
try {
Object object = bitmapDecodeLock;
synchronized (object) {
while (!(bitmapDecodeWorker.get() < BITMAP_DECODE_MAX_WORKER || cancelable != null && cancelable.isCancelled())) {
try {
bitmapDecodeLock.wait();
}
catch (InterruptedException iex2) {
throw new Callback.CancelledException("cancelled during decode image");
}
catch (Throwable iex2) {
}
}
}
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
bitmapDecodeWorker.incrementAndGet();
if (options.isCompress()) {
bitmap = ImageDecoder.getThumbCache(file, options);
}
if (bitmap == null && (bitmap = ImageDecoder.decodeBitmap(file, options, cancelable)) != null && options.isCompress()) {
finalBitmap = bitmap;
THUMB_CACHE_EXECUTOR.execute(new Runnable((Bitmap)finalBitmap){
final /* synthetic */ Bitmap val$finalBitmap;
{
this.val$finalBitmap = bitmap;
}
@Override
public void run() {
ImageDecoder.saveThumbCache(file, options, this.val$finalBitmap);
}
});
}
}
finally {
bitmapDecodeWorker.decrementAndGet();
finalBitmap = bitmapDecodeLock;
synchronized (finalBitmap) {
bitmapDecodeLock.notifyAll();
}
}
if (bitmap != null) {
result = new ReusableBitmapDrawable(x.app().getResources(), bitmap);
}
}
return result;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
public static boolean isGif(File file) {
boolean bl;
FileInputStream in = null;
try {
in = new FileInputStream(file);
byte[] header = IOUtil.readBytes(in, 0L, 3);
bl = Arrays.equals(GIF_HEADER, header);
}
catch (Throwable ex) {
try {
LogUtil.e(ex.getMessage(), ex);
}
catch (Throwable throwable) {
IOUtil.closeQuietly(in);
throw throwable;
}
IOUtil.closeQuietly(in);
}
IOUtil.closeQuietly(in);
return bl;
return false;
}
public static Bitmap decodeBitmap(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException {
if (file == null || !file.exists() || file.length() < 1L) {
return null;
}
if (options == null) {
options = ImageOptions.DEFAULT;
}
if (options.getMaxWidth() <= 0 || options.getMaxHeight() <= 0) {
options.optimizeMaxSize(null);
}
Bitmap result = null;
try {
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
BitmapFactory.Options bitmapOps = new BitmapFactory.Options();
bitmapOps.inJustDecodeBounds = true;
bitmapOps.inPurgeable = true;
bitmapOps.inInputShareable = true;
BitmapFactory.decodeFile((String)file.getAbsolutePath(), (BitmapFactory.Options)bitmapOps);
bitmapOps.inJustDecodeBounds = false;
bitmapOps.inPreferredConfig = options.getConfig();
int rotateAngle = 0;
int rawWidth = bitmapOps.outWidth;
int rawHeight = bitmapOps.outHeight;
int optionWith = options.getWidth();
int optionHeight = options.getHeight();
if (options.isAutoRotate() && (rotateAngle = ImageDecoder.getRotateAngle(file.getAbsolutePath())) / 90 % 2 == 1) {
rawWidth = bitmapOps.outHeight;
rawHeight = bitmapOps.outWidth;
}
if (!options.isCrop() && optionWith > 0 && optionHeight > 0) {
if (rotateAngle / 90 % 2 == 1) {
bitmapOps.outWidth = optionHeight;
bitmapOps.outHeight = optionWith;
} else {
bitmapOps.outWidth = optionWith;
bitmapOps.outHeight = optionHeight;
}
}
bitmapOps.inSampleSize = ImageDecoder.calculateSampleSize(rawWidth, rawHeight, options.getMaxWidth(), options.getMaxHeight());
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile((String)file.getAbsolutePath(), (BitmapFactory.Options)bitmapOps);
if (bitmap == null) {
throw new IOException("decode image error");
}
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
if (rotateAngle != 0) {
bitmap = ImageDecoder.rotate(bitmap, rotateAngle, true);
}
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
if (options.isCrop() && optionWith > 0 && optionHeight > 0) {
bitmap = ImageDecoder.cut2ScaleSize(bitmap, optionWith, optionHeight, true);
}
if (bitmap == null) {
throw new IOException("decode image error");
}
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
if (options.isCircular()) {
bitmap = ImageDecoder.cut2Circular(bitmap, true);
} else if (options.getRadius() > 0) {
bitmap = ImageDecoder.cut2RoundCorner(bitmap, options.getRadius(), options.isSquare(), true);
} else if (options.isSquare()) {
bitmap = ImageDecoder.cut2Square(bitmap, true);
}
if (bitmap == null) {
throw new IOException("decode image error");
}
result = bitmap;
}
catch (IOException ex) {
throw ex;
}
catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
result = null;
}
return result;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
* Loose catch block
* Enabled aggressive block sorting
* Enabled unnecessary exception pruning
* Enabled aggressive exception aggregation
* Lifted jumps to return sites
*/
public static Movie decodeGif(File file, ImageOptions options, Callback.Cancelable cancelable) throws IOException {
if (file == null) return null;
if (!file.exists()) return null;
if (file.length() < 1L) {
return null;
}
BufferedInputStream in = null;
try {
if (cancelable != null && cancelable.isCancelled()) {
throw new Callback.CancelledException("cancelled during decode image");
}
int buffSize = 16384;
in = new BufferedInputStream(new FileInputStream(file), buffSize);
in.mark(buffSize);
Movie movie = Movie.decodeStream((InputStream)in);
if (movie == null) {
throw new IOException("decode image error");
}
Movie movie2 = movie;
IOUtil.closeQuietly(in);
return movie2;
}
catch (IOException ex) {
try {
throw ex;
catch (Throwable ex2) {
LogUtil.e(ex2.getMessage(), ex2);
Movie movie = null;
return movie;
}
}
catch (Throwable throwable) {}
throw throwable;
}
finally {
IOUtil.closeQuietly(in);
}
}
public static int calculateSampleSize(int rawWidth, int rawHeight, int maxWidth, int maxHeight) {
int sampleSize = 1;
if (rawWidth > maxWidth || rawHeight > maxHeight) {
sampleSize = rawWidth > rawHeight ? Math.round((float)rawHeight / (float)maxHeight) : Math.round((float)rawWidth / (float)maxWidth);
if (sampleSize < 1) {
sampleSize = 1;
}
float totalPixels = rawWidth * rawHeight;
float maxTotalPixels = maxWidth * maxHeight * 2;
while (totalPixels / (float)(sampleSize * sampleSize) > maxTotalPixels) {
++sampleSize;
}
}
return sampleSize;
}
public static Bitmap cut2Square(Bitmap source, boolean recycleSource) {
int height;
int width = source.getWidth();
if (width == (height = source.getHeight())) {
return source;
}
int squareWith = Math.min(width, height);
Bitmap result = Bitmap.createBitmap((Bitmap)source, (int)((width - squareWith) / 2), (int)((height - squareWith) / 2), (int)squareWith, (int)squareWith);
if (result != null) {
if (recycleSource && result != source) {
source.recycle();
source = null;
}
} else {
result = source;
}
return result;
}
public static Bitmap cut2Circular(Bitmap source, boolean recycleSource) {
int width = source.getWidth();
int height = source.getHeight();
int diameter = Math.min(width, height);
Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap result = Bitmap.createBitmap((int)diameter, (int)diameter, (Bitmap.Config)Bitmap.Config.ARGB_8888);
if (result != null) {
Canvas canvas = new Canvas(result);
canvas.drawCircle((float)(diameter / 2), (float)(diameter / 2), (float)(diameter / 2), paint);
paint.setXfermode((Xfermode)new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(source, (float)((diameter - width) / 2), (float)((diameter - height) / 2), paint);
if (recycleSource) {
source.recycle();
source = null;
}
} else {
result = source;
}
return result;
}
public static Bitmap cut2RoundCorner(Bitmap source, int radius, boolean isSquare, boolean recycleSource) {
if (radius <= 0) {
return source;
}
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
int targetWidth = sourceWidth;
int targetHeight = sourceHeight;
if (isSquare) {
targetWidth = targetHeight = Math.min(sourceWidth, sourceHeight);
}
Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap result = Bitmap.createBitmap((int)targetWidth, (int)targetHeight, (Bitmap.Config)Bitmap.Config.ARGB_8888);
if (result != null) {
Canvas canvas = new Canvas(result);
RectF rect = new RectF(0.0f, 0.0f, (float)targetWidth, (float)targetHeight);
canvas.drawRoundRect(rect, (float)radius, (float)radius, paint);
paint.setXfermode((Xfermode)new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(source, (float)((targetWidth - sourceWidth) / 2), (float)((targetHeight - sourceHeight) / 2), paint);
if (recycleSource) {
source.recycle();
source = null;
}
} else {
result = source;
}
return result;
}
public static Bitmap cut2ScaleSize(Bitmap source, int dstWidth, int dstHeight, boolean recycleSource) {
int width = source.getWidth();
int height = source.getHeight();
if (width == dstWidth && height == dstHeight) {
return source;
}
Matrix m = new Matrix();
int l = 0;
int t = 0;
int r = width;
int b = height;
float sx = (float)dstWidth / (float)width;
float sy = (float)dstHeight / (float)height;
if (sx > sy) {
sy = sx;
l = 0;
r = width;
t = (int)(((float)height - (float)dstHeight / sx) / 2.0f);
b = (int)(((float)height + (float)dstHeight / sx) / 2.0f);
} else {
sx = sy;
l = (int)(((float)width - (float)dstWidth / sx) / 2.0f);
r = (int)(((float)width + (float)dstWidth / sx) / 2.0f);
t = 0;
b = height;
}
m.setScale(sx, sy);
Bitmap result = Bitmap.createBitmap((Bitmap)source, (int)l, (int)t, (int)(r - l), (int)(b - t), (Matrix)m, (boolean)true);
if (result != null) {
if (recycleSource && result != source) {
source.recycle();
source = null;
}
} else {
result = source;
}
return result;
}
public static Bitmap rotate(Bitmap source, int angle, boolean recycleSource) {
Bitmap result = null;
if (angle != 0) {
Matrix m = new Matrix();
m.setRotate((float)angle);
try {
result = Bitmap.createBitmap((Bitmap)source, (int)0, (int)0, (int)source.getWidth(), (int)source.getHeight(), (Matrix)m, (boolean)true);
}
catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
}
if (result != null) {
if (recycleSource && result != source) {
source.recycle();
source = null;
}
} else {
result = source;
}
return result;
}
public static int getRotateAngle(String filePath) {
int angle = 0;
try {
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt("Orientation", 0);
switch (orientation) {
case 6: {
angle = 90;
break;
}
case 3: {
angle = 180;
break;
}
case 8: {
angle = 270;
break;
}
default: {
angle = 0;
break;
}
}
}
catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
return angle;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
private static void saveThumbCache(File file, ImageOptions options, Bitmap thumbBitmap) {
DiskCacheFile cacheFile;
FileOutputStream out;
block4 : {
DiskCacheEntity entity = new DiskCacheEntity();
entity.setKey(file.getAbsolutePath() + "@" + file.lastModified() + options.toString());
cacheFile = null;
out = null;
try {
cacheFile = THUMB_CACHE.createDiskCacheFile(entity);
if (cacheFile == null) break block4;
out = new FileOutputStream(cacheFile);
thumbBitmap.compress(supportWebP ? Bitmap.CompressFormat.WEBP : Bitmap.CompressFormat.PNG, 80, (OutputStream)out);
out.flush();
cacheFile = cacheFile.commit();
}
catch (Throwable ex) {
try {
IOUtil.deleteFileOrDir(cacheFile);
LogUtil.w(ex.getMessage(), ex);
}
catch (Throwable throwable) {
IOUtil.closeQuietly(cacheFile);
IOUtil.closeQuietly(out);
throw throwable;
}
IOUtil.closeQuietly(cacheFile);
IOUtil.closeQuietly(out);
}
}
IOUtil.closeQuietly(cacheFile);
IOUtil.closeQuietly(out);
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
private static Bitmap getThumbCache(File file, ImageOptions options) {
DiskCacheFile cacheFile;
block5 : {
Bitmap bitmap;
cacheFile = null;
try {
cacheFile = THUMB_CACHE.getDiskCacheFile(file.getAbsolutePath() + "@" + file.lastModified() + options.toString());
if (cacheFile == null || !cacheFile.exists()) break block5;
BitmapFactory.Options bitmapOps = new BitmapFactory.Options();
bitmapOps.inJustDecodeBounds = false;
bitmapOps.inPurgeable = true;
bitmapOps.inInputShareable = true;
bitmapOps.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeFile((String)cacheFile.getAbsolutePath(), (BitmapFactory.Options)bitmapOps);
}
catch (Throwable ex) {
try {
LogUtil.w(ex.getMessage(), ex);
}
catch (Throwable throwable) {
throw throwable;
}
finally {
IOUtil.closeQuietly(cacheFile);
}
}
IOUtil.closeQuietly(cacheFile);
return bitmap;
}
IOUtil.closeQuietly(cacheFile);
return null;
}
static {
bitmapDecodeWorker = new AtomicInteger(0);
bitmapDecodeLock = new Object();
gifDecodeLock = new Object();
GIF_HEADER = new byte[]{71, 73, 70};
THUMB_CACHE_EXECUTOR = new PriorityExecutor(1, true);
THUMB_CACHE = LruDiskCache.getDiskCache("xUtils_img_thumb");
supportWebP = Build.VERSION.SDK_INT > 16;
int cpuCount = Runtime.getRuntime().availableProcessors();
BITMAP_DECODE_MAX_WORKER = cpuCount > 4 ? 2 : 1;
}
}