Tuesday, August 14, 2007

Keeping Simple Things Simple

You can always tell an overengineered API when you try to do something really simplistic and it takes you about 30 lines of code and 8 different classes.

For example: I want to read an image, make it smaller, and write it out as a JPG with a given quality. This is a fairly common and simple task. Here's the code:


BufferedImage sourceImage
try {
sourceImage = ImageIO.read(new ByteArrayInputStream(imageData));
} catch (IOException e) {
return new ServiceResult(ServiceResult.STATUS.FAIL_HARD,
"Unable to read image; image is unreadable or an unsupported type", e);
}

// figure out the target width and height

BufferedImage newImage = getScaledInstance(sourceImage, targetWidth, targetHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);

ByteArrayOutputStream output = new ByteArrayOutputStream();

Iterator imageWritersByMIMEType = ImageIO.getImageWritersByMIMEType("image/jpeg");
if (imageWritersByMIMEType.hasNext()) {
ImageWriter writer = imageWritersByMIMEType.next();
writer.setOutput(new MemoryCacheImageOutputStream(output));
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(COMPRESSION_QUALITY);


IIOImage tmpImage = new IIOImage(newImage, null, null);
try {
writer.write(null, tmpImage, iwp);
} catch (IOException e) {
return new ServiceResult(ServiceResult.STATUS.FAIL_HARD, "Exception while creating jpeg content", e);
}
} else {
return new ServiceResult(ServiceResult.STATUS.FAIL_HARD, "Couldn't find a jpeg encoder!");
}

return new ServiceResult(ServiceResult.STATUS.OK, "Created avatar successfully", output.toByteArray());


So we had to use: BufferedImage, ImageIO, ByteArrayInputStream, ByteArrayOutputStream, Graphics2D (inside the getScaledInstance method), ImageWriter, ImageWriteParam, MemoryCacheImageOutputStream and IIOImage. (Not counting any java.lang, java.util or exception stuff.)

Why can't ImageIO read a byte array? (I can almost forgive the design decision to work mainly with streams.) Why does an ImageWriter need to write to a MemoryCacheImageOutputStream (an ordinary OutputStream won't do)? What's with ImageWriter#setOutput taking an Object? Do we really expect to have multiple image writers for a given MIME type such that we need an iterator? Why can't an ImageWriter write a BufferedImage? Why is there a getDefaultWriteParam, if that's the only WriteParam there is to get?

javax.imageio has got to be the absolutely most retarded API I have seen to date, with the closest runner-up being jTidy.

Labels: , , , ,


Comments: Post a Comment





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]