1 /* 2 * Copyright (C) 2006 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 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.util.DisplayMetrics; 22 import java.io.OutputStream; 23 import java.nio.Buffer; 24 import java.nio.ByteBuffer; 25 import java.nio.IntBuffer; 26 import java.nio.ShortBuffer; 27 28 public final class Bitmap implements Parcelable { 29 30 /** 31 * Indicates that the bitmap was created for an unknown pixel density. 32 * 33 * @see Bitmap#getDensity() 34 * @see Bitmap#setDensity(int) 35 */ 36 public static final int DENSITY_NONE = 0; 37 38 /** 39 * Note: mNativeBitmap is used by FaceDetector_jni.cpp 40 * Don't change/rename without updating FaceDetector_jni.cpp 41 * 42 * @hide 43 */ 44 public final int mNativeBitmap; 45 46 /** 47 * Backing buffer for the Bitmap. 48 * Made public for quick access from drawing methods -- do NOT modify 49 * from outside this class. 50 * 51 * @hide 52 */ 53 public byte[] mBuffer; 54 55 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources 56 private final BitmapFinalizer mFinalizer; 57 58 private final boolean mIsMutable; 59 private byte[] mNinePatchChunk; // may be null 60 private int mWidth = -1; 61 private int mHeight = -1; 62 private boolean mRecycled; 63 64 // Package-scoped for fast access. 65 /*package*/ int mDensity = sDefaultDensity = getDefaultDensity(); 66 67 private static volatile Matrix sScaleMatrix; 68 69 private static volatile int sDefaultDensity = -1; 70 71 /** 72 * For backwards compatibility, allows the app layer to change the default 73 * density when running old apps. 74 * @hide 75 */ setDefaultDensity(int density)76 public static void setDefaultDensity(int density) { 77 sDefaultDensity = density; 78 } 79 getDefaultDensity()80 /*package*/ static int getDefaultDensity() { 81 if (sDefaultDensity >= 0) { 82 return sDefaultDensity; 83 } 84 sDefaultDensity = DisplayMetrics.DENSITY_DEVICE; 85 return sDefaultDensity; 86 } 87 88 /** 89 * @noinspection UnusedDeclaration 90 */ 91 /* Private constructor that must received an already allocated native 92 bitmap int (pointer). 93 94 This can be called from JNI code. 95 */ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int density)96 /*package*/ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, 97 int density) { 98 if (nativeBitmap == 0) { 99 throw new RuntimeException("internal error: native bitmap is 0"); 100 } 101 102 mBuffer = buffer; 103 // we delete this in our finalizer 104 mNativeBitmap = nativeBitmap; 105 mFinalizer = new BitmapFinalizer(nativeBitmap); 106 107 mIsMutable = isMutable; 108 mNinePatchChunk = ninePatchChunk; 109 if (density >= 0) { 110 mDensity = density; 111 } 112 } 113 114 /** 115 * <p>Returns the density for this bitmap.</p> 116 * 117 * <p>The default density is the same density as the current display, 118 * unless the current application does not support different screen 119 * densities in which case it is 120 * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}. Note that 121 * compatibility mode is determined by the application that was initially 122 * loaded into a process -- applications that share the same process should 123 * all have the same compatibility, or ensure they explicitly set the 124 * density of their bitmaps appropriately.</p> 125 * 126 * @return A scaling factor of the default density or {@link #DENSITY_NONE} 127 * if the scaling factor is unknown. 128 * 129 * @see #setDensity(int) 130 * @see android.util.DisplayMetrics#DENSITY_DEFAULT 131 * @see android.util.DisplayMetrics#densityDpi 132 * @see #DENSITY_NONE 133 */ getDensity()134 public int getDensity() { 135 return mDensity; 136 } 137 138 /** 139 * <p>Specifies the density for this bitmap. When the bitmap is 140 * drawn to a Canvas that also has a density, it will be scaled 141 * appropriately.</p> 142 * 143 * @param density The density scaling factor to use with this bitmap or 144 * {@link #DENSITY_NONE} if the density is unknown. 145 * 146 * @see #getDensity() 147 * @see android.util.DisplayMetrics#DENSITY_DEFAULT 148 * @see android.util.DisplayMetrics#densityDpi 149 * @see #DENSITY_NONE 150 */ setDensity(int density)151 public void setDensity(int density) { 152 mDensity = density; 153 } 154 155 /** 156 * Sets the nine patch chunk. 157 * 158 * @param chunk The definition of the nine patch 159 * 160 * @hide 161 */ setNinePatchChunk(byte[] chunk)162 public void setNinePatchChunk(byte[] chunk) { 163 mNinePatchChunk = chunk; 164 } 165 166 /** 167 * Free the native object associated with this bitmap, and clear the 168 * reference to the pixel data. This will not free the pixel data synchronously; 169 * it simply allows it to be garbage collected if there are no other references. 170 * The bitmap is marked as "dead", meaning it will throw an exception if 171 * getPixels() or setPixels() is called, and will draw nothing. This operation 172 * cannot be reversed, so it should only be called if you are sure there are no 173 * further uses for the bitmap. This is an advanced call, and normally need 174 * not be called, since the normal GC process will free up this memory when 175 * there are no more references to this bitmap. 176 */ recycle()177 public void recycle() { 178 if (!mRecycled) { 179 mBuffer = null; 180 nativeRecycle(mNativeBitmap); 181 mNinePatchChunk = null; 182 mRecycled = true; 183 } 184 } 185 186 /** 187 * Returns true if this bitmap has been recycled. If so, then it is an error 188 * to try to access its pixels, and the bitmap will not draw. 189 * 190 * @return true if the bitmap has been recycled 191 */ isRecycled()192 public final boolean isRecycled() { 193 return mRecycled; 194 } 195 196 /** 197 * Returns the generation ID of this bitmap. The generation ID changes 198 * whenever the bitmap is modified. This can be used as an efficient way to 199 * check if a bitmap has changed. 200 * 201 * @return The current generation ID for this bitmap. 202 */ getGenerationId()203 public int getGenerationId() { 204 return nativeGenerationId(mNativeBitmap); 205 } 206 207 /** 208 * This is called by methods that want to throw an exception if the bitmap 209 * has already been recycled. 210 */ checkRecycled(String errorMessage)211 private void checkRecycled(String errorMessage) { 212 if (mRecycled) { 213 throw new IllegalStateException(errorMessage); 214 } 215 } 216 217 /** 218 * Common code for checking that x and y are >= 0 219 * 220 * @param x x coordinate to ensure is >= 0 221 * @param y y coordinate to ensure is >= 0 222 */ checkXYSign(int x, int y)223 private static void checkXYSign(int x, int y) { 224 if (x < 0) { 225 throw new IllegalArgumentException("x must be >= 0"); 226 } 227 if (y < 0) { 228 throw new IllegalArgumentException("y must be >= 0"); 229 } 230 } 231 232 /** 233 * Common code for checking that width and height are > 0 234 * 235 * @param width width to ensure is > 0 236 * @param height height to ensure is > 0 237 */ checkWidthHeight(int width, int height)238 private static void checkWidthHeight(int width, int height) { 239 if (width <= 0) { 240 throw new IllegalArgumentException("width must be > 0"); 241 } 242 if (height <= 0) { 243 throw new IllegalArgumentException("height must be > 0"); 244 } 245 } 246 247 /** 248 * Possible bitmap configurations. A bitmap configuration describes 249 * how pixels are stored. This affects the quality (color depth) as 250 * well as the ability to display transparent/translucent colors. 251 */ 252 public enum Config { 253 // these native values must match up with the enum in SkBitmap.h 254 255 /** 256 * Each pixel is stored as a single translucency (alpha) channel. 257 * This is very useful to efficiently store masks for instance. 258 * No color information is stored. 259 * With this configuration, each pixel requires 1 byte of memory. 260 */ 261 ALPHA_8 (2), 262 263 /** 264 * Each pixel is stored on 2 bytes and only the RGB channels are 265 * encoded: red is stored with 5 bits of precision (32 possible 266 * values), green is stored with 6 bits of precision (64 possible 267 * values) and blue is stored with 5 bits of precision. 268 * 269 * This configuration can produce slight visual artifacts depending 270 * on the configuration of the source. For instance, without 271 * dithering, the result might show a greenish tint. To get better 272 * results dithering should be applied. 273 * 274 * This configuration may be useful when using opaque bitmaps 275 * that do not require high color fidelity. 276 */ 277 RGB_565 (4), 278 279 /** 280 * Each pixel is stored on 2 bytes. The three RGB color channels 281 * and the alpha channel (translucency) are stored with a 4 bits 282 * precision (16 possible values.) 283 * 284 * This configuration is mostly useful if the application needs 285 * to store translucency information but also needs to save 286 * memory. 287 * 288 * It is recommended to use {@link #ARGB_8888} instead of this 289 * configuration. 290 * 291 * @deprecated Because of the poor quality of this configuration, 292 * it is advised to use {@link #ARGB_8888} instead. 293 */ 294 @Deprecated 295 ARGB_4444 (5), 296 297 /** 298 * Each pixel is stored on 4 bytes. Each channel (RGB and alpha 299 * for translucency) is stored with 8 bits of precision (256 300 * possible values.) 301 * 302 * This configuration is very flexible and offers the best 303 * quality. It should be used whenever possible. 304 */ 305 ARGB_8888 (6); 306 307 final int nativeInt; 308 309 @SuppressWarnings({"deprecation"}) 310 private static Config sConfigs[] = { 311 null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 312 }; 313 Config(int ni)314 Config(int ni) { 315 this.nativeInt = ni; 316 } 317 nativeToConfig(int ni)318 static Config nativeToConfig(int ni) { 319 return sConfigs[ni]; 320 } 321 } 322 323 /** 324 * Copy the bitmap's pixels into the specified buffer (allocated by the 325 * caller). An exception is thrown if the buffer is not large enough to 326 * hold all of the pixels (taking into account the number of bytes per 327 * pixel) or if the Buffer subclass is not one of the support types 328 * (ByteBuffer, ShortBuffer, IntBuffer). 329 */ copyPixelsToBuffer(Buffer dst)330 public void copyPixelsToBuffer(Buffer dst) { 331 int elements = dst.remaining(); 332 int shift; 333 if (dst instanceof ByteBuffer) { 334 shift = 0; 335 } else if (dst instanceof ShortBuffer) { 336 shift = 1; 337 } else if (dst instanceof IntBuffer) { 338 shift = 2; 339 } else { 340 throw new RuntimeException("unsupported Buffer subclass"); 341 } 342 343 long bufferSize = (long)elements << shift; 344 long pixelSize = getByteCount(); 345 346 if (bufferSize < pixelSize) { 347 throw new RuntimeException("Buffer not large enough for pixels"); 348 } 349 350 nativeCopyPixelsToBuffer(mNativeBitmap, dst); 351 352 // now update the buffer's position 353 int position = dst.position(); 354 position += pixelSize >> shift; 355 dst.position(position); 356 } 357 358 /** 359 * Copy the pixels from the buffer, beginning at the current position, 360 * overwriting the bitmap's pixels. The data in the buffer is not changed 361 * in any way (unlike setPixels(), which converts from unpremultipled 32bit 362 * to whatever the bitmap's native format is. 363 */ copyPixelsFromBuffer(Buffer src)364 public void copyPixelsFromBuffer(Buffer src) { 365 checkRecycled("copyPixelsFromBuffer called on recycled bitmap"); 366 367 int elements = src.remaining(); 368 int shift; 369 if (src instanceof ByteBuffer) { 370 shift = 0; 371 } else if (src instanceof ShortBuffer) { 372 shift = 1; 373 } else if (src instanceof IntBuffer) { 374 shift = 2; 375 } else { 376 throw new RuntimeException("unsupported Buffer subclass"); 377 } 378 379 long bufferBytes = (long)elements << shift; 380 long bitmapBytes = getByteCount(); 381 382 if (bufferBytes < bitmapBytes) { 383 throw new RuntimeException("Buffer not large enough for pixels"); 384 } 385 386 nativeCopyPixelsFromBuffer(mNativeBitmap, src); 387 } 388 389 /** 390 * Tries to make a new bitmap based on the dimensions of this bitmap, 391 * setting the new bitmap's config to the one specified, and then copying 392 * this bitmap's pixels into the new bitmap. If the conversion is not 393 * supported, or the allocator fails, then this returns NULL. The returned 394 * bitmap initially has the same density as the original. 395 * 396 * @param config The desired config for the resulting bitmap 397 * @param isMutable True if the resulting bitmap should be mutable (i.e. 398 * its pixels can be modified) 399 * @return the new bitmap, or null if the copy could not be made. 400 */ copy(Config config, boolean isMutable)401 public Bitmap copy(Config config, boolean isMutable) { 402 checkRecycled("Can't copy a recycled bitmap"); 403 Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable); 404 if (b != null) { 405 b.mDensity = mDensity; 406 } 407 return b; 408 } 409 410 /** 411 * Creates a new bitmap, scaled from an existing bitmap. 412 * 413 * @param src The source bitmap. 414 * @param dstWidth The new bitmap's desired width. 415 * @param dstHeight The new bitmap's desired height. 416 * @param filter true if the source should be filtered. 417 * @return the new scaled bitmap. 418 */ createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)419 public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, 420 int dstHeight, boolean filter) { 421 Matrix m; 422 synchronized (Bitmap.class) { 423 // small pool of just 1 matrix 424 m = sScaleMatrix; 425 sScaleMatrix = null; 426 } 427 428 if (m == null) { 429 m = new Matrix(); 430 } 431 432 final int width = src.getWidth(); 433 final int height = src.getHeight(); 434 final float sx = dstWidth / (float)width; 435 final float sy = dstHeight / (float)height; 436 m.setScale(sx, sy); 437 Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter); 438 439 synchronized (Bitmap.class) { 440 // do we need to check for null? why not just assign everytime? 441 if (sScaleMatrix == null) { 442 sScaleMatrix = m; 443 } 444 } 445 446 return b; 447 } 448 449 /** 450 * Returns an immutable bitmap from the source bitmap. The new bitmap may 451 * be the same object as source, or a copy may have been made. It is 452 * initialized with the same density as the original bitmap. 453 */ createBitmap(Bitmap src)454 public static Bitmap createBitmap(Bitmap src) { 455 return createBitmap(src, 0, 0, src.getWidth(), src.getHeight()); 456 } 457 458 /** 459 * Returns an immutable bitmap from the specified subset of the source 460 * bitmap. The new bitmap may be the same object as source, or a copy may 461 * have been made. It is 462 * initialized with the same density as the original bitmap. 463 * 464 * @param source The bitmap we are subsetting 465 * @param x The x coordinate of the first pixel in source 466 * @param y The y coordinate of the first pixel in source 467 * @param width The number of pixels in each row 468 * @param height The number of rows 469 */ createBitmap(Bitmap source, int x, int y, int width, int height)470 public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { 471 return createBitmap(source, x, y, width, height, null, false); 472 } 473 474 /** 475 * Returns an immutable bitmap from subset of the source bitmap, 476 * transformed by the optional matrix. It is 477 * initialized with the same density as the original bitmap. 478 * 479 * @param source The bitmap we are subsetting 480 * @param x The x coordinate of the first pixel in source 481 * @param y The y coordinate of the first pixel in source 482 * @param width The number of pixels in each row 483 * @param height The number of rows 484 * @param m Optional matrix to be applied to the pixels 485 * @param filter true if the source should be filtered. 486 * Only applies if the matrix contains more than just 487 * translation. 488 * @return A bitmap that represents the specified subset of source 489 * @throws IllegalArgumentException if the x, y, width, height values are 490 * outside of the dimensions of the source bitmap. 491 */ createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)492 public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, 493 Matrix m, boolean filter) { 494 495 checkXYSign(x, y); 496 checkWidthHeight(width, height); 497 if (x + width > source.getWidth()) { 498 throw new IllegalArgumentException("x + width must be <= bitmap.width()"); 499 } 500 if (y + height > source.getHeight()) { 501 throw new IllegalArgumentException("y + height must be <= bitmap.height()"); 502 } 503 504 // check if we can just return our argument unchanged 505 if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() && 506 height == source.getHeight() && (m == null || m.isIdentity())) { 507 return source; 508 } 509 510 int neww = width; 511 int newh = height; 512 Canvas canvas = new Canvas(); 513 Bitmap bitmap; 514 Paint paint; 515 516 Rect srcR = new Rect(x, y, x + width, y + height); 517 RectF dstR = new RectF(0, 0, width, height); 518 519 Config newConfig = Config.ARGB_8888; 520 final Config config = source.getConfig(); 521 // GIF files generate null configs, assume ARGB_8888 522 if (config != null) { 523 switch (config) { 524 case RGB_565: 525 newConfig = Config.RGB_565; 526 break; 527 case ALPHA_8: 528 newConfig = Config.ALPHA_8; 529 break; 530 //noinspection deprecation 531 case ARGB_4444: 532 case ARGB_8888: 533 default: 534 newConfig = Config.ARGB_8888; 535 break; 536 } 537 } 538 539 if (m == null || m.isIdentity()) { 540 bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha()); 541 paint = null; // not needed 542 } else { 543 final boolean transformed = !m.rectStaysRect(); 544 545 RectF deviceR = new RectF(); 546 m.mapRect(deviceR, dstR); 547 548 neww = Math.round(deviceR.width()); 549 newh = Math.round(deviceR.height()); 550 551 bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig, 552 transformed || source.hasAlpha()); 553 554 canvas.translate(-deviceR.left, -deviceR.top); 555 canvas.concat(m); 556 557 paint = new Paint(); 558 paint.setFilterBitmap(filter); 559 if (transformed) { 560 paint.setAntiAlias(true); 561 } 562 } 563 564 // The new bitmap was created from a known bitmap source so assume that 565 // they use the same density 566 bitmap.mDensity = source.mDensity; 567 568 canvas.setBitmap(bitmap); 569 canvas.drawBitmap(source, srcR, dstR, paint); 570 canvas.setBitmap(null); 571 572 return bitmap; 573 } 574 575 /** 576 * Returns a mutable bitmap with the specified width and height. Its 577 * initial density is as per {@link #getDensity}. 578 * 579 * @param width The width of the bitmap 580 * @param height The height of the bitmap 581 * @param config The bitmap config to create. 582 * @throws IllegalArgumentException if the width or height are <= 0 583 */ createBitmap(int width, int height, Config config)584 public static Bitmap createBitmap(int width, int height, Config config) { 585 return createBitmap(width, height, config, true); 586 } 587 588 /** 589 * Returns a mutable bitmap with the specified width and height. Its 590 * initial density is as per {@link #getDensity}. 591 * 592 * @param width The width of the bitmap 593 * @param height The height of the bitmap 594 * @param config The bitmap config to create. 595 * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the 596 * bitmap as opaque. Doing so will clear the bitmap in black 597 * instead of transparent. 598 * 599 * @throws IllegalArgumentException if the width or height are <= 0 600 */ createBitmap(int width, int height, Config config, boolean hasAlpha)601 private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { 602 if (width <= 0 || height <= 0) { 603 throw new IllegalArgumentException("width and height must be > 0"); 604 } 605 Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true); 606 if (config == Config.ARGB_8888 && !hasAlpha) { 607 bm.eraseColor(0xff000000); 608 nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha); 609 } else { 610 bm.eraseColor(0); 611 } 612 return bm; 613 } 614 615 /** 616 * Returns a immutable bitmap with the specified width and height, with each 617 * pixel value set to the corresponding value in the colors array. Its 618 * initial density is as per {@link #getDensity}. 619 * 620 * @param colors Array of {@link Color} used to initialize the pixels. 621 * @param offset Number of values to skip before the first color in the 622 * array of colors. 623 * @param stride Number of colors in the array between rows (must be >= 624 * width or <= -width). 625 * @param width The width of the bitmap 626 * @param height The height of the bitmap 627 * @param config The bitmap config to create. If the config does not 628 * support per-pixel alpha (e.g. RGB_565), then the alpha 629 * bytes in the colors[] will be ignored (assumed to be FF) 630 * @throws IllegalArgumentException if the width or height are <= 0, or if 631 * the color array's length is less than the number of pixels. 632 */ createBitmap(int colors[], int offset, int stride, int width, int height, Config config)633 public static Bitmap createBitmap(int colors[], int offset, int stride, 634 int width, int height, Config config) { 635 636 checkWidthHeight(width, height); 637 if (Math.abs(stride) < width) { 638 throw new IllegalArgumentException("abs(stride) must be >= width"); 639 } 640 int lastScanline = offset + (height - 1) * stride; 641 int length = colors.length; 642 if (offset < 0 || (offset + width > length) || lastScanline < 0 || 643 (lastScanline + width > length)) { 644 throw new ArrayIndexOutOfBoundsException(); 645 } 646 if (width <= 0 || height <= 0) { 647 throw new IllegalArgumentException("width and height must be > 0"); 648 } 649 return nativeCreate(colors, offset, stride, width, height, 650 config.nativeInt, false); 651 } 652 653 /** 654 * Returns a immutable bitmap with the specified width and height, with each 655 * pixel value set to the corresponding value in the colors array. Its 656 * initial density is as per {@link #getDensity}. 657 * 658 * @param colors Array of {@link Color} used to initialize the pixels. 659 * This array must be at least as large as width * height. 660 * @param width The width of the bitmap 661 * @param height The height of the bitmap 662 * @param config The bitmap config to create. If the config does not 663 * support per-pixel alpha (e.g. RGB_565), then the alpha 664 * bytes in the colors[] will be ignored (assumed to be FF) 665 * @throws IllegalArgumentException if the width or height are <= 0, or if 666 * the color array's length is less than the number of pixels. 667 */ createBitmap(int colors[], int width, int height, Config config)668 public static Bitmap createBitmap(int colors[], int width, int height, Config config) { 669 return createBitmap(colors, 0, width, width, height, config); 670 } 671 672 /** 673 * Returns an optional array of private data, used by the UI system for 674 * some bitmaps. Not intended to be called by applications. 675 */ getNinePatchChunk()676 public byte[] getNinePatchChunk() { 677 return mNinePatchChunk; 678 } 679 680 /** 681 * Specifies the known formats a bitmap can be compressed into 682 */ 683 public enum CompressFormat { 684 JPEG (0), 685 PNG (1), 686 WEBP (2); 687 CompressFormat(int nativeInt)688 CompressFormat(int nativeInt) { 689 this.nativeInt = nativeInt; 690 } 691 final int nativeInt; 692 } 693 694 /** 695 * Number of bytes of temp storage we use for communicating between the 696 * native compressor and the java OutputStream. 697 */ 698 private final static int WORKING_COMPRESS_STORAGE = 4096; 699 700 /** 701 * Write a compressed version of the bitmap to the specified outputstream. 702 * If this returns true, the bitmap can be reconstructed by passing a 703 * corresponding inputstream to BitmapFactory.decodeStream(). Note: not 704 * all Formats support all bitmap configs directly, so it is possible that 705 * the returned bitmap from BitmapFactory could be in a different bitdepth, 706 * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque 707 * pixels). 708 * 709 * @param format The format of the compressed image 710 * @param quality Hint to the compressor, 0-100. 0 meaning compress for 711 * small size, 100 meaning compress for max quality. Some 712 * formats, like PNG which is lossless, will ignore the 713 * quality setting 714 * @param stream The outputstream to write the compressed data. 715 * @return true if successfully compressed to the specified stream. 716 */ compress(CompressFormat format, int quality, OutputStream stream)717 public boolean compress(CompressFormat format, int quality, OutputStream stream) { 718 checkRecycled("Can't compress a recycled bitmap"); 719 // do explicit check before calling the native method 720 if (stream == null) { 721 throw new NullPointerException(); 722 } 723 if (quality < 0 || quality > 100) { 724 throw new IllegalArgumentException("quality must be 0..100"); 725 } 726 return nativeCompress(mNativeBitmap, format.nativeInt, quality, 727 stream, new byte[WORKING_COMPRESS_STORAGE]); 728 } 729 730 /** 731 * Returns true if the bitmap is marked as mutable (i.e. can be drawn into) 732 */ isMutable()733 public final boolean isMutable() { 734 return mIsMutable; 735 } 736 737 /** Returns the bitmap's width */ getWidth()738 public final int getWidth() { 739 return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth; 740 } 741 742 /** Returns the bitmap's height */ getHeight()743 public final int getHeight() { 744 return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight; 745 } 746 747 /** 748 * Convenience for calling {@link #getScaledWidth(int)} with the target 749 * density of the given {@link Canvas}. 750 */ getScaledWidth(Canvas canvas)751 public int getScaledWidth(Canvas canvas) { 752 return scaleFromDensity(getWidth(), mDensity, canvas.mDensity); 753 } 754 755 /** 756 * Convenience for calling {@link #getScaledHeight(int)} with the target 757 * density of the given {@link Canvas}. 758 */ getScaledHeight(Canvas canvas)759 public int getScaledHeight(Canvas canvas) { 760 return scaleFromDensity(getHeight(), mDensity, canvas.mDensity); 761 } 762 763 /** 764 * Convenience for calling {@link #getScaledWidth(int)} with the target 765 * density of the given {@link DisplayMetrics}. 766 */ getScaledWidth(DisplayMetrics metrics)767 public int getScaledWidth(DisplayMetrics metrics) { 768 return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi); 769 } 770 771 /** 772 * Convenience for calling {@link #getScaledHeight(int)} with the target 773 * density of the given {@link DisplayMetrics}. 774 */ getScaledHeight(DisplayMetrics metrics)775 public int getScaledHeight(DisplayMetrics metrics) { 776 return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi); 777 } 778 779 /** 780 * Convenience method that returns the width of this bitmap divided 781 * by the density scale factor. 782 * 783 * @param targetDensity The density of the target canvas of the bitmap. 784 * @return The scaled width of this bitmap, according to the density scale factor. 785 */ getScaledWidth(int targetDensity)786 public int getScaledWidth(int targetDensity) { 787 return scaleFromDensity(getWidth(), mDensity, targetDensity); 788 } 789 790 /** 791 * Convenience method that returns the height of this bitmap divided 792 * by the density scale factor. 793 * 794 * @param targetDensity The density of the target canvas of the bitmap. 795 * @return The scaled height of this bitmap, according to the density scale factor. 796 */ getScaledHeight(int targetDensity)797 public int getScaledHeight(int targetDensity) { 798 return scaleFromDensity(getHeight(), mDensity, targetDensity); 799 } 800 801 /** 802 * @hide 803 */ scaleFromDensity(int size, int sdensity, int tdensity)804 static public int scaleFromDensity(int size, int sdensity, int tdensity) { 805 if (sdensity == DENSITY_NONE || sdensity == tdensity) { 806 return size; 807 } 808 809 // Scale by tdensity / sdensity, rounding up. 810 return ((size * tdensity) + (sdensity >> 1)) / sdensity; 811 } 812 813 /** 814 * Return the number of bytes between rows in the bitmap's pixels. Note that 815 * this refers to the pixels as stored natively by the bitmap. If you call 816 * getPixels() or setPixels(), then the pixels are uniformly treated as 817 * 32bit values, packed according to the Color class. 818 * 819 * @return number of bytes between rows of the native bitmap pixels. 820 */ getRowBytes()821 public final int getRowBytes() { 822 return nativeRowBytes(mNativeBitmap); 823 } 824 825 /** 826 * Returns the number of bytes used to store this bitmap's pixels. 827 */ getByteCount()828 public final int getByteCount() { 829 // int result permits bitmaps up to 46,340 x 46,340 830 return getRowBytes() * getHeight(); 831 } 832 833 /** 834 * If the bitmap's internal config is in one of the public formats, return 835 * that config, otherwise return null. 836 */ getConfig()837 public final Config getConfig() { 838 return Config.nativeToConfig(nativeConfig(mNativeBitmap)); 839 } 840 841 /** Returns true if the bitmap's config supports per-pixel alpha, and 842 * if the pixels may contain non-opaque alpha values. For some configs, 843 * this is always false (e.g. RGB_565), since they do not support per-pixel 844 * alpha. However, for configs that do, the bitmap may be flagged to be 845 * known that all of its pixels are opaque. In this case hasAlpha() will 846 * also return false. If a config such as ARGB_8888 is not so flagged, 847 * it will return true by default. 848 */ hasAlpha()849 public final boolean hasAlpha() { 850 return nativeHasAlpha(mNativeBitmap); 851 } 852 853 /** 854 * Tell the bitmap if all of the pixels are known to be opaque (false) 855 * or if some of the pixels may contain non-opaque alpha values (true). 856 * Note, for some configs (e.g. RGB_565) this call is ignored, since it 857 * does not support per-pixel alpha values. 858 * 859 * This is meant as a drawing hint, as in some cases a bitmap that is known 860 * to be opaque can take a faster drawing case than one that may have 861 * non-opaque per-pixel alpha values. 862 */ setHasAlpha(boolean hasAlpha)863 public void setHasAlpha(boolean hasAlpha) { 864 nativeSetHasAlpha(mNativeBitmap, hasAlpha); 865 } 866 867 /** 868 * Fills the bitmap's pixels with the specified {@link Color}. 869 * 870 * @throws IllegalStateException if the bitmap is not mutable. 871 */ eraseColor(int c)872 public void eraseColor(int c) { 873 checkRecycled("Can't erase a recycled bitmap"); 874 if (!isMutable()) { 875 throw new IllegalStateException("cannot erase immutable bitmaps"); 876 } 877 nativeErase(mNativeBitmap, c); 878 } 879 880 /** 881 * Returns the {@link Color} at the specified location. Throws an exception 882 * if x or y are out of bounds (negative or >= to the width or height 883 * respectively). 884 * 885 * @param x The x coordinate (0...width-1) of the pixel to return 886 * @param y The y coordinate (0...height-1) of the pixel to return 887 * @return The argb {@link Color} at the specified coordinate 888 * @throws IllegalArgumentException if x, y exceed the bitmap's bounds 889 */ getPixel(int x, int y)890 public int getPixel(int x, int y) { 891 checkRecycled("Can't call getPixel() on a recycled bitmap"); 892 checkPixelAccess(x, y); 893 return nativeGetPixel(mNativeBitmap, x, y); 894 } 895 896 /** 897 * Returns in pixels[] a copy of the data in the bitmap. Each value is 898 * a packed int representing a {@link Color}. The stride parameter allows 899 * the caller to allow for gaps in the returned pixels array between 900 * rows. For normal packed results, just pass width for the stride value. 901 * 902 * @param pixels The array to receive the bitmap's colors 903 * @param offset The first index to write into pixels[] 904 * @param stride The number of entries in pixels[] to skip between 905 * rows (must be >= bitmap's width). Can be negative. 906 * @param x The x coordinate of the first pixel to read from 907 * the bitmap 908 * @param y The y coordinate of the first pixel to read from 909 * the bitmap 910 * @param width The number of pixels to read from each row 911 * @param height The number of rows to read 912 * @throws IllegalArgumentException if x, y, width, height exceed the 913 * bounds of the bitmap, or if abs(stride) < width. 914 * @throws ArrayIndexOutOfBoundsException if the pixels array is too small 915 * to receive the specified number of pixels. 916 */ getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)917 public void getPixels(int[] pixels, int offset, int stride, 918 int x, int y, int width, int height) { 919 checkRecycled("Can't call getPixels() on a recycled bitmap"); 920 if (width == 0 || height == 0) { 921 return; // nothing to do 922 } 923 checkPixelsAccess(x, y, width, height, offset, stride, pixels); 924 nativeGetPixels(mNativeBitmap, pixels, offset, stride, 925 x, y, width, height); 926 } 927 928 /** 929 * Shared code to check for illegal arguments passed to getPixel() 930 * or setPixel() 931 * @param x x coordinate of the pixel 932 * @param y y coordinate of the pixel 933 */ checkPixelAccess(int x, int y)934 private void checkPixelAccess(int x, int y) { 935 checkXYSign(x, y); 936 if (x >= getWidth()) { 937 throw new IllegalArgumentException("x must be < bitmap.width()"); 938 } 939 if (y >= getHeight()) { 940 throw new IllegalArgumentException("y must be < bitmap.height()"); 941 } 942 } 943 944 /** 945 * Shared code to check for illegal arguments passed to getPixels() 946 * or setPixels() 947 * 948 * @param x left edge of the area of pixels to access 949 * @param y top edge of the area of pixels to access 950 * @param width width of the area of pixels to access 951 * @param height height of the area of pixels to access 952 * @param offset offset into pixels[] array 953 * @param stride number of elements in pixels[] between each logical row 954 * @param pixels array to hold the area of pixels being accessed 955 */ checkPixelsAccess(int x, int y, int width, int height, int offset, int stride, int pixels[])956 private void checkPixelsAccess(int x, int y, int width, int height, 957 int offset, int stride, int pixels[]) { 958 checkXYSign(x, y); 959 if (width < 0) { 960 throw new IllegalArgumentException("width must be >= 0"); 961 } 962 if (height < 0) { 963 throw new IllegalArgumentException("height must be >= 0"); 964 } 965 if (x + width > getWidth()) { 966 throw new IllegalArgumentException( 967 "x + width must be <= bitmap.width()"); 968 } 969 if (y + height > getHeight()) { 970 throw new IllegalArgumentException( 971 "y + height must be <= bitmap.height()"); 972 } 973 if (Math.abs(stride) < width) { 974 throw new IllegalArgumentException("abs(stride) must be >= width"); 975 } 976 int lastScanline = offset + (height - 1) * stride; 977 int length = pixels.length; 978 if (offset < 0 || (offset + width > length) 979 || lastScanline < 0 980 || (lastScanline + width > length)) { 981 throw new ArrayIndexOutOfBoundsException(); 982 } 983 } 984 985 /** 986 * Write the specified {@link Color} into the bitmap (assuming it is 987 * mutable) at the x,y coordinate. 988 * 989 * @param x The x coordinate of the pixel to replace (0...width-1) 990 * @param y The y coordinate of the pixel to replace (0...height-1) 991 * @param color The {@link Color} to write into the bitmap 992 * @throws IllegalStateException if the bitmap is not mutable 993 * @throws IllegalArgumentException if x, y are outside of the bitmap's 994 * bounds. 995 */ setPixel(int x, int y, int color)996 public void setPixel(int x, int y, int color) { 997 checkRecycled("Can't call setPixel() on a recycled bitmap"); 998 if (!isMutable()) { 999 throw new IllegalStateException(); 1000 } 1001 checkPixelAccess(x, y); 1002 nativeSetPixel(mNativeBitmap, x, y, color); 1003 } 1004 1005 /** 1006 * Replace pixels in the bitmap with the colors in the array. Each element 1007 * in the array is a packed int prepresenting a {@link Color} 1008 * 1009 * @param pixels The colors to write to the bitmap 1010 * @param offset The index of the first color to read from pixels[] 1011 * @param stride The number of colors in pixels[] to skip between rows. 1012 * Normally this value will be the same as the width of 1013 * the bitmap, but it can be larger (or negative). 1014 * @param x The x coordinate of the first pixel to write to in 1015 * the bitmap. 1016 * @param y The y coordinate of the first pixel to write to in 1017 * the bitmap. 1018 * @param width The number of colors to copy from pixels[] per row 1019 * @param height The number of rows to write to the bitmap 1020 * @throws IllegalStateException if the bitmap is not mutable 1021 * @throws IllegalArgumentException if x, y, width, height are outside of 1022 * the bitmap's bounds. 1023 * @throws ArrayIndexOutOfBoundsException if the pixels array is too small 1024 * to receive the specified number of pixels. 1025 */ setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)1026 public void setPixels(int[] pixels, int offset, int stride, 1027 int x, int y, int width, int height) { 1028 checkRecycled("Can't call setPixels() on a recycled bitmap"); 1029 if (!isMutable()) { 1030 throw new IllegalStateException(); 1031 } 1032 if (width == 0 || height == 0) { 1033 return; // nothing to do 1034 } 1035 checkPixelsAccess(x, y, width, height, offset, stride, pixels); 1036 nativeSetPixels(mNativeBitmap, pixels, offset, stride, 1037 x, y, width, height); 1038 } 1039 1040 public static final Parcelable.Creator<Bitmap> CREATOR 1041 = new Parcelable.Creator<Bitmap>() { 1042 /** 1043 * Rebuilds a bitmap previously stored with writeToParcel(). 1044 * 1045 * @param p Parcel object to read the bitmap from 1046 * @return a new bitmap created from the data in the parcel 1047 */ 1048 public Bitmap createFromParcel(Parcel p) { 1049 Bitmap bm = nativeCreateFromParcel(p); 1050 if (bm == null) { 1051 throw new RuntimeException("Failed to unparcel Bitmap"); 1052 } 1053 return bm; 1054 } 1055 public Bitmap[] newArray(int size) { 1056 return new Bitmap[size]; 1057 } 1058 }; 1059 1060 /** 1061 * No special parcel contents. 1062 */ describeContents()1063 public int describeContents() { 1064 return 0; 1065 } 1066 1067 /** 1068 * Write the bitmap and its pixels to the parcel. The bitmap can be 1069 * rebuilt from the parcel by calling CREATOR.createFromParcel(). 1070 * @param p Parcel object to write the bitmap data into 1071 */ writeToParcel(Parcel p, int flags)1072 public void writeToParcel(Parcel p, int flags) { 1073 checkRecycled("Can't parcel a recycled bitmap"); 1074 if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) { 1075 throw new RuntimeException("native writeToParcel failed"); 1076 } 1077 } 1078 1079 /** 1080 * Returns a new bitmap that captures the alpha values of the original. 1081 * This may be drawn with Canvas.drawBitmap(), where the color(s) will be 1082 * taken from the paint that is passed to the draw call. 1083 * 1084 * @return new bitmap containing the alpha channel of the original bitmap. 1085 */ extractAlpha()1086 public Bitmap extractAlpha() { 1087 return extractAlpha(null, null); 1088 } 1089 1090 /** 1091 * Returns a new bitmap that captures the alpha values of the original. 1092 * These values may be affected by the optional Paint parameter, which 1093 * can contain its own alpha, and may also contain a MaskFilter which 1094 * could change the actual dimensions of the resulting bitmap (e.g. 1095 * a blur maskfilter might enlarge the resulting bitmap). If offsetXY 1096 * is not null, it returns the amount to offset the returned bitmap so 1097 * that it will logically align with the original. For example, if the 1098 * paint contains a blur of radius 2, then offsetXY[] would contains 1099 * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then 1100 * drawing the original would result in the blur visually aligning with 1101 * the original. 1102 * 1103 * <p>The initial density of the returned bitmap is the same as the original's. 1104 * 1105 * @param paint Optional paint used to modify the alpha values in the 1106 * resulting bitmap. Pass null for default behavior. 1107 * @param offsetXY Optional array that returns the X (index 0) and Y 1108 * (index 1) offset needed to position the returned bitmap 1109 * so that it visually lines up with the original. 1110 * @return new bitmap containing the (optionally modified by paint) alpha 1111 * channel of the original bitmap. This may be drawn with 1112 * Canvas.drawBitmap(), where the color(s) will be taken from the 1113 * paint that is passed to the draw call. 1114 */ extractAlpha(Paint paint, int[] offsetXY)1115 public Bitmap extractAlpha(Paint paint, int[] offsetXY) { 1116 checkRecycled("Can't extractAlpha on a recycled bitmap"); 1117 int nativePaint = paint != null ? paint.mNativePaint : 0; 1118 Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY); 1119 if (bm == null) { 1120 throw new RuntimeException("Failed to extractAlpha on Bitmap"); 1121 } 1122 bm.mDensity = mDensity; 1123 return bm; 1124 } 1125 1126 /** 1127 * Given another bitmap, return true if it has the same dimensions, config, 1128 * and pixel data as this bitmap. If any of those differ, return false. 1129 * If other is null, return false. 1130 */ sameAs(Bitmap other)1131 public boolean sameAs(Bitmap other) { 1132 return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap)); 1133 } 1134 1135 /** 1136 * Rebuilds any caches associated with the bitmap that are used for 1137 * drawing it. In the case of purgeable bitmaps, this call will attempt to 1138 * ensure that the pixels have been decoded. 1139 * If this is called on more than one bitmap in sequence, the priority is 1140 * given in LRU order (i.e. the last bitmap called will be given highest 1141 * priority). 1142 * 1143 * For bitmaps with no associated caches, this call is effectively a no-op, 1144 * and therefore is harmless. 1145 */ prepareToDraw()1146 public void prepareToDraw() { 1147 nativePrepareToDraw(mNativeBitmap); 1148 } 1149 1150 private static class BitmapFinalizer { 1151 private final int mNativeBitmap; 1152 BitmapFinalizer(int nativeBitmap)1153 BitmapFinalizer(int nativeBitmap) { 1154 mNativeBitmap = nativeBitmap; 1155 } 1156 1157 @Override finalize()1158 public void finalize() { 1159 try { 1160 super.finalize(); 1161 } catch (Throwable t) { 1162 // Ignore 1163 } finally { 1164 nativeDestructor(mNativeBitmap); 1165 } 1166 } 1167 } 1168 1169 //////////// native methods 1170 nativeCreate(int[] colors, int offset, int stride, int width, int height, int nativeConfig, boolean mutable)1171 private static native Bitmap nativeCreate(int[] colors, int offset, 1172 int stride, int width, int height, 1173 int nativeConfig, boolean mutable); nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable)1174 private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig, 1175 boolean isMutable); nativeDestructor(int nativeBitmap)1176 private static native void nativeDestructor(int nativeBitmap); nativeRecycle(int nativeBitmap)1177 private static native void nativeRecycle(int nativeBitmap); 1178 nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage)1179 private static native boolean nativeCompress(int nativeBitmap, int format, 1180 int quality, OutputStream stream, 1181 byte[] tempStorage); nativeErase(int nativeBitmap, int color)1182 private static native void nativeErase(int nativeBitmap, int color); nativeWidth(int nativeBitmap)1183 private static native int nativeWidth(int nativeBitmap); nativeHeight(int nativeBitmap)1184 private static native int nativeHeight(int nativeBitmap); nativeRowBytes(int nativeBitmap)1185 private static native int nativeRowBytes(int nativeBitmap); nativeConfig(int nativeBitmap)1186 private static native int nativeConfig(int nativeBitmap); nativeHasAlpha(int nativeBitmap)1187 private static native boolean nativeHasAlpha(int nativeBitmap); 1188 nativeGetPixel(int nativeBitmap, int x, int y)1189 private static native int nativeGetPixel(int nativeBitmap, int x, int y); nativeGetPixels(int nativeBitmap, int[] pixels, int offset, int stride, int x, int y, int width, int height)1190 private static native void nativeGetPixels(int nativeBitmap, int[] pixels, 1191 int offset, int stride, int x, 1192 int y, int width, int height); 1193 nativeSetPixel(int nativeBitmap, int x, int y, int color)1194 private static native void nativeSetPixel(int nativeBitmap, int x, int y, 1195 int color); nativeSetPixels(int nativeBitmap, int[] colors, int offset, int stride, int x, int y, int width, int height)1196 private static native void nativeSetPixels(int nativeBitmap, int[] colors, 1197 int offset, int stride, int x, 1198 int y, int width, int height); nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst)1199 private static native void nativeCopyPixelsToBuffer(int nativeBitmap, 1200 Buffer dst); nativeCopyPixelsFromBuffer(int nb, Buffer src)1201 private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src); nativeGenerationId(int nativeBitmap)1202 private static native int nativeGenerationId(int nativeBitmap); 1203 nativeCreateFromParcel(Parcel p)1204 private static native Bitmap nativeCreateFromParcel(Parcel p); 1205 // returns true on success nativeWriteToParcel(int nativeBitmap, boolean isMutable, int density, Parcel p)1206 private static native boolean nativeWriteToParcel(int nativeBitmap, 1207 boolean isMutable, 1208 int density, 1209 Parcel p); 1210 // returns a new bitmap built from the native bitmap's alpha, and the paint nativeExtractAlpha(int nativeBitmap, int nativePaint, int[] offsetXY)1211 private static native Bitmap nativeExtractAlpha(int nativeBitmap, 1212 int nativePaint, 1213 int[] offsetXY); 1214 nativePrepareToDraw(int nativeBitmap)1215 private static native void nativePrepareToDraw(int nativeBitmap); nativeSetHasAlpha(int nBitmap, boolean hasAlpha)1216 private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha); nativeSameAs(int nb0, int nb1)1217 private static native boolean nativeSameAs(int nb0, int nb1); 1218 ni()1219 /* package */ final int ni() { 1220 return mNativeBitmap; 1221 } 1222 } 1223