用于JPEG压缩的自定义量化表

时间:2014-07-30 12:46:07

标签: java jpeg quantization

正如标题所说,我试图使用自定义量化表来压缩JPEG格式的图像。我的问题是无法打开生成的文件,错误是:

Quantization table 0x00 was not defined

这就是我的代码的样子:

        JPEGImageWriteParam params = new JPEGImageWriteParam(null);
        if (mQMatrix != null) {
            JPEGHuffmanTable[] huffmanDcTables = {JPEGHuffmanTable.StdDCLuminance, JPEGHuffmanTable.StdDCChrominance};
            JPEGHuffmanTable[] huffmanAcTables = {JPEGHuffmanTable.StdACLuminance, JPEGHuffmanTable.StdACChrominance};
            dumpMatrices(mQMatrix);
            params.setEncodeTables(mQMatrix, huffmanDcTables, huffmanAcTables);
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        Iterator writers = ImageIO.getImageWritersByFormatName("JPEG");
        ImageWriter imageWriter = (ImageWriter) writers.next();

        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
        imageWriter.setOutput(imageOutputStream);
        imageWriter.write(null, new IIOImage(mSourceImage, null, null), params);

        mCompressedImageSize = outputStream.size();

        try (FileOutputStream fileOutputStream = new FileOutputStream(mOutFileName)) {
            fileOutputStream.write(outputStream.toByteArray());

        }
        mCompressedImage = ImageIO.read(new ByteArrayInputStream(outputStream.toByteArray()));

我的猜测是它与元数据有关,但我找不到解决方案。

谢谢, R上。

更新:使用十六进制查看器我确定量化表(DQT - 0xFF,0xDB部分)没有被写入输出文件。我假设我必须强迫它以某种方式写出来。

更新2:所以在实际调试执行之后,我发现如果在参数对象中设置了表,则既不为量化而不为霍夫曼表生成元数据。如果缺少元数据,则表格不会写入文件中。事情是我看不到自定义元数据的内容。

1 个答案:

答案 0 :(得分:1)

非常有趣的问题,不幸的是非平凡......这就是我发现的:

首先,使用JPEGImageWriteParam.setEncodeTables(...)是不行的。来自JavaDoc

  

设置用于编码缩写流的量化和Huffman表。

进一步来自JPEG Metadata Format Specification and Usage Notes

  

此排序实现了表{I}}中仅包含表的设计意图,作为在没有其他源可用时指定表的方法,并且只有在没有使用已知非表的表的情况下写入缩写流时才会出现这种情况。 - 用于压缩的标准表。

即,param选项只能 用于编写“缩写流”(没有表格的海关JPEG,假设在回读时会提供表格)。结论:我们可以指定要用JPEG编码的表的唯一方法是将其传递给元数据。

从上面提到的同一文档中,除非压缩模式为JPEGImageWriteParams,否则将忽略和替换元数据中的表,因此我们需要指定。{/ p>

有关元数据结构的文档,请参阅Image Metadata DTD。重要的部分是具有子节点的MODE_COPY_FROM_METADATAdqt节点,以及它们的“用户对象”(不要与普通的DOM“userData”混淆)。我们需要使用我们想要使用的新表来更新这些节点。

这是我提出的代码:

dht