C: TIFFWriteEncodedStrip vs Java:?

62 views Asked by At

In Java, how could the same byte array be written to a tiff file using TIFFImageWriter, after creating an associated TIFFDirectory configured with TIFFFields

Haven't seen any Java parallels yet.

More info

Compression: T4_COMPRESSION_T4_1D

In https://github.com/freeswitch/spandsp/blob/master/src/t4_t6_decode.c

Per line of compressed fax image:

/* Convert the runs to a bit image of the row */

/* White/black/white... runs, always starting with white. 
    That means the first run could be zero length. */

        for (x = 0, fudge = 0;  x < s->a_cursor;  x++, fudge ^= 0xFF)
        {
            i = s->cur_runs[x];
            if ((int) i >= s->pixels)
            {
                s->pixel_stream = (s->pixel_stream << s->pixels) |
                                  (msbmask[s->pixels] & fudge);
                for (i += (8 - s->pixels);  i >= 8;  i -= 8)
                {
                    s->pixels = 8;
                    s->row_buf[row_pos++] = (uint8_t) s->pixel_stream;
                    s->pixel_stream = fudge;
                }
            }
            s->pixel_stream = (s->pixel_stream << i) | (msbmask[i] & fudge);
            s->pixels -= i;
        }
        s->image_length++;
    

Each row_buf bytes get accumulated in image_buffer for a page, and in t4_rx.c write_tiff_image(t4_rx_state_t *s), the strip is written to file via:

 /* Let libtiff do the compression */
 TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size)
    

Q: To do this in java, how would the byte array that contains the page pixels/bits be passed to a TiffImageWriter object ?

1

There are 1 answers

2
VGR On

I’m not entirely certain I understand your question, but it appears your byte array contains 1-bit pixel information packed into bytes.

You can create a BufferedImage based on those bytes, then write it as a TIFF using ImageIO.

First, one makes a BufferedImage from the data:

  • Wrap the byte array in a DataBufferByte
  • Create a Raster, specifying that it should treat the buffer’s bytes as 1-bit pixels packed into bytes.
  • Create a ColorModel indicating how the 1-bit pixels are to be written.
  • Finally, create a BufferedImage from that Raster and ColorModel.
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
WritableRaster raster =
    Raster.createPackedRaster(buffer, imageWidth, imageHeight, 1, null);

byte[] colors = { 0x00, (byte) 0xff };  // 0=black, 1=white
ColorModel colorModel =
    new IndexColorModel(1, colors.length, colors, colors, colors);

BufferedImage image =
    new BufferedImage(colorModel, raster, false, new Properties());

The ImageIO TIFF metadata specification describes how to specify TIFF compression:

ImageWriter tiffWriter =
    ImageIO.getImageWritersByFormatName("TIFF").next();

ImageWriteParam param = tiffWriter.getDefaultWriteParam();

param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("CCITT T.4");

IIOImage iioImage = new IIOImage(image, null, null);

try (ImageOutputStream out = ImageIO.createImageOutputStream(
    new BufferedOutputStream(
        Files.newOutputStream(filename)))) {

    tiffWriter.setOutput(out);
    tiffWriter.write(null, iioImage, param);
} finally {
    tiffWriter.dispose();
}

Here is the full method:

public void writeTIFF(byte[] pixels,
                      int imageWidth,
                      int imageHeight,
                      Path filename)
throws IOException {
    DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
    WritableRaster raster =
        Raster.createPackedRaster(buffer, imageWidth, imageHeight, 1, null);

    byte[] colors = { 0x00, (byte) 0xff };  // 0=black, 1=white
    ColorModel colorModel =
        new IndexColorModel(1, colors.length, colors, colors, colors);

    BufferedImage image =
        new BufferedImage(colorModel, raster, false, new Properties());

    ImageWriter tiffWriter =
        ImageIO.getImageWritersByFormatName("TIFF").next();

    ImageWriteParam param = tiffWriter.getDefaultWriteParam();

    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionType("CCITT T.4");

    IIOImage iioImage = new IIOImage(image, null, null);

    try (ImageOutputStream out = ImageIO.createImageOutputStream(
        new BufferedOutputStream(
            Files.newOutputStream(filename)))) {

        tiffWriter.setOutput(out);
        tiffWriter.write(null, iioImage, param);
    } finally {
        tiffWriter.dispose();
    }
}