I have an image that I want to crop given the corners.
For example
I want to cut just the sudoku puzzle. I have the corners (x1, y1), (x2, y2), (x3, y3), (x4, y4).
Tried this:
javaxt.io.Image image = new javaxt.io.Image(bufferedImage);
image.setCorners((float) pointTopLeft.getX(), (float) pointTopLeft.getY(), //UL
(float) pointTopRight.getX(), (float) pointTopRight.getY(), //UR
(float) pointBottomRight.getX(), (float) pointBottomRight.getY(), //LR
(float) pointBottomLeft.getX(), (float) pointBottomLeft.getY()); //LL
But the result it returns is this (which is not what I want):
You could first skew the image by shifting the bottom corners and the top right corner - this will result in a more rectangular shape. Then you can crop the image.
I tried it with this:
Image image = new javaxt.io.Image(bufferedImage);
// skew image
image.setCorners(
// keep the upper left corner as it is
0,0, // UL
// push the upper right corner more to the bottom
image.getWidth(),20, // UR
// push the lower right corner more to the left
image.getWidth()-45,image.getHeight(), // LR
// push the lower left corner more to the right
55,image.getHeight()); // LL
// crop image
image.crop(80, 105, image.getWidth()-150, image.getHeight()-105);
And the result is this:
Hope this helps.
You should use the method image.getSubImage(x1,y1,x2,y2) so that you can crop. After this, you can skew it to the right amount.
Related
What I'm trying to do:
Create a compass when given a direction in degrees (0 - 360). Like so:
What I have done:
I have managed to get the SVG image to point in the right direction but I can't seem to get it to rotate around the circle. To attempt a solution around the circle, I have decided to try get the positioning using the ellipse tool and this formula. This is what it looks like at the moment:
(notice how the arrow faces a different direction to the ellipse, in the circle, on the axis - given the center point is the middle of the green circle)
void setDirection(float value, int radius) {
fill(secondaryColour);
float origin_x = (1280 - (width-400)/2);
float origin_y = height/2;
float x = origin_x + radius * cos(radians(value));
float y = origin_y +radius * sin(radians(value));
//grey circle
ellipse(x, y, 20, 20);
//arrow SVG
pushMatrix();
translate(200, 300);
rotate(radians(value));
scale(0.5);
shape(arrow);
popMatrix();
}
Please note: value is in degrees and radius is the radius I want the arrow to sit on. What am I doing wrong with the ellipse? and how can I bring them both together?
I found that the starting angle started on the white line, but I was assuming it would start on the red (similar to the angle of the arrow). To resolve the issue I needed to subtract 90 degrees from the variable value before converting it into radians.
I'm working with PDFBox and trying to rotate an image and have it position correctly on the screen. The design editor I'm using outputs the following information about images that may be useful.
Image bounding box top-left coords (I'm using the bottom left coords to better suit PDFBox coord space.)
Image rotation in degrees
Image width & height
The translation appears to be off.
// Rotation
AffineTransform rotation = new AffineTransform();
rotation.rotate(Math.toRadians(360 - element.getAngle()),
element.getLeft() + scaledWidth/2,
adjustedYPos + scaledHeight/2);
stream.transform(new Matrix(rotation));
// Position & scale
AffineTransform mat = new AffineTransform(scaledWidth,
0,
0,
scaledHeight,
element.getLeft(),
adjustedYPos);
// Draw the final image
stream.drawImage(pdfImage, new Matrix(mat));
Rotations are based on the center of the image as an anchor point.
You can correctly position images using code like this:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
(PlaceRotatedImage utility method)
This method accepts coordinates as they are meaningful in the context of PDF, i.e. coordinate values and dimensions according to the default user space coordinate system of the given page (y values increasing upwards, the origin arbitrary but fairly fairly often in the lower left), (bounding) box given by lower left corner, angles as in math in counterclockwise radians...
If you need the parameters differently, you can fairly easily adapt the method, though. If you e.g. get the upper left corner of the bounding box instead of the lower left, you can simply subtract the bounding box height determined in the method as bbHeight to calculate the lower left y coordinate used here.
You can use this method like this:
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
(PlaceRotatedImage test testPlaceByBoundingBox)
This code draws the left and bottom lines corresponding to the left and bottom side of the given lower left bounding box coordinates and draws an image at different magnifications and angles with the constant given lower left bounding box corner.
The result looks like this:
You can find more information on the calculation of the bounding box sizes in these answers:
Calculate Bounding box coordinates from a rotated rectangle
How to get width and height of the bounding box of a rotated rectangle
How to get size of a rotated rectangle
Find the Bounding Rectangle of Rotated Rectangle
...
I would like to create a Rectangle that has got one side different than the other.
(All lines depicted are meant to be straight lines)
The normal rectangle is generated like new Rectangle(50 /*LocationX*/, 50 */LocationY*/, 50 /*SizeX*/, 100 /*SizeY*/);, and looks like this:
However, I want a constructor like new Rectangle(50 /*LocationX*/, 50 */LocationY*/, 25 /*25 from the centre point for the red line*/, 30 /*30 from the centre point for the blue line*/, 50 /*50 from centre for green line*/, 100 /*100 from centre for yellow line*/);
In other words, I effectively want to keep the shape the same but move the centre point.
How can I do that?
In java, rectangles are defined by upper-left corner coordinates, width and height.
If I understand your question here what describes your rectangle:
pointX, pointY coordinates of a point in the rectangle. Named the point.
distanceToTop distance from the point to the top of the rectangle (green line).
distanceToBottom distance from the point to the bottom of the rectangle (yellow line).
distanceToLeft distance from the point to the left of the rectangle (red line).
distanceToRight distance from the point to the right of the rectangle (blue line).
That given. The upper-left corner of the rectangle has for coordinates:
(pointX - distanceToLeft, pointY - distanceToTop)
And the whole rectangle has for size (width, height):
(distanceToLeft + distanceToRight, distanceToTop + distanceToBottom)
So your instance will be:
Rectangle r = new Rectangle(
pointX - distanceToLeft, // upper-left corner X
pointY - distanceToTop, // upper-left corner Y
distanceToLeft + distanceToRight, // width
distanceToTop + distanceToBottom // height
);
How can I change coordinates to bottom left corner?
I know that's in Java the coordinates begin from Top=Left corner, but I'm asking if can someone help me how can I change it to begin (0,0) coordinates from Bottom-Left corner?
I think it's too late, but for people like me (new to android development). The above answers are correct but here is a more detailed one
If you get the coordinate with respect to top left as (a,b),
then the coordinates with respect to the bottom left are simply
(a, h-b) where h is the height of the view.
Example:
float x = getXcoordinatesonTouch();
float y = getYcoordinatesonTouch();
//should return height
float h = getHeightoftheView();
float transformY = h - y;
//"x" should be as it is
//Now you can show "x" and "transformY"
getHeight() will get you the size height. so (0, getHeight()) will give you the left-bottom point. But take into consideration the height of the object you want to place. So you may want to use
(0, getHeight() - heightOfObject)
Use the value (x, HEIGHT - y).
I have an image with a softcrop.
i.e
The image bounds are width 3 and height 5.
In the image I have a soft crop at (x,y) 1,4 and bounds width 1 and height 1.
How can I get the new position (x,y) for the crop after I rotate the image 90 degrees?
AffineTransform perhaps?
Yes you can use AffineTransform.
You can use AffineTransform.getRotateInstance and AffineTransform#transform(Point2D, Point2D).
Use it like so:
AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 2.0, width / 2.0, height / 2.0);
Point2D.Double point = new Point2D.Double(1, 4);
Point2D.Double result = new Point2D.Double();
transform.transform(point, result);
Please note that the top left point of the soft crop area will no longer be the top left point after rotation but the bottom left.