Zooming in on a particular part of a BufferedImage - java

I am trying to get a subImage of a BufferedImage and then use this subImage to replace the original BufferedImage, to implement a zooming feature based on a user specified selection. However, when I redraw the subImage onto the original image the bottom of the sub-image is not being displayed. I have no idea why. I was wondering if anyone could spot any obvious faults!?!
private void zoomImage(int x1, int x2, int y1, int y2){
BufferedImage subImage = originalImage.getSubimage(x1, y1, x2-x1, y2-y1);
Graphics2D graphics2D = (Graphics2D) originalImage.getGraphics();
graphics2D.drawImage(subImage, 0, 0, 600, 400, 0,0, x2-x1,y2-y1, null);
// clean up
graphics2D.dispose();
}
I was also wondering if there is a better way to implement zooming in on a particular rectangular selection and use the zoomed in section to replace the original image.

It should be noted that the size of sub image should not exceeds the original image width and height.
For example, if the originalimage.width=600 and orignalimage.height=800 then the sub image can be created whose size should be subimage.horizentalorigin+subimage.width<=600 and subimage.veticalorigin+subimage.height<=800.Other wise there will always be dark shadow found at the corners of the image.
subimage.horizentalorigin=x1,
subimage.verticalorigin=x2,
subimage.width=y1,
subimage.height=y2 in your case particularly.
The rest of calculation you do varies from algorithm to algorithm.....

Related

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

How to move everything in Graphics2D by x,y coordinates.

I need to move already made BufferedImage by x,y coordinates and then draw another things on it with Graphics2D object. I tried to use this code to do that :
Graphics2D g = img.createGraphics();
g.translate(x, y);
but it doesn't work. Is there any way to move everything in Graphics2D object and then draw on it or I have to use this code to do that:
BufferedImage temp = new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D g = temp.createGraphics();
g.drawImage(img,x, y,null);
Using this code and then drawing only few elements rather than making whole image from scratch isn't big leap in performance so I think making new BufferedImage then drawing image on it isn't best way. I would rather just create Graphics2D object from already made image and then just move it by a few pixels diagonally, but I couldn't find the way to do that.
From the Graphics2d docs when you use translate:
All coordinates used in subsequent rendering operations on this graphics context are relative to this new origin.
You are defining a transformation that affects future operations. After calling translate if you were to call a method on graphics like draw3DRect(0, 0, ... snipped ... ) the starting coordinates 0,0 would be translated by x,y.
I think your best bet might be to use the methods of BufferedImage to move all the pixels before you get the graphics object. You have getRgb and setRgb
A naive example of moving the pixels:
BufferedImage buffImg = ImageIO.read(img);
int width = buffImg.getWidth();
int horizontalOffset = 10;
int verticalOffset = 10;
int widthToMove = width - horizontalOffset;
int heightToMove = buffImg.getHeight() - verticalOffset;
int[] rgb = buffImg.getRGB(0, 0, widthToMove, heightToMove, null, 0, widthToMove);
buffImg.setRGB(horizontalOffset,verticalOffset,widthToMove, heightToMove,rgb, 0, widthToMove);
This still leaves you with some work to do because there is a strip at the top and to the left that you need to fill with background colour.
If it's going to be used on big images you might want to use a buffer int[] and pass it to getRGB in a loop, getting and setting in chunks.

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.

How to scale an object according to window size?

I am trying to create a shape inside of a JPanel, and as the JPanel increases and decreases the size of the shape also changes accordingly.
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(0,100,50,0);
}
My problem is that I don't know how to scale it using something along the lines of this.getHeight() or this.getLength().
Besides the path outlined by #MadProgrammer, there are two other ways I can think of to scale graphics.
Swing components can generally rely on the Graphics object actually being a Graphics2D object.
We can then use Graphics2D.scale(sx,sy).
A scale instance of an AffineTransform (obtained using getScaleInstance(sx,sy). Set it to the Graphics2D before drawing.
Using either method, the original co-ordinates will be scaled as needed.
Assuming you mean you want to maintain a proportional ratio as the component size changes...
There are a few ways to do this...
You could start by determining the "default" values, that is, if the "preferred" width was 200, the line start point would 50% of the width and the end point would be 25% of the width.
This would allow you to do something like...
int width = getWidth();
int x1 = (int)(Math.round(width * 0.5d);
int x2 = (int)(Math.round(width * 0.25d);
g.drawLine(0, x1, x2, 0);

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