Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2008 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 android.graphics;
     18 
     19 
     20 import java.awt.image.BufferedImage;
     21 import java.io.File;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 
     25 import javax.imageio.ImageIO;
     26 
     27 public final class Bitmap extends _Original_Bitmap {
     28 
     29     private BufferedImage mImage;
     30 
     31     public Bitmap(File input) throws IOException {
     32         super(1, true, null, -1);
     33 
     34         mImage = ImageIO.read(input);
     35     }
     36 
     37     public Bitmap(InputStream is) throws IOException {
     38         super(1, true, null, -1);
     39 
     40         mImage = ImageIO.read(is);
     41     }
     42 
     43     Bitmap(BufferedImage image) {
     44         super(1, true, null, -1);
     45         mImage = image;
     46     }
     47 
     48     public BufferedImage getImage() {
     49         return mImage;
     50     }
     51 
     52     // ----- overriden methods
     53 
     54     public enum Config {
     55         // these native values must match up with the enum in SkBitmap.h
     56         ALPHA_8     (2),
     57         RGB_565     (4),
     58         ARGB_4444   (5),
     59         ARGB_8888   (6);
     60 
     61         Config(int ni) {
     62             this.nativeInt = ni;
     63         }
     64         final int nativeInt;
     65 
     66         /* package */ static Config nativeToConfig(int ni) {
     67             return sConfigs[ni];
     68         }
     69 
     70         private static Config sConfigs[] = {
     71             null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
     72         };
     73     }
     74 
     75     @Override
     76     public int getWidth() {
     77         return mImage.getWidth();
     78     }
     79 
     80     @Override
     81     public int getHeight() {
     82         return mImage.getHeight();
     83     }
     84 
     85     /**
     86      * Returns an immutable bitmap from the source bitmap. The new bitmap may
     87      * be the same object as source, or a copy may have been made.
     88      */
     89     public static Bitmap createBitmap(Bitmap src) {
     90         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
     91     }
     92 
     93     /**
     94      * Returns an immutable bitmap from the specified subset of the source
     95      * bitmap. The new bitmap may be the same object as source, or a copy may
     96      * have been made.
     97      *
     98      * @param source   The bitmap we are subsetting
     99      * @param x        The x coordinate of the first pixel in source
    100      * @param y        The y coordinate of the first pixel in source
    101      * @param width    The number of pixels in each row
    102      * @param height   The number of rows
    103      */
    104     public static Bitmap createBitmap(Bitmap source, int x, int y,
    105                                       int width, int height) {
    106         return new Bitmap(source.mImage.getSubimage(x, y, width, height));
    107     }
    108 
    109     /**
    110      * Returns an immutable bitmap from subset of the source bitmap,
    111      * transformed by the optional matrix.
    112      *
    113      * @param source   The bitmap we are subsetting
    114      * @param x        The x coordinate of the first pixel in source
    115      * @param y        The y coordinate of the first pixel in source
    116      * @param width    The number of pixels in each row
    117      * @param height   The number of rows
    118      * @param m        Option matrix to be applied to the pixels
    119      * @param filter   true if the source should be filtered.
    120      *                   Only applies if the matrix contains more than just
    121      *                   translation.
    122      * @return A bitmap that represents the specified subset of source
    123      * @throws IllegalArgumentException if the x, y, width, height values are
    124      *         outside of the dimensions of the source bitmap.
    125      */
    126     public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
    127                                       int height, Matrix m, boolean filter) {
    128         checkXYSign(x, y);
    129         checkWidthHeight(width, height);
    130         if (x + width > source.getWidth()) {
    131             throw new IllegalArgumentException(
    132                     "x + width must be <= bitmap.width()");
    133         }
    134         if (y + height > source.getHeight()) {
    135             throw new IllegalArgumentException(
    136                     "y + height must be <= bitmap.height()");
    137         }
    138 
    139         // check if we can just return our argument unchanged
    140         if (!source.isMutable() && x == 0 && y == 0
    141                 && width == source.getWidth() && height == source.getHeight()
    142                 && (m == null || m.isIdentity())) {
    143             return source;
    144         }
    145 
    146         if (m == null || m.isIdentity()) {
    147             return new Bitmap(source.mImage.getSubimage(x, y, width, height));
    148         }
    149 
    150         int neww = width;
    151         int newh = height;
    152         Paint paint;
    153 
    154         Rect srcR = new Rect(x, y, x + width, y + height);
    155         RectF dstR = new RectF(0, 0, width, height);
    156 
    157         /*  the dst should have alpha if the src does, or if our matrix
    158             doesn't preserve rectness
    159         */
    160         boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
    161         RectF deviceR = new RectF();
    162         m.mapRect(deviceR, dstR);
    163         neww = Math.round(deviceR.width());
    164         newh = Math.round(deviceR.height());
    165 
    166         Canvas canvas = new Canvas(neww, newh);
    167 
    168         canvas.translate(-deviceR.left, -deviceR.top);
    169         canvas.concat(m);
    170         paint = new Paint();
    171         paint.setFilterBitmap(filter);
    172         if (!m.rectStaysRect()) {
    173             paint.setAntiAlias(true);
    174         }
    175 
    176         canvas.drawBitmap(source, srcR, dstR, paint);
    177 
    178         return new Bitmap(canvas.getImage());
    179     }
    180 
    181     /**
    182      * Returns a mutable bitmap with the specified width and height.
    183      *
    184      * @param width    The width of the bitmap
    185      * @param height   The height of the bitmap
    186      * @param config   The bitmap config to create.
    187      * @throws IllegalArgumentException if the width or height are <= 0
    188      */
    189     public static Bitmap createBitmap(int width, int height, Config config) {
    190         return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
    191     }
    192 
    193     /**
    194      * Returns a immutable bitmap with the specified width and height, with each
    195      * pixel value set to the corresponding value in the colors array.
    196      *
    197      * @param colors   Array of {@link Color} used to initialize the pixels.
    198      * @param offset   Number of values to skip before the first color in the
    199      *                 array of colors.
    200      * @param stride   Number of colors in the array between rows (must be >=
    201      *                 width or <= -width).
    202      * @param width    The width of the bitmap
    203      * @param height   The height of the bitmap
    204      * @param config   The bitmap config to create. If the config does not
    205      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
    206      *                 bytes in the colors[] will be ignored (assumed to be FF)
    207      * @throws IllegalArgumentException if the width or height are <= 0, or if
    208      *         the color array's length is less than the number of pixels.
    209      */
    210     public static Bitmap createBitmap(int colors[], int offset, int stride,
    211                                       int width, int height, Config config) {
    212         checkWidthHeight(width, height);
    213         if (Math.abs(stride) < width) {
    214             throw new IllegalArgumentException("abs(stride) must be >= width");
    215         }
    216         int lastScanline = offset + (height - 1) * stride;
    217         int length = colors.length;
    218         if (offset < 0 || (offset + width > length)
    219             || lastScanline < 0
    220             || (lastScanline + width > length)) {
    221             throw new ArrayIndexOutOfBoundsException();
    222         }
    223 
    224         // TODO: create an immutable bitmap...
    225         throw new UnsupportedOperationException();
    226     }
    227 
    228     /**
    229      * Returns a immutable bitmap with the specified width and height, with each
    230      * pixel value set to the corresponding value in the colors array.
    231      *
    232      * @param colors   Array of {@link Color} used to initialize the pixels.
    233      *                 This array must be at least as large as width * height.
    234      * @param width    The width of the bitmap
    235      * @param height   The height of the bitmap
    236      * @param config   The bitmap config to create. If the config does not
    237      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
    238      *                 bytes in the colors[] will be ignored (assumed to be FF)
    239      * @throws IllegalArgumentException if the width or height are <= 0, or if
    240      *         the color array's length is less than the number of pixels.
    241      */
    242     public static Bitmap createBitmap(int colors[], int width, int height,
    243                                       Config config) {
    244         return createBitmap(colors, 0, width, width, height, config);
    245     }
    246 
    247     public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
    248             int dstHeight, boolean filter) {
    249         Matrix m;
    250         synchronized (Bitmap.class) {
    251             // small pool of just 1 matrix
    252             m = sScaleMatrix;
    253             sScaleMatrix = null;
    254         }
    255 
    256         if (m == null) {
    257             m = new Matrix();
    258         }
    259 
    260         final int width = src.getWidth();
    261         final int height = src.getHeight();
    262         final float sx = dstWidth  / (float)width;
    263         final float sy = dstHeight / (float)height;
    264         m.setScale(sx, sy);
    265         Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
    266 
    267         synchronized (Bitmap.class) {
    268             // do we need to check for null? why not just assign everytime?
    269             if (sScaleMatrix == null) {
    270                 sScaleMatrix = m;
    271             }
    272         }
    273 
    274         return b;
    275     }
    276 
    277 
    278 }
    279