可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an image which I resize:
if((width != null) || (height != null))
{
try{
// scale image on disk
BufferedImage originalImage = ImageIO.read(file);
int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB
: originalImage.getType();
BufferedImage resizeImageJpg = resizeImage(originalImage, type, 200, 200);
ImageIO.write(resizeImageJpg, "jpg", file);
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
This is how I resize the image:
private static BufferedImage resizeImage(BufferedImage originalImage, int type,
Integer img_width, Integer img_height)
{
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();
return resizedImage;
}
Now the problem is, I also need to maintain aspect ratio. That is, I need the new 200/200 image to contain the new image scaled. Something like this:
I tried some things but they didn't work out as expected.
Any help is appreciated. Thanks alot.
回答1:
Here we go:
Dimension imgSize = new Dimension(500, 100);
Dimension boundary = new Dimension(200, 200);
Function to return the new size depending on the boundary
public static Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Dimension(new_width, new_height);
}
In case anyone also needs the image resizing code, here is a decent solution.
If you're unsure about the above solution there are different ways to achieve the same result.
回答2:
You will want to check out Image.getScaledInstance(), and more in this answer: How to improve the performance of g.drawImage() method for resizing images
回答3:
Translated from here:
Dimension getScaledDimension(Dimension imageSize, Dimension boundary) {
double widthRatio = boundary.getWidth() / imageSize.getWidth();
double heightRatio = boundary.getHeight() / imageSize.getHeight();
double ratio = Math.min(widthRatio, heightRatio);
return new Dimension((int) (imageSize.width * ratio), (int) (imageSize.height * ratio));
}
You can also use imgscalr to resize images while maintaining aspect ratio:
BufferedImage resizeMe = ImageIO.read(new File("orig.jpg"));
Dimension newMaxSize = new Dimension(255, 255);
BufferedImage resizedImg = Scalr.resize(resizeMe, Method.QUALITY, newMaxSize.width, newMaxSize.height);
回答4:
try this
float rateX = (float)jpDisplayImagen.getWidth()/(float)img.getWidth();
float rateY = (float)jpDisplayImagen.getHeight()/(float)img.getHeight();
if (rateX>rateY){
int W=(int)(img.getWidth()*rateY);
int H=(int)(img.getHeight()*rateY);
jpDisplayImagen.getGraphics().drawImage(img, 0, 0,W,H, null);
}
else{
int W=(int)(img.getWidth()*rateX);
int H=(int)(img.getHeight()*rateX);
jpDisplayImagen.getGraphics().drawImage(img, 0, 0,W,H, null);
}
回答5:
public class ImageTransformation {
public static final String PNG = "png";
public static byte[] resize(FileItem fileItem, int width, int height) {
try {
ResampleOp resampleOp = new ResampleOp(width, height);
BufferedImage scaledImage = resampleOp.filter(ImageIO.read(fileItem.getInputStream()), null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(scaledImage, PNG, baos);
return baos.toByteArray();
} catch (Exception ex) {
throw new MapsException("An error occured during image resizing.", ex);
}
}
public static byte[] resizeAdjustMax(FileItem fileItem, int maxWidth, int maxHeight) {
try {
BufferedInputStream bis = new BufferedInputStream(fileItem.getInputStream());
BufferedImage bufimg = ImageIO.read(bis);
//check size of image
int img_width = bufimg.getWidth();
int img_height = bufimg.getHeight();
if(img_width > maxWidth || img_height > maxHeight) {
float factx = (float) img_width / maxWidth;
float facty = (float) img_height / maxHeight;
float fact = (factx>facty) ? factx : facty;
img_width = (int) ((int) img_width / fact);
img_height = (int) ((int) img_height / fact);
}
return resize(fileItem,img_width, img_height);
} catch (Exception ex) {
throw new MapsException("An error occured during image resizing.", ex);
}
}
}
回答6:
This is my solution:
/*
Change dimension of Image
*/
public static Image resizeImage(Image image, int scaledWidth, int scaledHeight, boolean preserveRatio) {
if (preserveRatio) {
double imageHeight = image.getHeight();
double imageWidth = image.getWidth();
if (imageHeight/scaledHeight > imageWidth/scaledWidth) {
scaledWidth = (int) (scaledHeight * imageWidth / imageHeight);
} else {
scaledHeight = (int) (scaledWidth * imageHeight / imageWidth);
}
}
BufferedImage inputBufImage = SwingFXUtils.fromFXImage(image, null);
// creates output image
BufferedImage outputBufImage = new BufferedImage(scaledWidth, scaledHeight, inputBufImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputBufImage.createGraphics();
g2d.drawImage(inputBufImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
return SwingFXUtils.toFXImage(outputBufImage, null);
}
回答7:
All other answers show how to calculate the new image height in function of the new image width or vice-versa and how to resize the image using Java Image API. For those people who are looking for a straightforward solution I recommend any java image processing framework that can do this in a single line.
The exemple below uses Marvin Framework:
// 300 is the new width. The height is calculated to maintain aspect.
scale(image.clone(), image, 300);
Necessary import:
import static marvin.MarvinPluginCollection.*
回答8:
Load image:
BufferedImage bufferedImage = ImageIO.read(file);
Resize it:
private BufferedImage resizeAndCrop(BufferedImage bufferedImage, Integer width, Integer height) {
Mode mode = (double) width / (double) height >= (double) bufferedImage.getWidth() / (double) bufferedImage.getHeight() ? Scalr.Mode.FIT_TO_WIDTH
: Scalr.Mode.FIT_TO_HEIGHT;
bufferedImage = Scalr.resize(bufferedImage, Scalr.Method.ULTRA_QUALITY, mode, width, height);
int x = 0;
int y = 0;
if (mode == Scalr.Mode.FIT_TO_WIDTH) {
y = (bufferedImage.getHeight() - height) / 2;
} else if (mode == Scalr.Mode.FIT_TO_HEIGHT) {
x = (bufferedImage.getWidth() - width) / 2;
}
bufferedImage = Scalr.crop(bufferedImage, x, y, width, height);
return bufferedImage;
}
Using Scalr library:
<dependency>
<groupId>org.imgscalr</groupId>
<artifactId>imgscalr-lib</artifactId>
<version>4.2</version>
</dependency>
回答9:
I have found the selected answer to have problems with upscaling, and so I have made (yet) another version (which I have tested):
public static Point scaleFit(Point src, Point bounds) {
int newWidth = src.x;
int newHeight = src.y;
double boundsAspectRatio = bounds.y / (double) bounds.x;
double srcAspectRatio = src.y / (double) src.x;
// first check if we need to scale width
if (boundsAspectRatio < srcAspectRatio) {
// scale width to fit
newWidth = bounds.x;
//scale height to maintain aspect ratio
newHeight = (newWidth * src.y) / src.x;
} else {
//scale height to fit instead
newHeight = bounds.y;
//scale width to maintain aspect ratio
newWidth = (newHeight * src.x) / src.y;
}
return new Point(newWidth, newHeight);
}
Written in Android terminology :-)
as for the tests:
@Test public void scaleFit() throws Exception {
final Point displaySize = new Point(1080, 1920);
assertEquals(displaySize, Util.scaleFit(displaySize, displaySize));
assertEquals(displaySize, Util.scaleFit(new Point(displaySize.x / 2, displaySize.y / 2), displaySize));
assertEquals(displaySize, Util.scaleFit(new Point(displaySize.x * 2, displaySize.y * 2), displaySize));
assertEquals(new Point(displaySize.x, displaySize.y * 2), Util.scaleFit(new Point(displaySize.x / 2, displaySize.y), displaySize));
assertEquals(new Point(displaySize.x * 2, displaySize.y), Util.scaleFit(new Point(displaySize.x, displaySize.y / 2), displaySize));
assertEquals(new Point(displaySize.x, displaySize.y * 3 / 2), Util.scaleFit(new Point(displaySize.x / 3, displaySize.y / 2), displaySize));
}
回答10:
Here's a small piece of code that I wrote, it resizes the image to fit the container while keeping the image's original aspect ratio. It takes in as parameters the container's width, height and the image. You can modify it to fit your needs.
It's simple and works fine for my applications.
private Image scaleimage(int wid, int hei, BufferedImage img){
Image im = img;
double scale;
double imw = img.getWidth();
double imh = img.getHeight();
if (wid > imw && hei > imh){
im = img;
}else if(wid/imw < hei/imh){
scale = wid/imw;
im = img.getScaledInstance((int) (scale*imw), (int) (scale*imh), Image.SCALE_SMOOTH);
}else if (wid/imw > hei/imh){
scale = hei/imh;
im = img.getScaledInstance((int) (scale*imw), (int) (scale*imh), Image.SCALE_SMOOTH);
}else if (wid/imw == hei/imh){
scale = wid/imw;
im = img.getScaledInstance((int) (scale*imw), (int) (scale*imh), Image.SCALE_SMOOTH);
}
return im;
}
回答11:
Just add one more block to Ozzy's code so the thing looks like this:
public static Dimension getScaledDimension(Dimension imgSize,Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
// upscale if original is smaller
if (original_width < bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
return new Dimension(new_width, new_height);
}