22

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

Unsigned
  • 9,640
  • 4
  • 43
  • 72
Henry
  • 32,689
  • 19
  • 120
  • 221
  • not in Java, but http://jpegclub.org/jpegtran/ should be the best command line utility for lossless jpeg rotate (Windows / Linux) – Henry Apr 24 '14 at 23:40
  • Hello if you have used below solution I would like to request your help if you can. I have difficulties to find where to import java.awt.Rectangle; I have tried some jars in web but I cant use them with Android Studio. Can you help me with the jar that you have imported. Thanks – Ultimo_m Sep 12 '15 at 21:38

5 Answers5

15

I found this: http://mediachest.sourceforge.net/mediautil/

API: http://mediachest.sourceforge.net/mediautil/javadocs/mediautil/image/jpeg/LLJTran.html

Henry
  • 32,689
  • 19
  • 120
  • 221
  • @Henry hey please could you tell me how do I save the image using this..apparently this post isnt helping me or I am doing the wrong way – therealprashant Mar 01 '15 at 12:03
7

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
    ...
}
quietmint
  • 13,885
  • 6
  • 48
  • 73
  • I've ran a test with retrieving the EXIF rotation tag with both Sanselan and MediaUtil, but the MediaUtil approach above fails for me at the llj.getImageInfo(); step (not finding any EXIF metadata), where the Sanselan approach does find the EXIF metadata. It seems that LLJtran does not support reading all modern JPEGs. – JeroenHoek Dec 02 '13 at 10:26
  • I have difficulties to find where to import java.awt.Rectangle; I have tried some jars in web but I cant use them with Android Studio. Can you help me with the jar that you have imported. Thanks – Ultimo_m Sep 12 '15 at 21:37
  • @user113215 Thanks a lot for your comment, I dont know what library I have imported but I did that again and you were right. Anyway this approach takes 10 seconds to rotate 4 mb image taken from camera. Thanks – Ultimo_m Sep 17 '15 at 22:50
6

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.

user3400408
  • 61
  • 1
  • 2
0

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

Nicolas Raoul
  • 58,567
  • 58
  • 222
  • 373
-4

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.

J_Y_C
  • 697
  • 1
  • 5
  • 7
  • 7
    That wouldn't be lossles, as you'd have to decode and re-encode the image, which will result in loss of data. JPEGs can be losslessly rotate in 90-degree steps, when done correctly. – Joachim Sauer Apr 01 '09 at 18:52
  • This is fine for PNG / GIF I guess, but not lossless to JPEG unfortunately. – Henry Apr 01 '09 at 21:28
  • I don't understand why you would say this isn't lossless? Especially if you are doing this operation pixel by pixel? – J_Y_C Apr 02 '09 at 00:35