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