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