使用 iText 将 TIFF 转换为 PDF 的多线程方法
Multi threaded approach to convert TIFF to PDF using iText
我实际上是在尝试使用 itext 将 tiff 文件转换为 pdf,这非常简单。
但据我所知,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;
}
但是我在 future.get()
得到了一个 NullPointerException
。问题是执行没有等待 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)
不要自己创建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。
这似乎是因为RandomAccessFileOrArray
不是线程安全的。
您在 future.get()
调用中遇到的异常是 TiffImage.getTiffImage()
调用中的一个潜在异常,这似乎正在发生,因为该方法对它的 TIFF 数据不满意被通过。特别是,它正在寻找一些领域,但似乎没有。可能是图像高度或宽度?
但这是因为 RandomAccessFileOrArray
正在多个线程中使用。每当一个线程移动文件中的指针时,它就会搞砸其他线程正在做的事情。
您需要使用 RandomAccessFileOrArray.createView()
获取文件的新视图以传递给每个线程:
Image image = TiffImage.getTiffImage(tiffFile.createView(), pageNo);
我实际上是在尝试使用 itext 将 tiff 文件转换为 pdf,这非常简单。
但据我所知,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;
}
但是我在 future.get()
得到了一个 NullPointerException
。问题是执行没有等待 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)
不要自己创建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。
这似乎是因为RandomAccessFileOrArray
不是线程安全的。
您在 future.get()
调用中遇到的异常是 TiffImage.getTiffImage()
调用中的一个潜在异常,这似乎正在发生,因为该方法对它的 TIFF 数据不满意被通过。特别是,它正在寻找一些领域,但似乎没有。可能是图像高度或宽度?
但这是因为 RandomAccessFileOrArray
正在多个线程中使用。每当一个线程移动文件中的指针时,它就会搞砸其他线程正在做的事情。
您需要使用 RandomAccessFileOrArray.createView()
获取文件的新视图以传递给每个线程:
Image image = TiffImage.getTiffImage(tiffFile.createView(), pageNo);