2015-10-20 4 views
3

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

Мое требование состоит в использовании 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) 
+0

Можете ли вы опубликовать полную трассировку стека? –

+0

@ chiastic-security отредактировал сообщение – beingsuplab

+0

Это потому, что 'RandomAccessFileOrArray' не является потокобезопасным. См. Мой ответ ниже. –

ответ

0

Это похоже на то, что RandomAccessFileOrArrayне является потокобезопасным.

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

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

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

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

Я понимаю вашу точку зрения, но странно то, что если я отлаживаю этот код в любой стандартной среде IDE, отлично работает и доволен данными, которые я передаю getTiffImage(). Но работает то же самое, вызывает проблему. Спасибо за помощь, хотя, попробуем вставить try/catch для мониторинга данных. – beingsuplab

+0

@beingsuplab см. Обновление. Это пронизывающая вещь. –

+0

Это сделало трюк .... Спасибо за помощь – beingsuplab

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 ,

+0

java.util.concurrent.ExecutionException: ExceptionConverter: java.io.EOFException \t на java.util.concurrent.FutureTask.report (FutureTask.java:122) \t в java.util.concurrent.FutureTask.get (FutureTask. Java: 188) \t в com.app.convertor.TiffParser.convert (TiffParser.java:118) \t в com.app.start.TiffToPdf.main (TiffToPdf.java:40) – beingsuplab

+1

Да, это разумный совет, но я не думаю, что это решает проблему OP. –

Смежные вопросы