Java 处理大型TIFF文件和内存分配
我一直在开发一个应用程序,它接收一个可能非常大的TIFF文件,并将其拆分为多个更小的文件。为此,它需要遍历所有页面(Java 处理大型TIFF文件和内存分配,java,memory,tiff,javax.imageio,Java,Memory,Tiff,Javax.imageio,我一直在开发一个应用程序,它接收一个可能非常大的TIFF文件,并将其拆分为多个更小的文件。为此,它需要遍历所有页面(BufferedImageobjects)并执行一些操作,以确定是否应在此启动新文件,或者此特定页面是已创建文件的一部分 显然,我无法将整个文件加载到内存中-这就是为什么我只能使用ImageIO读取其中的一页。我使用以下方法创建了一个util类: public static BufferedImage getSinglePageFromTiffFile(File file, int
BufferedImage
objects)并执行一些操作,以确定是否应在此启动新文件,或者此特定页面是已创建文件的一部分
显然,我无法将整个文件加载到内存中-这就是为什么我只能使用ImageIO
读取其中的一页。我使用以下方法创建了一个util类:
public static BufferedImage getSinglePageFromTiffFile(File file, int pageIndex) throws IOException {
ImageInputStream is = ImageIO.createImageInputStream(file);
ImageReader reader;
try {
reader = ImageIO.getImageReaders(is).next();
reader.setInput(is);
return reader.read(pageIndex);
} finally {
if(is != null) is.close();
}
}
public static int getNumPages(File file) throws IOException {
ImageInputStream is = ImageIO.createImageInputStream(file);
ImageReader reader;
try {
reader = ImageIO.getImageReaders(is).next();
reader.setInput(is);
return reader.getNumImages(true);
} finally {
if(is != null) is.close();
}
}
要将页面写入文件,我使用ImageWriter
类,如下所示:
int pagesQty = ImageUtils.getNumPages(documentToSplit);
int currentPageIndex = 0;
final ImageWriter writer = ImageIO.getImageWritersByFormatName(resultsExtension).next();
final ImageWriteParam writeParams = writer.getDefaultWriteParam();
writeParams.setCompressionMode(ImageWriteParam.MODE_COPY_FROM_METADATA);
BufferedImage page = ImageUtils.getSinglePageFromTiffFile(file, currentPageIndex);
while(currentPageIndex < pagesQty) {
OutputStream outStream = null;
ImageOutputStream imgOutStream = null;
final File newDocFile = new File(pathName);
try {
outStream = new FileOutputStream(newDocFile);
imgOutStream = ImageIO.createImageOutputStream(outStream);
writer.setOutput(imgOutStream);
writer.prepareWriteSequence(null);
writer.writeToSequence(new IIOImage(page, null, null), writeParams);
currentPageIndex++;
while(currentPageIndex < pagesQty) {
page = ImageUtils.getSinglePageFromTiffFile(documentToSplit, currentPageIndex);
if(NEWPAGE) {
writer.endWriteSequence();
break;
}
writer.writeToSequence(new IIOImage(page, null, null), writeParams);
}
} finally {
if(imgOutStream != null) imgOutStream.close();
if(outStream != null) outStream.close();
}
}
}
int pagesQty=ImageUtils.getNumPages(documentToSplit);
int currentPageIndex=0;
final ImageWriter writer=ImageIO.getImageWritersByFormatName(ResultExtension).next();
final ImageWriteParam writeParams=writer.getDefaultWriteParam();
writeParams.setCompressionMode(ImageWriteParam.MODE_从_元数据复制_);
BuffereImage page=ImageUtils.getSinglePageFromTiffFile(文件,currentPageIndex);
while(currentPageIndex
我对这种方法的保留意见适用于内存使用。在处理文件时,最多分配2GB的内存。平均约为1-1.5GB。有没有一种方法可以在内存使用方面更有效地执行这些操作 通过将TIFF页面作为缓冲图像读取,基本上可以解压缩存储的图像,这可能需要大量内存,具体取决于图像的大小:每个像素将占用3(RGB)或4(ARGB)字节,因此具有10000 x 10000像素的图像将占用大约300或400 MB的内存 根据分配给Java进程的内存量,以及垃圾回收何时开始,进程实际上可能会积累大量已用内存 由于主内存消耗可能来自解压缩图像(
BufferedImage
),因此减少内存使用的最有效方法不是解压缩单个图像以提取它们。我不知道如何用普通Java实现这一点,但是有第三方库可以做到这一点。其中之一是声称:
将多页TIFF图像拆分为单个TIFF图像,而不解压缩图像
我将此库用于其他图像格式(例如创建动画GIF),但尚未将其用于TIFF,但我认为绝对值得一试。在其上,它提供了以下片段来拆分多页TIFF:
import com.icafe4j.io.RandomAccessInputStream;
import com.icafe4j.io.FileCacheRandomAccessInputStream;
import com.icafe4j.util.FileUtils;
public class TestTIFFTweaker {
public static void main(String[] args) throws Exception {
FileOutputStream fin = new FileInputStream(args[0]);
RandomAccessInputStream rin = new FileCacheRandomAccessInputStream(fin);
TIFFTweaker.splitPages(rin, FileUtils.getNameWithoutExtension(new File(args[0])));
rin.close();
fin.close(); // Need to close the underlying stream explicitly!!!
}
}
可能的副本: