Reputation: 199
I am compressing an image doing Jpeg compression in Java and then resizing them before storing. I am keeping the storage height as 480
and calculating the height
based on aspect ratio, so to keep the original height:width
ratio same.
This is the code I am using
String inputImagePath = "1.JPG";
String outputImagePath = "Test Compression\\" + "1.JPG";
File imageFile = new File(inputImagePath);
File compressedImageFile = new File(outputImagePath);
int height = 640;
System.out.print("Conversion Start!\n");
if (imageFile != null)
{
InputStream is = new FileInputStream(imageFile);
OutputStream os = new FileOutputStream(compressedImageFile);
float quality = 0.2 f;
BufferedImage image = ImageIO.read(is);
double aspectRatio = (double) image.getWidth() / image.getHeight();
width = (int)(height * aspectRatio);
System.out.println("Original height = " + image.getHeight() + " Original width = " + image.getWidth());
System.out.println(" aspect ratio = " + aspectRatio);
System.out.println("height = " + height + " width = " + width + " aspect ratio = " + aspectRatio);
BufferedImage resizedImage = new BufferedImage(width, height, image.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
if (!writers.hasNext())
throw new IllegalStateException("No writers found");
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
writer.write(null, new IIOImage(resizedImage, null, null), param);
}
System.out.print("Conversion compete!");
Here is the image metadata
Here is the printed content:
Original height = 1920 Original width = 2560
aspect ratio = 1.3333333333333333
height = 480 width = 640
aspect ratio = 1.3333333333333333
I applied the code to other images which actually had width > height
and I had no rotation issues. This rotaion issue is only occuring for the images with height > width
As far as I know there is nothing wrong in my code, I must be missing something related to getHeight() and getWidth() functions. Please help me out
Upvotes: 6
Views: 3032
Reputation: 199
For future references, I got through the references given by Sergey Grinev and altered the code a little bit and got desired results. Here is the code
Metadata metadata = ImageMetadataReader.readMetadata(imageFile);
Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
int orientation = 1;
try{
orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
} catch (MetadataException me) {
System.out.println("Could not get orientation");
}
int orgWidth = image.getWidth();
int orgHeight = image.getHeight();
double orgAspectRatio = (double)orgWidth/orgHeight;
AffineTransform affineTransform = new AffineTransform();
AffineTransformOp affineTransformOp;
BufferedImage orientedImage = new BufferedImage(image.getHeight(), image.getWidth(), image.getType());
boolean rotation = false;
switch (orientation) {
case 1:
orientedImage = image;
break;
case 2: // Flip X
affineTransform.scale(-1.0, 1.0);
affineTransform.translate(-orgWidth, 0);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 3: // PI rotation
affineTransform.translate(orgWidth, orgHeight);
affineTransform.rotate(Math.PI);
affineTransformOp = new AffineTransformOp(affineTransform,AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 4: // Flip Y
affineTransform.scale(1.0, -1.0);
affineTransform.translate(0, -orgHeight);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 5: // - PI/2 and Flip X
rotation = true;
affineTransform.rotate(-Math.PI / 2);
affineTransform.scale(-1.0, 1.0);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 6: // -PI/2 and -width
rotation = true;
affineTransform.translate(orgHeight, 0);
affineTransform.rotate(Math.PI/2);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 7: // PI/2 and Flip
rotation = true;
affineTransform.scale(-1.0, 1.0);
affineTransform.translate(-orgHeight, 0);
affineTransform.translate(0, orgWidth);
affineTransform.rotate(3 * Math.PI / 2);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
case 8: // PI / 2
rotation = true;
affineTransform.translate(0, orgWidth);
affineTransform.rotate(3 * Math.PI / 2);
affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
orientedImage = affineTransformOp.filter(image, orientedImage);
break;
default:
orientedImage = image;
break;
}
double aspectRatio;
if(rotation){
aspectRatio = (double)orientedImage.getWidth()/orientedImage.getHeight();
width = outWidth;
height = (int)(width/aspectRatio);
}
else{
aspectRatio = (double)orientedImage.getWidth()/orientedImage.getHeight();
width = (int)(height*aspectRatio);
}
Upvotes: 2
Reputation: 34508
There can be rotation metadata in the jpeg images which Java doesn't recognize by default.
It looks like: Orientation : rotate 90
in the jpeg properties.
You need a 3rd party library to handle it, see How to rotate JPEG images based on the orientation metadata?
Upvotes: 3