Java help needed for Mac port

2 replies [Last post]
Joined: 11/04/2008

Sorry Mac users, I didn't manage to get the Mac port done before I left (and I no longer have access to a Mac).

Pretty much everything is done, the bin file encryption/decryption is working fine and the addins are merging fine. The last remaining thing to be done is the PNG decoding/encoding.

The Mac images are stored as squares in a power of 2 (256x256, 512x512 etc) with the actual size stored in the header. They're zlib deflated too.

Basically I've got it to the stage where I've decompressed the image fine, and I can tell that it's correct RGBA data, I just don't know how to turn that RGBA byte[] array into a Java Image object. I'm getting a blank image every time.

So if you know a bit of Java, take a look at the code below and see if you can help:

package com.goofans.gootool.io;
 
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.MemoryImageSource;
import java.awt.image.RenderedImage;
import java.io.*;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
 
/**
 * @author David Croft
 * @version $Id$
 */
public class MacGraphicFormat
{
  private MacGraphicFormat()
  {
  }
 
  public static RenderedImage decodeImage(File file) throws IOException
  {
    System.out.println("file.length() = " + file.length());
    InputStream is = new FileInputStream(file);
 
    int width = readUnsignedShort(is);
    System.out.println("width = " + width);
    int height = readUnsignedShort(is);
    System.out.println("height = " + height);
 
    int squareSide = 1;
    while (squareSide < width || squareSide < height) squareSide *= 2;
    System.out.println("squareSide = " + squareSide);
 
    int compressedSize = readUnsignedInt(is);
    System.out.println("compressedSize = " + compressedSize);
    int uncompressedSize = readUnsignedInt(is);
    System.out.println("uncompressedSize = " + uncompressedSize);
 
    byte[] compressedData = new byte[compressedSize];
    if (is.read(compressedData) != compressedSize) {
      throw new EOFException("Short read on compressed data, expected " + compressedSize);
    }
 
    Inflater compresser = new Inflater();
    compresser.setInput(compressedData);
 
    byte[] uncompressedData = new byte[uncompressedSize];
    int gotBytes;
    try {
      gotBytes = compresser.inflate(uncompressedData);
    }
    catch (DataFormatException e) {
      throw new IOException("zlib compression format error: " + e.getMessage());
    }
    compresser.end();
    if (gotBytes != uncompressedSize) {
      throw new IOException("Uncompressed size is not " + uncompressedSize + ", we got " + gotBytes);
    }
 
    System.out.println("uncompressedData.length = " + uncompressedData.length);
 
//    DataBuffer buf = new DataBufferByte(uncompressedData, uncompressedSize);
//    SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, squareSide, squareSide, squareSide);
//WritableRaster raster = Raster.createWritableRaster(sm, buf, new Point(0,0));
 
    File f = new File("output.raw");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(uncompressedData);
    fos.close();
 
    MemoryImageSource producer = new MemoryImageSource(squareSide, squareSide, new DirectColorModel(32, 0xff, 0xff00, 0xff0000, 0xff000000), uncompressedData, 0, squareSide * 4);
    Image srcImage = Toolkit.getDefaultToolkit().createImage(producer);
//        BufferedImageFilter fil = new BufferedImageFilter(new RescaleOp(1, 0, null));
//    fil.
 
 
    showImageWindow(srcImage);
 
    BufferedImage destImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//    ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.TYPE_RGB), true, false, 0, DataBuffer.TYPE_BYTE);
//    BufferedImage destImg = new BufferedImage(ColorModel.getRGBdefault(), raster, false, null);
//    boolean b = destImg.getGraphics().drawImage(srcImage, 0, 0, null);
//    ((Graphics2D)destImg.getGraphics()).drawRenderedImage();
    destImg.getGraphics().drawImage(srcImage, 0, 0, null);
 
    return destImg;
  }
 
  private static void showImageWindow(Image image)
  {
    JDialog dlg = new JDialog((Frame) null, "Image", true);
    JPanel rootPanel = new JPanel();
    dlg.add(rootPanel);
    dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    JLabel imgLabel = new JLabel(new ImageIcon(image));
    Dimension d = new Dimension(image.getWidth(null), image.getHeight(null));
    imgLabel.setPreferredSize(d);
    rootPanel.add(imgLabel);
    dlg.pack();
    dlg.setVisible(true);
  }
 
 
  private static int readUnsignedShort(InputStream is) throws IOException
  {
    byte[] tmp = new byte[2];
    if (is.read(tmp, 0, 2) != 2)
      throw new EOFException("End of file reading unsignedShort");
    return ((int) tmp[0] & 0xff) + (((int) tmp[1] & 0xff) << 8);
  }
 
  private static int readUnsignedInt(InputStream is) throws IOException
  {
    byte[] tmp = new byte[4];
    if (is.read(tmp, 0, 4) != 4)
      throw new EOFException("End of file reading unsignedInt");
    return ((int) tmp[0] & 0xff) + (((int) tmp[1] & 0xff) << 8) + (((int) tmp[2] & 0xff) << 16) + (((int) tmp[3] & 0xff) << 24);
  }
 
  public static void main(String[] args) throws IOException
  {
    RenderedImage image = decodeImage(new File("cliff_left.png.binltl"));
 
    ImageIO.write(image, "PNG", new File("cliff_left.png"));
  }
}

Joined: 12/12/2008

could you just release what you have so far?

Joined: 11/04/2008

Unfortunately it's pretty useless if it doesn't compile images, pretty much every new level or ball will have new images.

I'm looking for a Mac user to help testing something, check out http://goofans.com/node/62#comment-106 if you can help.

-davidc