Многопоточный подход для преобразования TIFF в PDF с использованием iText

По сути, я пытаюсь преобразовать файл tiff в pdf, используя itext, что довольно просто. Но из того, что я вижу, TiffImage.getTiffImage требуется много времени для выполнения больших файлов.

Мое требование состоит в том, чтобы использовать FutureTask и ExecutorService для предоставления многопоточного решения. Вот мой текущий код:

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)

person beingsuplab    schedule 20.10.2015    source источник
comment
Не могли бы вы опубликовать полную трассировку стека?   -  person chiastic-security    schedule 20.10.2015
comment
@chiastic-security отредактировал сообщение   -  person beingsuplab    schedule 20.10.2015
comment
Это потому, что RandomAccessFileOrArray не является потокобезопасным. Смотрите мой ответ ниже.   -  person chiastic-security    schedule 20.10.2015


Ответы (2)


Похоже, это происходит из-за того, что RandomAccessFileOrArray не является потокобезопасным.

Исключение, которое вы получаете в вызове future.get(), является основным исключением в вызове TiffImage.getTiffImage(), и, похоже, это происходит из-за того, что этому методу не нравятся данные TIFF, которые он передает. В частности, он хочет получить какое-то поле, и кажется, что его там нет. Возможно, высота или ширина изображения?

Но это происходит потому, что RandomAccessFileOrArray используется в нескольких потоках. Каждый раз, когда один поток перемещает указатель в файле, он портит то, что делают другие потоки.

Вам нужно использовать RandomAccessFileOrArray.createView() чтобы получить новое представление файла для передачи в каждый поток:

Image image = TiffImage.getTiffImage(tiffFile.createView(), pageNo);
person chiastic-security    schedule 20.10.2015
comment
Я понимаю вашу точку зрения, но странно то, что если я отлаживаю этот код в любой стандартной среде IDE, он работает отлично и доволен данными, которые я передаю в getTiffImage(). Но работает то же самое, вызывает проблему. Спасибо за помощь, постараюсь поставить try/catch для мониторинга данных. - person beingsuplab; 20.10.2015

Не создавайте 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.

person Sleiman Jneidi    schedule 20.10.2015
comment
java.util.concurrent.ExecutionException: ExceptionConverter: java.io.EOFException в java.util.concurrent.FutureTask.report(FutureTask.java:122) в java.util.concurrent.FutureTask.get(FutureTask.java:188) в com.app.convertor.TiffParser.convert(TiffParser.java:118) в com.app.start.TiffToPdf.main(TiffToPdf.java:40) - person beingsuplab; 20.10.2015
comment
Да, это разумный совет, но я не думаю, что он решает проблему ОП. - person chiastic-security; 20.10.2015