I have a Java app where the user can crop a subimage from its original self. The crop area is selected by drawing a rectangle over the original image. The rectangle can then be resized diagonally. And so far, everything works!
The user also has an option to lock the aspect ratio of the rectangle to 4:3. I can achieve this simply by setting the width to w = h / 4 * 3;
However, when it comes to resizing with locked ratio, the rectangle behaves strangely and is no longer stationary when dragging from the northwest corner (see gif below). Had the same problem with southwest corner, but that could be fixed by instead setting height to h = w / 3 * 4; but I can't figure out how to do this mathematically for the northwest corner. I have provided a copy-pastable demo for experimentation:
public class CropDemo {
public static void main(String[] args) {
CropPanel cropPanel = new CropPanel();
cropPanel.setPreferredSize(new Dimension(640, 480));
JFrame jFrame = new JFrame("Crop Panel");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.getContentPane().add(cropPanel);
jFrame.setResizable(false);
jFrame.pack();
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
}
class CropPanel extends JPanel {
private static final long serialVersionUID = 1L;
private boolean fixedRatio = true;
private Rectangle rectangle;
private Point clickPoint;
private static final int HOVERING = 0;
private static final int MOVING = 1;
private static final int RESIZING = 2;
public CropPanel() {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint = null;
#Override
public void mouseClicked(MouseEvent e) {
if (rectangle != null && getCursorState() == HOVERING) {
rectangle = null;
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
startPoint = e.getPoint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (rectangle != null) {
Point mouse = e.getPoint();
int width = rectangle.x + rectangle.width;
int height = rectangle.y + rectangle.height;
final int off = 5;
if (mouse.x > rectangle.x - off && mouse.x < width + off && mouse.y > rectangle.y - off
&& mouse.y < height + off) {
if (mouse.x <= rectangle.x + off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
} else if (mouse.x <= rectangle.x + off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (clickPoint != null) {
Point mouse = e.getPoint();
if (getCursorState() == MOVING) {
int dx = rectangle.x + mouse.x - clickPoint.x;
int dy = rectangle.y + mouse.y - clickPoint.y;
rectangle.setLocation(dx, dy);
clickPoint = e.getPoint();
} else if (getCursorState() == RESIZING) {
int dx = mouse.x - startPoint.x;
int dy = mouse.y - startPoint.y;
int height = rectangle.height;
int width = rectangle.width;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
switch (getCursor().getType()) {
case Cursor.SW_RESIZE_CURSOR:
x = mouse.x + dx;
y = rectangle.y;
w = width - dx;
h = height + dy;
if (fixedRatio) {
h = w / 3 * 4;
}
break;
case Cursor.SE_RESIZE_CURSOR:
x = rectangle.x;
y = rectangle.y;
w = width + dx;
h = height + dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NW_RESIZE_CURSOR:
x = mouse.x + dx;
y = mouse.y + dy;
w = width - dx;
h = height - dy;
// This is where I'm lost
// something else needs to be done
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NE_RESIZE_CURSOR:
x = rectangle.x;
y = mouse.y + dy;
w = width + dx;
h = height - dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
}
rectangle.setBounds(x, y, w, h);
startPoint = mouse;
} else {
int x = Math.min(clickPoint.x, mouse.x);
int y = Math.min(clickPoint.y, mouse.y);
int w = Math.max(clickPoint.x - mouse.x, mouse.x - clickPoint.x);
int h = Math.max(clickPoint.y - mouse.y, mouse.y - clickPoint.y);
if (rectangle == null) {
rectangle = new Rectangle(x, y, w, h);
} else {
rectangle.setBounds(x, y, w, h);
}
}
repaint();
}
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D graphics2D = (Graphics2D) g.create();
if (rectangle != null) {
Area fill = new Area(new Rectangle(new Point(0, 0), getSize()));
fill.subtract(new Area(rectangle));
if (clickPoint != null) {
graphics2D.setColor(new Color(0, 0, 0, 0));
} else {
graphics2D.setColor(new Color(0, 0, 0, 200));
}
int x = rectangle.x;
int y = rectangle.y;
int w = rectangle.width;
int h = rectangle.height;
graphics2D.fill(fill);
graphics2D.setColor(Color.WHITE);
graphics2D.setStroke(
new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 6 }, 0));
graphics2D.drawRect(x, y, w, h);
if (w >= 30 && h >= 30) {
graphics2D.setStroke(new BasicStroke(3));
graphics2D.drawLine(x + 1, y + 1, x + 8, y + 1);
graphics2D.drawLine(x + 1, y + 1, x + 1, y + 8);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 8, y + 1);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 1, y + 8);
graphics2D.drawLine(x + 1, y + h - 1, x + 8, y + h - 1);
graphics2D.drawLine(x + 1, y + h - 1, x + 1, y + h - 8);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 8, y + h - 1);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 1, y + h - 8);
}
}
graphics2D.dispose();
g.dispose();
}
private int getCursorState() {
switch (getCursor().getType()) {
case Cursor.CROSSHAIR_CURSOR:
return HOVERING;
case Cursor.MOVE_CURSOR:
return MOVING;
case Cursor.SW_RESIZE_CURSOR:
case Cursor.SE_RESIZE_CURSOR:
case Cursor.NW_RESIZE_CURSOR:
case Cursor.NE_RESIZE_CURSOR:
case Cursor.N_RESIZE_CURSOR:
case Cursor.S_RESIZE_CURSOR:
case Cursor.W_RESIZE_CURSOR:
case Cursor.E_RESIZE_CURSOR:
return RESIZING;
default:
return -1;
}
}
}
Firstly just to note, the aspect ratio you are using is 3:4 not 4:3:
3:4 means that for every 3 units of width there are 4 units of height.
4:3 means that for every 4 units of width, there are 3 units of height.
w = h / 4 * 3 is calculating 3:4, not 4:3.
w = h / 3 * 4 or h = w / 4 * 3 calculates 4:3
Moving on to why your resizing breaks, when you create a Rectangle you provide the x, y coordinates of it's top left corner, and it's width and height:
Rectangle rectangle = new Rectangle(x, y, width, height)
The rectangle will then be drawn from x, y to x + width, y + height
The resizing part of your code works fine, when the mouse is dragged you update x, y, width, and height correctly.
The reason why applying the aspect ratio breaks it, is because you are updating width, and height, but you are not updating x and y.
Lets say the user performed a Northwest resize, and you now have a rectangle as follows:
x => 10
y => 10
width => 5
height => 10
You then apply your aspect ratio w = h / 4 * 3:
x => 10
y => 10
width => 8
height => 10
Because you are drawing from the top left corner, the rectangle has now grown from left to right, but you want it to grow from right to left. When you resize in the Northwest direction, you always want the bottom right corner of the rectangle to remain in the same place. The reason why this does not happen with your code is because when you apply the aspect ratio to the rectangle's width, you do not then update the start x, y point of the rectangle.
Using the above example, x and y should be updated as follows:
x => 7
y => 10
width => 8
height => 10
Here is a solution that I came up with:
else if (getCursorState() == RESIZING) {
Point startPoint = null;
Point endPoint = null;
switch(getCursor().getType()) {
case Cursor.SW_RESIZE_CURSOR:
startPoint = new Point((int) mouse.getX(), (int) rectangle.getMinY());
endPoint = new Point((int) rectangle.getMaxX(), (int) mouse.getY());
break;
case Cursor.NW_RESIZE_CURSOR:
startPoint = new Point((int) mouse.getX(), (int) mouse.getY());
endPoint = new Point((int) rectangle.getMaxX(), (int) rectangle.getMaxY());
break;
case Cursor.NE_RESIZE_CURSOR:
startPoint = new Point((int) rectangle.getMinX(), (int) mouse.getY());
endPoint = new Point((int) mouse.getX(), (int) rectangle.getMaxY());
break;
case Cursor.SE_RESIZE_CURSOR:
startPoint = new Point((int) rectangle.getMinX(), (int) rectangle.getMinY());
endPoint = new Point((int) mouse.getX(), (int) mouse.getY());
break;
}
rectangle.setFrameFromDiagonal(startPoint, endPoint);
if (fixedRatio) {
// Calculate 3:4 aspect ratio
rectangle.height = rectangle.width / 3 * 4;
// If this is a NW or NE resize, we need to adjust the start y coordinate to account for the new height
// This keeps the bottom right corner in the same place for a NW resize
// and the bottom left corner in the same place for a NE resize
if (getCursor().getType() == Cursor.NW_RESIZE_CURSOR || getCursor().getType() == Cursor.NE_RESIZE_CURSOR) {
rectangle.y = endPoint.y - rectangle.height;
}
}
}
So when the rectangle is resized in the Northwest or Northeast directions, and the aspect ratio is applied, I also update the rectangle's start y coordinate to account for the change in height.
I want to draw image on Top in each Arc of Canvas
private void drawImage(Canvas canvas, float tempAngle, Bitmap bitmap,String mValue) {
//get every arc img width and angle
int imgWidth = (radius / mWheelItems.size());
//int imgWidth = (radius / 3);
float angle = (float) ((tempAngle + 360 / mWheelItems.size() /2) * Math.PI / 180);
//calculate x and y
int x = (int) (center + radius / 2 / 2 * Math.cos(angle));
int y = (int) (center + radius / 2 / 2 * Math.sin(angle));
int top=y - imgWidth/2;
int bottom=y +imgWidth/2;
int left=x - imgWidth /2;
int right=x + imgWidth / 2;
Rect rect = new Rect(left, top, right, bottom);
final Rect rect1 = new Rect(x - imgWidth /2 , y - imgWidth / 2 , bitmap.getWidth() , bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rect, null);
}
the Arc is made according to the size of items
The Result is shown like that
But I want the image bitmap shown on top like that of rect. Red also want to large size of images or bitmap
Solved by Specific Tab and Big Screen Tablets
Change the X and Y coordination According to Angle
if(tempAngle==0) {
x = x + 50;
}
if(tempAngle==60) {
y = y + 50;
}
if(tempAngle==120) {
imgWidth = imgWidth-12;
y = y + 20;
x = x - 40;
}
if(tempAngle==180) {
imgWidth = imgWidth+12;
x = x - 50;
}
if(tempAngle==240) {
y = y - 50;
}
if(tempAngle==300) {
y = y - 20;
x = x + 40;
}
I unable scroll down page in bottom in hybrid app in appium using java. I am using Appium v1.6.3
You can use Swipe method to swipe from bottom to up.
ds.swipe(startx,starty , endx, endy, 500);
or
you can use scrollto("name of the element")
As it is hybrid app then first we have to change to Native_APP then we have to apply below code
Dimension size = driver.manage().window().getSize();
System.out.println(size);
//Find swipe start and end point from screen's with and height.
//Find starty point which is at bottom side of screen.
int starty = (int) (size.height * 0.70);
//Find endy point which is at top side of screen.
int endy = (int) (size.height * 0.20);
//Find horizontal point where you wants to swipe. It is in middle of screen width.
int startx = size.width / 2;
System.out.println("starty = " + starty + " ,endy = " + endy + " , startx = " + startx);
This is how i tried a scroll down a side menu and find a logout
//Swipe down the side menu and click on logout
#Test
public void T4b_logout() throws InterruptedException{
size = driver.manage().window().getSize(); //Get the size of screen.
System.out.println(size);
int starty = (int) (size.height * 0.80);//Find starty point which is at bottom side of screen.
int endy = (int) (size.height * 0.20); //Find endy point which is at top side of screen.
int startx = size.width / 2; //Find horizontal point where you wants to swipe. It is in middle of screen width.
System.out.println("starty = " + starty + " ,endy = " + endy + " , startx = " + startx); // int startx = size.width;
driver.swipe(startx, starty, startx, endy, 3000);//Swipe from Bottom to Top.
Thread.sleep(2000);
driver.findElement(By.name("Logout")).click();
driver.findElement(By.xpath("//android.widget.Button[#text='Ok']")).click();
}
Below is the code to swipe down. Interchange the start, end values for swipe up.
public void scrollDown(AndroidDriver driver,int swipeTimes, int durationOfSwipe){
Dimension dimension = driver.manage().window().getSize();
for (int i=0; i<=swipeTimes;i++){
int start = (int) (dimension.getHeight() * 0.8);
int end = (int) (dimension.getHeight() * 0.1);
int x = (int) (dimension.getWidth()*.5);
driver.swipe(x, start, x, end, durationOfSwipe);
}
}
I am trying to crop image inside bounding box from camera preview and display in a activity. I have a surfaceview and a square imageview on top of it. I have to capture image that appears only inside imageview. Following is my cropping code, No idea as to what is wrong here,Please help
int width = rotatedBitmap.getWidth();
int height = rotatedBitmap.getHeight();
int newWidth = (height > width) ? width : height;
int newHeight = (height > width)? height - ( height - width) : height;
int x = (width - height) / 2;
x = (x < 0)? 0: x;
int y = (height - width) / 2;
y = (y < 0)? 0: y;
Bitmap cropImg = Bitmap.createBitmap(rotatedBitmap, x, y,newWidth, newHeight);
what's wrong with my code?
My Question is how can I move a bitmap on a canvas?
Recently I'm making a game and There's a button.
When I'm clicking on this button I want to move the bitmap (Only X)
but when i'm doing this the bitmap is gone.
Here's the code :
"main_right" is the button that I'm clicking on.
I also tried to put "invalidate()" there but it also didn't work.
#Override
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (x > width - main_right.getWidth()
&& x < width - main_right.getWidth()
+ main_right.getWidth()
&& y > height
- (main_right.getHeight() + main_right.getHeight() / 2)
&& y < height
- (main_right.getHeight() + main_right.getHeight() / 2)
+ main_right.getHeight()) {
x += 1;
canvas_main.drawBitmap(image, (width / 2) + x2,
height - (image.getHeight() + image.getHeight() / 2),
paint);
} else {
x = 0;
}
return true;
}
return false;
}
Store the x position on your onTouchEvent and draw at your canvas inside the onDraw(Canvas), that is the surface you need to draw.
canvas_main.drawBitmap(image, (width / 2) + x,
height - (image.getHeight() + image.getHeight() / 2),
paint);
The height might be the problem if your bitmap is > (device height/3)
height - (image.getHeight() + image.getHeight() / 2)
In essence means height - 1.5*image height. Since the top left of the bitmap is placed at that coordinate, the image will disappear out of the screen.
It should be
height - (image.getHeight() - image.getHeight() / 2)
or
height - image.getHeight() / 2