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):
They all have shortcomings and didn't satisfy my expectations:
Image
to a BufferedImage
, results in poor performance for large images due to the creation of a new RGB
instance for every Pixel.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) Color
s 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) Image
s 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With