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 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 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 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 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 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 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