Convert Leptonica PIX data into 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)

File used in example :

Image represented by the data:
binary

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

3 thoughts on “Convert Leptonica PIX data into Java BufferedImage”

  1. Greg,

    Do you happen to have a code for the opposite conversion, going from BufferedImage to Leptonica Pix? Thank you.

    Quan

  2. 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.

Leave a Comment

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