I am trying to place two words at the center of the image. But the drawString method does not seem to correctly pickup the "x" coodinate. For example I am trying to place the words "setupa" and "asetup" (image width 30). My image width is 106, thus the x-cord value is 38 in both the cases. But in reality asetup is places at 1-2 pixel shift.
It produces just minor difference, but that shows up in my images.
Sample code is follows.
Graphics2D textGraphics;
textGraphics = image.createGraphics();
textGraphics.setColor(fontColor);
textGraphics.setFont(font);
FontRenderContext frc = new FontRenderContext(null, true, true);
TextLayout layout = new TextLayout(label, font, frc);
Rectangle r = layout.getPixelBounds(frc, 0, 0);
textGraphics.drawString(label, ((imageWidth / 2) - (r.width/2)), (imageWidth / 2));
Is they any way around this? or a better way to place the text at the center.
Thanks
Related
I am trying to draw a string exactly in the center of a rectangle using JavaFX GraphicsContext2D.
I don't want to use JavaFX components so please do not recommend them.
For example, I stroke a rectangle with attributes: x = 10, y = 10, width = 100, height = 100. Now I want to stroke a text in a way that it comes exactly in the center(horizontally and vertically) of the rectangle. How can I do it?
As #James_D comments, you can use the GraphicsContext methods setTextAlign() and setTextBaseline() to center the fillText() in an arbitrary Rectangle. Starting from this example, I added the following lines in the tooltips loop in order to produce the image shown:
gc.setTextAlign(TextAlignment.CENTER);
gc.setTextBaseline(VPos.CENTER);
gc.setFill(Color.BLACK);
gc.fillText(color.toString(),
bounds.getX() + bounds.getWidth() / 2,
bounds.getY() + bounds.getHeight() / 2);
I've read all the existing questions I could find and have tried it both ways.
FontMetrics fm = g.getFontMetrics();
FontRenderContext frc = g.getFontRenderContext();
Rectangle2D rect = font.getStringBounds(line,frc);
int width = (int)rect.getWidth();
and also
int width = fm.stringWidth(line);
Neither are giving me the correct number of pixels.
As an example...the word 'ELLIS' in a particular font and size is actually 58 pixels wide.
Both of those methods tell me that it's 42 wide.
Its black font on a white field, so I'm considering re arranging my entire code so I can loop through a line of the BufferedImage and count the distance between the first and last black pixel. This would at least get me a lot closer.
There has to be a simpler way to do this though.
Appreciate any help.
I have a method that creates shadows based on where things are on the screen and the final product of that method is an Area, which I then draw onto the screen and it contains all shadows on screen in the same Area. This is because the drawn shadows are a low opacity so if it is not all one thing they will overlap and the opacity will make it look weird.
The issue that I want the shadows to look like they fade out, but I have absolutely no idea how, or if that would even be possible. Is there a way to soften the edges of the Area or make them gradient fade out? I tried to do graphics2D.setPaint(new GradientPaint[a gradient effect]) but it did nothing.
Thanks in advance
EDIT: Here is a screenshot of the program making a shadow around a 'building' rectangle. The green rectangle is to show the effect of the shadow. The end result I want is instead of the shadow abruptly ending, it should fade out.
i guess you have problems setting up the proper colors for the gradient:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(30, 30, 50, 20);
Graphics2D g2d = (Graphics2D) g;
Polygon p = new Polygon(new int[]{10,20,50,50,40,10}, new int[]{10,10,40,50,50,20}, 6);
Area a = new Area(p);
Color b = new Color(0xFF000000, true); //using colors with transparency!!!
Color w = new Color(0x00FFFFFF, true); //using colors with transparency!!!
//try to use proper values for the x/y values - both, start and end
GradientPaint gradient = new GradientPaint(0, 0, b, 40, 40, w);
g2d.setPaint(gradient);
g2d.fill(a); // fill your area!
}
result is a gradient with alpha (Transparency) ...
Area drawn in red <==> Area drawn with Gradient
don't forget to set the alpha value 0xAARRGGBB to FF for 100% opaque (0xFF000000 is black 100%opaque) to 0 (0x00FFFFFF white, 100% transparent)
The first "foo" is normal, but the second one is so huge I can only see the base of the "f". The font-size is the default.
BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
Shape ellipse = new Ellipse2D.Double(0, 0, 1.0, 1.0);
g2.setPaint(Color.RED);
g2.drawString("foo", 100, 100);
g2.scale(500.0f / length, 500.0f / length);
g2.drawString("foo", 1, 1);
Changing the font size will not help because it only allows int sizes and the size that would make sense for the scale is something like 0.02.
The reason I need to draw the text while in scaled space is because I am drawing a grid of nodes and I want to scale the coordinates to the number of nodes in each dimension. That way I do not have to do complicated calculations.
I need the text to label the edges.
Update: I am able to get the text by doing the following sequence each time I want to draw the text: saving the transform, translating to the desired location in scaled space, unscaling, drawing the text at (0, 0), and restoring the transform.
You can use Font method
public Font deriveFont(float size)
to obtain desired font size font. Guess the 0.02 shoud be fine.
I'm playing around with the 2.0.0-SNAPSHOT, and I want to set the page to landscape and also rotate my picture. So I've done page.setRotation(90);
There seems to be a bug with using PDFBox and AffineTransform
This code doesn't do anything like I'd expect:
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
Don't do an extra translation, instead put the translation when creating the AT. Remember that the rotation is around the bottom-left axis, so add the width w to the x-position.
PDPage page = new PDPage();
document.addPage(page);
page.setRotation(90);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
int x = 150;
int y = 300;
// draw unrotated
contentStream.drawXObject(ximage, x, y, ximage.getWidth() / 2, ximage.getHeight() / 2);
// draw 90° rotated, placed on the right of the first image
AffineTransform at = new AffineTransform(ximage.getHeight() / 2, 0, 0, ximage.getWidth() / 2, x + ximage1.getWidth(), y);
at.rotate(Math.toRadians(90));
contentStream.drawXObject(ximage, at);
This will draw the image twice, once normally and once rotated 90°, and positioned to the right. "/2" is used to scale 50%, you can of course use another factor. Note that "/2" is not used for the initial x position, because the (scaled) width is needed twice. Once to position to the old position (because of the axis!), and once to move it to the right so that the images don't overlap.
Note also that getHeight() and getWidth() are reversed, for the page rotation.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
at.rotate(Math.toRadians(90));
Width and Height have to be tiny to keep the image on the page, rotate by itself squishes the image, and translate before rotate seems to scale the image huge.
Is this a bug, or am I just not understanding PDFBox?
It is not a bug, it simply is math. You merely have to be aware that if you have an AffineTransform at and then call at.translate(...) or at.rotate(...), you do not set the translation / rotation part of the affine transformation to the given values but instead replace your transformation by the composition of the former transformation and the translation / rotation.
This means that e.g.
AffineTransform at = new AffineTransform(w, 0, 0, h, 20, 20);
at.translate(0.5, 1);
is not the same as
AffineTransform at = new AffineTransform(w, 0, 0, h, 20.5, 21);
as you might have expected, but instead
AffineTransform at = new AffineTransform(w, 0, 0, h, 20 + w/2, 20 + h);
This is why Width and Height have to be tiny to keep the image on the page - translate(0.5, 1) pushes very far otherwise.
As the order in which you compose the transformation matters, you might be happier if you created your transformation in this order:
AffineTransform at = AffineTransform.getTranslateInstance(0.5, 1);
at.rotate(Math.toRadians(90));
af.concatenate(new AffineTransform(w, 0, 0, h, 20, 20));
PS: As Tilman said: Remember that the rotation is around the bottom-left, so this composition will rotate off-screen, too. Simply add h+20 to the x coordinate of the initial translation.