package com.doumee.lib_coremodel.util.luban;
|
|
import android.content.Context;
|
import android.net.Uri;
|
import android.os.AsyncTask;
|
import android.os.Handler;
|
import android.os.Looper;
|
import android.os.Message;
|
import android.text.TextUtils;
|
import android.util.Log;
|
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.util.ArrayList;
|
import java.util.Iterator;
|
import java.util.List;
|
|
@SuppressWarnings("unused")
|
public class Luban implements Handler.Callback {
|
private static final String TAG = "Luban";
|
private static final String DEFAULT_DISK_CACHE_DIR = "luban_disk_cache";
|
|
private static final int MSG_COMPRESS_SUCCESS = 0;
|
private static final int MSG_COMPRESS_START = 1;
|
private static final int MSG_COMPRESS_ERROR = 2;
|
|
private String mTargetDir;
|
private boolean focusAlpha;
|
private int mLeastCompressSize;
|
private OnRenameListener mRenameListener;
|
private OnCompressListener mCompressListener;
|
private CompressionPredicate mCompressionPredicate;
|
private List<InputStreamProvider> mStreamProviders;
|
|
private Handler mHandler;
|
|
private Luban(Builder builder) {
|
this.mTargetDir = builder.mTargetDir;
|
this.mRenameListener = builder.mRenameListener;
|
this.mStreamProviders = builder.mStreamProviders;
|
this.mCompressListener = builder.mCompressListener;
|
this.mLeastCompressSize = builder.mLeastCompressSize;
|
this.mCompressionPredicate = builder.mCompressionPredicate;
|
mHandler = new Handler(Looper.getMainLooper(), this);
|
}
|
|
public static Builder with(Context context) {
|
return new Builder(context);
|
}
|
|
/**
|
* Returns a file with a cache image name in the private cache directory.
|
*
|
* @param context A context.
|
*/
|
private File getImageCacheFile(Context context, String suffix) {
|
if (TextUtils.isEmpty(mTargetDir)) {
|
mTargetDir = getImageCacheDir(context).getAbsolutePath();
|
}
|
|
String cacheBuilder = mTargetDir + "/" +
|
System.currentTimeMillis() +
|
(int) (Math.random() * 1000) +
|
(TextUtils.isEmpty(suffix) ? ".jpg" : suffix);
|
|
return new File(cacheBuilder);
|
}
|
|
private File getImageCustomFile(Context context, String filename) {
|
if (TextUtils.isEmpty(mTargetDir)) {
|
mTargetDir = getImageCacheDir(context).getAbsolutePath();
|
}
|
|
String cacheBuilder = mTargetDir + "/" + filename;
|
|
return new File(cacheBuilder);
|
}
|
|
/**
|
* Returns a directory with a default name in the private cache directory of the application to
|
* use to store retrieved audio.
|
*
|
* @param context A context.
|
* @see #getImageCacheDir(Context, String)
|
*/
|
private File getImageCacheDir(Context context) {
|
return getImageCacheDir(context, DEFAULT_DISK_CACHE_DIR);
|
}
|
|
/**
|
* Returns a directory with the given name in the private cache directory of the application to
|
* use to store retrieved media and thumbnails.
|
*
|
* @param context A context.
|
* @param cacheName The name of the subdirectory in which to store the cache.
|
* @see #getImageCacheDir(Context)
|
*/
|
private static File getImageCacheDir(Context context, String cacheName) {
|
File cacheDir = context.getExternalCacheDir();
|
if (cacheDir != null) {
|
File result = new File(cacheDir, cacheName);
|
if (!result.mkdirs() && (!result.exists() || !result.isDirectory())) {
|
// File wasn't able to create a directory, or the result exists but not a directory
|
return null;
|
}
|
return result;
|
}
|
if (Log.isLoggable(TAG, Log.ERROR)) {
|
Log.e(TAG, "default disk cache dir is null");
|
}
|
return null;
|
}
|
|
/**
|
* start asynchronous compress thread
|
*/
|
private void launch(final Context context) {
|
if (mStreamProviders == null || mStreamProviders.size() == 0 && mCompressListener != null) {
|
mCompressListener.onError(new NullPointerException("image file cannot be null"));
|
}
|
|
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
|
|
while (iterator.hasNext()) {
|
final InputStreamProvider path = iterator.next();
|
|
AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
|
@Override
|
public void run() {
|
try {
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_START));
|
|
File result = compress(context, path);
|
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_SUCCESS, result));
|
} catch (IOException e) {
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, e));
|
}
|
}
|
});
|
|
iterator.remove();
|
}
|
}
|
|
/**
|
* start compress and return the file
|
*/
|
private File get(InputStreamProvider input, Context context) throws IOException {
|
try {
|
return new Engine(input, getImageCacheFile(context, Checker.SINGLE.extSuffix(input)), focusAlpha).compress();
|
} finally {
|
input.close();
|
}
|
}
|
|
private List<File> get(Context context) throws IOException {
|
List<File> results = new ArrayList<>();
|
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
|
|
while (iterator.hasNext()) {
|
results.add(compress(context, iterator.next()));
|
iterator.remove();
|
}
|
|
return results;
|
}
|
|
private File compress(Context context, InputStreamProvider path) throws IOException {
|
try {
|
return compressReal(context,path);
|
} finally {
|
path.close();
|
}
|
}
|
|
private File compressReal(Context context, InputStreamProvider path) throws IOException {
|
File result;
|
|
File outFile = getImageCacheFile(context, Checker.SINGLE.extSuffix(path));
|
|
if (mRenameListener != null) {
|
String filename = mRenameListener.rename(path.getPath());
|
outFile = getImageCustomFile(context, filename);
|
}
|
|
if (mCompressionPredicate != null) {
|
if (mCompressionPredicate.apply(path.getPath())
|
&& Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath())) {
|
result = new Engine(path, outFile, focusAlpha).compress();
|
} else {
|
result = new File(path.getPath());
|
}
|
} else {
|
result = Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath()) ?
|
new Engine(path, outFile, focusAlpha).compress() :
|
new File(path.getPath());
|
}
|
|
return result;
|
}
|
|
@Override
|
public boolean handleMessage(Message msg) {
|
if (mCompressListener == null) {
|
return false;
|
}
|
|
switch (msg.what) {
|
case MSG_COMPRESS_START:
|
mCompressListener.onStart();
|
break;
|
case MSG_COMPRESS_SUCCESS:
|
mCompressListener.onSuccess((File) msg.obj);
|
break;
|
case MSG_COMPRESS_ERROR:
|
mCompressListener.onError((Throwable) msg.obj);
|
break;
|
}
|
return false;
|
}
|
|
public static class Builder {
|
private Context context;
|
private String mTargetDir;
|
private boolean focusAlpha;
|
private int mLeastCompressSize = 100;
|
private OnRenameListener mRenameListener;
|
private OnCompressListener mCompressListener;
|
private CompressionPredicate mCompressionPredicate;
|
private List<InputStreamProvider> mStreamProviders;
|
|
Builder(Context context) {
|
this.context = context;
|
this.mStreamProviders = new ArrayList<>();
|
}
|
|
private Luban build() {
|
return new Luban(this);
|
}
|
|
public Builder load(InputStreamProvider inputStreamProvider) {
|
mStreamProviders.add(inputStreamProvider);
|
return this;
|
}
|
|
public Builder load(final File file) {
|
mStreamProviders.add(new InputStreamAdapter() {
|
@Override
|
public InputStream openInternal() throws IOException {
|
return new FileInputStream(file);
|
}
|
|
@Override
|
public String getPath() {
|
return file.getAbsolutePath();
|
}
|
});
|
return this;
|
}
|
|
public Builder load(final String string) {
|
mStreamProviders.add(new InputStreamAdapter() {
|
@Override
|
public InputStream openInternal() throws IOException {
|
return new FileInputStream(string);
|
}
|
|
@Override
|
public String getPath() {
|
return string;
|
}
|
});
|
return this;
|
}
|
|
public <T> Builder load(List<T> list) {
|
for (T src : list) {
|
if (src instanceof String) {
|
load((String) src);
|
} else if (src instanceof File) {
|
load((File) src);
|
} else if (src instanceof Uri) {
|
load((Uri) src);
|
} else {
|
throw new IllegalArgumentException("Incoming data type exception, it must be String, File, Uri or Bitmap");
|
}
|
}
|
return this;
|
}
|
|
public Builder load(final Uri uri) {
|
mStreamProviders.add(new InputStreamAdapter() {
|
@Override
|
public InputStream openInternal() throws IOException {
|
return context.getContentResolver().openInputStream(uri);
|
}
|
|
@Override
|
public String getPath() {
|
return uri.getPath();
|
}
|
});
|
return this;
|
}
|
|
public Builder putGear(int gear) {
|
return this;
|
}
|
|
public Builder setRenameListener(OnRenameListener listener) {
|
this.mRenameListener = listener;
|
return this;
|
}
|
|
public Builder setCompressListener(OnCompressListener listener) {
|
this.mCompressListener = listener;
|
return this;
|
}
|
|
public Builder setTargetDir(String targetDir) {
|
this.mTargetDir = targetDir;
|
return this;
|
}
|
|
/**
|
* Do I need to keep the image's alpha channel
|
*
|
* @param focusAlpha <p> true - to keep alpha channel, the compress speed will be slow. </p>
|
* <p> false - don't keep alpha channel, it might have a black background.</p>
|
*/
|
public Builder setFocusAlpha(boolean focusAlpha) {
|
this.focusAlpha = focusAlpha;
|
return this;
|
}
|
|
/**
|
* do not compress when the origin image file size less than one value
|
*
|
* @param size the value of file size, unit KB, default 100K
|
*/
|
public Builder ignoreBy(int size) {
|
this.mLeastCompressSize = size;
|
return this;
|
}
|
|
/**
|
* do compress image when return value was true, otherwise, do not compress the image file
|
*
|
* @param compressionPredicate A predicate callback that returns true or false for the given input path should be compressed.
|
*/
|
public Builder filter(CompressionPredicate compressionPredicate) {
|
this.mCompressionPredicate = compressionPredicate;
|
return this;
|
}
|
|
|
/**
|
* begin compress image with asynchronous
|
*/
|
public void launch() {
|
build().launch(context);
|
}
|
|
public File get(final String path) throws IOException {
|
return build().get(new InputStreamAdapter() {
|
@Override
|
public InputStream openInternal() throws IOException {
|
return new FileInputStream(path);
|
}
|
|
@Override
|
public String getPath() {
|
return path;
|
}
|
}, context);
|
}
|
|
/**
|
* begin compress image with synchronize
|
*
|
* @return the thumb image file list
|
*/
|
public List<File> get() throws IOException {
|
return build().get(context);
|
}
|
}
|
}
|