Home | History | Annotate | Download | only in sample
      1 /*
      2  * Copyright (C) 2016 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 
     17 package com.android.car.cluster.sample;
     18 
     19 import static android.graphics.Color.blue;
     20 import static android.graphics.Color.green;
     21 import static android.graphics.Color.red;
     22 
     23 import android.graphics.Bitmap;
     24 import android.graphics.Bitmap.Config;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.Paint;
     28 import android.graphics.PorterDuff.Mode;
     29 import android.graphics.PorterDuffXfermode;
     30 import android.graphics.Rect;
     31 import android.graphics.RectF;
     32 
     33 /**
     34  * Utility functions to work with bitmaps.
     35  */
     36 public class BitmapUtils {
     37 
     38     // Non-transparent color to crop images using Xfermode.
     39     private static final int OPAQUE_COLOR = 0xff424242;
     40 
     41     /**
     42      * Scales a bitmap while preserving the proportions such that both dimensions are the smallest
     43      * values possible that are equal to or larger than the given dimensions.
     44      *
     45      * This function can be a few times as expensive as Bitmap.createScaledBitmap with
     46      * filtering when downscaling, but it produces much nicer results.
     47      *
     48      * @param bm The bitmap to scale.
     49      * @param width The desired width.
     50      * @param height The desired height.
     51      * @return The scaled bitmap, or the original bitmap if scaling was not necessary.
     52      */
     53     public static Bitmap scaleBitmap(Bitmap bm, int width, int height) {
     54         if (bm == null || (bm.getHeight() == height && bm.getWidth() == width)) {
     55             return bm;
     56         }
     57 
     58         float heightScale = (float) height / bm.getHeight();
     59         float widthScale = (float) width / bm.getWidth();
     60 
     61         float scale = heightScale > widthScale ? heightScale : widthScale;
     62         int scaleWidth = (int) Math.ceil(bm.getWidth() * scale);
     63         int scaleHeight = (int) Math.ceil(bm.getHeight() * scale);
     64 
     65         Bitmap scaledBm = bm;
     66         // If you try to scale an image down too much in one go, you can end up with discontinuous
     67         // interpolation. Therefore, if necessary, we scale the image to twice the desired size
     68         // and do a second scaling to the desired size, which smooths jaggedness from the first go.
     69         if (scale < .5f) {
     70             scaledBm = Bitmap.createScaledBitmap(scaledBm, scaleWidth * 2, scaleHeight * 2, true);
     71         }
     72 
     73         if (scale != 1f) {
     74             Bitmap newScaledBitmap = Bitmap
     75                     .createScaledBitmap(scaledBm, scaleWidth, scaleHeight, true);
     76             if (scaledBm != bm) {
     77                 scaledBm.recycle();
     78             }
     79             scaledBm = newScaledBitmap;
     80         }
     81         return scaledBm;
     82     }
     83 
     84     public static Bitmap squareCropBitmap(Bitmap bitmap) {
     85         if (bitmap.getWidth() == bitmap.getHeight()) {
     86             return bitmap;
     87         }
     88 
     89         int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
     90 
     91         Bitmap output = Bitmap.createBitmap(size,
     92                 size, Config.ARGB_8888);
     93         Canvas canvas = new Canvas(output);
     94 
     95         int x = size < bitmap.getWidth() ? (bitmap.getWidth() - size ) / 2 : 0;
     96         int y = size < bitmap.getHeight() ? (bitmap.getHeight() - size ) / 2 : 0;
     97         Rect srcRect = new Rect(x, y, x + size, y + size);
     98         Rect dstRect = new Rect(0, 0, output.getWidth(), output.getHeight());
     99 
    100         canvas.drawBitmap(bitmap, srcRect, dstRect, null);
    101         return output;
    102     }
    103 
    104     public static Bitmap circleCropBitmap(Bitmap bitmap) {
    105         bitmap = squareCropBitmap(bitmap);
    106         Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
    107                 bitmap.getHeight(), Config.ARGB_8888);
    108         Canvas canvas = new Canvas(output);
    109 
    110         Paint paint = new Paint();
    111         Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
    112 
    113         paint.setAntiAlias(true);
    114         canvas.drawARGB(0, 0, 0, 0);
    115         paint.setColor(OPAQUE_COLOR);
    116         canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
    117                 bitmap.getWidth() / 2, paint);
    118         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    119         canvas.drawBitmap(bitmap, rect, rect, paint);
    120         return output;
    121     }
    122 
    123     public static Bitmap generateNavManeuverIcon(int size, int bgColor, Bitmap maneuver) {
    124         Bitmap bm = Bitmap.createBitmap(size, size, Config.ARGB_8888);
    125         Canvas canvas = new Canvas(bm);
    126         drawCircle(canvas, bgColor);
    127 
    128         canvas.drawBitmap(maneuver,
    129                 (bm.getWidth() - maneuver.getWidth()) / 2,
    130                 (bm.getHeight() - maneuver.getHeight()) / 2,
    131                 new Paint(Paint.ANTI_ALIAS_FLAG));
    132         return bm;
    133     }
    134 
    135     public static Bitmap generateMediaIcon(int size, int bgColor, int fgColor) {
    136         final float goldenRatio = 1.618f;
    137 
    138         Bitmap bm = Bitmap.createBitmap(size, size, Config.ARGB_8888);
    139         Canvas canvas = new Canvas(bm);
    140         drawCircle(canvas, bgColor);
    141 
    142         // Calculate column parameters relative to the size.
    143         int bottom = (int) (size / goldenRatio);
    144         int columnWidth = size / 17;
    145         int columnSpace = columnWidth / 2;
    146         int allColumnsWidth = columnWidth * 3 + columnSpace * 2;
    147         int left = size / 2 - (allColumnsWidth) / 2;
    148 
    149         Paint columnPaint = new Paint();
    150         columnPaint.setColor(fgColor);
    151         columnPaint.setAntiAlias(true);
    152         canvas.drawRect(new RectF(left, bottom - columnWidth * 2, left + columnWidth, bottom),
    153                 columnPaint);
    154 
    155         left += columnWidth + columnSpace;
    156         canvas.drawRect(new RectF(left, bottom - columnWidth * 4, left + columnWidth, bottom),
    157                 columnPaint);
    158 
    159         left += columnWidth + columnSpace;
    160         canvas.drawRect(new RectF(left, bottom - columnWidth * 3, left + columnWidth, bottom),
    161                 columnPaint);
    162 
    163         return bm;
    164     }
    165 
    166     private static Canvas drawCircle(Canvas canvas, int bgColor) {
    167         int size = canvas.getWidth();
    168         Paint p = new Paint();
    169         p.setAntiAlias(true);
    170         p.setColor(bgColor);
    171         canvas.drawCircle(size / 2, size / 2, (size / 2) - 1, p);
    172         return canvas;
    173     }
    174 
    175     public static int[] getBaseColors(int color) {
    176         return new int[] {red(color), green(color), blue(color)};
    177     }
    178 
    179     /**
    180      * Scales colors for given bitmap. This could be used as color filter for example.
    181      */
    182     public static Bitmap scaleBitmapColors(Bitmap original, int minColor, int maxColor) {
    183         int[] pixels = new int[original.getWidth() * original.getHeight()];
    184         original.getPixels(pixels, 0, original.getWidth(), 0, 0,
    185                 original.getWidth(), original.getHeight());
    186 
    187         int[] min = getBaseColors(minColor);
    188         int[] max = getBaseColors(maxColor);
    189 
    190         for (int i = 0; i < pixels.length; i++) {
    191             int pixel = pixels[i];
    192             int[] colors = new int[] {red(pixel), green(pixel), blue(pixel)};
    193 
    194             for (int j = 0; j < 3; j++) {
    195                 colors[j] = (int)((colors[j] / 255.0) * (max[j] - min[j]) + min[j]);
    196             }
    197 
    198             pixels[i] = Color.rgb(colors[0], colors[1], colors[2]);
    199         }
    200 
    201         Bitmap bmp = Bitmap.createBitmap(original.getWidth(), original.getHeight(), Config.ARGB_8888);
    202         bmp.setPixels(pixels, 0, original.getWidth(), 0, 0, original.getWidth(),
    203                 original.getHeight());
    204         return bmp;
    205     }
    206 }
    207