1package com.jme3.asset;
2
3import android.graphics.Bitmap;
4import android.graphics.BitmapFactory;
5import android.graphics.Matrix;
6import com.jme3.texture.Image;
7import com.jme3.texture.Image.Format;
8import java.io.IOException;
9import java.io.InputStream;
10
11/**
12  * <code>AndroidImageInfo</code> is set in a jME3 image via the {@link Image#setEfficientData(java.lang.Object)}
13  * method to retrieve a {@link Bitmap} when it is needed by the renderer.
14  * User code may extend <code>AndroidImageInfo</code> and provide their own implementation of the
15  * {@link AndroidImageInfo#loadBitmap()} method to acquire a bitmap by their own means.
16  *
17  * @author Kirill Vainer
18  */
19public class AndroidImageInfo {
20
21    protected AssetInfo assetInfo;
22    protected Bitmap bitmap;
23    protected Format format;
24
25    public AndroidImageInfo(AssetInfo assetInfo) {
26        this.assetInfo = assetInfo;
27    }
28
29    public Bitmap getBitmap(){
30        if (bitmap == null || bitmap.isRecycled()){
31            try {
32                loadBitmap();
33            } catch (IOException ex) {
34                // If called first inside AssetManager, the error will propagate
35                // correctly. Assuming that if the first calls succeeds
36                // then subsequent calls will as well.
37                throw new AssetLoadException("Failed to load image " + assetInfo.getKey(), ex);
38            }
39        }
40        return bitmap;
41    }
42
43
44
45    public Format getFormat(){
46        return format;
47    }
48
49    /**
50     * Loads the bitmap directly from the asset info, possibly updating
51     * or creating the image object.
52     */
53    protected void loadBitmap() throws IOException{
54        InputStream in = null;
55        try {
56            in = assetInfo.openStream();
57            bitmap = BitmapFactory.decodeStream(in);
58            if (bitmap == null) {
59                throw new IOException("Failed to load image: " + assetInfo.getKey().getName());
60            }
61        } finally {
62            if (in != null) {
63                in.close();
64            }
65        }
66
67        switch (bitmap.getConfig()) {
68            case ALPHA_8:
69                format = Image.Format.Alpha8;
70                break;
71            case ARGB_4444:
72                format = Image.Format.ARGB4444;
73                break;
74            case ARGB_8888:
75                format = Image.Format.RGBA8;
76                break;
77            case RGB_565:
78                format = Image.Format.RGB565;
79                break;
80            default:
81                // This should still work as long
82                // as renderer doesn't check format
83                // but just loads bitmap directly.
84                format = null;
85        }
86
87        TextureKey texKey = (TextureKey) assetInfo.getKey();
88        if (texKey.isFlipY()) {
89            // Flip the image, then delete the old one.
90            Matrix flipMat = new Matrix();
91            flipMat.preScale(1.0f, -1.0f);
92            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), flipMat, false);
93            bitmap.recycle();
94            bitmap = newBitmap;
95
96            if (bitmap == null) {
97                throw new IOException("Failed to flip image: " + texKey);
98            }
99        }
100    }
101}
102