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