ImageUtils.java revision 05c362d5645367c816069aa138b597b77f317aa4
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.internal.util; 18 19import android.graphics.Bitmap; 20import android.graphics.Canvas; 21import android.graphics.Matrix; 22import android.graphics.Paint; 23import android.graphics.PorterDuff; 24 25/** 26 * Utility class for image analysis and processing. 27 * 28 * @hide 29 */ 30public class ImageUtils { 31 32 // Amount (max is 255) that two channels can differ before the color is no longer "gray". 33 private static final int TOLERANCE = 20; 34 35 // Alpha amount for which values below are considered transparent. 36 private static final int ALPHA_TOLERANCE = 50; 37 38 // Size of the smaller bitmap we're actually going to scan. 39 private static final int COMPACT_BITMAP_SIZE = 64; // pixels 40 41 private int[] mTempBuffer; 42 private Bitmap mTempCompactBitmap; 43 private Canvas mTempCompactBitmapCanvas; 44 private Paint mTempCompactBitmapPaint; 45 private final Matrix mTempMatrix = new Matrix(); 46 47 /** 48 * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect 49 * gray". 50 * 51 * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than 52 * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements 53 * will survive the squeezing process, contaminating the result with color. 54 */ 55 public boolean isGrayscale(Bitmap bitmap) { 56 int height = bitmap.getHeight(); 57 int width = bitmap.getWidth(); 58 59 // shrink to a more manageable (yet hopefully no more or less colorful) size 60 if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) { 61 if (mTempCompactBitmap == null) { 62 mTempCompactBitmap = Bitmap.createBitmap( 63 COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888 64 ); 65 mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap); 66 mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 67 mTempCompactBitmapPaint.setFilterBitmap(true); 68 } 69 mTempMatrix.reset(); 70 mTempMatrix.setScale( 71 (float) COMPACT_BITMAP_SIZE / width, 72 (float) COMPACT_BITMAP_SIZE / height, 73 0, 0); 74 mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase 75 mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint); 76 bitmap = mTempCompactBitmap; 77 width = height = COMPACT_BITMAP_SIZE; 78 } 79 80 final int size = height*width; 81 ensureBufferSize(size); 82 bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); 83 for (int i = 0; i < size; i++) { 84 if (!isGrayscale(mTempBuffer[i])) { 85 return false; 86 } 87 } 88 return true; 89 } 90 91 /** 92 * Makes sure that {@code mTempBuffer} has at least length {@code size}. 93 */ 94 private void ensureBufferSize(int size) { 95 if (mTempBuffer == null || mTempBuffer.length < size) { 96 mTempBuffer = new int[size]; 97 } 98 } 99 100 /** 101 * Classifies a color as grayscale or not. Grayscale here means "very close to a perfect 102 * gray"; if all three channels are approximately equal, this will return true. 103 * 104 * Note that really transparent colors are always grayscale. 105 */ 106 public static boolean isGrayscale(int color) { 107 int alpha = 0xFF & (color >> 24); 108 if (alpha < ALPHA_TOLERANCE) { 109 return true; 110 } 111 112 int r = 0xFF & (color >> 16); 113 int g = 0xFF & (color >> 8); 114 int b = 0xFF & color; 115 116 return Math.abs(r - g) < TOLERANCE 117 && Math.abs(r - b) < TOLERANCE 118 && Math.abs(g - b) < TOLERANCE; 119 } 120} 121