I need a bit logical help with my program. I need to crop a photo to be 600x600 around the point ( x, y ). The thing I need help with is when the point is close to the edge, how can I then move the cropped area so it fits inside the photo.
I have the code:
BufferedImage finalImg = capture.getSubimage(Math.max( 0, x - 300 ), Math.max( 0, y - 300 ), 200, 200 );
As far as I can see, the code works for the top and left side, but I have no clue how to get the same effect on the bottom and right side.
If it helps, I want to capture the screen and crop the photo around the mouse ( x, y ).
Thank you
BufferedImage originalImage = readImage(inputFileLocation);
/**
* Image Cropping Parameters
*/
int cropHeight = 600;
int cropWidth = 600;
int cropStartX = 50;
int cropStartY = 50;
BufferedImage processedImage = cropMyImage(originalImage, cropWidth,
cropHeight, cropStartX, cropStartY);
follow this site for full code.
Related
a have a problem with scaling images up. I have a png file that looks like this:
raw png
The image is 8px * 8px and has some red straight lines on it.
But when i draw this image with java and scale it up this happens: java image
And as you can barly see, the line is not exactly straight. It is always one pixel off and makes this kind of wavy shape. If the image gets drawn somewhere else on the frame the "waves" are somewhere else. The image is rotated 90° but I tested it without rotation and it was still there. Apart from this I do need rotated images.
Is there any way to fix this? I enabled text-antialiasing in the same Graphics2D object. Is there also some sort of anitaliasing for this?
Code
private void loadImage(String path, int field, int imageNumber) {
BufferedImage image;
image = new Resource().readImg(path);
images[field][imageNumber][0] = image;
images[field][imageNumber][1] = rotateClockwise90(image);
images[field][imageNumber][2] = rotateClockwise90(rotateClockwise90(image));
images[field][imageNumber][3] = rotateClockwise90(rotateClockwise90(rotateClockwise90(image)));
}
private BufferedImage rotateClockwise90(BufferedImage src) {
int width = src.getWidth();
int height = src.getHeight();
BufferedImage dest = new BufferedImage(height, width, src.getType());
Graphics2D graphics2D = dest.createGraphics();
graphics2D.translate((height - width) / 2, (height - width) / 2);
graphics2D.rotate(Math.PI / 2, height / 2, width / 2);
graphics2D.drawRenderedImage(src, null);
return dest;
}
When the program starts I load the image I rotate it in all 4 directions, so I don't have to do this over and over again while the program is running.
public BufferedImage getTile(int type, int part, int rotation) {
return images[type][part][rotation];
}
And then all I have to do is calling this get method and draw the image:
g2d.drawImage(tiles.getShipTile(type, part, rotation), x, y, null);
I actually found a way to avoid these weird pixels but this method makes the image a little bit blurry.
Instead of using
g2d.drawImage(img, x, y, width, height, null);
you can simply use
g2d.drawImage(img.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING), x, y, null);
which does basically the same thing but wehn I scale it up it uses this smooth making key.
I tried this and noticed that its not verry comfortable because it lags a lot.
So I just scale it up in the beginning when I also rotate the images.
As I said this method is a bit blurry but if there are no other ways avoiding this problem I have to get use of this. You almost can't see the blur, so this would be an option for me.
I've been stuck at something recently.
What I want to do is to get multiple sub-images out of 1 big image.
So take this example. I have a frame of 128x128 pixels where all the images need to be in.
I'm putting all the bufferedImages inside a list and scaling all those images to 128x128.
The image you see on that link is showing that I need 4 sub-images from that image, so at the end, I have 4 images which are 128x128 but 4 times.
Or if you have an image with 128x384 it will give 3 sub-images going from top to bottom.
https://i.stack.imgur.com/RsCkf.png
I know there is a function called
BufferedImage.getSubimage(int x, int y, int w, int h);
But the problem is that I can't figure out what math I need to implement.
What I tried is if the height or width is higher than 200 then divide it by 2 but that never worked for me.
I'm not sure I fully understand what you are asking, but I think what you want is something like this:
First, loop over the image in both dimensions.
Then compute the size of the tile (the smaller value of 128 and (image dimension - start pos)). This is to make sure you don't try to fetch a tile out of bounds. If your images are always a multiple of 128 in any dimension, you could just skip this step and just use 128 (just make sure you validate that input images follow this assumption).
If you only want tiles of exactly 128x128, you could also just skip the remainder, if the tile is less than 128x128, I'm not sure what your requirement is here. Anyway, I'll leave that to you. :-)
Finally, get the subimage of that size and coordinates and store in the list.
Code:
BufferedImage image = ...;
int tileSize = 128;
List<BufferedImage> tiles = new ArrayList<>();
for (int y = 0; y < image.height(); y += tileSize) {
int h = Math.min(tileSize, image.height() - y);
for (int x = 0; x < image.width(); x += tileSize) {
int w = Math.min(tileSize, image.width() - x);
tiles .add(image.getSubimage(x, y, w, h));
}
}
I had searched about it but I did not get straight forward answer.
I want a buffered image to be rotated but not cropped
I knew the new dimensions are gonna be some thing like this
int w = originalImage.getWidth();
int h = originalImage.getHeight();
double toRad = Math.toRadians(degree);
int hPrime = (int) (w * Math.abs(Math.sin(toRad)) + h * Math.abs(Math.cos(toRad)));
int wPrime = (int) (h * Math.abs(Math.sin(toRad)) + w * Math.abs(Math.cos(toRad)));
Provide me a method for that.
BTW is there any way to rotate a JLabel with an ImageIcon?
Intention: adding to panels and layered pane and also saving it to file (saving the layered pane).
Or can we rotate the layered pane?
How to rotate a buffered image without cropping it?
You had already half of the work by calculating the size of the rotated BufferedImage.
The other half is actually creating the rotated BufferedImage.
You can do that by using Graphics2D
and applying some coordinate transformations before drawing the original image onto the new one. Furthermore, it makes sense to paint the "excess" area with some background color.
public BufferedImage rotateImage(BufferedImage originalImage, double degree) {
int w = originalImage.getWidth();
int h = originalImage.getHeight();
double toRad = Math.toRadians(degree);
int hPrime = (int) (w * Math.abs(Math.sin(toRad)) + h * Math.abs(Math.cos(toRad)));
int wPrime = (int) (h * Math.abs(Math.sin(toRad)) + w * Math.abs(Math.cos(toRad)));
BufferedImage rotatedImage = new BufferedImage(wPrime, hPrime, BufferedImage.TYPE_INT_RGB);
Graphics2D g = rotatedImage.createGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, wPrime, hPrime); // fill entire area
g.translate(wPrime/2, hPrime/2);
g.rotate(toRad);
g.translate(-w/2, -h/2);
g.drawImage(originalImage, 0, 0, null);
g.dispose(); // release used resources before g is garbage-collected
return rotatedImage;
}
Here is a test example from the above code:
Original image
Rotated image (by 30 degree)
BTW is there any way to rotate a JLabel with an ImageIcon?
The easier way is to rotate the Icon, not the label.
Check out Rotated Icon for a class that does the rotation and recalculates the size of the Icon as it is rotated.
Intention: adding to panels and layered pane and also saving it to file (saving the layered pane).
Don't know exactly what that means, but if you just want to save an "image" of the layered pane then check out Screen Image.
i have a java.util.List filled with java.io.File and i wan't to list them in a gui. To display them i wan't to show their name which is accessable by the method getName() of java.io.File. And i want to display their icon/image with which they are displayed for example on the desktop. To build this i am using the newest javaversion (Java8/1.8). So far i found one way to do get the image of any file which looks like this:
Icon icon = FileSystemView.getFileSystemView().getSystemIcon(pFile);
The problem about that is, that the returned icon is in a very small resolution(16x16) and i d like to display it in a bigger size. 80x80 would be perfect but doesn't have to be exactly it. 64x64 or smth like that would be fine, too. So i managed to resize the icon and stretch it but streatching 16x16 to 80x80 is not cool as you can imagine. There are to less pixels to get a good result.
I also found this tutorial but the first method shown in this tutorial doesn't work with Java8: http://www.rgagnon.com/javadetails/java-0439.html The method i am using right now is copied from there.
So is there any way to get a bigger sized icon like the one which is shown on the desktop of a specific file?
Thanks
Baschdi
private BufferedImage getBufferedImage(final File pFile)
throws FileNotFoundException {
Image icon = ShellFolder.getShellFolder(pFile).getIcon(true);
BufferedImage im = new BufferedImage(icon.getWidth(null),
icon.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = im.createGraphics();
g.drawImage(icon, 0, 0, null);
g.dispose();
int width = im.getWidth();
int height = im.getHeight();
System.out.println(width);
System.out.println(height);
final int maxHeigh = 79;
double scaleValue = 0;
if (height > width)
scaleValue = maxHeigh / height;
else
scaleValue = maxHeigh / width;
final int scaledWidth = (int) (im.getWidth() * scaleValue);
final int scaledHeigh = (int) (im.getHeight() * scaleValue);
BufferedImage resized = new BufferedImage(scaledWidth, scaledHeigh,
im.getType());
g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(im, 0, 0, scaledWidth, scaledHeigh, 0, 0, im.getWidth(),
im.getHeight(), null);
g.dispose();
return resized;
}
I imported the jdk7 and used the older function with ShellFolder. Works fine, even when running on java8. Thanks for the help :)
I have created a library called JIconExtractReloaded which can extract all icons sizes not only 32x32. Here is the link https://github.com/MrMarnic/JIconExtractReloaded.
Just write:
BufferedImage image = JIconExtract.getIconForFile(128,128,"C:\\Windows\\explorer.exe");
And you have the icon.
I'll start of by showing examples of what's wrong then I'll explain how, and finally I'll ask my question.
This is the picture I want to rotate.
I am rotating it 90 degrees and 270 degrees, on multiple occasions and then combiningthose into a big buffered-image.
The code I am using to rotate a single bufferedImage is this:
public static BufferedImage rotate(BufferedImage img, int angle) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = new BufferedImage(w, h, img.getType());
Graphics2D g = dimg.createGraphics();
g.rotate(Math.toRadians(angle), w/2, h/2);
g.drawImage(img, null, 0, 0);
return dimg;
}
The out come of the rotation looks something like this.
The reason those black bars are these is because in the code you can clearly see I create a separate buffered-image which will be the final image.
Which uses the original width and hight, since the image is rotated the with and height switch so I compensated for this by changing BufferedImage dimg = new BufferedImage(w, h, img.getType()); to BufferedImage dimg = new BufferedImage(h, w, img.getType());.
I though it would be logical that this would solve my problem.
But I was wrong now the rotational outcome is this.
So from this point on is where I have no clue why it's doing this.
I might just be overlooking a tiny thing, or it's a common error even though I can't find any instance of this occurring.
So here is my question to you, why does it do this? And how do I fix this.
The image isn't square. If you rotate it by 90°, then you will create a gap that you need to fill.
Solutions:
Make sure the image is square
"Rotate" the size: When you rotate by 90° or 270°, you need to create a target image with swapped width and height (i.e. 200x100 -> 100x200)
Crop the image. Good in your case since scaling will make the arrow look bad but it might be out of center
Scale the image. If it's 609x579, scale it down to 579x579 (scaling down will usually look a little bit better).
Find the border color and fill the gap with the border color after the rotation
I figured it out.
The thing I was doing in the start was rotating the host image (dimg),
and then drawing the original image to it.
I could just as well have tried to fit a square in a circle my earlier rotation actually makes no sense at all.
So what I need to do is first create the host, draw the image to the host, the rotate the host and return it as the final image.
public static BufferedImage rotate(BufferedImage img, int angle) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = new BufferedImage(w, h, img.getType());
Graphics2D g = dimg.createGraphics();
g.drawImage(img, null, 0, 0); //Draw before rotating
g.rotate(Math.toRadians(angle), w/2, h/2); //Rotating after drawing
return dimg;
}
I hope this helps out some other people as well
if you want to use a similar code as first code
this may help ( if you remove the comments and debug lines (such as painting the background) it has only the translate((W-w)/2,(H-h)/2) line in addition )
// do not forget to import static java.lang.Math.*
public static BufferedImage rotate(BufferedImage img, int angle) {
int w = img.getWidth(null);
int h = img.getHeight(null);
double rad = toRadians(angle);
double eps = 1e-3;
int W=(int)(abs(cos(rad))*w+abs(sin(rad))*h-eps)+1;//W after rotation(calculated by using a little geometry )
int H=(int)(abs(sin(rad))*w+abs(cos(rad))*h-eps)+1;//H after rotation
//you may use max value ( diameter of the rectangle ) instead of dynamic value but in that case you must be careful of the black edges ( in this case red edges )
// if 90 is not a divisor of angle then you can't fit a rectangle with that angle in another one so the red edges are inevitable
// but with calculated W and H this edges are minimum
BufferedImage dimg = new BufferedImage(W,H, BufferedImage.TYPE_INT_RGB);// you can change it to any type you want it's just a sample
Graphics2D g = dimg.createGraphics();
g.setColor(Color.RED); // background color of red for displaying the red edges when image is not completely fit
g.fillRect(0, 0, W, H);
int x=(W-w)/2;
int y=(H-h)/2;
g.translate(x, y); // moving dimg center to img center ( this was what first code lack in )
g.rotate(-rad, w/2, h/2); // now rotating dimg around the center of img ( which is now same as center of dimg )
// we rotate dimg by -rad and draw img normally , it's like rotating img by rad instead of dimg by -rad
g.drawImage(img,null,0,0); // and drawing
return dimg;
}