Extreme Java When vanilla Java is not enough

30Oct/080

BufferedImage and ByteBuffers

Direct ByteBuffer are really cool, because they can allocate and wrap native memory outside the JVM heap. This is very useful with JNI or with large files. I'm playing with OpenGL and PCX files (this is evil, I know). Since I want to keep a small footprint, I want to keep only a pointer to PCX raw data (run-lenght encoded), and decompress it into a RGBA ByteBuffer as needed. This, in theory, allows me to share the same code with OpenGL and BufferedImage - since I'm bound only to a pointer of RGBA data. The former is easy: TextureData did the dirt job. The latter... Well... Not that easy. If you try something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
final IntBuffer buf = myPCXLoader.getImage();
DataBuffer dataBuffer = new DataBuffer(
    DataBuffer.TYPE_INT, buf.limit()) {
  @Override
  public int getElem(int bank, int i) {
    return buf.get(i);
  }
  @Override
  public void setElem(int bank, int i, int val) {
  }
};
SampleModel sm = new SinglePixelPackedSampleModel(
    DataBuffer.TYPE_INT, w, h,
    new int[] { 0xFF000000, 0xFF0000, 0xFF00, 0xFF });
    WritableRaster raster = Raster.createWritableRaster(
    sm, dataBuffer, null);
BufferedImage img = new BufferedImage(
    new DirectColorModel(32, 0xFF000000, 0xFF0000, 0xFF00, 0xFF),
    raster, false, null);

Line 15 leads me to an ugly exception:

java.awt.image.RasterFormatException: IntegerComponentRasters must
haveinteger DataBuffers
  at sun.awt.image.IntegerComponentRaster.
    (IntegerComponentRaster.java:155)
  at sun.awt.image.IntegerInterleavedRaster.
    (IntegerInterleavedRaster.java:111)
  at sun.awt.image.IntegerInterleavedRaster.
    (IntegerInterleavedRaster.java:78)
  at java.awt.image.Raster.createWritableRaster(Raster.java:994)

Asking Google, I found that ByteComponentRaster checks if DataBuffer is a instanceof ByteDataBuffer (instead of checking its type). Disgusting... Looks like Sun hired some kind of Baby Junior Programmer taking his first cup of Java to make that part of java.awt...

I also found this 3-years-old-and-not-solved-yet bug, with an workaround:

WritableRaster raster = new WritableRaster(sm, dataBuffer,
    new java.awt.Point()) {};

Works like a charm!

Sun is really disappointing me. There are a lot of small, simple-to-solve, really old bugs and seems like nobody cares about them. I think this is why they are opening the source of their major products: let the community clean the mess...

14Feb/080

Copying file in Java – NIO version

In old days, copying a file in Java wasn't easy: you had to create a array buffer to read from source and write to destination. Now, with NIO from JDK, it's a matter of creating the streams and let the API do the dirty job.

FileChannel src = new FileInputStream(srcFile).getChannel();
FileChannel dst = new FileOutputStream(dstFile).getChannel();
try {
  dst.transferFrom(src, 0, src.size());
} finally  {
  src.close();
  dst.close();
}