blob: f1e7620d5f6e8831318ce84ab5259f688385d5dc [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.photo_picker;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.FileDescriptor;
/**
* A collection of utility functions for dealing with bitmaps.
*/
class BitmapUtils {
/**
* Takes a |bitmap| and returns a square thumbnail of |size|x|size| from the center of the
* bitmap specified.
* @param bitmap The bitmap to adjust.
* @param size The desired size (width and height).
* @return The new bitmap thumbnail.
*/
private static Bitmap sizeBitmap(Bitmap bitmap, int size) {
// TODO(finnur): Investigate options that require fewer bitmaps to be created.
bitmap = ensureMinSize(bitmap, size);
bitmap = cropToSquare(bitmap, size);
return bitmap;
}
/**
* Given a FileDescriptor, decodes the contents and returns a bitmap of
* dimensions |size|x|size|.
* @param descriptor The FileDescriptor for the file to read.
* @param size The width and height of the bitmap to return.
* @return The resulting bitmap.
*/
public static Bitmap decodeBitmapFromFileDescriptor(FileDescriptor descriptor, int size) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(descriptor, null, options);
options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, size);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(descriptor, null, options);
if (bitmap == null) return null;
return sizeBitmap(bitmap, size);
}
/**
* Calculates the sub-sampling factor {@link BitmapFactory#inSampleSize} option for a given
* image dimensions, which will be used to create a bitmap of a pre-determined size (as small as
* possible without either dimension shrinking below |minSize|.
* @param width The calculated width of the image to decode.
* @param height The calculated height of the image to decode.
* @param minSize The maximum size the image should be (in either dimension).
* @return The sub-sampling factor (power of two: 1 = no change, 2 = half-size, etc).
*/
private static int calculateInSampleSize(int width, int height, int minSize) {
int inSampleSize = 1;
if (width > minSize && height > minSize) {
inSampleSize = Math.min(width, height) / minSize;
}
return inSampleSize;
}
/**
* Ensures a |bitmap| is at least |size| in both width and height.
* @param bitmap The bitmap to modify.
* @param size The minimum size (width and height).
* @return The resulting (scaled) bitmap.
*/
private static Bitmap ensureMinSize(Bitmap bitmap, int size) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width >= size && height >= size) return bitmap;
if (width < size) {
float scale = (float) size / width;
width = size;
height *= scale;
}
if (height < size) {
float scale = (float) size / height;
height = size;
width *= scale;
}
return Bitmap.createScaledBitmap(bitmap, width, height, true);
}
/**
* Crops a |bitmap| to a certain square |size|
* @param bitmap The bitmap to crop.
* @param size The size desired (width and height).
* @return The resulting (square) bitmap.
*/
private static Bitmap cropToSquare(Bitmap bitmap, int size) {
int x = 0;
int y = 0;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
if (width == size && height == size) return bitmap;
if (width > size) x = (width - size) / 2;
if (height > size) y = (height - size) / 2;
return Bitmap.createBitmap(bitmap, x, y, size, size);
}
/**
* Scales a |bitmap| to a certain size.
* @param bitmap The bitmap to scale.
* @param scaleMaxSize What to scale it to.
* @param filter True if the source should be filtered.
* @return The resulting scaled bitmap.
*/
public static Bitmap scale(Bitmap bitmap, float scaleMaxSize, boolean filter) {
float ratio = Math.min((float) scaleMaxSize / bitmap.getWidth(),
(float) scaleMaxSize / bitmap.getHeight());
int height = Math.round(ratio * bitmap.getHeight());
int width = Math.round(ratio * bitmap.getWidth());
return Bitmap.createScaledBitmap(bitmap, width, height, filter);
}
}