【问题标题】:Lossless JPEG Rotate (90/180/270 degrees) in Java?Java中的无损JPEG旋转(90/180/270度)?
【发布时间】:2023-12-24 04:49:01
【问题描述】:

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

【问题讨论】:

  • 不是在 Java 中,但 jpegclub.org/jpegtran 应该是无损 jpeg 旋转 (Windows / Linux) 的最佳命令行实用程序
  • 您好,如果您使用了以下解决方案,如果可以的话,我想请求您的帮助。我很难找到导入 java.awt.Rectangle 的位置;我在 web 中尝试了一些 jars,但我无法将它们与 Android Studio 一起使用。你能帮我处理你导入的罐子吗?谢谢

标签: java algorithm jpeg rotation lossless


【解决方案1】:

【讨论】:

  • @Henry 嘿,你能告诉我如何使用这个保存图像..显然这篇文章对我没有帮助,或者我做错了
【解决方案2】:

基于 Henry 的回答,这里有一个示例,说明如何使用 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
    ...
}

【讨论】:

  • 我已经用 Sanselan 和 MediaUtil 检索 EXIF 旋转标签进行了测试,但上面的 MediaUtil 方法在 llj.getImageInfo();步骤(未找到任何 EXIF 元数据),其中 Sanselan 方法确实找到了 EXIF 元数据。似乎 LLJtran 不支持读取所有现代 JPEG。
  • 我很难找到导入 java.awt.Rectangle 的位置;我在 web 中尝试了一些 jars,但我无法将它们与 Android Studio 一起使用。你能帮我处理你导入的罐子吗?谢谢
  • @user113215 非常感谢您的评论,我不知道我导入了哪个库,但我又这样做了,您是对的。无论如何,这种方法需要 10 秒来旋转从相机拍摄的 4 mb 图像。谢谢
【解决方案3】:

关于 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(); 
}

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

【讨论】:

  • 我无法使用此方法保存图像并在图库中查看...请帮助
【解决方案4】:

对于 Android,我发现了这个 fork:

https://github.com/juanitobananas/AndroidMediaUtil

优于上游的好处:

  • Gradle/Android Studio 项目
  • 与 jitpack.io 兼容

它甚至可以在普通 Java 上使用,因为代码不会导入任何 Android 特定的包(虽然我没有尝试过)。

【讨论】:

    【解决方案5】:

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

    例如:

       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();
    

    没有损失!

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

    【讨论】:

    • 那不会是lossles,因为您必须对图像进行解码和重新编码,这将导致数据丢失。如果正确完成,JPEG 可以以 90 度的步长无损旋转。
    • 我猜这对 PNG / GIF 没问题,但不幸的是对 JPEG 不是无损的。
    • 我不明白为什么你会说这不是无损的?特别是如果你是逐个像素地执行这个操作?
    最近更新 更多