/*
* Copyright (c) 2003-onwards Shaven Puppy Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'Shaven Puppy' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.shavenpuppy.jglib.tools;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import com.shavenpuppy.jglib.Image;
import com.shavenpuppy.jglib.Palette;
/**
* Convert all .png images to .jgimage files in the specified directory or the current working directory.
* Usage:
* ImageConverter [<source dir>] [<dest dir>]
*/
public class ImageConverter {
/**
* Constructor for ImageConverter.
*/
public ImageConverter() {
super();
}
public static void main(String[] args)
{
// Parse input arguments
String dirName;
if (args.length > 0)
{
dirName = args[0];
if (dirName.startsWith("\"") && dirName.endsWith("\""))
{
dirName = dirName.substring(1, dirName.length() - 1);
}
} else {
dirName = ".";
}
boolean jpeg = false;
if (args.length > 1)
{
if (args[1].equals("jpeg"))
{
Image.setCompressor(new JPEGCompressor());
jpeg = true;
}
}
// Find all input files
File inputDir = new File(dirName);
File[] pngs = findPngs(inputDir);
// Find our output directory
String destDir = inputDir.getAbsolutePath().substring(0, inputDir.getAbsolutePath().length() - 1);
if (args.length > 1)
{
destDir = args[jpeg ? 2 : 1];
}
System.out.println("Output to "+destDir);
// Convert all input files into the output directory
convertFiles(pngs, destDir, jpeg);
}
public static File[] findPngs(File dir)
{
File[] pngs = dir.listFiles(new FilenameFilter()
{
@Override
public boolean accept(File directory, String name)
{
return name.endsWith(".png");
}
});
return pngs;
}
public static File[] convertFiles(File[] inputFiles, String destDir, boolean isJpeg)
{
ArrayList outFiles = new ArrayList();
for (int i = 0; i < inputFiles.length; i++)
{
File inputFile = inputFiles[i];
try
{
BufferedImage bi = ImageIO.read(inputFile);
// JFrame f = new JFrame(inputFile.toString());
// JLabel l = new JLabel(new ImageIcon(bi));
// f.add(l, BorderLayout.CENTER);
// f.pack();
// f.setVisible(true);
// f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int pos = inputFile.getCanonicalPath().lastIndexOf('.');
int slashpos = inputFile.getCanonicalPath().lastIndexOf(File.separator);
String dest = destDir + inputFile.getCanonicalPath().substring(slashpos, pos) + ".jgimage";
Image image = convert(bi, isJpeg);
File destFile = new File(dest);
destFile.getParentFile().mkdirs();
Image.write(image, new BufferedOutputStream(new FileOutputStream(destFile)));
outFiles.add(destFile);
System.out.println("Converted "+inputFile);
}
catch (Exception e)
{
System.out.println("Failed to convert "+inputFile+" due to "+e);
e.printStackTrace();
}
}
File[] ret = new File[outFiles.size()];
for (int i=0; i<ret.length; i++)
{
ret[i] = (File)outFiles.get(i);
}
return ret;
}
/**
* Converts a BufferedImage into an SPGL Image, ready for use with OpenGL.
* @param bi The input buffered image
* @param jpeg Whether to use jpeg compression
* @return an Image
* @throws Exception if the conversion fails
*/
public static Image convert(BufferedImage bi, boolean jpeg) throws Exception {
BufferedImage newBI;
int type;
switch (bi.getColorModel().getNumComponents()) {
case 1:
type = Image.LUMINANCE;
newBI = bi;
break;
case 2:
type = Image.LUMINANCE_ALPHA;
newBI = bi;
break;
case 3:
{
type = Image.RGB;
ComponentColorModel ccm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
newBI = new BufferedImage(ccm, ccm.createCompatibleWritableRaster(bi.getWidth(), bi.getHeight()), false, null);
newBI.setData(bi.getRaster());
}
break;
case 4:
{
type = Image.RGBA;
ComponentColorModel ccm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
newBI = new BufferedImage(ccm, ccm.createCompatibleWritableRaster(bi.getWidth(), bi.getHeight()), false, null);
newBI.setData(bi.getRaster());
}
break;
default:
throw new Exception("Unsupported image type");
}
bi = newBI;
// int type;
// boolean useInts = false;
// int numComponents = 3;
// switch (bi.getType()) {
// case BufferedImage.TYPE_3BYTE_BGR :
// type = Image.BGR;
// break;
// case BufferedImage.TYPE_4BYTE_ABGR :
// type = Image.RGBA; // getTypeForColorModel((ComponentColorModel) bi.getColorModel());
// break;
// case BufferedImage.TYPE_INT_ARGB:
// type = Image.RGBA; // Will need conversion
// useInts = true;
// numComponents = 4;
// break;
// case BufferedImage.TYPE_INT_BGR:
// type = Image.RGB; // will need conversion
// useInts = true;
// numComponents = 3;
// break;
// case BufferedImage.TYPE_BYTE_GRAY :
// type = Image.LUMINANCE;
// break;
// case BufferedImage.TYPE_BYTE_INDEXED :
// type = Image.PALETTED;
// break;
// case BufferedImage.TYPE_USHORT_555_RGB :
// throw new Exception("Unsupported image format");
// case BufferedImage.TYPE_CUSTOM :
// ColorModel cm = bi.getColorModel();
// switch (numComponents = cm.getNumComponents()) {
// case 1:
// type = Image.LUMINANCE;
// break;
// case 2:
// type = Image.LUMINANCE_ALPHA;
// break;
// case 3:
// {
// DirectColorModel dcm = (DirectColorModel) cm;
// if (
// dcm.getRedMask() == 0xFF0000
// && dcm.getGreenMask() == 0xFF00
// && dcm.getBlueMask() == 0xFF
// )
// {
// type = Image.RGB;
// } else {
// type = Image.BGR;
// }
// }
// break;
// case 4:
// {
// DirectColorModel dcm = (DirectColorModel) cm;
// type = getTypeForColorModel(dcm);
// }
// break;
// default:
// throw new Exception("Unsupported number of color components.");
// }
// useInts = cm.getTransferType() == DataBuffer.TYPE_INT ? true : false;
// break;
// default :
// throw new Exception("Unsupported image type "+bi.getType());
// }
Image image;
// if (useInts) {
// int[] data = (int[]) bi.getRaster().getDataElements(0, 0, bi.getWidth(), bi.getHeight(), null);
// byte[] dataAsBytes = new byte[data.length * numComponents];
// int p = 0;
// for (int i = 0; i < data.length; i ++) {
// dataAsBytes[p ++] = (byte) ((data[i] >> 0) & 0xFF);
// dataAsBytes[p ++] = (byte) ((data[i] >> 8) & 0xFF);
// dataAsBytes[p ++] = (byte) ((data[i] >> 16) & 0xFF);
// if (numComponents == 4) {
// dataAsBytes[p ++] = (byte) ((data[i] >> 24) & 0xFF);
// }
// }
// image = new Image(bi.getWidth(), bi.getHeight(), type, dataAsBytes);
// } else {
byte[] data = (byte[]) bi.getRaster().getDataElements(0, 0, bi.getWidth(), bi.getHeight(), null);
image = new Image(bi.getWidth(), bi.getHeight(), type, data);
// }
if (type == Image.PALETTED) {
IndexColorModel icm = (IndexColorModel) bi.getColorModel();
int[] palette = new int[icm.getMapSize()];
icm.getRGBs(palette);
// Annoyingly getRGBs returns ARGB format which GL doesn't support...
// so we'll turn it into RGBA
for (int j = 0; j < palette.length; j ++) {
palette[j] =
((palette[j] & 0x00FF0000) >> 16) // red
| ((palette[j] & 0x0000FF00)) // green
| ((palette[j] & 0x000000FF) << 16) // blue
| ((palette[j] & 0xFF000000)); // alpha
}
Palette newP = new Palette(Palette.RGBA, palette);
image.setPalette(newP);
} else {
image.setUseJPEG(jpeg);
}
return image;
}
private static int getTypeForColorModel(DirectColorModel dcm) throws Exception {
if (
dcm.getAlphaMask() == 0xFF000000
&& dcm.getRedMask() == 0xFF0000
&& dcm.getGreenMask() == 0xFF00
&& dcm.getBlueMask() == 0xFF
)
{
return Image.ARGB;
} else if
(
dcm.getAlphaMask() == 0xFF000000
&& dcm.getBlueMask() == 0xFF0000
&& dcm.getGreenMask() == 0xFF00
&& dcm.getRedMask() == 0xFF
)
{
return Image.ABGR;
} else if
(
dcm.getRedMask() == 0xFF000000
&& dcm.getGreenMask() == 0xFF0000
&& dcm.getBlueMask() == 0xFF00
&& dcm.getAlphaMask() == 0xFF
)
{
return Image.RGBA;
} else if
(
dcm.getBlueMask() == 0xFF000000
&& dcm.getGreenMask() == 0xFF0000
&& dcm.getRedMask() == 0xFF00
&& dcm.getAlphaMask() == 0xFF
)
{
return Image.BGRA;
} else {
throw new Exception("Unsupported mask "+Integer.toHexString(dcm.getAlphaMask())+" "+Integer.toHexString(dcm.getRedMask())+
" "+Integer.toHexString(dcm.getGreenMask())+" "+Integer.toHexString(dcm.getBlueMask()));
}
}
}