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