Java swing high quality PNG - java

I have been trying to export my swing 2d diagram to a png file. I tried the following code :
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Graphics2D referenceGraphics = bufferedImage.createGraphics();
referenceGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
paintComponent(referenceGraphics);
File imageFile = new File(fileName);
if (imageFile.exists() || imageFile.createNewFile()) {
ImageIO.write(bufferedImage, "png", imageFile);
}
However the png file is been created successfully, but the quality is too low. I need to create at least 300ppi image file. How to achieve that?

Simply increasing the size of the component won't make the resolution of the image any better. It will just be larger. What you need to do is create the BufferedImage larger that the component (i.e. 3 times for 3 times the current resolution) and the scale the Graphics object of the BufferedImage. The resulting code would look something like this:
public static void main(String[] args) throws IOException {
Component comp = ...
BufferedImage img = scaledImageFromComponent(comp, 3);
File imageFile = new File(fileName);
if (imageFile.exists() || imageFile.createNewFile()) {
ImageIO.write(img, "png", imageFile);
}
}
public static BufferedImage scaledImageFromComponent(final Component c, final double scale) {
c.setSize(c.getPreferredSize());
c.doLayout();
Rectangle r = new Rectangle(0, 0, c.getWidth(), c.getHeight());
return scaledImageFromComponent(c, r, scale, scale, false);
}
public static BufferedImage scaledImageFromComponent(final Component c, final Rectangle bounds,
final double scalex, final double scaley,
final boolean print) {
BufferedImage image = createCompatibleTransparentImage((int) (scalex * bounds.width),
(int) (scaley * bounds.height));
final Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.scale(scalex, scaley);
g2d.translate(-bounds.x, -bounds.y);
if (print) {
c.print(g2d);
} else {
c.paint(g2d);
}
g2d.dispose();
return image;
}
public static BufferedImage createCompatibleTransparentImage(final int width,
final int height) {
return isHeadless() ? new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
: getGraphicsConfiguration().createCompatibleImage(width, height,
Transparency.BITMASK);
}
private static boolean isHeadless() {
return GraphicsEnvironment.isHeadless();
}
private static GraphicsConfiguration getGraphicsConfiguration() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
}
If your diagram contains text you may want to switch Transparency.BITMASK with Transparency.OPAQUE for better anti-aliasing support (on Windows).

Related

How to crop image in java?

I'm using java to crop image when upload file, I set value and to try to crop but is not get correct size of image as I expected
This my code: (updated)
private BufferedImage cropImageSquare(byte[] image) throws IOException {
InputStream in = new ByteArrayInputStream(image);
BufferedImage originalImage = ImageIO.read(in);
System.out.println("Original Image Dimension: "+originalImage.getWidth()+"x"+originalImage.getHeight());
BufferedImage croppedImage = originalImage.getSubimage(300, 150, 500, 500);
System.out.println("Cropped Image Dimension: "+croppedImage.getWidth()+"x"+croppedImage.getHeight());
return croppedImage;
}
my photo:
I want to crop image as above image (red line) but my code is seem incorrect.
How to crop image as expect?
I want to crop image as above image (red line) but my code is seem incorrect.
So, your input image is 1024x811 and your "target" image is 928x690, which is roughly 0.906x0.8509 reduction/difference - so the real question is ... which one of those is the right value?
Through my testing, based on this image, 0.8509 produces the best result
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Test {
public static void main(String[] args) throws IOException {
BufferedImage crop = new Test().crop(0.8509);
System.out.println(crop.getWidth() + "x" + crop.getHeight());
ImageIO.write(crop, "jpg", new File("Square.jpg"));
}
public BufferedImage crop(double amount) throws IOException {
BufferedImage originalImage = ImageIO.read(Test.class.getResource("Cat.jpg"));
int height = originalImage.getHeight();
int width = originalImage.getWidth();
int targetWidth = (int)(width * amount);
int targetHeight = (int)(height * amount);
// Coordinates of the image's middle
int xc = (width - targetWidth) / 2;
int yc = (height - targetHeight) / 2;
// Crop
BufferedImage croppedImage = originalImage.getSubimage(
xc,
yc,
targetWidth, // widht
targetHeight // height
);
return croppedImage;
}
}
Now, this doesn't do any checks (xc + targetWidth > imageWidth), but I'm sure you can fill that out
Code is working fine for me.
public class Test {
public static void main( String[] args ) throws IllegalAccessException, InstantiationException {
try{
BufferedImage image = ImageIO.read(new File("C:\\Users\\guptab\\Pictures\\American.png"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
byte[] res=baos.toByteArray();
image = new Test().cropImageSquare(res);
}
catch(Exception e) {
e.printStackTrace();
System.out.println("Error");
}
}
private BufferedImage cropImageSquare(byte[] image) throws IOException {
InputStream in = new ByteArrayInputStream(image);
BufferedImage originalImage = ImageIO.read(in);
System.out.println("Original Image Dimension: "+originalImage.getWidth()+"x"+originalImage.getHeight());
BufferedImage croppedImage = originalImage.getSubimage(300, 150, 300, 600);
System.out.println("Cropped Image Dimension: "+croppedImage.getWidth()+"x"+croppedImage.getHeight());
return croppedImage;
}
}
Output is:
Original Image Dimension: 1279x1023
Cropped Image Dimension: 300x600
Definition of getSubImage method:
BufferedImage java.awt.image.BufferedImage.getSubimage(int x, int y, int w, int h)
Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.
Parameters:x the X coordinate of the upper-left corner of the specified rectangular regiony the Y coordinate of the upper-left corner of the specified rectangular regionw the width of the specified rectangular regionh the height of the specified rectangular regionReturns:a BufferedImage that is the subimage of this BufferedImage.
So int x and int y (First two Parameters are coordinates of image, not dimensions), only int w, int h (last two parameters) are dimensions of the image which is working fine.

How to tint an ImageIcon [duplicate]

This question already has an answer here:
How to draw a BufferedImage with a color tint
(1 answer)
Closed 7 years ago.
How would I tint the icon that is passed through here to be a different color? Say I wanted to take a white image and make it a bit darker. I have looked into BufferedImages and such but I can't seem to find anything that will fit into the setup that I am using. I should also note that I am drawing the images onto a JLabel if that makes a difference.
Here is the source that I am using so that you can get an idea as to what I am working with.
public class Icon extends ImageIcon{
private int scale = 1;
private boolean mirror = false;
public Icon(URL url) throws IOException{
super(ImageIO.read(url));
}
public void setScale(int scale){
this.scale = scale;
}
#Override
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D)g.create();
int height = 0, width = this.getIconWidth(), x1 = 1;
if(mirror || scale != 1){
height = -this.getIconHeight();
}
if(mirror){
x1 = -1;
}else{
width = 0;
}
g2.translate(width * scale, height);
g2.scale(x1 * scale, 1 * scale);
super.paintIcon(c, g2, x, y);
}
public boolean isMirror() {
return mirror;
}
public void setMirror(boolean mirror) {
this.mirror = mirror;
}
}
you need to create a new BufferedImage to make the transform into:
public BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue) {
BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
BufferedImage.TRANSLUCENT);
Graphics2D graphics = img.createGraphics();
Color newColor = new Color(red, green, blue, 0 /* alpha needs to be zero */);
graphics.setXORMode(newColor);
graphics.drawImage(loadImg, null, 0, 0);
graphics.dispose();
return img;
}

Rendering multi-line multi-page formatted text to a BufferedImage (not in Android)

I've just had to implement the creation of a PNG Image, rendering out the contents of a text file. Searching online I found a few implementations using Android but no complete example for multi-line text using standard Java only so thought it would be worth posting my solution here.
The requirements were:
Take a String of potentially any size and render it out with properly formatted paragraphs to fit into PNG images, splitting the String into lines and paragraphs properly. If the rendered document does not fit into one page then generate multiple BufferedImages, one for each page.
I found some sample code in the Java documentation for rendering out a paragraph, building on that I made the following:
private static final Font FONT = new Font("Serif", Font.PLAIN, 14);
private static final float PARAGRAPH_BREAK = 10;
private static final float MARGIN = 20;
private Graphics2D setupGraphics(BufferedImage img) {
Graphics2D g2d = img.createGraphics();
g2d.setFont(FONT);
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
g2d.setColor(Color.BLACK);
return g2d;
}
private List<BufferedImage> renderText(String str, int width, int height) {
String[] paragraphs = str.split("\n");
List<BufferedImage> images = new ArrayList<>();
BufferedImage img = new BufferedImage(width,
height,
BufferedImage.TYPE_3BYTE_BGR);
images.add(img);
Graphics2D g2d = setupGraphics(img);
float drawPosY = 0;
for (int paragraph=0;paragraph<paragraphs.length;paragraph++) {
drawPosY += PARAGRAPH_BREAK;
AttributedString attStr = new AttributedString(paragraphs[paragraph]);
AttributedCharacterIterator it = attStr.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(it, g2d.getFontRenderContext());
measurer.setPosition(it.getBeginIndex());
while (measurer.getPosition() < it.getEndIndex()) {
TextLayout layout = measurer.nextLayout(img.getWidth()-MARGIN*2);
if (drawPosY > img.getHeight() - layout.getAscent() - layout.getDescent() - layout.getLeading()) {
drawPosY = 0;
img = new BufferedImage((int)(
width,
height,
BufferedImage.TYPE_3BYTE_BGR);
images.add(img);
g2d.dispose();
g2d = setupGraphics(img);
}
drawPosY += layout.getAscent();
layout.draw(g2d, MARGIN, drawPosY);
drawPosY += layout.getDescent()+layout.getLeading();
}
}
g2d.dispose();
return images;
}
In my case I needed the generated PNG in memory so I created it as follows:
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(output, "png", baos);
ret.setImageData(baos.toByteArray());
} catch (IOException ex) {
Logger.getLogger(ImageGenerationService.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
Almost identical code in this section would cause ImageIO to write out the file different formats (for example "jpg" instead of "png") or write the image to a file (using FileOutputStream instead of ByteArrayOutputStream).
I hope this helps anyone else with the same problem.

Bufferedimage resize

I am trying to resized a bufferedimage. I am able to store it and show up on a jframe no problems but I can't seem to resize it. Any tips on how I can change this to make it work and show the image as a 200*200 file would be great
private void profPic(){
String path = factory.getString("bottle");
BufferedImage img = ImageIO.read(new File(path));
}
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage 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;
}
Updated answer
I cannot recall why my original answer worked but having tested it in a separate environment, I agree, the original accepted answer doesn't work (why I said it did I cannot remember either). This, on the other hand, did work:
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;
}
If all that is required is to resize a BufferedImage in the resize method, then the Thumbnailator library can do that fairly easily:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
return Thumbnails.of(img).size(newW, newH).asBufferedImage();
}
The above code will resize the img to fit the dimensions of newW and newH while maintaining the aspect ratio of the original image.
If maintaining the aspect ratio is not required and resizing to exactly the given dimensions is required, then the forceSize method can be used in place of the size method:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
return Thumbnails.of(img).forceSize(newW, newH).asBufferedImage();
}
Using the Image.getScaledInstance method will not guarantee that the aspect ratio of the original image will be maintained for the resized image, and furthermore, it is in general very slow.
Thumbnailator uses a technique to progressively resize the image which can be several times faster than Image.getScaledInstance while achieving an image quality which generally is comparable.
Disclaimer: I am the maintainer of this library.
Here's some code that I have used to resize bufferedimages, no frills, pretty quick:
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;
}
This class resize from a file and get the format name:
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import org.apache.commons.io.IOUtils;
public class ImageResizer {
public static void main(String as[]) throws IOException{
File f = new File("C:/Users/samsungrob/Desktop/shuttle.jpg");
byte[] ba = resize(f, 600, 600);
IOUtils.write(ba, new FileOutputStream( new File("C:/Users/samsungrob/Desktop/shuttle_resized.jpg") ) );
}
public static byte[] resize(File file,
int maxWidth, int maxHeight) throws IOException{
int scaledWidth = 0, scaledHeight = 0;
BufferedImage img = ImageIO.read((ImageInputStream) file );
scaledWidth = maxWidth;
scaledHeight = (int) (img.getHeight() * ( (double) scaledWidth / img.getWidth() ));
if (scaledHeight> maxHeight) {
scaledHeight = maxHeight;
scaledWidth= (int) (img.getWidth() * ( (double) scaledHeight/ img.getHeight() ));
if (scaledWidth > maxWidth) {
scaledWidth = maxWidth;
scaledHeight = maxHeight;
}
}
Image resized = img.getScaledInstance( scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(scaledWidth, scaledHeight, Image.SCALE_REPLICATE);
buffered.getGraphics().drawImage(resized, 0, 0 , null);
String formatName = getFormatName( file ) ;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(buffered,
formatName,
out);
return out.toByteArray();
}
private static String getFormatName(ImageInputStream iis) {
try {
// Find all image readers that recognize the image format
Iterator iter = ImageIO.getImageReaders(iis);
if (!iter.hasNext()) {
// No readers found
return null;
}
// Use the first reader
ImageReader reader = (ImageReader)iter.next();
// Close stream
iis.close();
// Return the format name
return reader.getFormatName();
} catch (IOException e) {
}
return null;
}
private static String getFormatName(File file) throws IOException {
return getFormatName( ImageIO.createImageInputStream(file) );
}
private static String getFormatName(InputStream is) throws IOException {
return getFormatName( ImageIO.createImageInputStream(is) );
}
}
This is a shortened version of what is actually happening in imgscalr, if you just want to use the "balanced" smoothing:
/**
* Takes a BufferedImage and resizes it according to the provided targetSize
*
* #param src the source BufferedImage
* #param targetSize maximum height (if portrait) or width (if landscape)
* #return a resized version of the provided BufferedImage
*/
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;
}
try the imgscalr library. Best lib i found- very fast, good quality and simple to use
BufferedImage thumbnail = Scalr.resize(image, 150);
deprecated link: http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/
Apache 2 License
Check this out, it helps:
BufferedImage bImage = ImageIO.read(new File(C:\image.jpg);
BufferedImage thumbnail = Scalr.resize(bImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH,
750, 150, Scalr.OP_ANTIALIAS);

resize jpeg image in java

i am working on image comparison in java. I think before going to compare the images, it is better to process the images for setting a fixed size image. Is there any java functionality to resize the images. I want to rescale the images to 300*225.
BufferedImage img = ImageIO.read(imageFile);
Image scaled = img.getScaledInstance(300, 255, Image.SCALE_DEFAULT);
You can also take a look at the java-image-scaling library.
public ImageIcon resizeImage(String filePath, int w, int h) {
String data = filePath;
BufferedImage bsrc, bdest;
ImageIcon theIcon;
//scale the image
try
{
bsrc = ImageIO.read(new File(data));
bdest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bdest.createGraphics();
AffineTransform at = AffineTransform.getScaleInstance((double) w / bsrc.getWidth(),
(double) h / bsrc.getHeight());
g.drawRenderedImage(bsrc, at);
//add the scaled image
theIcon = new ImageIcon(bdest);
return theIcon;
}
catch (Exception e)
{
System.out.println("This image can not be resized. Please check the path and type of file.");
return null;
}
}
BufferedImage createResizedCopy(Image originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
This threads answers your question well
Very interesting article on manipulating images

Categories