java Java中的无损JPEG旋转(90/180/270度)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/706665/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:27:31  来源:igfitidea点击:

Lossless JPEG Rotate (90/180/270 degrees) in Java?

javaalgorithmjpegrotationlossless

提问by Henry

Is there a Java library for rotating JPEG files in increments of 90 degrees, without incurring image degradation?

是否有用于以 90 度为增量旋转 JPEG 文件而不会导致图像质量下降的 Java 库?

回答by quietmint

Building on Henry's answer, here's an example of how to use MediaUtilto perform lossless JPEG rotation based on the EXIF data:

基于亨利的回答,这里有一个示例,说明如何使用MediaUtil基于 EXIF 数据执行无损 JPEG 旋转:

try {
    // Read image EXIF data
    LLJTran llj = new LLJTran(imageFile);
    llj.read(LLJTran.READ_INFO, true);
    AbstractImageInfo<?> imageInfo = llj.getImageInfo();
    if (!(imageInfo instanceof Exif))
        throw new Exception("Image has no EXIF data");

    // Determine the orientation
    Exif exif = (Exif) imageInfo;
    int orientation = 1;
    Entry orientationTag = exif.getTagValue(Exif.ORIENTATION, true);
    if (orientationTag != null)
        orientation = (Integer) orientationTag.getValue(0);

    // Determine required transform operation
    int operation = 0;
    if (orientation > 0
            && orientation < Exif.opToCorrectOrientation.length)
        operation = Exif.opToCorrectOrientation[orientation];
    if (operation == 0)
        throw new Exception("Image orientation is already correct");

    OutputStream output = null;
    try {   
        // Transform image
        llj.read(LLJTran.READ_ALL, true);
        llj.transform(operation, LLJTran.OPT_DEFAULTS
                | LLJTran.OPT_XFORM_ORIENTATION);

        // Overwrite original file
        output = new BufferedOutputStream(new FileOutputStream(imageFile));
        llj.save(output, LLJTran.OPT_WRITE_ALL);

    } finally {
        IOUtils.closeQuietly(output);
        llj.freeMemory();
    }

} catch (Exception e) {
    // Unable to rotate image based on EXIF data
    ...
}

回答by user3400408

Regarding the issue of EXIF data not necessarily being handled correctly, since EXIF data is irrelevant in many situations, here's example code demonstrating only the LLJTran lossless JPEG rotation feature (with thanks to user113215):

关于不一定正确处理 EXIF 数据的问题,由于 EXIF 数据在许多情况下无关紧要,这里的示例代码仅演示 LLJTran 无损 JPEG 旋转功能(感谢 user113215):

final File              SrcJPEG  = new File("my-input.jpg");
final File              DestJPEG = new File("my-output.jpg");
final FileInputStream   In       = new FileInputStream(SrcJPEG);

try {
    final LLJTran           LLJT = new LLJTran(In);

    LLJT.read(LLJTran.READ_ALL, true);
    LLJT.transform(LLJTran.ROT_90);

    final FileOutputStream  Out = new FileOutputStream(DestJPEG);

    try {
        LLJT.save(Out, LLJTran.OPT_WRITE_ALL);
    } finally {
        Out.close();
    }

} finally {
    In.close(); 
}

If you make the input and output Fileobjects refer to the same file, you can run this over and over again, and observe that the image does not degrade, no matter how many iterations it is put through.

如果你让输入和输出File对象引用同一个文件,你可以一遍又一遍地运行这个,观察图像不会降级,不管它经过多少次迭代。

回答by J_Y_C

You don't need an external library for this kind of thing, it's all built into SE. The easiest being the rotate() function of the Graphics2D object.

这种事情不需要外部库,它都内置在 SE 中。最简单的是Graphics2D 对象的rotate() 函数。

For example:

例如:

   Image rotatedImage = new BufferedImage(imageToRotate.getHeight(null), imageToRotate.getWidth(null), BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
    g2d.rotate(Math.toRadians(90.0));
    g2d.drawImage(imageToRotate, 0, -rotatedImage.getWidth(null), null);
    g2d.dispose();

no loss!

没有损失!

Or, if you want to be extra careful, just use BufferedImage.getRGB(x,y), and translate it pixel by pixel on to the new image.

或者,如果您想格外小心,只需使用 BufferedImage.getRGB(x,y),并将其逐个像素地转换为新图像。