Resize Buffered Image without creating new instance (java) - java

I was wondering if there is a way to resize a BufferedImage without creating a new instance of another image. I am wondering this because I think that it will be inefficient to create a new image each time I want to resize a BufferedImage for my application. Here is some code I've seen that explains what I don't want:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = dimg.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return dimg;
}
public static BufferedImage scale(BufferedImage src, int w, int h)
{
BufferedImage img =
new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int x, y;
int ww = src.getWidth();
int hh = src.getHeight();
int[] ys = new int[h];
for (y = 0; y < h; y++)
ys[y] = y * hh / h;
for (x = 0; x < w; x++) {
int newX = x * ww / w;
for (y = 0; y < h; y++) {
int col = src.getRGB(newX, ys[y]);
img.setRGB(x, y, col);
}
}
return img;
}
private BufferedImage resize(BufferedImage src, int targetSize) {
if (targetSize <= 0) {
return src; //this can't be resized
}
int targetWidth = targetSize;
int targetHeight = targetSize;
float ratio = ((float) src.getHeight() / (float) src.getWidth());
if (ratio <= 1) { //square or landscape-oriented image
targetHeight = (int) Math.ceil((float) targetWidth * ratio);
} else { //portrait image
targetWidth = Math.round((float) targetHeight / ratio);
}
BufferedImage bi = new BufferedImage(targetWidth, targetHeight, src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); //produces a balanced resizing (fast and decent quality)
g2d.drawImage(src, 0, 0, targetWidth, targetHeight, null);
g2d.dispose();
return bi;
}
Thank you for any responses!

Related

How to fit a portrait image in landscape orientation in JAVA (with border) keeping the aspect ratio

my landscape images are already as i want them to be at the output, but for the portrait my code does not work, i know i have something to do when the source height > source width but I don't know exactly what. I need help !
Here is my code :
public static BufferedImage resize(BufferedImage img, int newW, int newH){
int w = img.getWidth();
int h = img.getHeight();
double thumbRatio = (double) newW / (double) newH;
int imageWidth = img.getWidth(null);
int imageHeight = img.getHeight(null);
double aspectRatio = (double) imageWidth / (double) imageHeight;
if (thumbRatio < aspectRatio) {
newH = (int) (newW / aspectRatio);
}
else {
newW = (int) (newH * aspectRatio);
}
//if (w > 1024 || h > 768) {
BufferedImage dimg = dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
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;
//}else return img;
}
this is the expected output
finally find the solution by adding the code between commentaries "PORTRAIT CASE", this does the trick except that i had to change the final resolution to 1010x740 because of black border apparition with the 1024x768 resoltuion. The solution was to place my image on other white image (jpanel here). Hope this code will be usefull for someone
public static BufferedImage resize(BufferedImage img, int newW, int newH){
int w = img.getWidth();
int h = img.getHeight();
double thumbRatio = (double) newW / (double) newH;
int imageWidth = img.getWidth(null);
int imageHeight = img.getHeight(null);
double aspectRatio = (double) imageWidth / (double) imageHeight;
//PORTRAIT CASE
if (h > w)
{
if (thumbRatio < aspectRatio) {
newH = (int) (newW / aspectRatio);
}
else {
newW = (int) (newH * aspectRatio);
}
BufferedImage dimg = dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
g.dispose();
JFrame frame = new JFrame();
JLayeredPane lpane = new JLayeredPane();
JPanel panelBlue = new JPanel();
JPanel panelGreen = new JPanel();
frame.setPreferredSize(new Dimension(1024, 768));
frame.setLayout(new BorderLayout());
frame.add(lpane, BorderLayout.CENTER);
lpane.setBounds(0, 0, 1024, 768);
panelBlue.setBackground(Color.WHITE);
panelBlue.setBounds(0, 0, 1024, 768);
panelBlue.setOpaque(true);
panelGreen.setBackground(Color.GREEN);
panelGreen.setBounds(0, 0, 1024, 768);
panelGreen.setOpaque(true);
lpane.add(panelGreen, new Integer(0), 0);
lpane.add(panelBlue, new Integer(1), 0);
ImageIcon imgg = new ImageIcon(dimg);
JLabel label = new JLabel("", imgg, JLabel.CENTER);
panelBlue.add( label, BorderLayout.CENTER );
frame.pack();
frame.setVisible(true);
BufferedImage bi = new BufferedImage(1010, 740, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
lpane.paint(g2);
g2.dispose();
return bi;
}
//PORTRAIT CASE
if (thumbRatio < aspectRatio) {
newH = (int) (newW / aspectRatio);
}
else {
newW = (int) (newH * aspectRatio);
}
if (w > 1024 || h > 768) {
BufferedImage dimg = dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
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;
}else return img;
}

How to fit width of a page when printing in java

I can print any component smartly with a footer by this code. Its working smartly.
public class MultiPagePrintable implements Printable {
private JComponent component;
private int lastPage = 0;
private double yOffset;
private Font footerFont;
public MultiPagePrintable(JComponent component) {
this.component = component;
footerFont = new Font("Arial", Font.BOLD, 24);
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = NO_SUCH_PAGE;
String name = "I be mighty!";
String page = Integer.toString(pageIndex);
FontMetrics fm = graphics.getFontMetrics(footerFont);
double footerHeight = fm.getHeight() + 4;
double height = pageFormat.getImageableHeight() - footerHeight;
component.setSize(component.getPreferredSize());
if (lastPage != pageIndex) {
lastPage = pageIndex;
yOffset = height * pageIndex;
if (yOffset > component.getHeight()) {
yOffset = -1;
}
}
if (yOffset >= 0) {
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());
g2d.translate(0, -yOffset);
component.printAll(g2d);
g2d.translate(0, +yOffset);
Shape footerArea = new Rectangle2D.Double(0, height, pageFormat.getImageableWidth(), footerHeight);
g2d.setColor(Color.WHITE);
g2d.fill(footerArea);
g2d.setColor(Color.RED);
g2d.draw(footerArea);
g2d.setColor(Color.BLACK);
g2d.translate(0, (pageFormat.getImageableHeight() - footerHeight));
float x = 2;
float y = (float)((footerHeight - fm.getHeight()) / 2d);
g2d.drawString(name, x, y + fm.getAscent());
x = (float)(pageFormat.getImageableWidth() - fm.stringWidth(page) - 2);
g2d.drawString(page, x, y + fm.getAscent());
g2d.dispose();
result = PAGE_EXISTS;
}
return result;
}
}
But problem is, it can't scale component width to fit page. However i don't want to fit height. Because this code can already print multiple page. and i need it.
You want to scale the Graphics2D:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = Math.min(width / component.getWidth(),
height / component.getHeight());
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);
I'm not sure what you mean by "I don't want to fit height" but you can always ignore the height, if you want:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = width / component.getWidth();
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);

Using Bitmap to draw an image in Android

I need to put a random image inside a screen with given resolution (640x480, 1280x720, etc). I finished it in Java. In Android do not support the BufferedImage and Graphics2D, I wonder if there is a way to replace this code from Java to Android. Here is my code from Java:
public BufferedImage resizeImage(BufferedImage originalImage, int type){
BufferedImage resizedImage = new BufferedImage(screenWidth, screenHeight, type);
Graphics2D g = resizedImage.createGraphics();
int imgWidth = originalImage.getWidth();
int imgHeight = originalImage.getHeight();
int newImgWidth = 0;
int newImgHeight = 0;
int X = 0;
int Y = 0;
if (imgWidth > screenWidth){
// scale width to fit
newImgWidth = screenWidth;
//scale height to maintain aspect ratio
newImgHeight = (newImgWidth * imgHeight) / imgWidth;
}
if (newImgHeight > screenHeight) {
//scale height to fit instead
newImgHeight = screenHeight;
//scale width to maintain aspect ratio
newImgWidth = (newImgHeight * imgWidth) / imgHeight;
}
if (imgWidth < screenWidth && imgHeight < screenHeight) {
X = screenWidth/2 - imgWidth/2;
Y = screenHeight/2 - imgHeight/2;
g.drawImage(originalImage, X, Y, imgWidth, imgHeight, null);
g.dispose();
return resizedImage;
}
X = screenWidth/2 - newImgWidth/2;
Y = screenHeight/2 - newImgHeight/2;
g.drawImage(originalImage, X, Y, newImgWidth, newImgHeight, null);
g.dispose();
return resizedImage;
}
Thank you in advance!

Where to/ how to call my resizeimage method

Ok so I created a method that resizes an ImageIcon my question is how/ where do I call it in order to make the ImageIcon I want to resize to that size here it is thanks, and the method should work so anyone looking for a method that does resize you should be able to use it :)
public static void resizeIcon(ImageIcon icon, int Width, int Height){
Image geticon = icon.getImage();
BufferedImage bi = new BufferedImage(geticon.getWidth(null), geticon.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(geticon, 0, 0, Width, Height, null);
ImageIcon resizedicon = new ImageIcon(bi);
icon = resizedicon;
}
you save the resized image first .Then set the imageicon by resource as the resized image.
public static Boolean resizeImage(String sourceImage, String destinationImage, Integer Width, Integer Height) {
BufferedImage origImage;
try {
origImage = ImageIO.read(new File(sourceImage));
int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();
//*Special* if the width or height is 0 use image src dimensions
if (Width == 0) {
Width = origImage.getWidth();
}
if (Height == 0) {
Height = origImage.getHeight();
}
int fHeight = Height;
int fWidth = Width;
//Work out the resized width/height
if (origImage.getHeight() > Height || origImage.getWidth() > Width) {
fHeight = Height;
int wid = Width;
float sum = (float)origImage.getWidth() / (float)origImage.getHeight();
fWidth = Math.round(fHeight * sum);
if (fWidth > wid) {
//rezise again for the width this time
fHeight = Math.round(wid/sum);
fWidth = wid;
}
}
BufferedImage resizedImage = new BufferedImage(fWidth, fHeight, type);
Graphics2D g = resizedImage.createGraphics();
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);
g.drawImage(origImage, 0, 0, fWidth, fHeight, null);
g.dispose();
ImageIO.write(resizedImage, "png", new File(destinationImage));
} catch (IOException ex) {
System.out.println(""+ex);
return false;
}
return true;
}
Then call
ImageIcon ico = new ImageIcon(destinationImage);
labelforIcon.setIcon(ico);

Java2D Image Rotation Issue

I am using following code to rotate an given image.
public int getImageWidth(BufferedImage img) {
if (rotate == Rotate.UPSIDE_DOWN || rotate == Rotate.ABOUT_CENTER)
return img.getWidth();
else
return img.getHeight();
}
public int getImageHeight(BufferedImage img) {
if (rotate == Rotate.UPSIDE_DOWN || rotate == Rotate.ABOUT_CENTER)
return img.getHeight();
else
return img.getWidth();
}
This is the Rotation enums
public enum Rotate {
DOWN, UP, UPSIDE_DOWN, ABOUT_CENTER;
}
Actual rotation method
public BufferedImage rotateImage(BufferedImage source, int x, int y,
float orientation) throws Exception {
int newWidth = getImageWidth(source);
int newHeight = getImageHeight(source);
int cWidth = newWidth / 2;
int cHeight = newHeight / 2;
int imgType = source.getType() == 0 ? 5 : source.getType();
BufferedImage result = new BufferedImage(getImageWidth(source),
getImageHeight(source),imgType);
Graphics2D g2 = result.createGraphics();
if (rotate == Rotate.DOWN) {
g2.translate(x + cHeight, y + cWidth);
g2.rotate(Math.toRadians(90));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.UP) {
g2.translate(x + cHeight, y + cWidth);
g2.rotate(Math.toRadians(-90));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.UPSIDE_DOWN) {
g2.translate(x + cWidth, y + cHeight);
g2.rotate(Math.toRadians(180));
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
} else if (rotate == Rotate.ABOUT_CENTER) {
Rectangle r = new Rectangle(x, y, newWidth, newHeight);
g2.setClip(r);
AffineTransform original = g2.getTransform();
AffineTransform at = new AffineTransform();
at.concatenate(original);
at.rotate(orientation, x + cWidth, y + cHeight);
g2.setTransform(at);
g2.drawImage(source, 0, 0, newWidth, newHeight, null);
g2.setTransform(original);
}
g2.dispose();
g2 = null;
return result;
}
The client code
// rotate derived & filtered image to 90 degree
// using Affine transform
setRotate(Rotate.UP);
BufferedImage rSubImage = rotateImage(fSubImage, 0, 0, -90);
Now the following is an source image,
When i rotate this image using above code , the result is very strange
What did i do wrong ?
also the quality is lost after rotation , please notice it.
I think the solution is to use AffineTranform, translating the Image to reamin in the center. I modified your code and tested it, for me it works:
public BufferedImage rotateImage(BufferedImage source, int x, int y,
float orientation) throws Exception {
int newWidth = getImageWidth(source);
int newHeight = getImageHeight(source);
int imgType = source.getType() == 0 ? 5 : source.getType();
BufferedImage result = new BufferedImage(getImageWidth(source),
getImageHeight(source), imgType);
if (rotate == Rotate.DOWN) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(90));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.UP) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(-90));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.UPSIDE_DOWN) {
AffineTransform tranform = new AffineTransform();
tranform.translate(newWidth / 2, newHeight / 2);
tranform.rotate(Math.toRadians(180));
tranform.translate(-source.getWidth()/2, -source.getHeight()/2);
Graphics2D g2d = result.createGraphics();
g2d.drawImage(source, tranform, null);
} else if (rotate == Rotate.ABOUT_CENTER) {
//......
}
return result;
}
Hope it helps!

Categories