Clip a BufferedImage to an Area - java

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.

Related

Apache poi loses shape quality when rendering to BufferedImage

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!

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);

Trying to do a spotlight effect in android canvas

I have a canvas and a simple bitmap for background image, fills the whole screen. I created a rect painted black and set it's alpha to 250 in order to make a "dark" effect on the background image. My aim to make a simple circle object that reveals the place it's hovering above. I tried thinking in many ways how to excecute it and failed.
I think the best way is to create a simple circle that manages to decrease the darkness alpha on the position it hovers above, but I have no idea how to do it.
The relevant part of my code:
private ColorFilter filter = new LightingColorFilter(Color.BLACK, 1);
private Paint darkPaint = new Paint(Color.BLACK), paint = new Paint(), paint2 = new Paint();//The style of the text and dark.
public DarkRoomView(Context context) {
super(context);
myChild = this;
darkPaint.setColorFilter(filter);
darkPaint.setAlpha(250);
paint2.setAlpha(10);
paint.setAlpha(50);
}
private void loadGFX() {//Loads all of this view GFX file.
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.darkroomscreen);
lightImage = BitmapFactory.decodeResource(getResources(), R.drawable.light);
}
private void drawGFX(Canvas canvas) {
canvas.drawBitmap(backgroundImage, 0, 0, paint2);//The backgeound image.
canvas.drawRect(0, 0, WIDTH, HEIGHT, darkPaint);//The darkness.
canvas.drawBitmap(lightImage, 50, 50, paint);//A spotlight.
}
Any ideas how I should get it done?
Thanks!
For the spotlight, you could draw a circle of the original image over the darkness. You'd simply need to find the correct rectangle of the original image (based on where your finger is), and then draw a circle of that particular rectangle over the darkness. Trying to look "through" the darkness won't really get you anywhere; you need to place something over it.
By the time you draw the "spotlight", you've already darkened the image with the rectangle. It would be difficult to recover information lost during that draw.
A more flexible approach would be to draw a dark rectangle with a spotlight in a separate image (that is, compose the "darkness" and spotlight alpha and color mask image first), and then draw that mask image on top of the background as a separate step. This would also let you easily do things like e.g. give the spotlight fuzzy borders.

Java padding image

I am working on creating an online image editing tool.Looking for some refernce how can I add an image with white space on right side.For example see this image
Presumably, you want to create a new image from an existing image, where the new image has white space on the left and right?
Suppose the unpadded image was a BufferedImage and is called 'image'. Suppose the amount of whitespace you want on each side is 'w'. What you want to do is create a new BufferedImage wider than the original, then paint the entire thing white, and finally draw the smaller image on top of it:
BufferedImage newImage = new BufferedImage(image.getWidth() + 2 * w, image.getHeight(), image.getType());
Graphics g = newImage.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, image.getWidth() + 2 * w, image.getHeight());
g.drawImage(image, w, 0, null);
g.dispose();
If anyone comes upon a similar problem, I would definitively recommend imgScalr. You can add padding with literally one line imageSource= Scalr.pad(imageSource,pad,Color.White);.
Create a new BufferedImage object of the right size; use Graphics.fillRect() to paint it white; draw the image into the top-left corner with drawImage(); then save your new image.

java image crop

I am aware of BufferedImage.getSubimage However, it cant deal with cropping images that are smaller than the cropping size throwing the exception:
java.awt.image.RasterFormatException: (y + height) is outside raster
I want to be able to crop either a PNG/JPG/GIF to a certain size however if the image is smaller than the cropping area centre itself on a white background. Is there a call to do this? Or do I need to create an image manually to centre the image on if so, how would I go about this?
Thanks
You cannot crop an image larger, only smaller. So, you start with the goal dimension,let's say 100x100. And your BufferedImage (bi), let's say 150x50.
Create a rectangle of your goal:
Rectangle goal = new Rectangle(100, 100);
Then intersect it with the dimensions of your image:
Rectangle clip = goal.intersection(new Rectangle(bi.getWidth(), bi.getHeight());
Now, clip corresponds to the portion of bi that will fit within your goal. In this case 100 x50.
Now get the subImage using the value of clip.
BufferedImage clippedImg = bi.subImage(clip,1, clip.y, clip.width, clip.height);
Create a new BufferedImage (bi2), the size of goal:
BufferedImage bi2 = new BufferedImage(goal.width, goal.height);
Fill it with white (or whatever bg color you choose):
Graphics2D big2 = bi2.getGraphics();
big2.setColor(Color.white);
big2.fillRect(0, 0, goal.width, goal.height);
and draw the clipped image onto it.
int x = goal.width - (clip.width / 2);
int y = goal.height - (clip.height / 2);
big2.drawImage(x, y, clippedImg, null);

Categories