1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.texture.plugins;
34 
35 import com.jme3.asset.AssetInfo;
36 import com.jme3.asset.AssetLoadException;
37 import com.jme3.asset.AssetLoader;
38 import com.jme3.asset.TextureKey;
39 import com.jme3.texture.Image;
40 import com.jme3.texture.Image.Format;
41 import com.jme3.util.BufferUtils;
42 import java.awt.Transparency;
43 import java.awt.color.ColorSpace;
44 import java.awt.image.*;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.nio.ByteBuffer;
48 import javax.imageio.ImageIO;
49 
50 public class AWTLoader implements AssetLoader {
51 
52     public static final ColorModel AWT_RGBA4444 = new DirectColorModel(16,
53                                                                        0xf000,
54                                                                        0x0f00,
55                                                                        0x00f0,
56                                                                        0x000f);
57 
58     public static final ColorModel AWT_RGBA5551
59             = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
60                                       new int[]{5, 5, 5, 1},
61                                       true,
62                                       false,
63                                       Transparency.BITMASK,
64                                       DataBuffer.TYPE_BYTE);
65 
extractImageData(BufferedImage img)66     private Object extractImageData(BufferedImage img){
67         DataBuffer buf = img.getRaster().getDataBuffer();
68         switch (buf.getDataType()){
69             case DataBuffer.TYPE_BYTE:
70                 DataBufferByte byteBuf = (DataBufferByte) buf;
71                 return byteBuf.getData();
72             case DataBuffer.TYPE_USHORT:
73                 DataBufferUShort shortBuf = (DataBufferUShort) buf;
74                 return shortBuf.getData();
75         }
76         return null;
77     }
78 
flipImage(byte[] img, int width, int height, int bpp)79     private void flipImage(byte[] img, int width, int height, int bpp){
80         int scSz = (width * bpp) / 8;
81         byte[] sln = new byte[scSz];
82         int y2 = 0;
83         for (int y1 = 0; y1 < height / 2; y1++){
84             y2 = height - y1 - 1;
85             System.arraycopy(img, y1 * scSz, sln, 0,         scSz);
86             System.arraycopy(img, y2 * scSz, img, y1 * scSz, scSz);
87             System.arraycopy(sln, 0,         img, y2 * scSz, scSz);
88         }
89     }
90 
flipImage(short[] img, int width, int height, int bpp)91     private void flipImage(short[] img, int width, int height, int bpp){
92         int scSz = (width * bpp) / 8;
93         scSz /= 2; // Because shorts are 2 bytes
94         short[] sln = new short[scSz];
95         int y2 = 0;
96         for (int y1 = 0; y1 < height / 2; y1++){
97             y2 = height - y1 - 1;
98             System.arraycopy(img, y1 * scSz, sln, 0,         scSz);
99             System.arraycopy(img, y2 * scSz, img, y1 * scSz, scSz);
100             System.arraycopy(sln, 0,         img, y2 * scSz, scSz);
101         }
102     }
103 
load(BufferedImage img, boolean flipY)104     public Image load(BufferedImage img, boolean flipY){
105         int width = img.getWidth();
106         int height = img.getHeight();
107 
108         switch (img.getType()){
109             case BufferedImage.TYPE_4BYTE_ABGR: // most common in PNG images w/ alpha
110                byte[] dataBuf1 = (byte[]) extractImageData(img);
111                if (flipY)
112                    flipImage(dataBuf1, width, height, 32);
113 
114                ByteBuffer data1 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4);
115                data1.put(dataBuf1);
116                return new Image(Format.ABGR8, width, height, data1);
117             case BufferedImage.TYPE_3BYTE_BGR: // most common in JPEG images
118                byte[] dataBuf2 = (byte[]) extractImageData(img);
119                if (flipY)
120                    flipImage(dataBuf2, width, height, 24);
121 
122                ByteBuffer data2 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*3);
123                data2.put(dataBuf2);
124                return new Image(Format.BGR8, width, height, data2);
125             case BufferedImage.TYPE_BYTE_GRAY: // grayscale fonts
126                 byte[] dataBuf3 = (byte[]) extractImageData(img);
127                 if (flipY)
128                     flipImage(dataBuf3, width, height, 8);
129                 ByteBuffer data3 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight());
130                 data3.put(dataBuf3);
131                 return new Image(Format.Luminance8, width, height, data3);
132             case BufferedImage.TYPE_USHORT_GRAY: // grayscale heightmap
133                 short[] dataBuf4 = (short[]) extractImageData(img);
134                 if (flipY)
135                     flipImage(dataBuf4, width, height, 16);
136 
137                 ByteBuffer data4 = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*2);
138                 data4.asShortBuffer().put(dataBuf4);
139                 return new Image(Format.Luminance16, width, height, data4);
140             default:
141                 break;
142         }
143 
144         if (img.getTransparency() == Transparency.OPAQUE){
145             ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*3);
146             // no alpha
147             for (int y = 0; y < height; y++){
148                 for (int x = 0; x < width; x++){
149                     int ny = y;
150                     if (flipY){
151                         ny = height - y - 1;
152                     }
153 
154                     int rgb = img.getRGB(x,ny);
155                     byte r = (byte) ((rgb & 0x00FF0000) >> 16);
156                     byte g = (byte) ((rgb & 0x0000FF00) >> 8);
157                     byte b = (byte) ((rgb & 0x000000FF));
158                     data.put(r).put(g).put(b);
159                 }
160             }
161             data.flip();
162             return new Image(Format.RGB8, width, height, data);
163         }else{
164             ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth()*img.getHeight()*4);
165             // no alpha
166             for (int y = 0; y < height; y++){
167                 for (int x = 0; x < width; x++){
168                     int ny = y;
169                     if (flipY){
170                         ny = height - y - 1;
171                     }
172 
173                     int rgb = img.getRGB(x,ny);
174                     byte a = (byte) ((rgb & 0xFF000000) >> 24);
175                     byte r = (byte) ((rgb & 0x00FF0000) >> 16);
176                     byte g = (byte) ((rgb & 0x0000FF00) >> 8);
177                     byte b = (byte) ((rgb & 0x000000FF));
178                     data.put(r).put(g).put(b).put(a);
179                 }
180             }
181             data.flip();
182             return new Image(Format.RGBA8, width, height, data);
183         }
184     }
185 
load(InputStream in, boolean flipY)186     public Image load(InputStream in, boolean flipY) throws IOException{
187         ImageIO.setUseCache(false);
188         BufferedImage img = ImageIO.read(in);
189         if (img == null){
190             return null;
191         }
192         return load(img, flipY);
193     }
194 
load(AssetInfo info)195     public Object load(AssetInfo info) throws IOException {
196         if (ImageIO.getImageReadersBySuffix(info.getKey().getExtension()) != null){
197             boolean flip = ((TextureKey) info.getKey()).isFlipY();
198             InputStream in = null;
199             try {
200                 in = info.openStream();
201                 Image img = load(in, flip);
202                 if (img == null){
203                     throw new AssetLoadException("The given image cannot be loaded " + info.getKey());
204                 }
205                 return img;
206             } finally {
207                 if (in != null){
208                     in.close();
209                 }
210             }
211         }else{
212             throw new AssetLoadException("The extension " + info.getKey().getExtension() + " is not supported");
213         }
214     }
215 }
216