I'm working with Java to store and modify .jpg images, (not Android or Swing). I want to transform an image with a new dimension keeping the aspect ratio and filling the background with white color if the new dimension is not proportional to the original image.
BufferedImage image = /*Here i read from disk and load the image */;
image = resizeImage(image, newWidth, newHeight);
ImageIO.write(image, extension, new File(filename + "_" + page + "." + extension));
The function I'm trying to implement is resizeImage: in the example resizes the image but it doesn't keep the aspect ratio.
private static BufferedImage resizeImage(BufferedImage originalImage, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height, originalImage.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
I think a picture will be more illustrative of what I'm asking for:
If the original image is 200x200 and is asked to resize to 400x300 the result should be a picture with white margin and the original picture resized inside. In this example should be 300x300.
The problem is not how to resize, it's how to fill the remaining image with white and the original resized image on the center of it.
This code worked for me:
private static BufferedImage resizeImage(BufferedImage originalImage, int newWidth, int newHeight) {
BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
Graphics2D graphics = resizedImage.createGraphics();
graphics.setColor(Color.WHITE);
// fill the entire picture with white
graphics.fillRect(0, 0, newWidth, newHeight);
int maxWidth = 0;
int maxHeight = 0;
// go along the width and height in increments of 1 until one value is equal to the specified resize value
while (maxWidth <= newWidth && maxHeight <= newHeight)
{
++maxWidth;
++maxHeight;
}
// calculate the x value with which the original image is centred
int centerX = (resizedImage.getWidth() - maxWidth) / 2;
// calculate the y value with which the original image is centred
int centerY = (resizedImage.getHeight() - maxHeight) / 2;
// draw the original image
graphics.drawImage(originalImage, centerX, centerY, maxWidth, maxHeight, null);
graphics.dispose();
return resizedImage;
}
Before:
After:
I'm trying to resize an image to 50 * 50 pixels. Im taking the images, from their path stored in a Database. I have no problem getting the images and displaying them. I'm just wondering at what point should I try resize the images. Should it be when I get the image as a buffered image, or just try to resize the icon?
while (rs.next()) {
i = 1;
imagePath = rs.getString("path");
System.out.println(imagePath + "\n");
System.out.println("TESTING - READING IMAGE");
System.out.println(i);
myImages[i] = ImageIO.read(new File(imagePath));
**resize(myImages[i]);**
imglab[i] = new JLabel(new ImageIcon(myImages[i]));
System.out.println(i);
imgPanel[i]= new JPanel();
imgPanel[i].add(imglab[i]);
loadcard.add(imgPanel[i], ""+i);
i++;
The above code is retrieving the image and assigning it to an ImageIcon, then JLabel. I have attempted to resize the buffered image, by using the below resize method. Could you guys, shed any light on why this isn't working for me? Not getting any errors, just the image remains its original size.
public static BufferedImage resize(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
int newH = 50;
int newW = 50;
BufferedImage dimg = dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
System.out.println("Is this getting here at all " + dimg);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
g.dispose();
return dimg;
}
You are calling resize() on each image, but not replacing the images in the array. So the output of resize() is being thrown away:
myImages[i] = ImageIO.read(new File(imagePath)); // create an image
resize(myImages[i]); // returns resized img, but doesn't assign it to anything
imglab[i] = new JLabel(new ImageIcon(myImages[i])); // uses _original_ img
You need to change the middle line to:
myImages[i] = resize(myImages[i]);
to make this work.
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);