package cl.monsoon.s1next.util; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import android.opengl.GLES10; import android.opengl.GLES20; import android.os.Build; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import com.bumptech.glide.load.resource.bitmap.TransformationUtils; import javax.microedition.khronos.opengles.GL10; public final class TransformationUtil { private TransformationUtil() {} /** * Applies a multiplier to the {@code toTransform}'s size. * <p> * Forked from {@link com.bumptech.glide.load.resource.bitmap.TransformationUtils#fitCenter(Bitmap, BitmapPool, int, int)}. * * @param sizeMultiplier The multiplier to apply to the {@code toTransform}'s dimensions. */ private static Bitmap sizeMultiplier(BitmapPool pool, Bitmap toTransform, float sizeMultiplier) { final int targetWidth = (int) (sizeMultiplier * toTransform.getWidth()); final int targetHeight = (int) (sizeMultiplier * toTransform.getHeight()); Bitmap.Config config = getSafeConfig(toTransform); Bitmap toReuse = pool.get(targetWidth, targetHeight, config); if (toReuse == null) { toReuse = Bitmap.createBitmap(targetWidth, targetHeight, config); } // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given. TransformationUtils.setAlpha(toTransform, toReuse); Canvas canvas = new Canvas(toReuse); Matrix matrix = new Matrix(); matrix.setScale(sizeMultiplier, sizeMultiplier); Paint paint = new Paint(TransformationUtils.PAINT_FLAGS); canvas.drawBitmap(toTransform, matrix, paint); return toReuse; } /** * Copied from {@link com.bumptech.glide.load.resource.bitmap.TransformationUtils#getSafeConfig(Bitmap)}. */ private static Bitmap.Config getSafeConfig(Bitmap bitmap) { return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888; } /** * A {@link com.bumptech.glide.load.Transformation} for transforming {@link android.graphics.Bitmap}'s * size with a multiplier. */ public static final class SizeMultiplierBitmapTransformation extends BitmapTransformation { private final float mSizeMultiplier; public SizeMultiplierBitmapTransformation(Context context, float sizeMultiplier) { super(context); this.mSizeMultiplier = sizeMultiplier; } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { return sizeMultiplier(pool, toTransform, mSizeMultiplier); } @Override public String getId() { return SizeMultiplierBitmapTransformation.class.getName(); } } /** * A {@link com.bumptech.glide.load.Transformation} for transforming {@link android.graphics.Bitmap}'s * size not to exceed the OpenGl texture size limit. */ public static final class GlMaxTextureSizeBitmapTransformation extends BitmapTransformation { public GlMaxTextureSizeBitmapTransformation(Context context) { super(context); } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { final int resWidth = toTransform.getWidth(); final int resHeight = toTransform.getHeight(); float maxTextureSize = GlMaxTextureCalculator.INSTANCE.glMaxTextureSize; float sizeMultiplier = Math.min(maxTextureSize / resWidth, maxTextureSize / resHeight); if (sizeMultiplier < 1) { return sizeMultiplier(pool, toTransform, sizeMultiplier); } else { return toTransform; } } @Override public String getId() { return GlMaxTextureSizeBitmapTransformation.class.getName(); } /** * A calculator for getting OpenGL texture size limit. */ private enum GlMaxTextureCalculator { INSTANCE; private static final int GL_TEXTURE_SIZE_MINIMUM = 2048; private int glMaxTextureSize; GlMaxTextureCalculator() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { glMaxTextureSize = getGl20MaxTextureSize(); } else { glMaxTextureSize = getGl10MaxTextureSize(); } if (glMaxTextureSize <= 0) { glMaxTextureSize = GL_TEXTURE_SIZE_MINIMUM; } } private int getGl10MaxTextureSize() { int[] maxTextureSize = new int[1]; GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0); return maxTextureSize[0]; } /** * Forked from https://github.com/android/platform_frameworks_base/blob/master/services/core/java/com/android/server/display/ColorFade.java * and http://stackoverflow.com/q/26985858 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private int getGl20MaxTextureSize() { EGLDisplay eglDisplay = null; EGLContext eglContext = null; EGLSurface eglSurface = null; try { // create EglContext eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); if (eglDisplay == EGL14.EGL_NO_DISPLAY) { return -1; } int[] version = new int[2]; if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { return -1; } int[] eglConfigAttribList = new int[]{ EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_RED_SIZE, 8, EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_NONE }; EGLConfig[] eglConfigs = new EGLConfig[1]; int[] numEglConfigs = new int[1]; if (!EGL14.eglChooseConfig(eglDisplay, eglConfigAttribList, 0, eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) { return -1; } EGLConfig eglConfig = eglConfigs[0]; int[] eglContextAttribList = new int[]{ EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE }; eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0); if (eglContext == null) { return -1; } // create EglSurface int[] eglSurfaceAttribList = new int[]{ EGL14.EGL_WIDTH, 64, EGL14.EGL_HEIGHT, 64, EGL14.EGL_NONE }; eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, eglSurfaceAttribList, 0); if (eglSurface == null) { return -1; } // attach EglContext if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { return -1; } int[] maxTextureSize = new int[1]; GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0); return maxTextureSize[0]; } finally { // tear down if (eglDisplay != null) { // detach EglContext EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); if (eglSurface != null) { EGL14.eglDestroySurface(eglDisplay, eglSurface); } if (eglContext != null) { EGL14.eglDestroyContext(eglDisplay, eglContext); } EGL14.eglTerminate(eglDisplay); } } } } } }