How to crop resize image in Java? - java

When I set the image with actual size onto a panel and cropping using mouse it's working fine but when I resize image onto panel and cropping it's getting wrong cropping image. How to crop resize image using mouse?
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
BufferedImage dest = image.getSubimage(x,y,w,h)

If you want to crop from the original image then you will need to calculate the x/y scale factors of the two images. Then you will need to adjust the x/y/width/height values by these scale factors.
So if your original image is 400 x 100 and the resized image is 100 x 100 you would do something like:
double xScale = originalImageWidth / resizeImageWidth = 400 / 100 = 4.
So now if the cropping rectangle on the resized image is (10, 10, 20, 30);
Then you need to calculate your values something like:
int x = rectangle.x * xScale;
int width = rectangle.width * xScale;
image.getSubImage(x, y, width, height);
You would obviously need to calculate the y / height values using the y scaling factor.

Related

Coordinates of content of ImageView

So I have an ImageView where I set png as a background. Let's assume the png picture is a circle, so it doesn't take all the space of the ImageView.
I need to catch the event of clicking only the content of the ImageView (the circle) and not the remaining empty area.
Is this actually possible at all or with any other Android control?
Edit:
I still can't get this to work.
So to be more precise I have this picture of an egg which I set as ImageView src
And I want to be able to click only on it. Foe example if I click slightly outside the egg I want to know that and prevent code inside the ImageView click event.
I tried this code but I don't have any idea how this helps me:
ImageView imageView = (ImageView)findViewById(R.id.imageview);
Drawable drawable = imageView.getDrawable();
Rect imageBounds = drawable.getBounds();
//original height and width of the bitmap
int intrinsicHeight = drawable.getIntrinsicHeight();
int intrinsicWidth = drawable.getIntrinsicWidth();
//height and width of the visible (scaled) image
int scaledHeight = imageBounds.height();
int scaledWidth = imageBounds.width();
//Find the ratio of the original image to the scaled image
//Should normally be equal unless a disproportionate scaling
//(e.g. fitXY) is used.
float heightRatio = intrinsicHeight / scaledHeight;
float widthRatio = intrinsicWidth / scaledWidth;
//do whatever magic to get your touch point
//MotionEvent event;
//get the distance from the left and top of the image bounds
int scaledImageOffsetX = event.getX() - imageBounds.left;
int scaledImageOffsetY = event.getY() - imageBounds.top;
//scale these distances according to the ratio of your scaling
//For example, if the original image is 1.5x the size of the scaled
//image, and your offset is (10, 20), your original image offset
//values should be (15, 30).
int originalImageOffsetX = scaledImageOffsetX * widthRatio;
int originalImageOffsetY = scaledImageOffsetY * heightRatio;
here is how you would get the click event:
int[] viewCoords = new int[2];
imageView.getLocationOnScreen(viewCoords);
//From this and the touch coordinates you can calculate the point inside the ImageView:
int touchX = (int) event.getX();
int touchY = (int) event.getY();
int imageX = touchX - viewCoords[0]; // viewCoords[0] is the X coordinate
int imageY = touchY - viewCoords[1]; // viewCoords[1] is the y coordinate

Scaling down and making image square in android

I need a way to scale an image down to 78x78. I have found ways of doing this by cutting part of the image off, like this:
Bitmap image = Bitmap.createBitmap(image, 0, 0, 78, 78);
but I need to maintain as much of the image as possible. I had thought of scaling the image down and then making it square:
Bitmap image = Bitmap.createScaledBitmap(imageTest, 78, 78, true);
but of course this creates a square image that is squashed.
Can anyone suggest how I can create a 78x78 image that doesn't rescale and maintains as much of the original image as possible?
From what I understood, you should scale down and center crop the image. Try this code out.
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
// Compute the scaling factors to fit the new height and width, respectively.
// To cover the final image, the final scaling will be the bigger
// of these two.
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
// Now get the size of the source bitmap when scaled
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
// Let's find out the upper left coordinates if the scaled bitmap
// should be centered in the new size give by the parameters
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
// The target rectangle for the new, scaled version of the source bitmap will now
// be
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
// Finally, we create a new bitmap of the specified size and draw our new,
// scaled bitmap onto it.
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
Hope it helps
Try this:
Bitmap image = Bitmap.createScaledBitmap(testImage, (int) 78 * (testImage.getWidth() / testImage.getHeight()), 78, true);
image = Bitmap.createBitmap(image, (int) (image.getWidth() - 78) / 2, 78);
Haven't tested this, as I'm on my way to bed, but it should accomplish what you want, so long as your image has a width greater than or equal to its height.
Regardless, I'd suggest you use BufferedImage instead of Bitmap.
The idea here would be resize your image using the same resize rate for width and height keeping the smaller size in 78. After that you can use a center point based crop to get the middle of your image and making it a squared image.
Image srcImage;
int widthSrc = 150;
int heightSrc = 180;
float resizeRate = 78 / min(widthSrc, heightSrc);
Image resizedImage = resizeImage($srcImage, resizeRate);
int widthDest = 78;
int heightDest = 78;
int cropX = ($widthSrc - $widthDest)/2;
int cropY = ($heightSrc - $heightDest)/2;
Image croppedImage = cropImage(resizedImage,$widthDest, $heightDest, $cropX, $cropY);
If the image is already square you can skip the crop part.

Need an algorithm to map co-ordinates of a point in images with different dimensions

I am stuck with a problem in my current project. I have 2 copies of same image say image1.tiff and image2.tiff but of different dimensions(Different pixel and DPIs). Suppose a point in image1.tiff lies at co-ordinates (x,y) ,I need to find the co-ordinates of the same point in image2.tiff. I have tried a lot to think of an algorithm. Requesting your help for this ..
You can use AffineTransformOp for this.
As an example:
BufferedImage img1 = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
BufferedImage img2 = new BufferedImage(400, 200, BufferedImage.TYPE_INT_ARGB);
double sx = img2.getWidth() / (double) img1.getWidth();
double sy = img2.getHeight() / (double) img1.getHeight();
AffineTransformOp xform =
new AffineTransformOp(AffineTransform.getScaleInstance(sx, sy), null);
Point srcPt = new Point(7, 49);
Point dstPoint = (Point) xform.getPoint2D(srcPt, new Point());
System.err.println("srcPt: " + srcPt);
System.err.println("dstPoint: " + dstPoint);
Will print:
srcPt: java.awt.Point[x=7,y=49]
dstPoint: java.awt.Point[x=14,y=98]
I would suggest the following approach:
double image1_to_image2 = image2.width()/image1.width();
double image2_to_image1 = image1.width()/image2.width();
If you have x1 and y1 as coordinates for the first image, you can calculate the corresponding location for the second image as follows:
int x2 = x1 * image1_to_image2;
int y2 = y1 * image1_to_image2;
If your images have a different aspect ratio, you will need to calculate scaling factors for the height separately.
The basic idea behind the approach is, that you map the coordinates of the images to the interval i_1 = [0;1] by dividing by the width (assuming the width is the larger dimension, but it does not matter if it is smaller than the height). By multiplying the scaled coordinate with the width of the second image, you map the coordinate back to the interval i_2 = [0; x_1 * width_2] which is at most the width of the second image.

Work out the maximum size of an image?

I am creating a little game in Java and I have an image which gets rotated.
As you can see in the two images below, there is a giant ship which slowly rotates in the game, but when it gets to a certain point it gets cut off (due to its own little BufferedImage).
Heres my rendering code:
public void drawImageRotated(BufferedImage img, double x, double y, double scale, double angle) {
x -= xScroll;
y -= yScroll;
BufferedImage image = new BufferedImage((int)(img.getWidth() * 1.5D), (int)(img.getHeight() * 1.5D), 2);
Graphics2D g = (Graphics2D)image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
g.drawImage(img, image.getWidth() / 2 - img.getWidth() / 2, image.getHeight() / 2 - image.getHeight() / 2, null);
g2d.drawImage(image, (int)(x-image.getWidth()*scale/2), (int)(y-image.getHeight()*scale/2), (int)(image.getWidth()*scale), (int)(image.getHeight()*scale), null);
g.dispose();
}
Back to the matter at hand, how can i work out the maximum x and y size of an image during rotation so I can compensate with my buffered images size?
If you have a basically rectangular image which is rotated around its center, the maximum width and height during rotation will be when a diagonal of the image rectangle is horizontal or vertical. This diagonal distance could be computed with the Pythagorean Theorem and used for the width and height of the BufferedImage.
int size = (int) Math.sqrt((img.getWidth() * img.getWidth()) + (img.getHeight() * img.getHeight()));
BufferedImage image = new BufferedImage(size, size, 2);
// The rest of your code as before
how can i work out the maximum x and y size of an image during rotation so I can compensate with my buffered images size?
double sin = Math.abs(Math.sin(angle));
double cos = Math.abs(Math.cos(angle));
int w = image.getWidth();
int h = image.getHeight();
int neww = (int)Math.floor(w*cos+h*sin);
int newh = (int)Math.floor(h*cos+w*sin);
The above code was taken from this example: Java(SWING) working with Rotation
An alternative is to rotate the actual Graphics object, draw the image, and restore the rotation:
AffineTransform old = g2d.getTransform();
g2d.rotate(Math.toRadians(angle), x + image.getWidth() / 2, y + image.getWidth() / 2);
g2d.drawImage(image, x, y, null);
g2d.setTransform(old);
Let's consider width being the width of the original image, height its original height and angle the rotation angle value in radians.
According to my calculations, the size of the rotated image is something like this:
rotatedWidth = Math.cos(angle) * width + Math.sin(angle) * height;
rotatedHeight = Math.sin(angle) * width + Math.cos(angle) * height;
You may also need to take a look at this thread as well, as it may help.

How to re-scale bitmap to different screen sizes but keep it square?

Hello great people of stackoverflow.com, I have a stumbled upon a great difficulty in my code; that being not being able to resize my images in-line with my screen size.
I have an image that is SAY 65 pixels by 65 pixels but I want this image to be a certain percentage of the screen say 6% while keeping square.
My brain cannot process the mathematics for this (because it is slow :-( )
(_width & _height is the screen width and height)
What I've got so far is:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int avg_screen_dimension = (_width + _height) / 2;
float scaleWidth =
((float) width + (avg_screen_dimension - _width)) / width;
float scaleHeight =
((float) height + (avg_screen_dimension - _height)) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// RECREATE THE NEW BITMAP
Bitmap resizedBitmap =
Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
return resizedBitmap;
Any help would be greatly appreciated!
It's little more than simple algebra - no complex math needed.
You'll have to choose between fraction of the width or height of your screen, unless they're equal.
Let h = screen height, w = screen width, f = fraction of screen dimension, x = image size.
Then x = h*f. If you want to make it a fraction of the width, substitute w for h.
(Just as an aside - in your pasted code, you've mixed up the variable names : you declare them as height and width but pass them as _width and _height

Categories