Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Image Cut Off

Same question as last time but I will provide more detail. I am currently rotating images using:

 int rotateNum //in main class

 double rotationRequired = Math.toRadians(rotateNum);

    double locationX = img.getWidth(this) / 2;
    double locationY = img.getHeight(this) / 2;
    AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
    AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);


    g2d.drawImage(op.filter((BufferedImage)img, null), imgX, imgY, null);

And then I am actually rotating the image using:

double deltaX = (double)(imgY - otherImg.imgY);
double deltaY = (double)(imgX - otherImg.imgX);
rotateNum = (int)(180 * Math.atan2(deltaY, deltaX) / Math.PI);

My images vary in size. The smaller images don't get cut off (meaning cut off with white space) but the larger ones do, on the left or right side. Resizing the images doesn't work, and I clipped out the white rectangle around the image using the GIMP.

Example Images: Before(ignore the grey area to the left)

After: See the cutoff at the side

like image 386
Jimmt Avatar asked Jan 04 '12 02:01

Jimmt


People also ask

How do you change the size of an image in Java?

You can resize an image in Java using the getScaledInstance() function, available in the Java Image class. We'll use the BufferedImage class that extends the basic Image class. It stores images as an array of pixels.

What is BufferedImage in Java?

A BufferedImage is comprised of a ColorModel and a Raster of image data. The number and types of bands in the SampleModel of the Raster must match the number and types required by the ColorModel to represent its color and alpha components. All BufferedImage objects have an upper left corner coordinate of (0, 0).

What function can be used to crop an image in Java?

To crop an image in Java, just use the Java BufferedImage class, specifically the getSubimage method of the BufferedImage class.


2 Answers

The problem is your source image is not exactly quadratic. When you implement the AffineTransform rotation with at.rotate(-rad, width/2, height/2);, it is the same as:

at.translate(width/2,height/2);
at.rotate(rads);
at.translate(-width/2,-height/2);

So, when it execute the last line, it translates to the origin. And if the width is greater than y (or vice versa), than the origin of the transform will be translated to a smaller distance than the side of greater length.

For example, if your width is 30 and your height is 60, than the origin point will be set as (-15,-30) from where the transform was original set. So, when you translate it, say, 90 degrees, the image will end up with "width" 60 and "height" 30, but according to the origin point, the image original bottom will be drawn at (-30,0), so it overflows the AffineTransform in -15 in X axis. Then this part of image will cut.

To correct this, you can use the following code instead:

double degreesToRotate = 90;
double locationX =bufferedImage.getWidth() / 2;
double locationY = bufferedImage.getHeight() / 2;

double diff = Math.abs(bufferedImage.getWidth() - bufferedImage.getHeight());

//To correct the set of origin point and the overflow
double rotationRequired = Math.toRadians(degreesToRotate);
double unitX = Math.abs(Math.cos(rotationRequired));
double unitY = Math.abs(Math.sin(rotationRequired));

double correctUx = unitX;
double correctUy = unitY;

//if the height is greater than the width, so you have to 'change' the axis to correct the overflow
if(bufferedImage.getWidth() < bufferedImage.getHeight()){
    correctUx = unitY;
    correctUy = unitX;
}

int posAffineTransformOpX = posX-(int)(locationX)-(int)(correctUx*diff);
int posAffineTransformOpY = posY-(int)(locationY)-(int)(correctUy*diff);

//translate the image center to same diff that dislocates the origin, to correct its point set
AffineTransform objTrans = new AffineTransform();
objTrans.translate(correctUx*diff, correctUy*diff);
objTrans.rotate(rotationRequired, locationX, locationY);

AffineTransformOp op = new AffineTransformOp(objTrans, AffineTransformOp.TYPE_BILINEAR);

// Drawing the rotated image at the required drawing locations
graphic2dObj.drawImage(op.filter(bufferedImage, null), posAffineTransformOpX, posAffineTransformOpY, null);

Hope it help.

like image 199
Lucas Borsatto Avatar answered Nov 04 '22 02:11

Lucas Borsatto


I imagine that it's not the size of the image that matters but rather its eccentricity: images that are more square-like have less of a problem then images that are either more fat or more thin.

I think that your problem is that your center of rotation shouldn't be [width / 2, height / 2] -- it's not that simple. Instead think of the image residing in the left upper portion of a large square the length of the square's side will be the image's width or height, whichever is larger. This is what gets rotated whenever you rotate your image.

For example, please see my reply here: https://stackoverflow.com/a/8720123/522444

like image 39
Hovercraft Full Of Eels Avatar answered Nov 04 '22 02:11

Hovercraft Full Of Eels