Month: July 2013

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