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

发布于 2024-07-16 03:37:01 字数 53 浏览 5 评论 0 原文

是否有一个 Java 库可以以 90 度的增量旋转 JPEG 文件,而不会导致图像质量下降?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

辞慾 2024-07-23 03:37:01

基于 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
    ...
}

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

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
    ...
}
手长情犹 2024-07-23 03:37:01

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

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

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):

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 File objects 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.

一桥轻雨一伞开 2024-07-23 03:37:01

特别是对于 Android,我发现了这个分支:

https://github.com/juanitobananas/AndroidMediaUtil

优点上游:

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

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

For Android specifically, I found this fork:

https://github.com/juanitobananas/AndroidMediaUtil

Benefits over upstream:

  • Gradle/Android Studio project
  • Compatible with jitpack.io

It might even be usable on normal Java, as the code does not import any Android-specific package (I haven't tried though).

云醉月微眠 2024-07-23 03:37:01

你不需要外部库来完成这种事情,它都内置在 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),并将其逐像素转换到新图像上。

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文