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
Related
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 was wondering why displaying text in my frame has to be so blury, and i came across this piece of code, which is working by the way
public void paint(Graphics graphicsObject){
if(graphicsObject instanceof Graphics2D){
Graphics2D g2D = (Graphics2D) graphicsObject;
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
graphicsObject.drawString("not blurry text display", 200, 200);
}
having dificulties trying to understand how this work out.
how come g2D.setRenderingHint is fixing my blurry problem, but i dont use it to paint my string?
First, what this fixed was not blurring. It was aliasing.
Aliasing occurs when drawing functions try to create curvy shapes using a raster image - a matrix of pixels, which are squares. If the lines are not vertical or horizontal, you end up with "stairs" - edges that are jaggy.
Antialiasing is a way to make this effect less visible to the eye, by using additional pixels around the drawn line, which are painted in different tones between the foreground and the background. This cheats our eyes to see the line as "smooth". If you zoom an image drawn with antialiasing, you may notice those pixels around the actual line.
So, actually, antialiasing blurs the line, and this makes it seem smoother to our eyes.
As to your actual question - you are using the graphics object to draw the line. You set the hint in the graphics object by accessing the object in its form as a Graphics2D. Even though you then go on and use the graphicsObject using its regular Graphics reference, the method drawString() is overridden. This means that it will be activated in the concrete object that implements it, which sees - and uses - the RenderingHint hash map where your hint is stored.
but i dont use it to paint my string?
Why do you think so? Because, you are actually using it.
Nowadays, Graphics is always a Graphics2D object, so your if-statement will be executed.
g2D and graphicsObject both point to the same object. For the compiler they are two variables of different types, allowing different methods to be called, but at execution time, these two variables actually point to the same object.
So by setting the rendering hint on g2D, and this being the same object as graphicsObject, drawing the string respects that hint and fixes the blurryness by using anti-aliasing as specified in the hint.
After experimenting back and forth with Graphics2D vs. JPanels I have noticed that strings written on a JPanel are much higher resolution (less pixilated) then those drawn with g.drawString().
Is there any way to increase the resolution of strings drawn with Graphics2D?
Set the Graphics2D RenderingHints parameter, RenderingHints.KEY_TEXT_ANTIALIASING, to RenderingHints.VALUE_TEXT_ANTIALIAS_ON or one of the other constants that turn this anti-aliasing on.
When you draw using Graphics2D directly, are you using RenderingHints.KEY_TEXT_ANTIALIASING as mentioned here?
It is possible to draw from one Graphics2D to another Graphics2D?
Let me explain.
I have printing issues, when i display a JTextArea or JTextPanel in screen, internaly its used sun.java2d.SunGraphics2D, but when im printing its used sun.print.PeekGraphics and sun.awt.windows.WPathGraphics.
The problem is with some kind of Fonts, like Arial. In some sizes lines are cut.
I have tryed a lot of ways to render the text in printing, Graphics2D.drawString, SwingUtilities2.drawString, TextLayout.drawString, but in some cases lines are still cut, or lines are not cut but some kind of justification makes disapear white spaces.
So my idea is try to render components with sun.java2d.SunGraphics2D and "copy" the surface to the printer via sun.print.PeekGraphics or sun.awt.windows.WPathGraphics.
Thanks in advance.
Yes its possible, thats how double buffering is achieved in a lot of Java Games. What you need is the Graphics2D's drawImage() method which takes in another Graphics2D object to draw in. E.g. from a small game of mine:
private Main(){
...
/* Create the backbuffer as a BufferedImage object */
this.doubleBuffer = new BufferedImage(this.WIDTH, this.HEIGHT, BufferedImage.TYPE_INT_RGB);
/* create a Graphics 2D object to draw INTO this backbuffer */
this.doubleBufferG2D = (Graphics2D) doubleBuffer.createGraphics();
...
}
Somewhere else:
/*Now lets draw the backbuffer INTO the screen */
g2d.drawImage(doubleBuffer, null , 0, 0);
Edit: heh I realized its not exactly as above...lemme think on it.
Edit2: Alright the above can still be used a sample, but the sequence of steps to draw from one Graphics2D to another should be as such:
1. From a Graphics2D object to an Image/BufferedImage object using drawGraphics().
2. From the Image/BufferedImage above, extract its member Graphics2D object by using itscreateGraphics().
Looks like you can do one of two things:
create a Graphics2D on an image, do your rendering, then draw the image into another Graphics2D
or create Graphics2D from original Graphics2D using Graphics.create() methods and then do you rendering.
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.