Rotating an image results in corruption - java

I am trying to rotate and image left and right by 90 degrees.
For some reason though, the output of this process results in corruption.
Here is my code:
(its groovy but it doesnt take much imagination to pretend its java)
void rotate(File file){
def image = ImageIO.read(file);
double theta = Math.PI / 2;
def w = image.width / 2;
def h = image.height / 2;
def transform = new AffineTransform();
transform.rotate(theta, h, w);
def op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
image = op.filter(image, null);
def name = file.getName();
def type = name.substring(name.lastIndexOf(".") + 1, name.length());
ImageIO.write(image,type,file);
}
original:
rotated:

If by corruption you are referring to the color change, take out the filter. That's giving you a negative image if I'm understanding the syntax properly.
Whenever I use transforms I leave filters off and do them by hand. It does take a lot of time, but they always turn out being more useful. Just a suggestion.

The filter() method requires a src and dst BufferedImage, which must be different.
Image image = null;
try {
image = ImageIO.read(new File("gZtC3.jpg"));
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
double theta = Math.PI / 2;
int w = image.getWidth(null);
int h = image.getHeight(null);
AffineTransform at = AffineTransform.getRotateInstance(theta, w / 2, h / 2);
BufferedImage src = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = src.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
BufferedImage dst = op.filter(src, null);
this.add(new JLabel(new ImageIcon(dst), JLabel.CENTER));

Related

How do you shrink an image in half in Java without using Graphics2D?

I need to write a program that shrinks an image in half without using any libraries other than Java Graphics and Java Color. I wrote one earlier with Graphics2D that looked like this --
public static void shrink(String orig, String convert) throws Exception { //Ahh damn we needed one from the red group
BufferedImage bufferedimg = null;
File f = new File(orig);
bufferedimg = ImageIO.read(f);
int width = bufferedimg.getWidth();
int height = bufferedimg.getHeight();
int finalWidth = width/2;
int finalHeight = height/2;
BufferedImage resizedImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(bufferedimg, 0, 0, finalWidth, finalHeight, null);
g.dispose();
f = new File(convert);
ImageIO.write(resizedImage, "png", f);
}
Can anyone please help?

Problems shearing BufferedImage with AffineTransform

I want to shear my images with AffineTransform in Java. If I do that I always get black bounds.
for (File input : inputImages) {
if (!input.getName().contains(".DS_Store")) {
BufferedImage buffer = ImageIO.read(input);
for (int i = 0; i <= 2; i++) {
AffineTransform tx = new AffineTransform();
tx.translate(buffer.getHeight() / 2, buffer.getWidth() / 2);
tx.shear(0.3, 0);
tx.translate(-buffer.getWidth() / 2, -buffer.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
BufferedImage newImage = new BufferedImage(buffer.getHeight(), buffer.getWidth(), buffer.getType());
op.filter(buffer, newImage);
File output = new File("output/" + FilenameUtils.getBaseName(input.getName()) + i + ".png");
ImageIO.write(newImage, "png", output);
}
}
}
Is there are way to avoid these black bounds and to get a white or transparent background?
Use BufferedImage.TYPE_INT_ARGB as the image type to create a transparent image
If I use TYPE_ARGB my output image is completely transparent
Works fine for more
BufferedImage buffer = ImageIO.read(...);
AffineTransform tx = new AffineTransform();
tx.translate(buffer.getHeight() / 2, buffer.getWidth() / 2);
tx.shear(0.3, 0);
tx.translate(-buffer.getWidth() / 2, -buffer.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
BufferedImage newImage = new BufferedImage(buffer.getHeight(), buffer.getWidth(), BufferedImage.TYPE_INT_ARGB);
op.filter(buffer, newImage);
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(newImage)));
If you prefer, you could fill the newImage with a default color

Problems with rotating a BufferedImage

I'm trying to rotate an image clockwise and counter clockwise. With the help of this answer from Sri Harsha Chilakapati I managed to get it working according to my needs. This is the code
String rotateURL = tmp_dir + "/" + strusername + "rotate.jpg";
File fileJPG = new File(tmp_dir + "/" + strusername + "FullSize.jpg");
fullImage = ImageIO.read(fileJPG);
leftImage = rotateLeft(fullImage, 90);
writeImageToFile(leftImage, "jpg", new File(rotateURL));
public static BufferedImage rotateLeft(BufferedImage img, double angle)
{
double sin = Math.abs(Math.sin(Math.toRadians(angle))),
cos = Math.abs(Math.cos(Math.toRadians(angle)));
int w = img.getWidth(null), h = img.getHeight(null);
int neww = (int) Math.floor(w*cos + h*sin),
newh = (int) Math.floor(h*cos + w*sin);
BufferedImage bimg = new BufferedImage(neww, newh, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimg.createGraphics();
g.translate((neww-w)/2, (newh-h)/2);
g.rotate(Math.toRadians(angle), w/2, h/2);
g.drawRenderedImage(img, null);
g.dispose();
return bimg;
}
However, I seem to have a caching (not sure about this) problem where I need to put a Thread.sleep(9000);above the fullImage = ImageIO.read(fileJPG); line otherwise my image element would contain the right dimension but doesn't show it rotated. Since a picture says more than a 1000 words:
To be clear, this is how it should look like:
Now the sleep is a solution but to be honest I don't want to wait 9 seconds (counted it, 8 doesn't work) before it rotates. Also, I'm not sure what it gives on a slower computer because it could be possible that it will take longer?
Since AffineTransform quadrantrotate should be more efficient (and the question is marked as duplicate) I tried following answer but the problem still occurs. The code:
AffineTransform at = new AffineTransform();
at.translate(100, 40);
at.quadrantRotate(1, img.getWidth() / 2, img.getHeight() / 2);
g.drawImage(img, at, null);
g.dispose();
still gives the same issues. I tried a different approach on reading the image
fullImage = Toolkit.getDefaultToolkit().getImage(new File(rotateURL).getAbsolutePath());
leftImage = rotatePicture(fullImage, 90);
but still the problem remains. So there seems to be a problem with the reading of the image, are there any other ways I didn't think about while reading the image?

JAI Change JPEG Resolution

I am having difficulty using the Java JAI (Java Advance Imaging) API to change the resolution of a JPEG image from lets say 1024x800 to 512x400.
I have played around with the API and keep getting stream or java.lang.OutOfMemory exceptions.
Anyone with a working example.
Here's one using JAI
public void resize(String filename, RenderedOp image, double wScale, double hScale)
{
// now resize the image
ParameterBlock pb = new ParameterBlock();
pb.addSource(image); // The source image
pb.add(wScale); // The xScale
pb.add(hScale); // The yScale
pb.add(0.0F); // The x translation
pb.add(0.0F); // The y translation
RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
RenderedOp resizedImage = JAI.create("SubsampleAverage", pb, hints);
// lastly, write the newly-resized image to an
// output stream, in a specific encoding
try
{
FileOutputStream fos = new FileOutputStream(new File(filename));
JAI.create("encode", resizedImage, fos, getImageType(filename), null);
}
catch (FileNotFoundException e)
{
}
}
Here's a working example, supplied on an "as is" basis with no warranty :)
BufferedImage scaleImage(BufferedImage sourceImage, int scaledWidth) {
float scale = scaledWidth / (float) sourceImage.getWidth();
int scaledHeight = (int) (sourceImage.getHeight() * scale);
Image scaledImage = sourceImage.getScaledInstance(
scaledWidth,
scaledHeight,
Image.SCALE_AREA_AVERAGING
);
BufferedImage bufferedImage = new BufferedImage(
scaledImage.getWidth(null),
scaledImage.getHeight(null),
BufferedImage.TYPE_INT_RGB
);
Graphics g = bufferedImage.createGraphics();
g.drawImage(scaledImage, 0, 0, null);
g.dispose();
return bufferedImage;
}

How do you create a thumbnail image out of a JPEG in Java?

Can someone please help with some code for creating a thumbnail for a JPEG in Java.
I'm new at this, so a step by step explanation would be appreciated.
Image img = ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, BufferedImage.SCALE_SMOOTH);
This will create a 100x100 pixels thumbnail as an Image object. If you want to write it back to disk simply convert the code to this:
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
img.createGraphics().drawImage(ImageIO.read(new File("test.jpg")).getScaledInstance(100, 100, Image.SCALE_SMOOTH),0,0,null);
ImageIO.write(img, "jpg", new File("test_thumb.jpg"));
Also if you are concerned about speed issues (the method described above is rather slow if you want to scale many images) use these methods and the following declaration :
private BufferedImage scale(BufferedImage source,double ratio) {
int w = (int) (source.getWidth() * ratio);
int h = (int) (source.getHeight() * ratio);
BufferedImage bi = getCompatibleImage(w, h);
Graphics2D g2d = bi.createGraphics();
double xScale = (double) w / source.getWidth();
double yScale = (double) h / source.getHeight();
AffineTransform at = AffineTransform.getScaleInstance(xScale,yScale);
g2d.drawRenderedImage(source, at);
g2d.dispose();
return bi;
}
private BufferedImage getCompatibleImage(int w, int h) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(w, h);
return image;
}
And then call :
BufferedImage scaled = scale(img,0.5);
where 0.5 is the scale ratio and img is a BufferedImage containing the normal-sized image.
As you might have found out "easy" and "good looking result" are two very different things. I have encapsulated both of these requirements into a very simple java image scaling library (Apache 2 license) that just does everything right for you.
Example code to create a thumbnail looks like this:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 150);
Your image proportions are honored, the library makes a best-guess at the method it should use based on the amount of change in the image due to scaling (FASTEST, BALANCED or QUALITY) and the best supported Java2D image types are always used to do the scaling to avoid the issue of "black" results or really terrible looking output (e.g. overly dithered GIF images).
Also, if you want to force it to output the best looking thumbnail possible in Java, the API call would look like this:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY,
150, 100, Scalr.OP_ANTIALIAS);
Not only will the library use the Java2D recommended incremental scaling for you to give you the best looking result, it will also apply an optional antialiasing effect to the thumbnail (ConvolveOp with a very fine-tuned kernel) to every-so-slightly soften the transitions between pixel values so make the thumbnail look more uniform and not sharp or poppy as you might have seen when you go from very large images down to very small ones.
You can read through all the comments in the library (the code itself is doc'ed heavily) to see all the different JDK bugs that are worked around or optimizations that are made to improve the performance or memory usage. I spent a LOT of time tuning this implementation and have had a lot of good feedback from folks deploying it in web apps and other Java projects.
This is simple way of creating a 100 X 100 thumbnail without any stretch or skew in image.
private void saveScaledImage(String filePath,String outputFile){
try {
BufferedImage sourceImage = ImageIO.read(new File(filePath));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
if(width>height){
float extraSize= height-100;
float percentHight = (extraSize/height)*100;
float percentWidth = width - ((width/100)*percentHight);
BufferedImage img = new BufferedImage((int)percentWidth, 100, BufferedImage.TYPE_INT_RGB);
Image scaledImage = sourceImage.getScaledInstance((int)percentWidth, 100, Image.SCALE_SMOOTH);
img.createGraphics().drawImage(scaledImage, 0, 0, null);
BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
img2 = img.getSubimage((int)((percentWidth-100)/2), 0, 100, 100);
ImageIO.write(img2, "jpg", new File(outputFile));
}else{
float extraSize= width-100;
float percentWidth = (extraSize/width)*100;
float percentHight = height - ((height/100)*percentWidth);
BufferedImage img = new BufferedImage(100, (int)percentHight, BufferedImage.TYPE_INT_RGB);
Image scaledImage = sourceImage.getScaledInstance(100,(int)percentHight, Image.SCALE_SMOOTH);
img.createGraphics().drawImage(scaledImage, 0, 0, null);
BufferedImage img2 = new BufferedImage(100, 100 ,BufferedImage.TYPE_INT_RGB);
img2 = img.getSubimage(0, (int)((percentHight-100)/2), 100, 100);
ImageIO.write(img2, "jpg", new File(outputFile));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The JMagick library (and implementation of ImageMagick in Java) will have what you need.
the Java code above (with the scale / getCompatibleImage methods) worked great for me, but when I deployed to a server, it stopped working, because the server had no display associated with it -- anyone else with this problem can fix it by using:
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
instead of
BufferedImage bi = getCompatibleImage(w, h);
and deleting the getCompatibleImage method
(later note -- it turns out this works great for most images, but I got a bunch from my companys marketing department that are 32 bit color depth jpeg images, and the library throws an unsupported image format exception for all of those :( -- imagemagick / jmagick are starting to look more appealing)
I have writtena util class with static methods years ago using JAI. Java Advanced Imaging API is the most reliable API in Java to deal with images. It's vector interpolation is closest thing to Photoshop in Java world. Here is one of them:
public static ByteArrayOutputStream resize(InputStream inputStream , int IMG_WIDTH,
int IMG_HEIGHT) throws Exception {
BufferedImage originalImage = ImageIO.read(inputStream);
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB
: originalImage.getType();
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
type);
{
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(resizedImage, "png", bos);
return bos;
}
I know this is a pretty old post. I have been looking for a solution to generate the thumbnail so end up using this
Thumbnails.of(originalImage).scale(0.25).asBufferedImage();
if you are using for mobile would suggest to set the scale to 0.45
Thumbnails.of(originalImage).scale(0.45).asBufferedImage();
https://github.com/coobird/thumbnailator
This is certainly much faster using the Graphics2D as have tested the both options.
I've used Thumbnailator! It solved my problem with two lines of code.
https://github.com/coobird/thumbnailator
Simple way to create a thumbnail without stretching or a library. Works with transparency in pngs, too.
public File createThumbnail(String imageUrl, String targetPath) {
final int imageSize = 100;
File thumbnail = new File(targetPath);
try {
thumbnail.getParentFile().mkdirs();
thumbnail.createNewFile();
BufferedImage sourceImage = ImageIO.read(new File(imageUrl));
float width = sourceImage.getWidth();
float height = sourceImage.getHeight();
BufferedImage img2;
if (width > height) {
float scaledWidth = (width / height) * (float) imageSize;
float scaledHeight = imageSize;
BufferedImage img = new BufferedImage((int) scaledWidth, (int) scaledHeight, sourceImage.getType());
Image scaledImage = sourceImage.getScaledInstance((int) scaledWidth, (int) scaledHeight, Image.SCALE_SMOOTH);
img.createGraphics().drawImage(scaledImage, 0, 0, null);
int offset = (int) ((scaledWidth - scaledHeight) / 2f);
img2 = img.getSubimage(offset, 0, imageSize, imageSize);
}
else if (width < height) {
float scaledWidth = imageSize;
float scaledHeight = (height / width) * (float) imageSize;
BufferedImage img = new BufferedImage((int) scaledWidth, (int) scaledHeight, sourceImage.getType());
Image scaledImage = sourceImage.getScaledInstance((int) scaledWidth, (int) scaledHeight, Image.SCALE_SMOOTH);
img.createGraphics().drawImage(scaledImage, 0, 0, null);
int offset = (int) ((scaledHeight - scaledWidth) / 2f);
img2 = img.getSubimage(0, offset, imageSize, imageSize);
}
else {
img2 = new BufferedImage(imageSize, imageSize, sourceImage.getType());
Image scaledImage = sourceImage.getScaledInstance(imageSize, imageSize, Image.SCALE_SMOOTH);
img2.createGraphics().drawImage(scaledImage, 0, 0, null);
}
ImageIO.write(img2, "png", thumbnail);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return thumbnail;
}
I have created a application called fotovault (sourceforge.net) which can upload images and create thumbnails in java using imagej apis.
Please read my blog below
http://www.gingercart.com/Home/java-snippets/create-image-thumbnail-in-java-using-imagej-api
I have gone through a blog according to which you have following options -
For simple RGB files use ImageScalr . ImageIO class is used for reading files and ImageScalr to create thumbnails
For supporting RGB + CYMK, use ImageIO and JAI (Java Advanced Imaging) API for reading files and ImageScalr to create thumbnail.
In case you don’t know what file formats, color mode you are going to deal with, safest option is to use ImageMagick.
Here is link that gives a complete answer with code snippets.
There are many image processing frameworks available that you can do this with just a few lines. The example below generates the thumbnails in different resolutions (given a width as reference) using Marvin Framework. The three thumbnails were generated in 92 ms.
input:
output:
import static marvin.MarvinPluginCollection.*;
MarvinImage image = MarvinImageIO.loadImage("./res/input.jpg");
MarvinImage scaledImage = new MarvinImage(1,1);
scale(image, scaledImage, 250);
MarvinImageIO.saveImage(scaledImage, "./res/output_x250.jpg");
scale(image, scaledImage, 150);
MarvinImageIO.saveImage(scaledImage, "./res/output_x150.jpg");
scale(image, scaledImage, 50);
MarvinImageIO.saveImage(scaledImage, "./res/output_x50.jpg");
Maybe the simplest approach would be:
static public BufferedImage scaleImage(BufferedImage image, int max_width, int max_height) {
int img_width = image.getWidth();
int img_height = image.getHeight();
float horizontal_ratio = 1;
float vertical_ratio = 1;
if(img_height > max_height) {
vertical_ratio = (float)max_height / (float)img_height;
}
if(img_width > max_width) {
horizontal_ratio = (float)max_width / (float)img_width;
}
float scale_ratio = 1;
if (vertical_ratio < horizontal_ratio) {
scale_ratio = vertical_ratio;
}
else if (horizontal_ratio < vertical_ratio) {
scale_ratio = horizontal_ratio;
}
int dest_width = (int) (img_width * scale_ratio);
int dest_height = (int) (img_height * scale_ratio);
BufferedImage scaled = new BufferedImage(dest_width, dest_height, image.getType());
Graphics graphics = scaled.getGraphics();
graphics.drawImage(image, 0, 0, dest_width, dest_height, null);
graphics.dispose();
return scaled;
}
Solution for the case when you want to create a quadrate (75x75) thumbnail from the non-quadrate source.
Code below first crop original image to quadrate using smaller size than resizes the quadrate image.
public static void generateThumbnailWithCrop(String imgPath, String thumbnailPath, int size) throws IOException {
BufferedImage sourceImage = ImageIO.read(new File(imgPath));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
int smallerSize = width > height ? height : width;
BufferedImage quadrateImage = cropToQuadrate(sourceImage, smallerSize);
int type = quadrateImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : quadrateImage.getType();
BufferedImage resizedImage = resizeImageWithHint(quadrateImage, type, size, size);
File thumb = new File(thumbnailPath);
thumb.getParentFile().mkdirs();
ImageIO.write(resizedImage, "jpg", thumb);
}
private static BufferedImage cropToQuadrate(BufferedImage sourceImage, int size) {
BufferedImage img = sourceImage.getSubimage(0, 0, size, size);
BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = copyOfImage.createGraphics();
g.drawImage(img, 0, 0, null);
return copyOfImage;
}
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setComposite(AlphaComposite.Src);
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
Thumbnails4j (I'm a maintainer, but it's owned by Elastic) is a java library that can be used to create thumbnails from image files, as well as from other file types.
File input = new File("/path/to/my_file.jpeg");
Thumbnailer thumbnailer = new ImageThumbnailer("png"); // or "jpg", whichever output format you want
List<Dimensions> outputDimensions = Collections.singletonList(new Dimensions(100, 100));
BufferedImage output = thumbnailer.getThumbnails(input, outputDimensions).get(0);

Categories

Resources