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