用Java压缩/缩小图像文件

时间:2018-08-16 07:23:09

标签: java image

One of the image file used

    String dirName=System.getProperty("user.home") + "/deleteme";
    ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(1000);
    BufferedImage bufferedImage=ImageIO.read(new File(dirName,"a.jpg"));
    ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);
    byteArrayOutputStream.flush();

    byteArrayOutputStream.close();

    byte[] bytearray = byteArrayOutputStream.toByteArray();

    BufferedImage imag=ImageIO.read(new ByteArrayInputStream(bytearray));
    ImageIO.write(imag, "jpg", new File(dirName,"snap.jpg"));

这段代码读取图像文件,将其转换为byteArray,然后将其存储回去。 现在,对于我测试过的大多数图像文件,其大小都急剧减小到仅原始大小的15%。

  1. 有人可以解释为什么这样做会减小图像文件的大小。

  2. 在此过程中质量是否下降。

[我已经比较了http://driiqm.mpi-inf.mpg.de中的图像,它表明新图像的质量相同。]

3 个答案:

答案 0 :(得分:1)

您将执行以下操作:

try (OutputStream out = new FileOutputStream(new File(dirName,"snap.jpg"))) {
    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
    JPEGEncodeParam eparm = encoder.getDefaultJPEGEncodeParam(img);
    eparm.setQuality(quality, true);
    encoder.setJPEGEncodeParam(eparm);
    encoder.encode(img);
}

其中质量是介于0和1之间的浮点数。

答案 1 :(得分:1)

TLDR:您的结果与原始质量不同。 JPEG总是会降低一些质量,但是您的结果会降低很多质量。 Exif元数据已丢失,但这只是微不足道的差异。

我用您的书写方式测试了示例图像,然后测试了以最高质量进行书写(例如@MauricePerry编写的代码)。然后,我将它们与http://driiqm.mpi-inf.mpg.dehttp://exif.regex.info/exif.cgi

进行了比较

原始文件:

通过您的方法,我得到了:

  • 大小为35kB
  • 没有嵌入的颜色配置文件
  • Sampling YCbCr4:2:0(2 2)
  • 原始内容和结果之间有很多区别:

comparison with first result

我以最高的质量得到了

  • 大小272kB
  • 没有嵌入的颜色配置文件
  • Sampling YCbCr4:2:0(2 2)
  • 原始数据和结果之间的最小差异(但仍然有些差异):

comparison with second result

我不确定您如何假设图像具有相同的质量,因为您发布的网页存在很多差异。即使具有最高质量,它也会显示出差异,这是有道理的,因为JPEG是有损格式。 BufferedImage将图像数据表示为位图,并且在转换为JPEG时会丢失一些信息。这就是为什么我们拥有PNG等无损格式。

我也做了您所说的-将结果图像用作源图像,然后输入和输出相同。我将其与达到本地最小值进行比较。 JPEG->位图转换会生成位图,其中位图-> JPEG会生成相同的JPEG数据,因为您使用的是相同的功能(相同的质量,相同的采样)。但是,如果位图-> JPEG转换使用其他功能(例如,这次使用最高质量),则会导致质量损失更大。

答案 2 :(得分:0)

质量正在更改为默认值。您使用此默认值两次写入。

db_name = False, dbfilter = .

现在图像已转换为字节,并使用有损压缩进行压缩。

ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);

这也使用默认压缩。

ImageIO.write(imag, "jpg", new File(dirName,"snap.jpg"));

在此示例中,字节数组将包含最少的有损压缩,接近输入大小。要写出来,不要使用ImageIO再次读/写它。相反,我只是将字节直接写到文件中。