如何在Java中压缩jpeg图像而不丢失该图像中的任何元数据?

时间:2022-10-03 21:19:14

I want compress jpeg files using Java. I do it like this:

我想使用Java压缩jpeg文件。我是这样做的:

  1. Read the image as BufferedImage
  2. 将图像读取为BufferedImage

  3. Write the image to another file with compression rate.
  4. 使用压缩率将图像写入另一个文件。

OK, that seems easy, but I find the ICC color profile and the EXIF information are gone in the new file and the DPI of the image is dropped from 240 to 72. It looks different from the origin image. I use a tool like preview in OS X. It can perfectly change the quality of the image without affecting other information.

好吧,这看起来很简单,但我发现ICC颜色配置文件和EXIF信息在新文件中消失了,图像的DPI从240降到72.它看起来与原始图像不同。我在OS X中使用类似预览的工具。它可以完美地改变图像的质量而不会影响其他信息。

Can I done this in Java? At least keep the ICC color profile and let the image color look the same as the origin photo?

我可以用Java完成吗?至少保留ICC颜色配置文件并让图像颜色看起来与原始照片相同?

2 个解决方案

#1


/**
 * @param inputFilenameWithPath : binary filepath
 * @param outputFilepath        : output image path
 * @param start                 : from where the image start in binary file
 * @param len                   : length of the image
 * @throws ImageAccessException
 */
public void extractImageFromBinaryFile(String inputFilenameWithPath, String outputFilepath, int start, int len) throws ImageAccessException
{
    try
    {
        File file = new File(inputFilenameWithPath);
        FileImageInputStream iis = new FileImageInputStream(file);

        // Added
        byte[] b = new byte[start];
        iis.read(b, 0, start);

        byte[] fb = new byte[]{};
        iis.read(fb);

        IIOByteBuffer iiob = new IIOByteBuffer(fb, start, len);
        iis.readBytes(iiob, len);

        OutputStream os = new FileOutputStream(outputFilepath);
        os.write(iiob.getData());
        iis.close();
        os.close();

    }
    catch (IOException ioe)
    {`enter code here`
        throw new ImageAccessException("Image File read/write error");
    }
}

#2


Finally find a way to do this.

最后找到一种方法来做到这一点。

Use javax.imageio.IIOImage. It can be readed by JpegImageReader.

使用javax.imageio.IIOImage。它可以由JpegImageReader重写。

But there was a bug in it, a bug last for 6 years. :(

但它有一个错误,一个错误持续了6年。 :(

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4924909

Luckily, if you do some hack(Fake the JFIF section), and it works. :D

幸运的是,如果你做了一些黑客攻击(伪造JFIF部分),它就可以了。 :d

So, this problem can be solved like this:

所以,这个问题可以这样解决:

  1. Use ImageIO to get the ImageReader for jpeg
  2. 使用ImageIO获取jpeg的ImageReader

  3. Read the jpeg image into a memory buffer
  4. 将jpeg图像读入内存缓冲区

  5. If it fails at bug 4924909 then fix the image buffer with a fake JFIF information
  6. 如果它在错误4924909失败,则使用假的JFIF信息修复图像缓冲区

  7. Use ImageWriter to write the file, let the ImageWriterParam to do the trick.
  8. 使用ImageWriter编写文件,让ImageWriterParam完成这一操作。

Well, it seems to be ok(Every information saved), except for one thing, the output image is brighter(or rather say, pale) than the original image(It won't happen when I use preview of OS X to compressed photo, so the problem must be in my code or java, or my wrong usage :( ).

好吧,它似乎没问题(保存每个信息),除了一件事,输出图像比原始图像更亮(或者更确切地说是苍白)(当我使用OS X预览压缩照片时不会发生这种情况,所以问题必须在我的代码或java中,或者我的错误用法:()。

So, my problem for compressing jpeg in java is not solved yet.

所以,我在java中压缩jpeg的问题还没有解决。

Any suggestions?

#1


/**
 * @param inputFilenameWithPath : binary filepath
 * @param outputFilepath        : output image path
 * @param start                 : from where the image start in binary file
 * @param len                   : length of the image
 * @throws ImageAccessException
 */
public void extractImageFromBinaryFile(String inputFilenameWithPath, String outputFilepath, int start, int len) throws ImageAccessException
{
    try
    {
        File file = new File(inputFilenameWithPath);
        FileImageInputStream iis = new FileImageInputStream(file);

        // Added
        byte[] b = new byte[start];
        iis.read(b, 0, start);

        byte[] fb = new byte[]{};
        iis.read(fb);

        IIOByteBuffer iiob = new IIOByteBuffer(fb, start, len);
        iis.readBytes(iiob, len);

        OutputStream os = new FileOutputStream(outputFilepath);
        os.write(iiob.getData());
        iis.close();
        os.close();

    }
    catch (IOException ioe)
    {`enter code here`
        throw new ImageAccessException("Image File read/write error");
    }
}

#2


Finally find a way to do this.

最后找到一种方法来做到这一点。

Use javax.imageio.IIOImage. It can be readed by JpegImageReader.

使用javax.imageio.IIOImage。它可以由JpegImageReader重写。

But there was a bug in it, a bug last for 6 years. :(

但它有一个错误,一个错误持续了6年。 :(

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4924909

Luckily, if you do some hack(Fake the JFIF section), and it works. :D

幸运的是,如果你做了一些黑客攻击(伪造JFIF部分),它就可以了。 :d

So, this problem can be solved like this:

所以,这个问题可以这样解决:

  1. Use ImageIO to get the ImageReader for jpeg
  2. 使用ImageIO获取jpeg的ImageReader

  3. Read the jpeg image into a memory buffer
  4. 将jpeg图像读入内存缓冲区

  5. If it fails at bug 4924909 then fix the image buffer with a fake JFIF information
  6. 如果它在错误4924909失败,则使用假的JFIF信息修复图像缓冲区

  7. Use ImageWriter to write the file, let the ImageWriterParam to do the trick.
  8. 使用ImageWriter编写文件,让ImageWriterParam完成这一操作。

Well, it seems to be ok(Every information saved), except for one thing, the output image is brighter(or rather say, pale) than the original image(It won't happen when I use preview of OS X to compressed photo, so the problem must be in my code or java, or my wrong usage :( ).

好吧,它似乎没问题(保存每个信息),除了一件事,输出图像比原始图像更亮(或者更确切地说是苍白)(当我使用OS X预览压缩照片时不会发生这种情况,所以问题必须在我的代码或java中,或者我的错误用法:()。

So, my problem for compressing jpeg in java is not solved yet.

所以,我在java中压缩jpeg的问题还没有解决。

Any suggestions?