Need help to start converting original G3 fax files to TIFF format via Java

I have an original fax file (G3 / T.4 format), which needs to be programmatically converted into multi page TIFF through Java So far, Jai has not been successful, even though I think it should be effective The tool from sfaxtools has successfully converted my original fax file to TIFF (batch fax2tif or faxsee), but I need to do this programmatically through Java I think it should be possible to use Java advanced imaging. Please check the following code snippet:

private void writeTiff(byte[] buffer,OutputStream outStream) {
    try {
         //reading image from given buffer
         RenderedImage rendImage = null;
         TIFFDecodeParam decodeParams = new TIFFDecodeparam();
         ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
         ImageDecoder decoder = ImageCodec.createImageDecoder("tiff",stream,decodeParams);
         TIFFEncodeParam encodeParams = new TIFFEncodeparam();
         int numPages = decoder.getNumPages();
         for (int i = 0; i < numPages; i++) {
            rendImage = decoder.decodeAsRenderedImage(i);
            ImageEncoder encoder = ImageCodec.createImageEncoder("TIFF",outStream,encodeParams);
            encoder.encode(rendImage);
         }
    } catch (Exception e) {
        e.printStackTrace();
    } catch (Error err) {
        err.printStackTrace();
    }
}

The problem is, especially in the reading section, imagedecoder decoder = imagecodec createImageDecoder(“tiff”,decodeParams); It should be replaced by some imagedecoder implementations that internally use faxdecoder to decode G3 original fax files There is a protected class tifffaxdecoder in the Jai package. Is it possible and how to use it for my purposes? Any ideas? thank you

Solution

I don't think Jai supports direct reading of G3 / T.4 original fax data However, the sample code here can be modified and extended to meet your needs and implement the ideas outlined in the review (originally published as GIST)

It does not decode G3 / T.4 data in any way, it just packages the original fax data in the smallest TIFF container This allows the data to be read later as normal tiff It is implemented using the (my own) twelvemonkeys imageio library

If you don't know the width / height of fax files, you can find them by using ccittfaxdecoderstream, trying to implement the algorithm with different widths (columns) defined in the standard, and see how many whole lines you can read If you have the correct number, you should consume the stream completely

import com.twelvemonkeys.imageio.Metadata.AbstractEntry;
import com.twelvemonkeys.imageio.Metadata.Entry;
import com.twelvemonkeys.imageio.Metadata.exif.EXIFWriter;
import com.twelvemonkeys.imageio.Metadata.exif.Rational;
import com.twelvemonkeys.imageio.Metadata.exif.TIFF;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.io.*;
import java.util.ArrayList;

public class G3Test {
    public static void main(String[] args) throws IOException {
        File input = new File(args[0]);
        File output = new File(args.length > 1 ? args[1] : input.getName().replace(".g3",".tif"));

        // ImageWidth = 1728,2048,2482. SHORT or LONG. These are the fixed page widths in pixels defined in CCITT Group 3.
        int columns = 1728; // The default
        int rows = 100;     // Trial and error for sample file found at http://www.filesuffix.com/en/extension/fax

        ArrayList<Entry> entries = new ArrayList<>();

        // http://cool.conservation-us.org/bytopic/imaging/std/tiff-f.html
        // required Class F tags
        entries.add(new TIFFEntry(TIFF.TAG_COMPRESSION,TIFF.TYPE_SHORT,3)); // CCITT T.4
        entries.add(new TIFFEntry(TIFF.TAG_FILL_ORDER,1));  // Left to right
        entries.add(new TIFFEntry(TIFF.TAG_GROUP3OPTIONS,TIFF.TYPE_LONG,0)); // No options set
        entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH,columns));
        entries.add(new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT,rows));
        entries.add(new TIFFEntry(TIFF.TAG_SUBFILE_TYPE,2)); // Page
        entries.add(new TIFFEntry(TIFF.TAG_RESOLUTION_UNIT,2)); // Inches
        entries.add(new TIFFEntry(TIFF.TAG_X_RESOLUTION,TIFF.TYPE_RATIONAL,new Rational(204))); // 204
        entries.add(new TIFFEntry(TIFF.TAG_Y_RESOLUTION,new Rational(98))); // 98,196
        // required Bilevel (Class B) tags
        entries.add(new TIFFEntry(TIFF.TAG_BITS_PER_SAMPLE,1)); // 1 bit/sample
        entries.add(new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION,0)); // White is zero
        entries.add(new TIFFEntry(TIFF.TAG_SOFTWARE,TIFF.TYPE_ASCII,"TwelveMonkeys FAX2TIFF 0.1 BETA ;-)"));
        entries.add(new TIFFEntry(TIFF.TAG_ROWS_PER_STRIP,rows));
        entries.add(new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL,1)); // 1 sample/pixel
        entries.add(new TIFFEntry(TIFF.TAG_STRIP_BYTE_COUNTS,input.length()));
        entries.add(new TIFFEntry(TIFF.TAG_STRIP_OFFSETS,-1)); // placeholder for Now

        // We Now have all our entries,compute size of the entries,and make that the offset (we'll write the data right after).
        EXIFWriter writer = new EXIFWriter();
        long offset = 12 + writer.computeIFDSize(entries); // + 12 for TIFF magic (4),IFD0 pointer (4) and EOF (4)
        entries.remove(entries.size() - 1);
        entries.add(new TIFFEntry(TIFF.TAG_STRIP_OFFSETS,offset));


        try (InputStream in = new FileInputStream(input)) {
            try (ImageOutputStream out = ImageIO.createImageOutputStream(output)) {
                // Write the TIFF IFD for the image data
                writer.write(entries,out);

                // Copy the already G3 compressed bytes verbatim to the output
                byte[] buffer = new byte[1024];
                int read;
                while ((read = in.read(buffer)) >= 0) {
                    out.write(buffer,read);
                }
            }
        }
    }

    // API stupidity,should be fixed in later verisons (ie. contain a predefined TIFFEntry class)
    static final class TIFFEntry extends AbstractEntry {
        private final short type;

        TIFFEntry(int identifier,short type,Object value) {
            super(identifier,value);
            this.type = type;
        }

        @Override
        public String getTypeName() {
            return TIFF.TYPE_NAMES[type];
        }
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>