使用iText将TIFF转换为PDF的多线程方法

时间:2015-10-20 11:41:17

标签: java multithreading itext tiff futuretask

我基本上是尝试使用itext将tiff文件转换为pdf,这非常简单。 但是从我所看到的TiffImage.getTiffImage花费了大量时间来执行更大的文件。

我的要求是使用FutureTaskExecutorService来提供多线程解决方案。这是我目前的代码:

import java.util.concurrent.Callable;

import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.codec.TiffImage;

public class ProcessTiffImage implements Callable<Image>{

    RandomAccessFileOrArray tiffFile;
    int pageNo;

    public ProcessTiffImage(RandomAccessFileOrArray tiffFile, int pageNo){
        this.tiffFile = tiffFile;
        this.pageNo = pageNo;
    }

    public Image call() throws Exception {
        Image image = TiffImage.getTiffImage(tiffFile, pageNo);

        return image;

    }

}

并且转换方法是

public boolean convert(Document document) {

        int numOfThreads = Runtime.getRuntime().availableProcessors()  ;
        ExecutorService service = Executors.newFixedThreadPool(numOfThreads );
        List<FutureTask<Image>> taskList = new ArrayList<FutureTask<Image>>();
        List<Image> imageList = new ArrayList<Image>();

        for (int page = 1; page <= numOfPages; page++) {
            FutureTask<Image> futureTask = new FutureTask<Image>(new ProcessTiffImage(tiffFile, page));
            taskList.add(futureTask);
            service.execute(futureTask);
        }

        try {
            // Wait until all results are available
            for (FutureTask<Image> future : taskList) {

                imageList.add(future.get());
            }

        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (ExecutionException ex) {
            ex.printStackTrace();
        }

        service.shutdown();


        boolean success = generatePdf(document, imageList);
        return success;
    }

但我在NullPointerException获得future.get()。问题是执行不是等待TiffImage.getTiffImage(tiffFile,pageNo)完成。因此我无法创建图像列表。 非常感谢任何帮助。

堆栈跟踪

java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:188)
    at com.app.convertor.TiffParser.convert(TiffParser.java:107)
    at com.app.start.TiffToPdf.main(TiffToPdf.java:40)
Caused by: java.lang.NullPointerException
Caused by: java.lang.NullPointerException
    at com.itextpdf.text.pdf.codec.TIFFDirectory.getFieldAsLong(TIFFDirectory.java:467)
    at com.itextpdf.text.pdf.codec.TIFFDirectory.getFieldAsLong(TIFFDirectory.java:477)
    at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:124)
    at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:106)
    at com.app.processor.ProcessTiffImage.call(ProcessTiffImage.java:20)
    at com.app.processor.ProcessTiffImage.call(ProcessTiffImage.java:1)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

2 个答案:

答案 0 :(得分:3)

不要自己创建Future,请执行人为您创建,(即:提交Callable

List<Future<Image>> taskList = new ArrayList<Future<Image>>();

 for (int page = 1; page <= numOfPages; page++) {
     Future<Image> futureTask = service.submit(new ProcessTiffImage(tiffFile, page));
     taskList.add(futureTask);
 }

for (Future<Image> future : taskList) {
   imageList.add(future.get());
}

注意:请考虑改为使用ExecutorCompletionService

答案 1 :(得分:0)

这似乎正在发生,因为RandomAccessFileOrArray 不是线程安全的

您在future.get()调用中遇到的异常是TiffImage.getTiffImage()调用中的基础异常,这似乎正在发生,因为该方法对传递的TIFF数据不满意。特别是,它正在寻找一些领域,似乎它不存在。可能是图像的高度还是宽度?

但是这种情况正在发生,因为RandomAccessFileOrArray正在多个线程中使用。每当一个线程移动文件中的指针时,它就会搞砸其他线程正在做的事情。

您需要使用RandomAccessFileOrArray.createView()来获取要传递给每个线程的文件的新视图:

Image image = TiffImage.getTiffImage(tiffFile.createView(), pageNo);