is it possible to print part of the screen around the mouse?
I try with :
Toolkit tool = Toolkit.getDefaultToolkit();
Dimension d = tool.getScreenSize();
Rectangle rect = new Rectangle(d);
Robot robot = new Robot();
File f = new File("screenshot.jpg");
BufferedImage img = robot.createScreenCapture(rect);
ImageIO.write(img,"jpeg",f);
but it prints all screen, i can see that i can set the size of rectangle but i don't see how can i center rectangle so that it be around mouse.
public static BufferedImage printScrAroundCursor(int width, int height)
{
Toolkit tool = Toolkit.getDefaultToolkit();
Robot robot = new Robot();
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int x = (int) b.getX();
int y = (int) b.getY();
int topLeftX = Math.max(0, x - (width / 2));
int topLeftY = Math.max(0, y - (height / 2));
if (topLeftX + width > tool.getScreenSize().getWidth())
width = tool.getScreenSize().getWidth() - topLeftX;
if (topLeftX + width > tool.getScreenSize().getHeight())
width = tool.getScreenSize().getHeight() - topLeftY;
return robot.createScreenCapture(new Rectangle(topLeftX , topLeftY , width, height));
}
You can use MouseInfo to get the mouse's location. From there, it's simple midpoint math:
int width = ...;
int height = ...;
Point m = MouseInfo.getPointerInfo().getLocation();
Rectangle rect = new Rectangle(m.x - width / 2, m.y - height / 2, width, height);
Robot robot = new Robot();
File f = new File("screenshot.jpg");
BufferedImage img = robot.createScreenCapture(rect);
ImageIO.write(img, "jpeg" ,f);
You will probably encounter strange results if the mouse is too close to the edge of the screen, but without more information, this special behavior is up to you to define how you wish for it to be.
Point mousePos = MouseInfo.getPointerInfo().getLocation();
int width = 300;
int height = 300;
Point origin = new Point(mousePos.getX() - width / 2, mousePos.getY() - height / 2);
Rectangle rect = new Rectangle(origin.getX(), origin.getY(), width, height);
BufferedImage img = robot.createScreenCapture(rect);
Related
I cannot seem to figure out how to draw a transparent and rotated image. I need to be able to draw an image that is transparent and rotated to a certain degree.
I tried this code:
// draws an image that is rotated to a certain degree
public static void drawRotatedImage(BufferedImage image_, int x, int y, int degrees, float scale) {
// graphics used for the utilities of drawing the image (processing)
Graphics2D utilGraphics;
// make rectangular image
int radius = (int) Math.sqrt(image_.getWidth() * image_.getWidth() + image_.getHeight() * image_.getHeight());
BufferedImage image1 = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_RGB);
utilGraphics = image1.createGraphics();
// centers image
utilGraphics.drawImage(image_, image1.getWidth() / 2 - image_.getWidth() / 2, image1.getHeight() / 2 - image_.getHeight() / 2, null);
// scale image
int nw = (int) (image1.getWidth() * scale);
int nh = (int) (image1.getHeight() * scale);
BufferedImage image = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_RGB);
utilGraphics.drawImage(image1, 0, 0, nw, nh, null);
// Rotation information
double rotationRequired = Math.toRadians (degrees);
double locationX = image.getWidth() / 2;
double locationY = image.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
ImageProducer filteredImgProd = new FilteredImageSource(op.filter(image, null).getSource(), filter);
Image transparentImg = Toolkit.getDefaultToolkit().createImage(filteredImgProd);
// Drawing the rotated image at the required drawing locations
g2d.drawImage(Toolkit.getDefaultToolkit().createImage(transparentImg.getSource()), x, y, null);
}
The filter variable is defined as:
private static final ImageFilter filter = new RGBImageFilter() {
int transparentColor = new Color(0, 0, 0, 0).getRGB() | 0x0000ffcc;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0x0000ffcc) == transparentColor) {
return 0x0000ffcc & rgb;
} else {
return rgb;
}
}
};
This ...
BufferedImage image = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_RGB);
centeredGraphics.drawImage(image1, 0, 0, nw, nh, null);
You're creating a new BufferedImage (image), but you never actually paint anything to it, instead, you paint image1 to it's own Graphics context.
Now, if you wanted a transparent image, you should have used...
BufferedImage centeredImage = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
instead of...
BufferedImage centeredImage = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_RGB);
And I never used g2d.drawImage(Toolkit.getDefaultToolkit().createImage(transparentImg.getSource()), x, y, null); as it just doesn't make sense to me (transparentImg is already an Image 🤷♂️)
Now, having said all that, I would "suggest" you take each step individually, start by scaling the original image using something like Java: maintaining aspect ratio of JPanel background image and the rotate the image using something like Rotate a buffered image in Java (which will generate a image large enough to contain the rotated image)
Also, if you "create" a Graphics context, you should also dispose of it when you no longer need it, otherwise you could end up with a memory leak.
"Fixed" code...
Just to be clear, I would still recommend sing ARGB instead of RGB for centeredImage as your filter workflow never seemed to work for, but I started with a transparent image anyway
public Image rotateAndScaleImage(BufferedImage originalImage, int degrees, float scale) {
// make rectangular image
int radius = (int) Math.sqrt(originalImage.getWidth() * originalImage.getWidth() + originalImage.getHeight() * originalImage.getHeight());
BufferedImage centeredImage = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = centeredImage.createGraphics();
// centers image
int xPos = (centeredImage.getWidth() - originalImage.getWidth()) / 2;
int yPos = (centeredImage.getHeight() - originalImage.getHeight()) / 2;
graphics.drawImage(originalImage, xPos, yPos, null);
graphics.dispose();
// scale image
int nw = (int) (centeredImage.getWidth() * scale);
int nh = (int) (centeredImage.getHeight() * scale);
BufferedImage image = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_RGB);
graphics = image.createGraphics();
// No scaling is done ???
graphics.drawImage(centeredImage, 0, 0, nw, nh, null);
// Rotation information
double rotationRequired = Math.toRadians(degrees);
double locationX = centeredImage.getWidth() / 2;
double locationY = centeredImage.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
ImageProducer filteredImgProd = new FilteredImageSource(op.filter(centeredImage, null).getSource(), filter);
Image transparentImg = Toolkit.getDefaultToolkit().createImage(filteredImgProd);
return transparentImg;
}
private static final ImageFilter filter = new RGBImageFilter() {
int transparentColor = new Color(0, 0, 0, 0).getRGB() | 0x0000ffcc;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0x0000ffcc) == transparentColor) {
return 0x0000ffcc & rgb;
} else {
return rgb;
}
}
};
Oh, and I'm returning an Image because I painted directly to a component for testing
Tile seamless is an image operation that is available in GIMP. It transforms the image so that it can cover a surface smoothly with a repeatable pattern. The edges will not be visible and the pieces will fit perfectly when tiled together. It makes senses for grass, floors, walls, etc... As far as the example shown in the GIMP documentation though, it is not good (the Taj Mahal https://docs.gimp.org/2.10/en/gimp-filter-tile-seamless.html) but it gives an idea of how it works.
A transparent layer is applied over the image. It's a translation of half the size of the image (modulo image size) and the closer to the center, the more transparent it gets to show more of the original image. I took a look at the algorithm used in GIMP but it was pretty hard to read (https://gitlab.gnome.org/GNOME/gegl/-/blob/master/operations/common/tile-seamless.c).
So instead I remembered Pythagore to compute the distance to the center.
Then I apply a pro-rata to have an alpha between 0 and 255 :
0 => fully transparent => center
255 => fully opaque => corner
So here is the code :
public class TileSeamless {
public static BufferedImage createSeamlessTile(BufferedImage inputImage) {
int w = inputImage.getWidth();
int h = inputImage.getHeight();
BufferedImage seamlessTile = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
seamlessTile.getGraphics().drawImage(inputImage, 0, 0, null);
seamlessTile.getGraphics().drawImage(createLayerImage(inputImage), 0, 0, null);
return seamlessTile;
}
public static BufferedImage createLayerImage(BufferedImage inputImage) {
int w = inputImage.getWidth();
int h = inputImage.getHeight();
BufferedImage layerImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
Color color = new Color(inputImage.getRGB((x + w / 2) % w, (y + h / 2) % h));
int alpha = (int) Math.round(255 * distanceToCenter(x, y, w, h) / distanceToCenter(0, 0, w, h));
Color newColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
layerImage.setRGB(x, y, newColor.getRGB());
}
}
return layerImage;
}
public static double distanceToCenter(int x, int y, int w, int h) {
double distanceToCenterX = x - w / 2d;
double distanceToCenterY = y - h / 2d;
return Math.sqrt(distanceToCenterX * distanceToCenterX + distanceToCenterY * distanceToCenterY);
}
public static void main(String[] args) throws IOException {
File inputFile = new File(args[0]);
File outputFile = new File(args[1]);
BufferedImage inputImage = ImageIO.read(inputFile);
BufferedImage seamlessTile = TileSeamless.createSeamlessTile(inputImage);
ImageIO.write(seamlessTile, "png", outputFile);
}
The result is not too bad. It looks a bit different from the one produced by GIMP.
It's a bit blury.
Any idea how I can have a slighly more neat result?
I need to resize alot of images from the ratio aspect (2:3) to (3:4).
The images are 800px x 1200px currently. I need them to be 600px x 800px eventually without any cropping.
May I know what libraries are available for me to do padding and resizing without cropping in Java?
From your current Image (assuming a java.awt.Image) you can use :
Image.getScaledInstance(w,h,h) as method
Image.SCALE_SMOOTH as algorithm for resize
And these steps:
compute the ratios in width and in height
depending on their values (padding width or padding height)
compute the width and height to obtain the scaled image
compute the padding required
write the image at the good position
static BufferedImage pad(BufferedImage image, double width, double height, Color pad) {
double ratioW = image.getWidth() / width;
double ratioH = image.getHeight() / height;
double newWidth = width, newHeight = height;
int fitW = 0, fitH = 0;
BufferedImage resultImage;
Image resize;
//padding width
if (ratioW < ratioH) {
newWidth = image.getWidth() / ratioH;
newHeight = image.getHeight() / ratioH;
fitW = (int) ((width - newWidth) / 2.0);
}//padding height
else if (ratioH < ratioW) {
newWidth = image.getWidth() / ratioW;
newHeight = image.getHeight() / ratioW;
fitH = (int) ((height - newHeight) / 2.0);
}
resize = image.getScaledInstance((int) newWidth, (int) newHeight, Image.SCALE_SMOOTH);
resultImage = new BufferedImage((int) width, (int) height, image.getType());
Graphics g = resultImage.getGraphics();
g.setColor(pad);
g.fillRect(0, 0, (int) width, (int) height);
g.drawImage(resize, fitW, fitH, null);
g.dispose();
return resultImage;
}
To use as
BufferedImage image = ...;
BufferedImage result = pad(image, 600, 800, Color.white);
Managed to do it using below code:
'w' is the amount of padding you need on each side.
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();
I think ffmpeg can help you to do anything with image.
e.g. Use ffmpeg to resize image
You can keep ffmpeg binaries in some conf folder.
Create sh script for ffmpeg command.
Use CommandLine from (Apache Commons exec library) to run the script.
I drew 4 lines from the center towards the button as I show you in the photo. I do not know how I can draw curved lines that are in red color in the picture.
[enter image description here]
or
[enter image description here (simpler)]
Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager()
.getDefaultDisplay().getWidth(), (int) getWindowManager()
.getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawingImageView.setImageBitmap(bitmap);
DisplayMetrics metrics = this.getResources().getDisplayMetrics();
int x = metrics.widthPixels;
int y = metrics.heightPixels;
Paint paint1 = new Paint () ;
paint1.setStrokeWidth(10);
int margin = 100;
int margin1 = 300;
int top = 0 + margin;
int bottom = canvas.getHeight() - margin;
int left = 0 + margin1;
int right = canvas.getWidth() - margin1;
int centerX = x / 2;
int centerY = y / 2;
canvas.drawLine(centerX, top, centerX, bottom,paint1);
canvas.drawLine(left, centerY, right, centerY,paint1);
You will need to split it in 4 different parts (curves) for easier drawing
Here is my sketch(sorry for quick drawing)
So you need to get 4 points for bezieres and should be something like this
1st move to start (drawing point)
path.moveTo(x1, y1);
then use next for draw path
cubicTo(x2, y2, x3, y3, x4,y4)
and finally
canvas.drawPath(path, paint);
Same procedure make for rest 3 quadrant/parts
hope this will help you to archive your goal
BufferedImage img = ImageIO.read(new File(paramString));
double locationX = img.getWidth(this) / 2;
double locationY = img.getHeight(this) / 2;
AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(paramInt3), locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
BufferedImage bimg = new BufferedImage (img.getWidth(this), img.getWidth(this), BufferedImage.TYPE_BYTE_INDEXED);
bimg = op.filter (img, null);
ImageIcon localImageIcon = new ImageIcon (bimg);
Why might the side be cut off?
I'm using a library that requires the end result to be a ImageIcon.
Your destination image is created here:
BufferedImage bimg = new BufferedImage (img.getWidth(this), img.getWidth(this), BufferedImage.TYPE_BYTE_INDEXED);
It's a square! If your source image is not a square you should create a destination image like this:
BufferedImage bimg = new BufferedImage (img.getHeight(this), img.getWidth(this), BufferedImage.TYPE_BYTE_INDEXED);
Maybe it's just a rounding problem:
double locationX = img.getWidth(this) / 2;
double locationY = img.getHeight(this) / 2;
Width and height are integers, if they are not even you might get rounding issues. Try this:
double locationX = ((double)img.getWidth(this)) / 2;
double locationY = ((double)img.getHeight(this)) / 2;