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