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