package at.favre.lib.dali.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Looper;
import android.support.v8.renderscript.RenderScript;
import android.util.Log;
import android.view.View;
import java.security.MessageDigest;
import at.favre.lib.dali.blur.EBlurAlgorithm;
import at.favre.lib.dali.blur.IBlur;
import at.favre.lib.dali.blur.algorithms.BoxBlur;
import at.favre.lib.dali.blur.algorithms.GaussianFastBlur;
import at.favre.lib.dali.blur.algorithms.IgnoreBlur;
import at.favre.lib.dali.blur.algorithms.RenderScriptBox5x5Blur;
import at.favre.lib.dali.blur.algorithms.RenderScriptGaussian5x5Blur;
import at.favre.lib.dali.blur.algorithms.RenderScriptGaussianBlur;
import at.favre.lib.dali.blur.algorithms.RenderScriptStackBlur;
import at.favre.lib.dali.blur.algorithms.StackBlur;
import at.favre.lib.dali.builder.BuilderDefaults;
import at.favre.lib.dali.builder.ContextWrapper;
import at.favre.lib.dali.builder.blur.BlurBuilder;
import at.favre.lib.dali.builder.processor.IBitmapProcessor;
/**
* Created by PatrickF on 29.05.2014.
*/
public class BuilderUtil {
private BuilderUtil() {}
/**
* Creates an IBlur instance for the given algorithm enum
* @param algorithm
* @param contextWrapper
* @return
*/
public static IBlur getIBlurAlgorithm(EBlurAlgorithm algorithm, ContextWrapper contextWrapper) {
RenderScript rs= contextWrapper.getRenderScript();
Context ctx = contextWrapper.getContext();
switch (algorithm) {
case RS_GAUSS_FAST:
return new RenderScriptGaussianBlur(rs);
case RS_BOX_5x5:
return new RenderScriptBox5x5Blur(rs);
case RS_GAUSS_5x5:
return new RenderScriptGaussian5x5Blur(rs);
case RS_STACKBLUR:
return new RenderScriptStackBlur(rs, ctx);
case STACKBLUR:
return new StackBlur();
case GAUSS_FAST:
return new GaussianFastBlur();
case BOX_BLUR:
return new BoxBlur();
default:
return new IgnoreBlur();
}
}
/**
* Check if blur radius is within valid range of {@link at.favre.lib.dali.builder.BuilderDefaults#BLUR_RADIUS_MIN} and {@link at.favre.lib.dali.builder.BuilderDefaults#BLUR_RADIUS_MAX}
* @param blurRadius
*/
public static void checkBlurRadiusPrecondition(int blurRadius) {
if(blurRadius < BuilderDefaults.BLUR_RADIUS_MIN || blurRadius > BuilderDefaults.BLUR_RADIUS_MAX) {
throw new IllegalArgumentException("Valid blur radius must be between (inclusive) "+BuilderDefaults.BLUR_RADIUS_MIN +" and "+BuilderDefaults.BLUR_RADIUS_MAX+" found "+blurRadius);
}
}
public static String getBuilderDescription(BlurBuilder.BlurData data) {
StringBuilder sb = new StringBuilder();
sb.append(data.imageReference.getContentId()+", ");
sb.append("radius: "+data.blurRadius+", ");
sb.append(data.blurAlgorithm.getClass().getSimpleName()+", ");
sb.append("rescaleIfDownScale: "+data.rescaleIfDownscaled+", ");
for (IBitmapProcessor preProcessor : data.preProcessors) {
sb.append(preProcessor.getProcessorTag()+", ");
}
for (IBitmapProcessor postProcessor : data.postProcessors) {
sb.append(postProcessor.getProcessorTag()+", ");
}
if(data.options != null) {
sb.append("sampleSize: "+data.options.inSampleSize+", ");
}
return sb.toString();
}
public static String getCacheKey(BlurBuilder.BlurData data) {
return sha1Hash(getBuilderDescription(data));
}
public static String sha1Hash(String text) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(text.getBytes("iso-8859-1"), 0, text.length());
byte[] sha1hash = md.digest();
return convertToHex(sha1hash);
} catch (Exception e) {
throw new RuntimeException("Could not hash",e);
}
}
private static String convertToHex(byte[] data) {
StringBuilder buf = new StringBuilder();
for (byte b : data) {
int halfbyte = (b >>> 4) & 0x0F;
int two_halfs = 0;
do {
buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
halfbyte = b & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
/**
* Draws the given view to a canvas with the given scale (higher = smaller)
* @param dest
* @param view
* @param downSampling
* @return
*/
public static Bitmap drawViewToBitmap(Bitmap dest, View view, int downSampling, Bitmap.Config bitmapConfig) {
float scale = 1f / downSampling;
int viewWidth = view.getWidth();
int viewHeight = view.getHeight();
int bmpWidth = Math.round(viewWidth * scale);
int bmpHeight = Math.round(viewHeight * scale);
if (dest == null || dest.getWidth() != bmpWidth || dest.getHeight() != bmpHeight) {
dest = Bitmap.createBitmap(bmpWidth, bmpHeight, bitmapConfig);
}
Canvas c = new Canvas(dest);
if (downSampling > 1) {
c.scale(scale, scale);
}
view.draw(c);
return dest;
}
public static void logDebug(String tag, String msg, boolean shouldLog) {
if(shouldLog) {
Log.d(tag, msg);
}
}
public static void logVerbose(String tag, String msg, boolean shouldLog) {
if(shouldLog) {
Log.v(tag, msg);
}
}
public static void checkMustNotRunOnUiThread() {
if (isOnUiThread()) {
throw new IllegalStateException("This method must NOT be called from the ui thread which is "+Looper.getMainLooper()+" was called from "+Looper.myLooper()+".");
}
}
public static boolean isOnUiThread() {
return Looper.myLooper() == null || Looper.myLooper() == Looper.getMainLooper();
}
}