5

寻找像 djpeg 这样的东西,它使用 O(1) RAM 通过子采样来调整大小,但是在 java 中并且能够处理 jpg、png、gif、bmp 等。也许已经存在一些实现。如何调整流中的图像大小(使用最少的 RAM)?

4

2 回答 2

6

FileImageInputStream特定的图像格式一无所知,它只是方便从文件支持的输入中读取整数、短裤、字节、字节数组等。文件格式支持由各种ImageReader实现处理。

对您的问题的简短回答是:您无法在不加载图像的情况下真正调整图像大小。

从 djpeg 的描述:

djpeg 解压缩命名的 JPEG 文件 [...]

(重点是我的)

但是,您可以对图像进行二次采样,这非常快(对于大多数格式),并且会使用更少的内存。看看ImageReadParam.setSourceSubSampling方法和ImageReader.read(int, ImageReadParam)方法。这将创建一个调整大小的图像,非常类似于“最近邻”或“点采样”算法(即,结果不一定看起来很好)。

可以先组合二次采样,然后再调整质量,以节省内存,并可能获得可接受的结果。这完全取决于您期望/需要的质量。

如果您真的非常想调整图像大小而不将它们加载到堆内存中(也许您的图像很大),我已经编写了一些使用内存映射文件的类,您可以查看它们,但是它们非常慢。

于 2013-06-27T09:18:46.677 回答
2
  • 十二罐子可以读取非 RGB jpeg
  • setSourceSubSamplingsetSourceRegion允许在流中调整图像大小。
  • 不支持渐进式 jpeg
  • 不支持大输出文件

例子:

File javaStreamSubsample(File inFile, int s, Rectangle sourceRegion) throws IOException  {
    File outFile = File.createTempFile("img", null);;
    ImageInputStream input = ImageIO.createImageInputStream(inFile);
    try {
        Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
        ImageReader reader = readers.next();
        try {
            reader.setInput(input);
            ImageReadParam param = reader.getDefaultReadParam();
            param.setSourceSubsampling(s, s, 0, 0);
            if(sourceRegion!=null){
                param.setSourceRegion(sourceRegion);
            }
            BufferedImage image = reader.read(0, param);
            ImageIO.write(image, "jpg", outFile);
        }finally {
            reader.dispose();
        }
    } finally {
        input.close();
    }
    return outFile;
}
于 2015-06-09T21:21:41.223 回答