Convert Leptonica PIX data to Java BufferedImage

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"));

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();
    }
}

Leave a Comment

Your email address will not be published. Required fields are marked *