This snippet allows us to convert Leptonica PIX data into Java BufferedImage, in my case the pix->data could be compressed using zlib so I am decompressing before recreating image.
We are assuming here that this is bi-tonal image(1 bpp)
File used in example :
Image represented by the data:
Sample Usage
byte[] zlibData = FileUtil.read("pix-compressed.txt"); BufferedImage image = LeptonicaUtil.convert(zlibData, width, height, 1); ImageIO.write(image, "png", new File("C:/temp/test.png")); |
Code
import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.zip.DataFormatException; import java.util.zip.Inflater; /** * Utility for help us work with leptonica pix data * @author gbugaj * */ public class LeptonicaUtil { public static BufferedImage convert(byte[] indata, int width, int height, int depth) { try { // Decompress the bytes byte[] pixdata = zlibDecompress(indata); // 4 (4 Bytes per Int) int wpl = (width * depth + 31) / 32; int byteCount = 4 * wpl * height; int rowSize = 4 * wpl; assert (byteCount == pixdata.length); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); WritableRaster raster = img.getRaster(); byte[] rasterdata = new byte[width * height]; int rasterindex = 0; for (int h = 0; h < height; ++h) { int start = h * rowSize; byte[] row = new byte[rowSize]; System.arraycopy(pixdata, start, row, 0, rowSize); // Convert row bytes into linedata using 4 bytes to represent a // 32 bit int IntBuffer intBuffer = ByteBuffer.wrap(row).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); int[] linedata = new int[intBuffer.remaining()]; intBuffer.get(linedata); for (int w = 0; w < width; ++w) { int word = w >> 5; // need this to get proper byte ordering int index = (31 - (w & 31)); byte val = (byte) (((linedata[word] >> index) & 1) ^ 1); rasterdata[rasterindex] = val; ++rasterindex; } } raster.setDataElements(0, 0, width, height, rasterdata); return img; } catch (IOException e) { e.printStackTrace(); } catch (DataFormatException e) { e.printStackTrace(); } return null; } public static byte[] zlibDecompress(byte[] data) throws IOException, DataFormatException { /** * 78 01 - No Compression/low 78 9C - Default Compression 78 DA - Best * Compression */ if (data.length < 2) return data; // Check magic headers if (!((data[0] & 0xff) == 0x78 && ((data[1] & 0xff) == 0x01 || (data[1] & 0xff) == 0x9C || (data[1] & 0xff) == 0xDA))) { return data; } Inflater inflater = new Inflater(); inflater.setInput(data); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); byte[] buffer = new byte[1024]; int count = -1; while (!inflater.finished() && count != 0) { count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); } inflater.end(); outputStream.close(); return outputStream.toByteArray(); } } |
Greg,
Do you happen to have a code for the opposite conversion, going from BufferedImage to Leptonica Pix? Thank you.
Quan
I do have it somewhere, I find it and post it.
It’s not pure java but the util class “de.vorb.leptonica.util.PixConversions” from “Jleptonica” (JNA wrapper for Leptonica) has two methods to convert between pix and BufferedImage.