I'm drawing a histogram (custom data, not related to coloring) on an BufferedImage. And I'd like to make it as wide and tall as possible. Can I do this passing only BufferedImage.createGraphics result to my drawing function? I can't find how to obtain image dimensions through an instance of Graphics.
Can I do this passing only BufferedImage.createGraphics result to my drawing function?
I recommend to pass either:
The BufferedImage itself or
The Graphics instance and a Dimension (unless the plot only requires height, as opposed to WxH - then use an int).
Related
I'm developing a little graphic engine using Canvas in JavaFX. In some point I had to render an off screen image, and then print it on my primary canvas using its GraphicContext.
I'm using this code right now:
private Canvas offScreenCanvas;
private GraphicsContext offScreenGraphic;
private SnapshotParameters parameters;
private WritableImage offScreenImage;
[...]
offScreenCanvas = new Canvas(WIDTH, HEIGHT);
offScreenGraphic = offScreenCanvas.getGraphicsContext2D();
parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
[...]
offScreenImage = offScreenCanvas.snapshot(parameters, offScreenImage);
graphic.setGlobalBlendMode(BlendMode.HARD_LIGHT);
graphic.drawImage(offScreenImage, 0, 0);
graphic.setGlobalBlendMode(BlendMode.SRC_OVER);
My problem is the method snaphot() takes too much time, ~14ms, in each execution. I need to update the canvas at least at 60fps, so this consumes practically all the time I have to draw.
Is there another way to get an Image or WritableImage from a canvas? Maybe another different process?
This is another method to obtain a visual equivalent result, without reduce performance.
I have used java.awt clases, instead of JavaFX clases. The creation of a java.awt.image.BufferedImage offers the possibility to get a java.awt.Graphics2D where you can draw using other methods. The main problem here is that draw big images consumes a lot of time using this libraries, but you can create a scaled image. In my case, I have created a quarter-size BufferedImage, and I have drawn all the objects using that scale factor.
At the end of the draw process, just convert the BufferedImage, to a javafx.scene.image.Image, using:
SwingFXUtils.WritableImage toFXImage(BufferedImage bimg, WritableImage wimg);
Then print it on the main canvas using:
graphic.drawImage(Image image, 0, 0, WIDTH, HEIGHT);
To fill all the canvas with the image.
Finally, the scale factor is configurable, so if you need a detailed image, just use a higher value. For me, a 25-percent-size image is enough because I am drawing gradients. Now, it takes 1-3ms to draw the image, this is much better than before.
Hope it helps someone.
I am drawing in a bitmap by creating a BufferedImage and then calling BufferedImage.createGraphics() to get a Graphics2D object. I then render to the Graphics2D object.
I want to do all my rendering using EMUs for coordinated. The device space for the Graphics2D object is the size of the image in pixels, which makes sense.
Is there a way for me to set the Graphics2D user space? I think if I can set that to be the EMUs/inch divided by DPI, then it all maps through clean.
I know I can use an AffineTransform. But I'd prefer to not do that so that I can apply transforms without worrying about including the scaling due to my EMUs to pixels conversion.
thanks - dave
I am creating images in Java that have fonts written on them with a transparent background. I make the fonts different colors and also different types of font styles so I need the program to be dynamic. The issue is that I am using Graphics2D and writing on a Buffered Image using g2d.drawString() and the images aren't nearly the definition I'm looking for. I've tried creating large images with large font sizes and then downscaling but that doesn't work either. I also have set all of the possible RenderingHints to highest definition. I would like the pixel density to be high enough that there isn't much of a difference if you compared it with regular text on a retina screen. Thanks.
To have "retina" quality images in Java, you must create and render your BufferedImage at 2 times the normal size in both dimensions (this will make the image 4 times as large, which I think is what #MadProgrammer means).
Then, you must not downsample (or "scale") the image in Java, but instead keep the BufferedImage in full size, and only draw the image in half size to a native backed Graphics2D instance. The Graphics object passed to the paint() or paintComponent() methods of an AWT or Swing component is normally fine (while the one from BufferedImage.get/createGraphics() isn't).
I've used code like this with success:
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform xform = AffineTransform.getScaleInstance(.5, .5);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(image, xform, null); // image being #2x or "retina" size
}
However, note that the font rendering on modern computer uses "sub pixel antialiasing" or "sub pixel rendering", which is specific to the screen device you are rendering to (see the link, but basically, the RGB pattern or "layout" differs from device to device). This means a BufferedImage usually can't use sub pixel rendering, and thus fonts will look less crisp. If you are rendering to a single LCD screen, you might be able to specify one of the RenderingHints.TEXT_ANTIALIAS_LCD_* rendering hints for better results.
I'm currently working on a game in Java and am trying to create a background without using any image files. The image consists of a square split into 4 triangles, each of which is a different color.
If anyone could point me towards some was of using Graphics2D and then saving it to a BufferedImage, that would be great.
I recommend:
First create a BufferedImage using the constructor that takes three ints: a width, height, and a BufferedImage type, BufferedImage.TYPE_INT_ARGB would probably work well, and the width and height will likely be constants in your program.
You would extract a Graphics2D object out of the BufferedImage by calling its createGraphics() method.
Then draw with the Graphics object using its drawXXX(...) methods of which you have many to select from.
To change color, simply call setColor(Color c) on your Graphics/Graphics2D object.
When done drawing, be sure to dispose of your Graphics object via its dispose() method.
Edit as per Adrian Blackburn, check out the BufferedImage Tutorial as part of the standard Oracle Java tutorials.
What is the difference between Image and BufferedImage?
Can I create a BufferedImage directly from an Image source "image.png"?
If you are familiar with Java's util.List, the difference between Image and BufferedImage is the same as the difference between List and LinkedList.
Image is a generic concept and BufferedImage is the concrete implementation of the generic concept; kind of like BMW is a make of a Car.
Image is an abstract class. You can't instantiate Image directly. BufferedImage is a descendant, and you can instantiate that one. So, if you understand abstract classes and inheritance, you'll understand when to use each.
For example, if you were using more than one Image descendant, they're going to share some common properties, which are inherited from Image.
If you wanted to write a function that would take either kind of descendant as a parameter you could do something like this:
function myFunction(Image myImage) {
int i = myImage.getHeight();
...
}
You could then call the function by passing it a BufferedImage or a VolatileImage.
BufferedImage myBufferedImage;
VolatileImage myVolatileImage;
...
myFunction(myVolatileImage);
myFunction(myBufferedImage);
You won't convert an Image to a BufferedImage because you'll never have an Image.
What is the difference between Image and BufferedImage?
As stated in the Oracle Java tutorial for working with Images
The java.awt.Image class is the superclass that represents graphical images as rectangular arrays of pixels.
The java.awt.image.BufferedImage class, which extends the Image class to allow the application to operate directly with image data (for example, retrieving or setting up the pixel color). Applications can directly construct instances of this class.
The BufferedImage class is a cornerstone of the Java 2D immediate-mode imaging API. It manages the image in memory and provides methods for storing, interpreting, and obtaining pixel data. Since BufferedImage is a subclass of Image it can be rendered by the Graphics and Graphics2D methods that accept an Image parameter.
A BufferedImage is essentially an Image with an accessible data buffer. It is therefore more efficient to work directly with BufferedImage. A BufferedImage has a ColorModel and a Raster of image data. The ColorModel provides a color interpretation of the image's pixel data.
Can I create a BufferedImage directly from an Image source "image.png"?
Sure.
BufferedImage img = ImageIO.read(getClass().getResource("/path/to/image"));