【问题标题】:Java BufferedImage JPG compression without writing to fileJava BufferedImage JPG 压缩而不写入文件
【发布时间】:2016-10-09 09:17:30
【问题描述】:

我已经看到several examples 通过写入文件从 Java BufferedImage 对象制作压缩的 JPG 图像,但是是否可以在不写入文件的情况下执行 JPG 压缩?也许通过写信给ByteArrayOutputStream,比如this

ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(0.7f);

ImageOutputStream outputStream = createOutputStream();
jpgWriter.setOutput(outputStream);
IIOImage outputImage = new IIOImage(image, null, null);

// in this example, the JPG is written to file...
// jpgWriter.write(null, outputImage, jpgWriteParam);
// jpgWriter.dispose();

// ...but I want to compress without saving, such as
ByteArrayOutputStream compressed = ???

【问题讨论】:

    标签: java image jpeg bufferedimage


    【解决方案1】:

    只需将您的ByteArrayOutputStream 传递给ImageIO.createImageOutputStream(...),如下所示:

    // The important part: Create in-memory stream
    ByteArrayOutputStream compressed = new ByteArrayOutputStream();
    
    try (ImageOutputStream outputStream = ImageIO.createImageOutputStream(compressed)) {
    
        // NOTE: The rest of the code is just a cleaned up version of your code
    
        // Obtain writer for JPEG format
        ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("JPEG").next();
    
        // Configure JPEG compression: 70% quality
        ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
        jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpgWriteParam.setCompressionQuality(0.7f);
    
        // Set your in-memory stream as the output
        jpgWriter.setOutput(outputStream);
    
        // Write image as JPEG w/configured settings to the in-memory stream
        // (the IIOImage is just an aggregator object, allowing you to associate
        // thumbnails and metadata to the image, it "does" nothing)
        jpgWriter.write(null, new IIOImage(image, null, null), jpgWriteParam);
    
        // Dispose the writer to free resources
        jpgWriter.dispose();
    }
    
    // Get data for further processing...
    byte[] jpegData = compressed.toByteArray();
    

    PS:默认情况下,ImageIO 在创建ImageOutputStream 时会使用磁盘缓存。这可能会减慢您的内存流写入速度。要禁用它,请使用ImageIO.setCache(false)(全局禁用磁盘缓存)或显式创建MemoryCacheImageOutputStream(本地),如下所示:

    ImageOutputStream outputStream = new MemoryCacheImageOutputStream(compressed);
    

    【讨论】:

    • 谢谢@haraldK!我不完全确定这里发生了什么。如果将JPG数据压缩并写入名为compressedByteArrayOutputStreamIIOImage部分是做什么的?
    • @JeffThompson 我为您更新了答案。 IIOImage 不“做”任何事情,它只包含您要写入的数据。如果您想了解更多信息,建议您阅读 API 文档或遵循教程。 :-)
    • @downwoter 请不要仅仅因为认为这个问题不值得回答而“惩罚”一个完全有效且正确的答案。相反,请对问题投反对票,或投票结束。
    • 再次感谢!我确实看过文档,但是用于存储和操作文件流的所有不同对象确实令人困惑。这更有意义!在不使用MemoryCacheImageOutputStream 的情况下,我确实遇到了内存不足的错误,仅供参考。
    • 如何在这个方法上写单元测试?有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2013-09-01
    相关资源
    最近更新 更多