How can I get a less pixelated screenshot in java? - java

I am using a BufferedImage in java after capturing the image out of a JFrame. I need some way to sharpen the image such that when it's enlarged it doesn't look so pixelated. Here's the thing it has to keep the same image size.
Here's the code I'm using to capture the image.
private void grabScreenShot() throws Exception
{
BufferedImage image = (BufferedImage)createImage(getSize().width, getSize().height);
paint(image.getGraphics());
try{
//ImageIO.write(image, "jpg", new File(TimeTable.path+"\\TimeLine.jpg"));
ImageIO.write(image, "jpg", new File("C:\\Users\\"+TimeTable.user+"\\AppData\\TimeLineMacroProgram\\TimeLine.jpg"));
//ImageIO.write(image, "jpg", new File("C:\\ProgramData\\TimeLineMacroProgram\\TimeLine.jpg"));
System.out.println("Image was created");
}
catch (IOException e){
System.out.println("Had trouble writing the image.");
throw e;
}
}
And here's the image it creates

JPG is ill suited for screenshots. It's designed for complex and colorful pictures wherein information loss during compression is nearly negligible, such as photos. For screenshots you should rather be using GIF or, better, PNG.
ImageIO.write(image, "png", new File("C:\\Users\\"+TimeTable.user+"\\AppData\\TimeLineMacroProgram\\TimeLine.png"));
You only end up with a bigger file, but you get pixelperfect sharpness and detail back, which is simply impossible with JPG.

I think it's because you're writing it out as a JPEG file.
I'd change the format to something non-lossy, or else force the writer to not use compression by accessing and changing its ImageWriteParam.

Related

Issues reading/writing images

I have been working on code to encrypt and decrypt images via a Spring webapp in which i use Thymeleaf. I have tested each method involved in the process and each one is sound. The way the process flows is supposed to be:
User1 uploads image and key, app breaks down image into pixels and then into 128-bit stateHexes, stateHexes are encrypted using AES, and rebuilt into encrypted image to be displayed to User1 for download. User1 then sends image to User2 who then downloads image and decrypts it using the same process.
When I treat it like the above scenario the image somehow changes after storing it. However, if i treat it as follows the file encrypts and decrypts perfectly.
So I assume the issue must lie in either saving the file or retrieving the file, or some other issue pertaining to file handling.
Below I will show code snippets of how i load and save the images.
This is how I get the image
// Get the filename and path for the image passed in from user
Path fileNameandPath = Paths.get(uploadDirectory, file.getOriginalFilename());
// Generate the file and write the image onto it
File imageFile = fileNameandPath.toFile();
BufferedImage image = null;
try {
Files.write(fileNameandPath, file.getBytes());
image = ImageIO.read(imageFile);
Files.delete(fileNameandPath);
} catch (IOException e) {
e.printStackTrace();
System.out.println("COULDNT READ IMAGE AT = " + fileNameandPath);
}
And this is how I create the outputImage
String outputFilePath = new File("src/main/resources/static").getAbsolutePath() + "\\output.jpg";
File outputFile = new File(outputFilePath);
try {
outputFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("FILE ALREADY EXISTS");
}
// Write the image to the outputfile
try {
ImageIO.write(outputImage, "jpg", outputFile);
} catch (IOException e) {
e.printStackTrace();
}
I pass in an all black image (each pixel's hex code is 000000) and it reads the image and encrypts as expected, but when decrypting it reads in the previous image wrong, leading me to believe that it's not the code but most likely how the file is stored/retrieved? I only have one guess: that somehow the file is getting mixed up. If anyone has any clues as to why this happening, any help or leads would be appreciated.
I think it may have to do with how I write to the image. Reading the image is no problem, but how I write to the image seems to alter it in a way.
After getting some sleep, I realized that because I need the image to remain the same when reading and writing, I was losing bits of the image due to the lossy nature of .jpg files. Now that I save my file as a .png I get no errors. Hope this helps someone down the road!

Write animated-gif stored in BufferedImage to java.io.File Object

I am reading a gif image from internet url.
// URL of a sample animated gif, needs to be wrapped in try-catch block
URL imageUrl = new Url("http://4.bp.blogspot.com/-CTUfMbxRZWg/URi_3Sp-vKI/AAAAAAAAAa4/a2n_9dUd2Hg/s1600/Kei_Run.gif");
// reads the image from url and stores in BufferedImage object.
BufferedImage bImage = ImageIO.read(imageUrl);
// creates a new `java.io.File` object with image name
File imageFile = new File("download.gif");
// ImageIO writes BufferedImage into File Object
ImageIO.write(bImage, "gif", imageFile);
The code executes successfully. But, the saved image is not animated as the source image is.
I have looked at many of the stack-overflow questions/answers, but i am not able to get through this. Most of them do it by BufferedImage frame by frame which alters frame-rate. I don't want changes to the source image. I want to download it as it is with same size, same resolution and same frame-rate.
Please keep in mind that i want to avoid using streams and unofficial-libraries as much as i can(if it can't be done without them, i will use them).
If there is an alternative to ImageIO or the way i read image from url and it gets the thing done, please point me in that direction.
There is no need to decode the image and then re-encode it.
Just read the bytes of the image, and write the bytes, as is, to the file:
try (InputStream in = imageUrl.openStream()) {
Files.copy(in, new File("download.gif").toPath());
}

Saving a dynamically created Image to a File.

I have an image, I read the image, add a few things to image (like some text etc).
All this I do inside a JPanel.
Now, I want to save the resulting image to a .png file.
I think, there is a way to do this for a buffered image using ImageIO.write()
But I cannot convert the dynamically created image to a BufferedImage.
Is there a way I can go about this ?
You can use the Screen Image class.
It will create a BufferedImage of your JPanel. The class also has code to write the image to a file.
All this I do inside a JPanel.
Do it instead in another BufferedImage displayed in a JLabel. The code can get a Graphics2D object using BufferedImage.createGraphics() method. Paint the image and text to the new Graphics2D instance and you then the new image can be saved directly, along with changes.
Use Following method it worked for me...
void TakeSnapShot(JPanel panel,String Locatefile){
BufferedImage bi = new BufferedImage(panel.getSize().width, panel.getSize().height,BufferedImage.TYPE_INT_RGB);
panel.paint(bi.createGraphics());
File image = new File(Locatefile);
try{
image.createNewFile();
ImageIO.write(bi, "png", image);
}catch(Exception ex){
}
}

ImageIO.write slow?

I've an application where I'm writing around 25 png image files to disk every second.
BufferedImage img = getBufferedImage();
// code below is very slow ~150ms.
File file = new File(count++ + ".png");
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
ImageIO.write(img, "png", os);
It usually takes 150ms per call, and achieving 25fps hence becomes impossible. Can I buffer IO so that I don't drop any frames?
PNG encoding takes a while and you can't improve it with any buffering ... if you want a speed up, use BMP (which will eat up your HDD) or if pixel-quality is not needed, try JPG (which should get encoded faster than PNG).

Java: Reading images and displaying as an ImageIcon

I'm writing an application which reads and displays images as ImageIcons (within a JLabel), the application needs to be able to support jpegs and bitmaps.
For jpegs I find that passing the filename directly to the ImageIcon constructor works fine (even for displaying two large jpegs), however if I use ImageIO.read to get the image and then pass the image to the ImageIcon constructor, I get an OutOfMemoryError( Java Heap Space ) when the second image is read (using the same images as before).
For bitmaps, if I try to read by passing the filename to ImageIcon, nothing is displayed, however by reading the image with ImageIO.read and then using this image in the ImageIcon constructor works fine.
I understand from reading other forum posts that the reason that the two methods don't work the same for the different formats is down to java's compatability issues with bitmaps, however is there a way around my problem so that I can use the same method for both bitmaps and jpegs without an OutOfMemoryError?
(I would like to avoid having to increase the heap size if possible!)
The OutOfMemoryError is triggered by this line:
img = getFileContentsAsImage(file);
and the method definition is:
public static BufferedImage getFileContentsAsImage(File file) throws FileNotFoundException {
BufferedImage img = null;
try {
ImageIO.setUseCache(false);
img = ImageIO.read(file);
img.flush();
} catch (IOException ex) {
//log error
}
return img;
}
The stack trace is:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
at java.awt.image.Raster.createWritableRaster(Raster.java:938)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1056)
at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:925)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1282)
at framework.FileUtils.getFileContentsAsImage(FileUtils.java:33)
You are running out of memory because ImageIO.read() returns an uncompressed BufferedImage which is very large and is retained in the heap because it is referenced by the ImageIcon. However, the images returned by Toolkit.createImage remain in their compressed format (using the private ByteArrayImageSource class.)
You cannot read a BMP using Toolkit.createImage (and even if you could it would still remain uncompressed in memory and you would probably run out of heap space again) but what you can do is read the uncompressed image and save it in a byte array in compressed form, e.g.
public static ImageIcon getPNGIconFromFile(File file) throws IOException {
BufferedImage bitmap = ImageIO.read(file);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ImageIO.write(bitmap, "PNG", bytes);
return new ImageIcon(bytes.toByteArray());
}
That way the only time the uncompressed bitmap must be held in memory is when it is being loaded or rendered.
Have you tried this?
ImageIcon im = new ImageIcon(Toolkit.getDefaultToolkit().createImage("filename"));
It couldn't be that you indeed just run out of memory? I mean, does the error still occur if you run java with, say, -Xmx1g ?

Categories

Resources