1 /* 2 * Copyright (C) 2010 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 com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.layoutlib.bridge.Bridge; 21 import com.android.layoutlib.bridge.impl.DelegateManager; 22 import com.android.resources.Density; 23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25 import android.graphics.Bitmap.Config; 26 import android.os.Parcel; 27 28 import java.awt.Graphics2D; 29 import java.awt.image.BufferedImage; 30 import java.io.File; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.OutputStream; 34 import java.nio.Buffer; 35 import java.util.Arrays; 36 import java.util.EnumSet; 37 import java.util.Set; 38 39 import javax.imageio.ImageIO; 40 41 /** 42 * Delegate implementing the native methods of android.graphics.Bitmap 43 * 44 * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced 45 * by calls to methods of the same name in this delegate class. 46 * 47 * This class behaves like the original native implementation, but in Java, keeping previously 48 * native data into its own objects and mapping them to int that are sent back and forth between 49 * it and the original Bitmap class. 50 * 51 * @see DelegateManager 52 * 53 */ 54 public final class Bitmap_Delegate { 55 56 57 public enum BitmapCreateFlags { 58 PREMULTIPLIED, MUTABLE 59 } 60 61 // ---- delegate manager ---- 62 private static final DelegateManager<Bitmap_Delegate> sManager = 63 new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class); 64 65 // ---- delegate helper data ---- 66 67 // ---- delegate data ---- 68 private final Config mConfig; 69 private BufferedImage mImage; 70 private boolean mHasAlpha = true; 71 private boolean mHasMipMap = false; // TODO: check the default. 72 private boolean mIsPremultiplied = true; 73 private int mGenerationId = 0; 74 75 76 // ---- Public Helper methods ---- 77 78 /** 79 * Returns the native delegate associated to a given {@link Bitmap_Delegate} object. 80 */ getDelegate(Bitmap bitmap)81 public static Bitmap_Delegate getDelegate(Bitmap bitmap) { 82 return sManager.getDelegate(bitmap.mNativeBitmap); 83 } 84 85 /** 86 * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object. 87 */ getDelegate(long native_bitmap)88 public static Bitmap_Delegate getDelegate(long native_bitmap) { 89 return sManager.getDelegate(native_bitmap); 90 } 91 92 /** 93 * Creates and returns a {@link Bitmap} initialized with the given file content. 94 * 95 * @param input the file from which to read the bitmap content 96 * @param isMutable whether the bitmap is mutable 97 * @param density the density associated with the bitmap 98 * 99 * @see Bitmap#isMutable() 100 * @see Bitmap#getDensity() 101 */ createBitmap(File input, boolean isMutable, Density density)102 public static Bitmap createBitmap(File input, boolean isMutable, Density density) 103 throws IOException { 104 return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density); 105 } 106 107 /** 108 * Creates and returns a {@link Bitmap} initialized with the given file content. 109 * 110 * @param input the file from which to read the bitmap content 111 * @param density the density associated with the bitmap 112 * 113 * @see Bitmap#isPremultiplied() 114 * @see Bitmap#isMutable() 115 * @see Bitmap#getDensity() 116 */ createBitmap(File input, Set<BitmapCreateFlags> createFlags, Density density)117 public static Bitmap createBitmap(File input, Set<BitmapCreateFlags> createFlags, 118 Density density) throws IOException { 119 // create a delegate with the content of the file. 120 Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888); 121 122 return createBitmap(delegate, createFlags, density.getDpiValue()); 123 } 124 125 /** 126 * Creates and returns a {@link Bitmap} initialized with the given stream content. 127 * 128 * @param input the stream from which to read the bitmap content 129 * @param isMutable whether the bitmap is mutable 130 * @param density the density associated with the bitmap 131 * 132 * @see Bitmap#isMutable() 133 * @see Bitmap#getDensity() 134 */ createBitmap(InputStream input, boolean isMutable, Density density)135 public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density) 136 throws IOException { 137 return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density); 138 } 139 140 /** 141 * Creates and returns a {@link Bitmap} initialized with the given stream content. 142 * 143 * @param input the stream from which to read the bitmap content 144 * @param density the density associated with the bitmap 145 * 146 * @see Bitmap#isPremultiplied() 147 * @see Bitmap#isMutable() 148 * @see Bitmap#getDensity() 149 */ createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags, Density density)150 public static Bitmap createBitmap(InputStream input, Set<BitmapCreateFlags> createFlags, 151 Density density) throws IOException { 152 // create a delegate with the content of the stream. 153 Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888); 154 155 return createBitmap(delegate, createFlags, density.getDpiValue()); 156 } 157 158 /** 159 * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage} 160 * 161 * @param image the bitmap content 162 * @param isMutable whether the bitmap is mutable 163 * @param density the density associated with the bitmap 164 * 165 * @see Bitmap#isMutable() 166 * @see Bitmap#getDensity() 167 */ createBitmap(BufferedImage image, boolean isMutable, Density density)168 public static Bitmap createBitmap(BufferedImage image, boolean isMutable, Density density) { 169 return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density); 170 } 171 172 /** 173 * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage} 174 * 175 * @param image the bitmap content 176 * @param density the density associated with the bitmap 177 * 178 * @see Bitmap#isPremultiplied() 179 * @see Bitmap#isMutable() 180 * @see Bitmap#getDensity() 181 */ createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags, Density density)182 public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags, 183 Density density) { 184 // create a delegate with the given image. 185 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888); 186 187 return createBitmap(delegate, createFlags, density.getDpiValue()); 188 } 189 190 /** 191 * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}. 192 */ getImage(Bitmap bitmap)193 public static BufferedImage getImage(Bitmap bitmap) { 194 // get the delegate from the native int. 195 Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap); 196 if (delegate == null) { 197 return null; 198 } 199 200 return delegate.mImage; 201 } 202 getBufferedImageType(int nativeBitmapConfig)203 public static int getBufferedImageType(int nativeBitmapConfig) { 204 switch (Config.nativeToConfig(nativeBitmapConfig)) { 205 case ALPHA_8: 206 return BufferedImage.TYPE_INT_ARGB; 207 case RGB_565: 208 return BufferedImage.TYPE_INT_ARGB; 209 case ARGB_4444: 210 return BufferedImage.TYPE_INT_ARGB; 211 case ARGB_8888: 212 return BufferedImage.TYPE_INT_ARGB; 213 } 214 215 return BufferedImage.TYPE_INT_ARGB; 216 } 217 218 /** 219 * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}. 220 */ getImage()221 public BufferedImage getImage() { 222 return mImage; 223 } 224 225 /** 226 * Returns the Android bitmap config. Note that this not the config of the underlying 227 * Java2D bitmap. 228 */ getConfig()229 public Config getConfig() { 230 return mConfig; 231 } 232 233 /** 234 * Returns the hasAlpha rendering hint 235 * @return true if the bitmap alpha should be used at render time 236 */ hasAlpha()237 public boolean hasAlpha() { 238 return mHasAlpha && mConfig != Config.RGB_565; 239 } 240 hasMipMap()241 public boolean hasMipMap() { 242 // TODO: check if more checks are required as in hasAlpha. 243 return mHasMipMap; 244 } 245 /** 246 * Update the generationId. 247 * 248 * @see Bitmap#getGenerationId() 249 */ change()250 public void change() { 251 mGenerationId++; 252 } 253 254 // ---- native methods ---- 255 256 @LayoutlibDelegate nativeCreate(int[] colors, int offset, int stride, int width, int height, int nativeConfig, boolean isMutable)257 /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width, 258 int height, int nativeConfig, boolean isMutable) { 259 int imageType = getBufferedImageType(nativeConfig); 260 261 // create the image 262 BufferedImage image = new BufferedImage(width, height, imageType); 263 264 if (colors != null) { 265 image.setRGB(0, 0, width, height, colors, offset, stride); 266 } 267 268 // create a delegate with the content of the stream. 269 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig)); 270 271 return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable), 272 Bitmap.getDefaultDensity()); 273 } 274 275 @LayoutlibDelegate nativeCopy(long srcBitmap, int nativeConfig, boolean isMutable)276 /*package*/ static Bitmap nativeCopy(long srcBitmap, int nativeConfig, boolean isMutable) { 277 Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap); 278 if (srcBmpDelegate == null) { 279 return null; 280 } 281 282 BufferedImage srcImage = srcBmpDelegate.getImage(); 283 284 int width = srcImage.getWidth(); 285 int height = srcImage.getHeight(); 286 287 int imageType = getBufferedImageType(nativeConfig); 288 289 // create the image 290 BufferedImage image = new BufferedImage(width, height, imageType); 291 292 // copy the source image into the image. 293 int[] argb = new int[width * height]; 294 srcImage.getRGB(0, 0, width, height, argb, 0, width); 295 image.setRGB(0, 0, width, height, argb, 0, width); 296 297 // create a delegate with the content of the stream. 298 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig)); 299 300 return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable), 301 Bitmap.getDefaultDensity()); 302 } 303 304 @LayoutlibDelegate nativeDestructor(long nativeBitmap)305 /*package*/ static void nativeDestructor(long nativeBitmap) { 306 sManager.removeJavaReferenceFor(nativeBitmap); 307 } 308 309 @LayoutlibDelegate nativeRecycle(long nativeBitmap)310 /*package*/ static boolean nativeRecycle(long nativeBitmap) { 311 sManager.removeJavaReferenceFor(nativeBitmap); 312 return true; 313 } 314 315 @LayoutlibDelegate nativeReconfigure(long nativeBitmap, int width, int height, int config, int allocSize, boolean isPremultiplied)316 /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height, 317 int config, int allocSize, boolean isPremultiplied) { 318 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 319 "Bitmap.reconfigure() is not supported", null /*data*/); 320 } 321 322 @LayoutlibDelegate nativeCompress(long nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage)323 /*package*/ static boolean nativeCompress(long nativeBitmap, int format, int quality, 324 OutputStream stream, byte[] tempStorage) { 325 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 326 "Bitmap.compress() is not supported", null /*data*/); 327 return true; 328 } 329 330 @LayoutlibDelegate nativeErase(long nativeBitmap, int color)331 /*package*/ static void nativeErase(long nativeBitmap, int color) { 332 // get the delegate from the native int. 333 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 334 if (delegate == null) { 335 return; 336 } 337 338 BufferedImage image = delegate.mImage; 339 340 Graphics2D g = image.createGraphics(); 341 try { 342 g.setColor(new java.awt.Color(color, true)); 343 344 g.fillRect(0, 0, image.getWidth(), image.getHeight()); 345 } finally { 346 g.dispose(); 347 } 348 } 349 350 @LayoutlibDelegate nativeRowBytes(long nativeBitmap)351 /*package*/ static int nativeRowBytes(long nativeBitmap) { 352 // get the delegate from the native int. 353 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 354 if (delegate == null) { 355 return 0; 356 } 357 358 return delegate.mImage.getWidth(); 359 } 360 361 @LayoutlibDelegate nativeConfig(long nativeBitmap)362 /*package*/ static int nativeConfig(long nativeBitmap) { 363 // get the delegate from the native int. 364 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 365 if (delegate == null) { 366 return 0; 367 } 368 369 return delegate.mConfig.nativeInt; 370 } 371 372 @LayoutlibDelegate nativeHasAlpha(long nativeBitmap)373 /*package*/ static boolean nativeHasAlpha(long nativeBitmap) { 374 // get the delegate from the native int. 375 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 376 if (delegate == null) { 377 return true; 378 } 379 380 return delegate.mHasAlpha; 381 } 382 383 @LayoutlibDelegate nativeHasMipMap(long nativeBitmap)384 /*package*/ static boolean nativeHasMipMap(long nativeBitmap) { 385 // get the delegate from the native int. 386 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 387 if (delegate == null) { 388 return true; 389 } 390 391 return delegate.mHasMipMap; 392 } 393 394 @LayoutlibDelegate nativeGetPixel(long nativeBitmap, int x, int y)395 /*package*/ static int nativeGetPixel(long nativeBitmap, int x, int y) { 396 // get the delegate from the native int. 397 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 398 if (delegate == null) { 399 return 0; 400 } 401 402 return delegate.mImage.getRGB(x, y); 403 } 404 405 @LayoutlibDelegate nativeGetPixels(long nativeBitmap, int[] pixels, int offset, int stride, int x, int y, int width, int height)406 /*package*/ static void nativeGetPixels(long nativeBitmap, int[] pixels, int offset, 407 int stride, int x, int y, int width, int height) { 408 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 409 if (delegate == null) { 410 return; 411 } 412 413 delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride); 414 } 415 416 417 @LayoutlibDelegate nativeSetPixel(long nativeBitmap, int x, int y, int color)418 /*package*/ static void nativeSetPixel(long nativeBitmap, int x, int y, int color) { 419 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 420 if (delegate == null) { 421 return; 422 } 423 424 delegate.getImage().setRGB(x, y, color); 425 } 426 427 @LayoutlibDelegate nativeSetPixels(long nativeBitmap, int[] colors, int offset, int stride, int x, int y, int width, int height)428 /*package*/ static void nativeSetPixels(long nativeBitmap, int[] colors, int offset, 429 int stride, int x, int y, int width, int height) { 430 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 431 if (delegate == null) { 432 return; 433 } 434 435 delegate.getImage().setRGB(x, y, width, height, colors, offset, stride); 436 } 437 438 @LayoutlibDelegate nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst)439 /*package*/ static void nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst) { 440 // FIXME implement native delegate 441 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 442 "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/); 443 } 444 445 @LayoutlibDelegate nativeCopyPixelsFromBuffer(long nb, Buffer src)446 /*package*/ static void nativeCopyPixelsFromBuffer(long nb, Buffer src) { 447 // FIXME implement native delegate 448 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 449 "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/); 450 } 451 452 @LayoutlibDelegate nativeGenerationId(long nativeBitmap)453 /*package*/ static int nativeGenerationId(long nativeBitmap) { 454 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 455 if (delegate == null) { 456 return 0; 457 } 458 459 return delegate.mGenerationId; 460 } 461 462 @LayoutlibDelegate nativeCreateFromParcel(Parcel p)463 /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) { 464 // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only 465 // used during aidl call so really this should not be called. 466 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 467 "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.", 468 null /*data*/); 469 return null; 470 } 471 472 @LayoutlibDelegate nativeWriteToParcel(long nativeBitmap, boolean isMutable, int density, Parcel p)473 /*package*/ static boolean nativeWriteToParcel(long nativeBitmap, boolean isMutable, 474 int density, Parcel p) { 475 // This is only called when sending a bitmap through aidl, so really this should not 476 // be called. 477 Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 478 "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.", 479 null /*data*/); 480 return false; 481 } 482 483 @LayoutlibDelegate nativeExtractAlpha(long nativeBitmap, long nativePaint, int[] offsetXY)484 /*package*/ static Bitmap nativeExtractAlpha(long nativeBitmap, long nativePaint, 485 int[] offsetXY) { 486 Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap); 487 if (bitmap == null) { 488 return null; 489 } 490 491 // get the paint which can be null if nativePaint is 0. 492 Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint); 493 494 if (paint != null && paint.getMaskFilter() != null) { 495 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, 496 "MaskFilter not supported in Bitmap.extractAlpha", 497 null, null /*data*/); 498 } 499 500 int alpha = paint != null ? paint.getAlpha() : 0xFF; 501 BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha); 502 503 // create the delegate. The actual Bitmap config is only an alpha channel 504 Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8); 505 506 // the density doesn't matter, it's set by the Java method. 507 return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.MUTABLE), 508 Density.DEFAULT_DENSITY /*density*/); 509 } 510 511 @LayoutlibDelegate nativePrepareToDraw(long nativeBitmap)512 /*package*/ static void nativePrepareToDraw(long nativeBitmap) { 513 // nothing to be done here. 514 } 515 516 @LayoutlibDelegate nativeIsPremultiplied(long nativeBitmap)517 /*package*/ static boolean nativeIsPremultiplied(long nativeBitmap) { 518 // get the delegate from the native int. 519 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 520 return delegate != null && delegate.mIsPremultiplied; 521 522 } 523 524 @LayoutlibDelegate nativeSetPremultiplied(long nativeBitmap, boolean isPremul)525 /*package*/ static void nativeSetPremultiplied(long nativeBitmap, boolean isPremul) { 526 // get the delegate from the native int. 527 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 528 if (delegate == null) { 529 return; 530 } 531 532 delegate.mIsPremultiplied = isPremul; 533 } 534 535 @LayoutlibDelegate nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha, boolean isPremul)536 /*package*/ static void nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha, 537 boolean isPremul) { 538 // get the delegate from the native int. 539 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 540 if (delegate == null) { 541 return; 542 } 543 544 delegate.mHasAlpha = hasAlpha; 545 } 546 547 @LayoutlibDelegate nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap)548 /*package*/ static void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap) { 549 // get the delegate from the native int. 550 Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap); 551 if (delegate == null) { 552 return; 553 } 554 555 delegate.mHasMipMap = hasMipMap; 556 } 557 558 @LayoutlibDelegate nativeSameAs(long nb0, long nb1)559 /*package*/ static boolean nativeSameAs(long nb0, long nb1) { 560 Bitmap_Delegate delegate1 = sManager.getDelegate(nb0); 561 if (delegate1 == null) { 562 return false; 563 } 564 565 Bitmap_Delegate delegate2 = sManager.getDelegate(nb1); 566 if (delegate2 == null) { 567 return false; 568 } 569 570 BufferedImage image1 = delegate1.getImage(); 571 BufferedImage image2 = delegate2.getImage(); 572 if (delegate1.mConfig != delegate2.mConfig || 573 image1.getWidth() != image2.getWidth() || 574 image1.getHeight() != image2.getHeight()) { 575 return false; 576 } 577 578 // get the internal data 579 int w = image1.getWidth(); 580 int h = image2.getHeight(); 581 int[] argb1 = new int[w*h]; 582 int[] argb2 = new int[w*h]; 583 584 image1.getRGB(0, 0, w, h, argb1, 0, w); 585 image2.getRGB(0, 0, w, h, argb2, 0, w); 586 587 // compares 588 if (delegate1.mConfig == Config.ALPHA_8) { 589 // in this case we have to manually compare the alpha channel as the rest is garbage. 590 final int length = w*h; 591 for (int i = 0 ; i < length ; i++) { 592 if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) { 593 return false; 594 } 595 } 596 return true; 597 } 598 599 return Arrays.equals(argb1, argb2); 600 } 601 602 // ---- Private delegate/helper methods ---- 603 Bitmap_Delegate(BufferedImage image, Config config)604 private Bitmap_Delegate(BufferedImage image, Config config) { 605 mImage = image; 606 mConfig = config; 607 } 608 createBitmap(Bitmap_Delegate delegate, Set<BitmapCreateFlags> createFlags, int density)609 private static Bitmap createBitmap(Bitmap_Delegate delegate, 610 Set<BitmapCreateFlags> createFlags, int density) { 611 // get its native_int 612 long nativeInt = sManager.addNewDelegate(delegate); 613 614 int width = delegate.mImage.getWidth(); 615 int height = delegate.mImage.getHeight(); 616 boolean isMutable = createFlags.contains(BitmapCreateFlags.MUTABLE); 617 boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED); 618 619 // and create/return a new Bitmap with it 620 return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable, 621 isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */); 622 } 623 getPremultipliedBitmapCreateFlags(boolean isMutable)624 private static Set<BitmapCreateFlags> getPremultipliedBitmapCreateFlags(boolean isMutable) { 625 Set<BitmapCreateFlags> createFlags = EnumSet.of(BitmapCreateFlags.PREMULTIPLIED); 626 if (isMutable) { 627 createFlags.add(BitmapCreateFlags.MUTABLE); 628 } 629 return createFlags; 630 } 631 632 /** 633 * Creates and returns a copy of a given BufferedImage. 634 * <p/> 635 * if alpha is different than 255, then it is applied to the alpha channel of each pixel. 636 * 637 * @param image the image to copy 638 * @param imageType the type of the new image 639 * @param alpha an optional alpha modifier 640 * @return a new BufferedImage 641 */ createCopy(BufferedImage image, int imageType, int alpha)642 /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) { 643 int w = image.getWidth(); 644 int h = image.getHeight(); 645 646 BufferedImage result = new BufferedImage(w, h, imageType); 647 648 int[] argb = new int[w * h]; 649 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); 650 651 if (alpha != 255) { 652 final int length = argb.length; 653 for (int i = 0 ; i < length; i++) { 654 int a = (argb[i] >>> 24 * alpha) / 255; 655 argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF); 656 } 657 } 658 659 result.setRGB(0, 0, w, h, argb, 0, w); 660 661 return result; 662 } 663 664 } 665