【问题标题】:Significant jpeg quality loss after downloading and base64 encoding下载和base64编码后显着的jpeg质量损失
【发布时间】:2017-01-28 21:54:53
【问题描述】:

我的应用程序下载 Facebook 用户的 jpeg 个​​人资料图片,并对其进行 base64 编码。解码时,生成的 jpeg 质量和大小会显着降低。我该如何避免这种情况?

这是我下载/编码的方式:

// Download the profile picture.
BufferedImage image = ImageIO.read(new URL("http://facebook-profile-pic"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", bos);

// Base64 encode it.
String imageData = new String(Base64.getEncoder().encode(bos.toByteArray()));

当我获取 imageData 的值并对其进行解码时,图像比原始下载 URL 处的图像小很多。

【问题讨论】:

  • new String(byteArray) 是不可靠的,因为它使用底层系统的默认字符集来编码字节。如果该字符集是 UTF-8 或某些 ISO-8859 字符集,它将适用于 Base64 编码的字节,但如果是其他字符集,您的数据将被损坏。请改用String imageData = Base64.getEncoder().encodeToString(bos.toByteArray());
  • JPEG 是一种无损文件格式,ImageIO 在写入时使用特定的质量。为了获得更高的质量和/或无损,您需要明确指定质量

标签: java compression base64 jpeg loss


【解决方案1】:

Base64 编码完全无损。保存时可能会发生质量损失。为防止这种情况,请直接使用ImageWriterImageIO.write 已在内部使用它,但您无法控制设置):

ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
writer.setOutput(bos);

ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1.0F); // Highest quality

writer.write(image, new IIOImage(image, null, null), param);

另外,根据您使用的 API,您可能已经下载了低质量的图像。

【讨论】:

    【解决方案2】:

    解码时,生成的 jpeg 质量和大小显着降低

    JPEG 是一种有损文件格式,ImageIO 在写入 jpg 文件时使用默认的有损压缩指标。要获得更高质量(或无损),您需要通过JPEGImageWriteParam 自己明确处理压缩质量。

    //create the params    
    JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
    jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    jpegParams.setCompressionQuality(1f);//set compression quality
    

    查看答案here 以写入文件。要写入内存,您需要使用MemoryCacheImageOutputStream

    //write to output stream
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    MemoryCacheImageOutputStream ios = new MemoryCacheImageOutputStream(bos);
    final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
    writer.setOutput(ios);
    writer.write(null, new IIOImage(image, null, null), jpegParams);
    

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 2016-02-22
      相关资源
      最近更新 更多