/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.gallery3d.common; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.net.Uri; import android.os.Build; import android.util.Log; import android.view.WindowManager; import com.android.gallery3d.exif.ExifInterface; import com.android.launcher3.WallpaperCropActivity; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; public class BitmapUtils { private static final String TAG = "BitmapUtils"; // Find the min x that 1 / x >= scale public static int computeSampleSizeLarger(float scale) { int initialSize = (int) Math.floor(1f / scale); if (initialSize <= 1) return 1; return initialSize <= 8 ? Utils.prevPowerOf2(initialSize) : initialSize / 8 * 8; } public static Bitmap resizeBitmapByScale( Bitmap bitmap, float scale, boolean recycle) { int width = Math.round(bitmap.getWidth() * scale); int height = Math.round(bitmap.getHeight() * scale); if (width == bitmap.getWidth() && height == bitmap.getHeight()) return bitmap; Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap)); Canvas canvas = new Canvas(target); canvas.scale(scale, scale); Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); canvas.drawBitmap(bitmap, 0, 0, paint); if (recycle) bitmap.recycle(); return target; } private static Bitmap.Config getConfig(Bitmap bitmap) { Bitmap.Config config = bitmap.getConfig(); if (config == null) { config = Bitmap.Config.ARGB_8888; } return config; } /** * As a ratio of screen height, the total distance we want the parallax effect to span * horizontally */ public static float wallpaperTravelToScreenWidthRatio(int width, int height) { float aspectRatio = width / (float) height; // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width // We will use these two data points to extrapolate how much the wallpaper parallax effect // to span (ie travel) at any aspect ratio: final float ASPECT_RATIO_LANDSCAPE = 16/10f; final float ASPECT_RATIO_PORTRAIT = 10/16f; final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; // To find out the desired width at different aspect ratios, we use the following two // formulas, where the coefficient on x is the aspect ratio (width/height): // (16/10)x + y = 1.5 // (10/16)x + y = 1.2 // We solve for x and y and end up with a final formula: final float x = (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; return x * aspectRatio + y; } private static Point sDefaultWallpaperSize; @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) { if (sDefaultWallpaperSize == null) { Point minDims = new Point(); Point maxDims = new Point(); windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); int maxDim = Math.max(maxDims.x, maxDims.y); int minDim = Math.max(minDims.x, minDims.y); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { Point realSize = new Point(); windowManager.getDefaultDisplay().getRealSize(realSize); maxDim = Math.max(realSize.x, realSize.y); minDim = Math.min(realSize.x, realSize.y); } // We need to ensure that there is enough extra space in the wallpaper // for the intended parallax effects final int defaultWidth, defaultHeight; if (res.getConfiguration().smallestScreenWidthDp >= 720) { defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); defaultHeight = maxDim; } else { defaultWidth = Math.max((int) (minDim * WallpaperCropActivity.WALLPAPER_SCREENS_SPAN), maxDim); defaultHeight = maxDim; } sDefaultWallpaperSize = new Point(defaultWidth, defaultHeight); } return sDefaultWallpaperSize; } public static int getRotationFromExif(Context context, Uri uri) { return BitmapUtils.getRotationFromExifHelper(null, 0, context, uri); } public static int getRotationFromExif(Resources res, int resId) { return BitmapUtils.getRotationFromExifHelper(res, resId, null, null); } private static int getRotationFromExifHelper(Resources res, int resId, Context context, Uri uri) { ExifInterface ei = new ExifInterface(); InputStream is = null; BufferedInputStream bis = null; try { if (uri != null) { is = context.getContentResolver().openInputStream(uri); bis = new BufferedInputStream(is); ei.readExif(bis); } else { is = res.openRawResource(resId); bis = new BufferedInputStream(is); ei.readExif(bis); } Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); if (ori != null) { return ExifInterface.getRotationForOrientationValue(ori.shortValue()); } } catch (IOException e) { Log.w(TAG, "Getting exif data failed", e); } catch (NullPointerException e) { // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid Log.w(TAG, "Getting exif data failed", e); } finally { Utils.closeSilently(bis); Utils.closeSilently(is); } return 0; } }