/**
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*
* This file should be compiled and run using standard j2se.
*/
package com.sun.midp.imageutil;
import java.io.*;
/**
* This class generates raw data from image according to
* specified raw format and pixel format.
* Supported formats are listed in static formatList array.
* To add new supported format one should define new raw or/and
* color format constants if needed, update static formatList array,
* implement new conversion function byte[] _function_name_(BufferedImage image)
* and update imageToByteArray function to support new format.
*/
public class ImageToRawConverter {
/** value for invalid format indication */
static public final int FORMAT_INVALID = -1;
/** Put Pixel raw format */
static public final int RAW_FORMAT_PP = 0;
/** RGBA raw format */
static public final int RAW_FORMAT_ARGB = 1;
/** pixel format - 24bit color */
static public final int COLOR_FORMAT_888 = 0;
/** pixel format - 16bit color */
static public final int COLOR_FORMAT_565 = 1;
/** int byte order - little-endian */
static public final int INT_FORMAT_LITTLE_ENDIAN = 0;
/** int byte order - big-endian */
static public final int INT_FORMAT_BIG_ENDIAN = 1;
/** list of supported pairs raw format - color format */
static final int formatList [][] = {
{RAW_FORMAT_PP, COLOR_FORMAT_565},
{RAW_FORMAT_ARGB, COLOR_FORMAT_888}
};
/** byte sequence that indentifies raw format */
static final short[] rawMagic = { 0x89, 'S', 'U', 'N'};
/** current raw, color and int formats */
protected int rawFormat, colorFormat, intFormat;
/**
* Defines if format is currently supported.
*
* @param rawFormat raw format
* @param colorFormat color format
* @return true if format is supported false otherwise
*/
static public boolean isFormatSupported(int rawFormat, int colorFormat)
{
for (int i = 0; i < formatList.length; ++i) {
if ((formatList[i][0] == rawFormat) &&
(formatList[i][1] == colorFormat)) {
return true;
}
}
return false;
}
/**
* Constructs instance of ImageToRawConverter which will
* convert images to raw data in specified here format.
* Raw format and color format should be in list of
* supported formarts, otherwise IllegalArgumentException
* will be thrown.
*
* @param rawFormat required raw format
* @param colorFormat required color format
* @param endian required int format
* @exception IllegalArgumentException if unsupported format
*/
public ImageToRawConverter(int rawFormat, int colorFormat, int endian)
throws IllegalArgumentException
{
if (!isFormatSupported(rawFormat, colorFormat)) {
throw new IllegalArgumentException("invalid format");
}
this.rawFormat = rawFormat;
this.colorFormat = colorFormat;
this.intFormat = endian;
}
/**
* Converts image to raw data in byte array.
*
* @param imageData image pixels in 32bit ARGB format
* @param width image width
* @param height image height
* @param hasAlpha true if image has alpha channel
* @return byte[] raw data
*/
public byte[] convertToRaw(int[] imageData, int width, int height,
boolean hasAlpha)
{
if (imageData == null) {
throw new IllegalArgumentException("Source image data is null");
}
byte [] ret = null;
// build raw data
if ((rawFormat == RAW_FORMAT_PP) &&
(colorFormat == COLOR_FORMAT_565)) {
ret = imageToPutpixel565(imageData, width, height, hasAlpha);
} else if ((rawFormat == RAW_FORMAT_ARGB) &&
(colorFormat == COLOR_FORMAT_888)) {
ret = imageToARGB888(imageData, width, height, hasAlpha);
}
return ret;
}
/**
* Convert 24bit color to 16bit color
* @param x the color in format 8bit-R 8bit-G 8bit-B to convert
* @return int 16bit color in format 5bit-R 6bit-G 5bit-B
*/
private short RGB888TORGB565(int x)
{
return ((short)(((x & 0x00F80000) >> 8) +
((x & 0x0000FC00) >> 5) +
((x & 0x000000F8) >> 3)));
}
/**
* Converts image to PutPixel raw format, 16bit color format, big-endian.
* Output byte array represents the following c-struct:
* typedef struct {
* byte header[4]; // Must equal RAW_HEADER
* int32 width;
* int32 height;
* int32 hasAlpha;
* byte data[1]; // variable length byte array
* } MIDP_IMAGE_BUFFER_RAW;
* where RAW image file header
* const byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
* and data array consists of image pixel array - 16bit per pixel,
* RGB(5, 6, 5) - and following alpha channel array if any - 8bit per pixel
*
* @param imageData image pixels in 32 bit ARGB format
* @param width image width
* @param height image height
* @param hasAlpha true if the image has alpha channel
* @return byte[] raw data in PutPixel raw format and 16bit color format
*/
private byte[] imageToPutpixel565(int[] imageData, int width, int height,
boolean hasAlpha)
{
hasAlpha = reallyHasAlpha(imageData);
// sizeof resulting raw buffer =
// sizeof(RAW_HEADER) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.width) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.height) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.hasAlpha) +
// sizeof(pixe_l565) * image_pixel_count +
// (hasAlpha ? alpha_size * image_pixel_count : 0)
int rawsz = 4 + 4 + 4 + 4 + 2 * imageData.length;
int dataOffset = 4 + 4 + 4 + 4;
int alphaOffset = rawsz;
if (hasAlpha) rawsz += 1 * imageData.length;
byte[] rawData = new byte[rawsz];
fillRawHeader(rawData, width, height, hasAlpha);
for (int i = 0; i < imageData.length; ++i) {
short val = RGB888TORGB565(imageData[i]);
storeValue(rawData, dataOffset + i * 2, val, intFormat);
if (hasAlpha) {
rawData[alphaOffset + i] = (byte)((imageData[i] >> 24) & 0xFF);
}
}
return rawData;
}
/**
* Converts image to ARGB with 24bits per pixel in big-endian.
* Output byte array represents the following c-struct:
* typedef struct {
* byte header[4]; // Must equal RAW_HEADER
* int32 width;
* int32 height;
* int32 hasAlpha;
* byte data[1]; // variable length byte array
* } MIDP_IMAGE_BUFFER_RAW;
* where RAW image file header
* const byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
* and data array consists of image pixel array - 24bit per pixel,
* RGBA(8, 8, 8, 8)
*
* @param imageData image pixels in 32 bit ARGB format
* @param width image width
* @param height image height
* @param hasAlpha true if the image has alpha channel
* @return byte[] raw data in RGBA format
*/
private byte[] imageToARGB888(int[] imageData, int width, int height,
boolean hasAlpha)
{
hasAlpha = reallyHasAlpha(imageData);
// sizeof resulting raw buffer =
// sizeof(RAW_HEADER) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.width) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.height) +
// sizeof(MIDP_IMAGE_BUFFER_RAW.hasAlpha) +
// sizeof(pixe_l565) * image_pixel_count +
// (hasAlpha ? alpha_size * image_pixel_count : 0)
int rawsz = 4 + 4 + 4 + 4 + 4 * imageData.length;
int dataOffset = 4 + 4 + 4 + 4;
byte[] rawData = new byte[rawsz];
fillRawHeader(rawData, width, height, hasAlpha);
for (int i = 0; i < imageData.length; ++i) {
// write ARGB
storeValue(rawData, dataOffset + i*4, imageData[i], intFormat);
}
return rawData;
}
/**
* Fills byte array with raw header
* byte RAW_HEADER[4] = {0x89, 'S', 'U', 'N'};
* int32 width;
* int32 height;
* int32 hasAlpha;
*
* @param rawData byte array to fill header for, length of that
* array must be greater than 16, otherwise function fails
* (returns false)
* @param width width of the image
* @param height height of the image
* @param hasAlpha if image has alpha channel
*/
void fillRawHeader(byte [] rawData, int width, int height,
boolean hasAlpha)
{
int magicLength = rawMagic.length;
for (int i = 0; i < magicLength; ++i) {
rawData[i] = (byte)(rawMagic[i] & 0xFF);
}
storeValue(rawData, magicLength, width, intFormat);
storeValue(rawData, magicLength + 4, height, intFormat);
storeValue(rawData, magicLength + 8,
(int)(hasAlpha ? 1 : 0), intFormat);
}
/**
* writes int to byte array at specified position
* in big- or little- endian.
*
* @param data target byte array
* @param offset offset in byte array
* @param value source integer
* @param endian endian type
*/
private static void storeValue(byte [] data, int offset,
int value, int endian)
{
if (endian == INT_FORMAT_BIG_ENDIAN) {
data[offset + 0] = (byte)((value >> 24) & 0xFF);
data[offset + 1] = (byte)((value >> 16) & 0xFF);
data[offset + 2] = (byte)((value >> 8) & 0xFF);
data[offset + 3] = (byte)(value & 0xFF);
} else {
data[offset + 0] = (byte)(value & 0xFF);
data[offset + 1] = (byte)((value >> 8) & 0xFF);
data[offset + 2] = (byte)((value >> 16) & 0xFF);
data[offset + 3] = (byte)((value >> 24) & 0xFF);
}
}
/**
* writes short to byte array at specified position
* in big- or little- endian.
*
* @param data target byte array
* @param offset offset in byte array
* @param value source integer
* @param endian endian type
*/
private static void storeValue(byte [] data, int offset,
short value, int endian)
{
if (endian == INT_FORMAT_BIG_ENDIAN) {
data[offset + 0] = (byte)((value >> 8) & 0xFF);
data[offset + 1] = (byte)(value & 0xFF);
} else {
data[offset + 0] = (byte)(value & 0xFF);
data[offset + 1] = (byte)((value >> 8) & 0xFF);
}
}
/**
* Checks if the image that supposely has alpha channel really
* has it, i.e there is at least one non opaque pixel.
*
* @param imageData image data in 32 bits ARGB format
* @return true if the image really has alpha channel
*/
private static boolean reallyHasAlpha(int[] imageData) {
boolean hasAlpha = false;
for (int i = 0; i < imageData.length; ++i) {
if ((imageData[i] & 0xFF000000) != 0xFF000000) {
hasAlpha = true;
break;
}
}
return hasAlpha;
}
}
|