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)
Sample Usage
BufferedImage image = LeptonicaUtil.convert(zlibData, width, height, 1);
ImageIO.write(image, "png", new File("C:/temp/test.png")); |
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();
}
} |
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();
}
}