tiffitext7multipage

iText7: Creating PDF from TIFF multipage image using iText


I am trying to use iText 7.1.1 to convert a TIFF image to PDF file with multiple pages. Thanks for those to get me started with this article Create PDF from TIFF image using iText. However, it is iText 5.5.x and I have trouble to duplicate it in iText 7.

I did find TiffImageData.getNumberOfPages(raf) to replace int pages = TiffImage.getNumberOfPages(rafa).

However, I am not able to replace TiffImage.getTiffImage(rafa, i) in iText7. Do I need to use new Image(ImageDataFactory.createTiff(...)). Appreciate any suggestion(s).

iText 5.5.x code

import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.io.FileChannelRandomAccessSource;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.codec.TiffImage;

public class Test1 {
    public static void main(String[] args) throws Exception {
    RandomAccessFile aFile = new RandomAccessFile("/myfolder/origin.tif", "r");
    FileChannel inChannel = aFile.getChannel();
    FileChannelRandomAccessSource fcra =  new FileChannelRandomAccessSource(inChannel);
    Document document = new Document();
    PdfWriter.getInstance(document,  new FileOutputStream("/myfolder/destination.pdf"));
    document.open();              
    RandomAccessFileOrArray rafa = new RandomAccessFileOrArray(fcra);
    int pages = TiffImage.getNumberOfPages(rafa);
    Image image;
    for (int i = 1; i <= pages; i++) {            
        image = TiffImage.getTiffImage(rafa, i);
        Rectangle pageSize = new Rectangle(image.getWidth(), image.getHeight());
        document.setPageSize(pageSize);
        document.newPage();
        document.add(image);
    }
    document.close();
    aFile.close();            
}

Solution

  • Do I need to use new Image( ImageDataFactory.createTiff(...))

    Yes.

    You want this: ImageDataFactory.createTiff(bytes, recoverFromImageError, page, direct)

    Then you would open a new PDF, loop through the TIFF pages and:

    1. Get the TIFF image size
    2. Create a new page in the PDF matching the TIFF page size
    3. Add the TIFF image to the new PDF page

    Here is a note from Bruno Lowagie on using TIFF with iText 7: How to avoid an exception when importing a TIFF file?

    I see you probably want fully working code. Here you go:

    import com.itextpdf.io.image.ImageData;
    import com.itextpdf.io.image.ImageDataFactory;
    import com.itextpdf.io.image.TiffImageData;
    import com.itextpdf.io.source.RandomAccessFileOrArray;
    import com.itextpdf.io.source.RandomAccessSourceFactory;
    import com.itextpdf.kernel.geom.PageSize;
    import com.itextpdf.kernel.geom.Rectangle;
    import com.itextpdf.kernel.pdf.PdfDocument;
    import com.itextpdf.kernel.pdf.PdfPage;
    import com.itextpdf.kernel.pdf.PdfWriter;
    import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
    
    public class TiffToPdf {
        public static void main(String[] args) throws IOException {
            Path tiffFile = Paths.get("/myfolder/origin.tiff");
            RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().createBestSource(tiffFile.toString()));
            int tiffPages = TiffImageData.getNumberOfPages(raf);
            raf.close();
            try (PdfDocument output = new PdfDocument(new PdfWriter("/myfolder/destination.pdf"))) {
                for (int page = 1; page <= tiffPages; page++) {
                    ImageData tiffImage = ImageDataFactory.createTiff(tiffFile.toUri().toURL(), true, page, true);
                    Rectangle tiffPageSize = new Rectangle(tiffImage.getWidth(), tiffImage.getHeight());
                    PdfPage newPage = output.addNewPage(new PageSize(tiffPageSize));
                    PdfCanvas canvas = new PdfCanvas(newPage);
                    canvas.addImage(tiffImage, tiffPageSize, false);
                }
            }
        }
    }
    

    Some might suggest you use the high level API to achieve this a little more cleanly but this should be sufficient for your question.