001: /**
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: *
027: * This file should be compiled and run using standard j2se.
028: */package com.sun.midp.imageutil;
029:
030: import java.io.*;
031:
032: /**
033: * This class generates raw data from image according to
034: * specified raw format and pixel format.
035: * Supported formats are listed in static formatList array.
036: * To add new supported format one should define new raw or/and
037: * color format constants if needed, update static formatList array,
038: * implement new conversion function byte[] _function_name_(BufferedImage image)
039: * and update imageToByteArray function to support new format.
040: */
041:
042: public class ImageToRawConverter {
043:
044: /** value for invalid format indication */
045: static public final int FORMAT_INVALID = -1;
046: /** Put Pixel raw format */
047: static public final int RAW_FORMAT_PP = 0;
048: /** RGBA raw format */
049: static public final int RAW_FORMAT_ARGB = 1;
050:
051: /** pixel format - 24bit color */
052: static public final int COLOR_FORMAT_888 = 0;
053: /** pixel format - 16bit color */
054: static public final int COLOR_FORMAT_565 = 1;
055:
056: /** int byte order - little-endian */
057: static public final int INT_FORMAT_LITTLE_ENDIAN = 0;
058: /** int byte order - big-endian */
059: static public final int INT_FORMAT_BIG_ENDIAN = 1;
060:
061: /** list of supported pairs raw format - color format */
062: static final int formatList[][] = {
063: { RAW_FORMAT_PP, COLOR_FORMAT_565 },
064: { RAW_FORMAT_ARGB, COLOR_FORMAT_888 } };
065:
066: /** byte sequence that indentifies raw format */
067: static final short[] rawMagic = { 0x89, 'S', 'U', 'N' };
068:
069: /** current raw, color and int formats */
070: protected int rawFormat, colorFormat, intFormat;
071:
072: /**
073: * Defines if format is currently supported.
074: *
075: * @param rawFormat raw format
076: * @param colorFormat color format
077: * @return true if format is supported false otherwise
078: */
079: static public boolean isFormatSupported(int rawFormat,
080: int colorFormat) {
081: for (int i = 0; i < formatList.length; ++i) {
082: if ((formatList[i][0] == rawFormat)
083: && (formatList[i][1] == colorFormat)) {
084: return true;
085: }
086: }
087: return false;
088: }
089:
090: /**
091: * Constructs instance of ImageToRawConverter which will
092: * convert images to raw data in specified here format.
093: * Raw format and color format should be in list of
094: * supported formarts, otherwise IllegalArgumentException
095: * will be thrown.
096: *
097: * @param rawFormat required raw format
098: * @param colorFormat required color format
099: * @param endian required int format
100: * @exception IllegalArgumentException if unsupported format
101: */
102: public ImageToRawConverter(int rawFormat, int colorFormat,
103: int endian) throws IllegalArgumentException {
104: if (!isFormatSupported(rawFormat, colorFormat)) {
105: throw new IllegalArgumentException("invalid format");
106: }
107: this .rawFormat = rawFormat;
108: this .colorFormat = colorFormat;
109: this .intFormat = endian;
110: }
111:
112: /**
113: * Converts image to raw data in byte array.
114: *
115: * @param imageData image pixels in 32bit ARGB format
116: * @param width image width
117: * @param height image height
118: * @param hasAlpha true if image has alpha channel
119: * @return byte[] raw data
120: */
121: public byte[] convertToRaw(int[] imageData, int width, int height,
122: boolean hasAlpha) {
123: if (imageData == null) {
124: throw new IllegalArgumentException(
125: "Source image data is null");
126: }
127:
128: byte[] ret = null;
129: // build raw data
130: if ((rawFormat == RAW_FORMAT_PP)
131: && (colorFormat == COLOR_FORMAT_565)) {
132: ret = imageToPutpixel565(imageData, width, height, hasAlpha);
133: } else if ((rawFormat == RAW_FORMAT_ARGB)
134: && (colorFormat == COLOR_FORMAT_888)) {
135: ret = imageToARGB888(imageData, width, height, hasAlpha);
136: }
137: return ret;
138: }
139:
140: /**
141: * Convert 24bit color to 16bit color
142: * @param x the color in format 8bit-R 8bit-G 8bit-B to convert
143: * @return int 16bit color in format 5bit-R 6bit-G 5bit-B
144: */
145: private short RGB888TORGB565(int x) {
146: return ((short) (((x & 0x00F80000) >> 8)
147: + ((x & 0x0000FC00) >> 5) + ((x & 0x000000F8) >> 3)));
148: }
149:
150: /**
151: * Converts image to PutPixel raw format, 16bit color format, big-endian.
152: * Output byte array represents the following c-struct:
153: * typedef struct {
154: * byte header[4]; // Must equal RAW_HEADER
155: * int32 width;
156: * int32 height;
157: * int32 hasAlpha;
158: * byte data[1]; // variable length byte array
159: * } MIDP_IMAGE_BUFFER_RAW;
160: * where RAW image file header
161: * const byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
162: * and data array consists of image pixel array - 16bit per pixel,
163: * RGB(5, 6, 5) - and following alpha channel array if any - 8bit per pixel
164: *
165: * @param imageData image pixels in 32 bit ARGB format
166: * @param width image width
167: * @param height image height
168: * @param hasAlpha true if the image has alpha channel
169: * @return byte[] raw data in PutPixel raw format and 16bit color format
170: */
171: private byte[] imageToPutpixel565(int[] imageData, int width,
172: int height, boolean hasAlpha) {
173: hasAlpha = reallyHasAlpha(imageData);
174:
175: // sizeof resulting raw buffer =
176: // sizeof(RAW_HEADER) +
177: // sizeof(MIDP_IMAGE_BUFFER_RAW.width) +
178: // sizeof(MIDP_IMAGE_BUFFER_RAW.height) +
179: // sizeof(MIDP_IMAGE_BUFFER_RAW.hasAlpha) +
180: // sizeof(pixe_l565) * image_pixel_count +
181: // (hasAlpha ? alpha_size * image_pixel_count : 0)
182:
183: int rawsz = 4 + 4 + 4 + 4 + 2 * imageData.length;
184: int dataOffset = 4 + 4 + 4 + 4;
185: int alphaOffset = rawsz;
186: if (hasAlpha)
187: rawsz += 1 * imageData.length;
188:
189: byte[] rawData = new byte[rawsz];
190:
191: fillRawHeader(rawData, width, height, hasAlpha);
192:
193: for (int i = 0; i < imageData.length; ++i) {
194: short val = RGB888TORGB565(imageData[i]);
195: storeValue(rawData, dataOffset + i * 2, val, intFormat);
196: if (hasAlpha) {
197: rawData[alphaOffset + i] = (byte) ((imageData[i] >> 24) & 0xFF);
198: }
199: }
200:
201: return rawData;
202: }
203:
204: /**
205: * Converts image to ARGB with 24bits per pixel in big-endian.
206: * Output byte array represents the following c-struct:
207: * typedef struct {
208: * byte header[4]; // Must equal RAW_HEADER
209: * int32 width;
210: * int32 height;
211: * int32 hasAlpha;
212: * byte data[1]; // variable length byte array
213: * } MIDP_IMAGE_BUFFER_RAW;
214: * where RAW image file header
215: * const byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
216: * and data array consists of image pixel array - 24bit per pixel,
217: * RGBA(8, 8, 8, 8)
218: *
219: * @param imageData image pixels in 32 bit ARGB format
220: * @param width image width
221: * @param height image height
222: * @param hasAlpha true if the image has alpha channel
223: * @return byte[] raw data in RGBA format
224: */
225: private byte[] imageToARGB888(int[] imageData, int width,
226: int height, boolean hasAlpha) {
227: hasAlpha = reallyHasAlpha(imageData);
228:
229: // sizeof resulting raw buffer =
230: // sizeof(RAW_HEADER) +
231: // sizeof(MIDP_IMAGE_BUFFER_RAW.width) +
232: // sizeof(MIDP_IMAGE_BUFFER_RAW.height) +
233: // sizeof(MIDP_IMAGE_BUFFER_RAW.hasAlpha) +
234: // sizeof(pixe_l565) * image_pixel_count +
235: // (hasAlpha ? alpha_size * image_pixel_count : 0)
236:
237: int rawsz = 4 + 4 + 4 + 4 + 4 * imageData.length;
238: int dataOffset = 4 + 4 + 4 + 4;
239:
240: byte[] rawData = new byte[rawsz];
241:
242: fillRawHeader(rawData, width, height, hasAlpha);
243:
244: for (int i = 0; i < imageData.length; ++i) {
245: // write ARGB
246: storeValue(rawData, dataOffset + i * 4, imageData[i],
247: intFormat);
248: }
249:
250: return rawData;
251:
252: }
253:
254: /**
255: * Fills byte array with raw header
256: * byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
257: * int32 width;
258: * int32 height;
259: * int32 hasAlpha;
260: *
261: * @param rawData byte array to fill header for, length of that
262: * array must be greater than 16, otherwise function fails
263: * (returns false)
264: * @param width width of the image
265: * @param height height of the image
266: * @param hasAlpha if image has alpha channel
267: */
268: void fillRawHeader(byte[] rawData, int width, int height,
269: boolean hasAlpha) {
270: int magicLength = rawMagic.length;
271: for (int i = 0; i < magicLength; ++i) {
272: rawData[i] = (byte) (rawMagic[i] & 0xFF);
273: }
274:
275: storeValue(rawData, magicLength, width, intFormat);
276: storeValue(rawData, magicLength + 4, height, intFormat);
277: storeValue(rawData, magicLength + 8, (int) (hasAlpha ? 1 : 0),
278: intFormat);
279: }
280:
281: /**
282: * writes int to byte array at specified position
283: * in big- or little- endian.
284: *
285: * @param data target byte array
286: * @param offset offset in byte array
287: * @param value source integer
288: * @param endian endian type
289: */
290: private static void storeValue(byte[] data, int offset, int value,
291: int endian) {
292: if (endian == INT_FORMAT_BIG_ENDIAN) {
293: data[offset + 0] = (byte) ((value >> 24) & 0xFF);
294: data[offset + 1] = (byte) ((value >> 16) & 0xFF);
295: data[offset + 2] = (byte) ((value >> 8) & 0xFF);
296: data[offset + 3] = (byte) (value & 0xFF);
297: } else {
298: data[offset + 0] = (byte) (value & 0xFF);
299: data[offset + 1] = (byte) ((value >> 8) & 0xFF);
300: data[offset + 2] = (byte) ((value >> 16) & 0xFF);
301: data[offset + 3] = (byte) ((value >> 24) & 0xFF);
302: }
303: }
304:
305: /**
306: * writes short to byte array at specified position
307: * in big- or little- endian.
308: *
309: * @param data target byte array
310: * @param offset offset in byte array
311: * @param value source integer
312: * @param endian endian type
313: */
314: private static void storeValue(byte[] data, int offset,
315: short value, int endian) {
316: if (endian == INT_FORMAT_BIG_ENDIAN) {
317: data[offset + 0] = (byte) ((value >> 8) & 0xFF);
318: data[offset + 1] = (byte) (value & 0xFF);
319: } else {
320: data[offset + 0] = (byte) (value & 0xFF);
321: data[offset + 1] = (byte) ((value >> 8) & 0xFF);
322: }
323: }
324:
325: /**
326: * Checks if the image that supposely has alpha channel really
327: * has it, i.e there is at least one non opaque pixel.
328: *
329: * @param imageData image data in 32 bits ARGB format
330: * @return true if the image really has alpha channel
331: */
332: private static boolean reallyHasAlpha(int[] imageData) {
333: boolean hasAlpha = false;
334: for (int i = 0; i < imageData.length; ++i) {
335: if ((imageData[i] & 0xFF000000) != 0xFF000000) {
336: hasAlpha = true;
337: break;
338: }
339: }
340:
341: return hasAlpha;
342: }
343: }
|