How to convert Image to BufferedImage with no init? - java

I am wondering is there a way to convert Image to BufferedImage without code like a
new BufferedImage(...)
because every new init makes app run slower , moreover, if it is in paint() method :(
Please advise the most optimal conversion way.
Thanks

No. Not unless the original Image happens to be a BufferedImage already. Then you can just do a cast:
BufferedImage bufImg = null;
if (origImage instanceof BufferedImage) {
bufImg = (BufferedImage) origImage;
else {
bugImg = new BufferedImage(...);
// proper initialization
}
If it's not a BufferedImage it may very well be for instance a VolatileImage (the other concrete subclass in the API).
From the docs on volatile image:
VolatileImage is an image which can lose its contents at any time due to circumstances beyond the control of the application (e.g., situations caused by the operating system or by other applications).
As you may understand, such image can not provide the same interface as a BufferedImage, thus the only way to get hold of a BufferedImage is to create one, and draw the original image on top of it.

because every new init makes app run slower
Cache one BufferedImage, then only create a new image if the required size changes. Otherwise clear the Graphics object of the current instance and do whatever new drawing is needed.

Is there a way to draw a BufferedImage to JLabel with the paint() method?
One convenient approach is to implement the Icon interface. In this example, Histogram simply draws itself when the label is told to repaint().
If the source of the image requires a time-consuming operation such as scaling, pre-render the image as shown in the static factory, GradientImage.

Related

How To Reset or Clear or Undo DrawLine in Java

Please consider the following sample image :
All the objects (rectangles, shapes, texts, etc..) are written in BufferedImage. My questions is, after I write a graphics.drawline(..) on top of them, how to undo, or reset or clear the line(s) I created. Even if I re-execute the initialization of my graph, the lines that I drew are still there.
I can still capture the coordinates of the lines. If it is a plain background I can just re-draw it with the same background. But, in this case, this wont work.
There is no way to undo things that you do with Graphics. But there are other things you can do instead with which you can get your image back.
Keep a copy of image before you do anything which you might want to undo.
And redraw it when required.
Keep a clip image of the area of image before you do anything which you might want to undo. And redraw that area when required.
To keep a Stack of these images of limited size will be a good idea to undo back in series. Don't make the stack size too big because it will consume your heap memory
I found an answer using deep copy :)
So, first, I deep copied the original or default image. Then, If I write something on the original I overwrite it with the back up copied (deep copied again)..
static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
Complete code can be found here..

Drawing AWT BufferedImage on SWT Canvas

I am trying to write a SWT component, that is able to take and draw an instance of java.awt.BufferedImage. My problem is that SWT's Image and AWT's BufferedImage are incompatible: SWT components can't draw java.awt.Image, AWT/Swing components can't draw org.eclipse.swt.graphics.Image.
There are several approaches that try to solve this problem in other ways (which also may have some variations, but basically there are these two):
Convert between SWT Image and AWT BufferedImage
Swing/SWT Integration
They all have shortcomings and didn't satisfy my expectations:
The first approach, to convert an SWT Image to a BufferedImage, results in poor performance for large images due to the creation of a new RGB instance for every Pixel.
The second approach has several shortcomings in usability. See the "workarounds" at the end of the linked article.
This lead to the conclusion that I'd try my best to write a component (based on org.eclipse.swt.widgets.Canvas or org.eclipse.swt.widgets.Composite) which allows to draw a BufferedImage directly without any conversion of images.
My approach was to draw it pixel by pixel. Therefore I simply had to get an instance of GC, walk the source BufferedImage line by line, left-to-right and drawing the corresponding Color using GC.setForeground(Color color) and GC.drawPoint(int x, int y).
First, I created a new instance of Color for every pixel, which uses quite a lot of memory and adds an additional delay, since new Color acquires system resources and creating a new object for every pixel also takes its time.
Then I tried to pre-load all possible (24 bit) Colors into an array before drawing the image. This lead to an explosion of memory usage (>= 600 MB), which was clear before I was trying it, but I had to verify it.
Caching only the used Colors also lead to more memory consumption than would have been required.
I think there has to be a more low-level approach that doesn't require that much memory, since SWT is able to draw whole (SWT) Images without consuming that much memory.
I would appreciate any ideas or solutions.
I found out there's a way to "convert" an BufferedImage to an Image by using the original image's data buffer if it is 24 bit RGB. This is possible, since the image formats are compatible.
final BufferedImage original = ImageIO.read(new File("some-image.jpg");
final PaletteData palette =
new PaletteData(0x0000FF, 0x00FF00, 0xFF0000);
// the last argument contains the byte[] with the image data
final ImageData data = new ImageData(original.getWidth(), original.getHeight(),
24, palette, 4,
((DataBufferByte) original.getData().getDataBuffer()).getData());
final Image converted = new Image(getDevice(), data);
This way, one doesn't have to create thousands of new objects. This approach comes with the disadvantage that one needs to ensure that the original image is of type RGB 24 bit. Otherwise the image has to be converted to this format.
After that, an image can be drawn with the following code:
// get the GC of your component
gc.drawImage(image, 0, 0);
Probably other bit depths can be converted in a similar way, but this is all I need for the moment.

Finding Android equivalent code for graphics2D

I have been trying to get an Android equivalent code for the following:
private BufferedImage user_space(BufferedImage image)
{
BufferedImage new_img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = new_img.createGraphics();
graphics.drawRenderedImage(image, null);
graphics.dispose();
return new_img;
}
I want an android equivalent of Graphics2D. I have been searching for a while and found out that Canvas in android can do some similar tasks as performed by the Graphics2D class here but the main problem is that I'm not getting the android equivalent of the whole process that is being performed in the code.
android does not have BufferedImage or Graphics2D as you probably already found out.
I'm not a java developer (just android) so I'm not 100% sure on what you're trying to achieve, but it seems to me that you're simply creating a copy of the image.
here a few classes that you'll be using for those type of manipulation:
Bitmap: that's like the BufferedImage, it's the object that actually stores all the bytes from the image (possibly large object with potential for memory crash). There're some static methods here for copy bitmaps, create new mutable or immutable bitmaps, scale, or compress as PNG or JPG to a stream.
BitmapFactory: lots of static methods to create new bitmaps from resources, files, streams, etc.
Canvas: You'll actually only use this one if you want to draw on the image (overlay image, put some text, or a line, stuff like that)

Image vs. BufferedImage

Whenever dealing with the loading and rendering of images in Java, I have previously always used BufferedImages to store and manipulate the images in memory.
However, I have recently come across a few different sites that use the Image class instead of BufferedImage and this got me wondering - what are the differences?
I'm aware that a BufferedImage has a larger/optimised toolset, but does come at any cost? If so, when does this cost become noticeable? In which situations would you use an Image over a BufferedImage, or vice-versa?
BufferedImage extends Image. Image is just a base abstract class and you can't instantiate it. Under the hood you are using BufferedImage or another implementation for sure.
There shouldn't be any real performance difference between directly creating a BufferedImage and a Toolkit image (java.awt.Toolkit or Image#getScaledInstance). You'll never have an actual instance of Image because it's an abstract class; you'll only be dealing with its subclasses (e.g. BufferedImage).

output a jFrame to jpeg or bitmap

I've been working on an assignment, and have all the requirements completed. The project is to compare the differences in runtime between a linear search algorithm and a binary search. I have a graph class that puts out the results of those searches in a xy graph.
The graph object is a Turtle class that extends JFrame. Is there any way I can convert that graph object to a bitmap and save it for future printing?
The professor requires printouts of the results. Since I don't want a printout of every time the program is run, I would prefer to save the graphics results in a designated folder, rather than using screen-grab.
Unfortunately, I haven't come up with any answers on Google or here. Is something like this even possible?
Another approach is to tell your Component to paint() itself into a BufferedImage, as seen in this complete example. The Container returned by a JFrame's getContentPane() method is suitable. In summary:
Component component = f.getContentPane();
BufferedImage image = new BufferedImage(…);
component.paint(image.getGraphics());
ImageIO.write(image,…);
You can pass the bounds of the area into the Robot.createScreenCapture(Rectangle) method to create a BufferedImage of the area. The easiest way to save the screenshot as an image file is to use the ImageIO class.

Categories