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); 
 | 
    } 
 | 
  } 
 | 
} 
 |