Apache poi loses shape quality when rendering to BufferedImage - java

I have a slideshow with some simple shapes in PowerPoint. I am loading it with Apache Poi:
XMLSlideShow ppt = MY_SLIDE_SHOW;
for (XSLFSlide slide: ppt.getSlides()) {
List<XSLFShape> shapeList = slide.getShapes();
for (XSLFShape shape: shapeList) {
// data about shape dimensions
Rectangle2D anchor = shape.getAnchor();
// buffered image to draw into
BufferedImage img = new BufferedImage((int)anchor.getWidth(), (int)anchor.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
// set a clear transparent background to the image
graphics.setComposite(AlphaComposite.Clear);
graphics.fillRect(0, 0, (int)anchor.getWidth(), (int)anchor.getHeight());
// draw the shape into the buffered image
graphics.setComposite(AlphaComposite.Src);
shape.draw(graphics, new Rectangle(0, 0, (int)anchor.getWidth(), (int)anchor.getHeight()));
graphics.dispose();
}
}
However, while I am able to render the shapes they come out at a much lower resolution and lose any effects (glow, bevel, 3d format, shadow, reflection, etc.)
Here below is a comparison of the powerpoint (with effects) and the rendered object (without effects):
I believe the required solution will likely be threefold and so would appreciate answers to:
How to render the shape effects along with the shapes?
How to render the shapes at a higher resolution than face value and then scale down (rather than at a lower resolution and scaling up as it seems to currently be doing)?
How to render the shapes with transparent backgrounds, which I am surprised is not currently working?
Thank you!

Related

Can I assign an image gradient to a rectangle

I'm currently making Mario as a school graphics project.
I have most of the collisions done, but I just want the land and bricks to actually look like land and bricks instead of just colored rectangles. I have an ImageIcon for the "land" in my graphics project. The problem is that it is only 16x16 pixels large. In order to make enough land by just making each part of the land one 16x16 pixel, it would essentially be horribly inefficient.
I was wondering if I could get the ImageIcon or possibly buffered image and use it as the "color" for a rectangle to make the chunks of land easier. If that's not possible, can you offer other suggestions on how to go about this problem?
Using a background of tiled images, a texture:
private BufferedImage image;
URL url = getClass().getResource("/mytexture.png");
assert url != null;
image = ImageIO.read(url);
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(0, 0, width, height);
Rectangle textureRect = new Rectangle(0, 0, image.getWidth(), image.getHeight());
TexturePaint paint = new TexturePaint(image, textureRect);
g2.setPaint(paint);
g2.fill(rect);
}
In general create your own JPanel.
Gimp and other tools allow to create a tilable image by ensuring that a line running to a border will enter at the opposite border.

How to draw a sector of a BufferedImage?

I'm making a game with a mouse cursor, and I'd like to represent the health by overlaying the cursor with a green version of the image, but only a geometric sector of it corresponding to the health percentage. Solutions from posts like these: Drawing slices of a circle in java? & How to draw portions of circles based on percentages in Graphics2D? are pretty much what I want to do, but with a BufferedImage as opposed to a solid color fill.
//Unfortunately all this does is cause nothing to draw, but commenting this out allows the overlay image to draw
Arc2D.Double clip = new Arc2D.Double(Arc2D.PIE);
double healthAngle = Math.toRadians((((Double)data.get("health")).doubleValue() * 360.0 / 100.0) - 270.0);
clip.setAngles(0, -1, Math.cos(healthAngle), Math.sin(healthAngle));
System.out.println(Math.cos(healthAngle) + " " + Math.sin(healthAngle));
g.setClip(clip);
In short, how do I draw a sector of a BufferedImage given any angle?
If you read the API docs for setClip(Shape) you'll see that the only shape that is guaranteed to work, is a rectangle. So, setting the clip probably won't work.
However, there are other options. The most obvious is probably to use a TexturePaint to fill your arc with the BufferedImage. Something like:
TexturePaint healthTexture = new TexturePaint(healthImg, new Rectangle(x, y, w, h));
g.setPaint(healthTexture);
g.fill(arc); // "arc" is same as you used for "clip" above
Another option is to first draw the arc in solid color, over a transparent background, then paint the image over that, using the SRC_IN Porter-Duff mode. Something like:
g.setPaint(Color.WHITE);
g.fill(arc); // arc is same as your clip
g.setComposite(AlphaComposite.SrcIn); // (default is SrcOver)
g.drawImage(x, y, healthImg, null);

Clip a BufferedImage to an Area

I'm trying to draw an image within a certain area. Right now I have code that fills an area with a RadialGradientPaint.
Area lightArea = ...
// fill the polygon with the gradient paint
g.setPaint(light.paint);
g.fill(lightArea);
I would like to draw a BufferedImage in that area instead of drawing a RadialGradientPaint. Is there a way I can do that?
You could use BufferdImage#getSubimage
Rectangle bounds = area.getBounds();
BufferedImage img = master.getSubImage(0, 0, Math.min(bounds.width, master.getWidth()), Math.min(bounds.height, master.getHeight());
This assumes that the area is rectangular. If it's not, you cold create a mask image, based on the shape of the Area and use it to generate masked image (cookie cutting the image out of the shape)
As demonstrated here. The benefit of which is it allows for antialiasing
Use Graphics.setClip:
g.setClip(lightArea);
g.drawImage(yourImage, x, y, null);
See http://docs.oracle.com/javase/tutorial/2d/advanced/clipping.html for more details.

Image Quality Gets Ruined In Java Graphics2D Rotate

I am experiencing an issue with rotating an Image with the Graphics2D rotate method.
Here's an image of the issue I'm having:
As I move the ball, the image gets completely distorted as it rotates.
Here's my rotate method:
public static void rotate(BufferedImage img, Rectangle rect, int degrees) {
Graphics2D g = (Graphics2D) img.createGraphics();
g.rotate(degrees, rect.x + rect.width/2, rect.y + rect.height/2);
g.drawImage(img, rect.x, rect.y, rect.width, rect.height, null);
g.dispose();
}
Is there anything I can do to avoid the quality loss?
So currently as the ball moves, you rotate the image a few degrees and overwrite the original image with the new one? Each time the image is rotated, a tiny bit of distortion is added; over many rotations, the distortion is compounded.
Instead, just keep the original image in memory and also store the number of degrees it should appear to be rotated on screen. Then each time you render it, rotate the original image by the current number of degrees.
I know this is a pretty old question but for anyone looking to do something similar try putting the following code before your g.drawImage
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
That should help to make the image look a better.

Component painted to image renders with ugly fonts

When I'm rendering a Swing component to an image the fonts are different then when the component is rendered on screen. Here is an image showing the difference:
And this is the code:
public static BufferedImage renderComponent(Component component) {
int width = component.getWidth();
int height = component.getHeight();
BufferedImage buffImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) buffImage.getGraphics();
g.setFont(component.getFont());
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
component.paint(g);
g.dispose();
return buffImage;
}
What should I change to make a perfect screen shot of a Swing component? (The app is running on Windows 7)
What should I change to make a perfect screen shot of a Swing component?
I would guess you should not be providing rendering hints.
I use the Screen Image class for this (it is basically your code with a few other features built in).
After comparing the ScreenImage class (suggested by camickr) I found the cause of the problem. If I create a BufferedImage with the type set to TYPE_INT_RGB instead of TYPE_INT_ARGB the fonts are fine.
Class Robot
public synchronized BufferedImage createScreenCapture(Rectangle screenRect)
?

Categories