I've tried using affine transform to scale down a BufferedImage, But I only manage to scale up the image and not make it smaller like I need to.
Here's my scale up code.
public BufferedImage Scale(){
BufferedImage after = new BufferedImage(before.getWidth(), before.getHeight(), BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(-2.0, -2.0);
AffineTransformOp scale = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
after = scale.filter(before, after);
return after;
}
To scale down, use a scale in the range (0.0, 1.0), instead of negatives.
When you apply a scaling Affine Transform with scale (xScale, yScale), the new dimensions are (imgWidth*xScale, imgHeight*yScale).
If you draw this onto a graphics context, you can specify a new width and height in the drawImage call.
Related
This question already has an answer here:
Rotate BufferedImage with transparent background
(1 answer)
Closed 2 years ago.
I want to rotate a BufferedImage by an angle in radians. I used the following code. matrixImage is a matrix of integers where foreground pixels have 1 as value while background pixels have 0 as value. The new BufferedImage is correctly rotated but the extra borders are black. The new image is bigger than the original one and the new parts are black. I want that all the background pixels of the new image are white. I tried the solution proposed at Rotate BufferedImage and remove black bound, but I noticed that during the rotation the image changes.
bufferedImage = matrix2BufferedImage(matrixImage);
AffineTransform transform = new AffineTransform();
transform.rotate(radians, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
bufferedImage = op.filter(bufferedImage, null);
I solved using the following code for rotating
private BufferedImage rotateImage(BufferedImage sourceImage, double angle) {
AffineTransform transform = new AffineTransform();
transform.rotate(angle, sourceImage.getWidth() / 2, sourceImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage destImage = op.filter(sourceImage, null);
Graphics2D g2d = destImage.createGraphics();
g2d.drawRenderedImage(sourceImage, transform);
g2d.dispose();
return destImage;
}
Then, I binarised the buffered image with the following code
int value=binarized.getRGB(x,y);
if(value==0)
value=-1;
output[y][x] = ((0xFFFFFF & value) == 0xFFFFFF) ? (byte) 0 : 1;
Thanks for suggesting me the right post!
I am currently trying to get some kind of 2D dungeoncrawler (think: roguelike) running. Now I want to work with square tiles (32x32) but I wonder if there's a way to make my textures in a higher resolution, say 64x64, and scale them down onto a 32x32 square?
I imagine there has to be since almost all games do this in one way or another but all I can seem to find online is about 3D stuff.
Yeah. When you draw an image, you can add the new width and height to it to resize it.
public static BufferedImage resizeImage(BufferedImage image, int newwidth, int newheight) {
BufferedImage image2 = new BufferedImage(newwidth, newheight, BufferedImage.TYPE_INT_ARGB);
Graphics g = image2.getGraphics();
g.drawImage(image, 0, 0, newwidth, newheight, null);
g.dispose();
return image2;
}
Refer to here for more info.
I have been trying to no avail. I want a 128x128 image be rotated using AffineTransform but whenever I rotate it to a specific degree, I get a 130x133 or 131x129 image. I want to preserve its 128x128. How do I do this in Java using AffineTransform? Or can this be done in any other methods? Thank you!
public BufferedImage generate() {
AffineTransform tx = new AffineTransform();
tx.rotate(Math.toRadians(0.1));
AffineTransformOp operation = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC);
BufferedImage t = operation.createCompatibleDestImage(img, img.getColorModel());
return operation.filter(img, t);
}
You can use the CropImageFilter (http://docs.oracle.com/javase/7/docs/api/java/awt/image/CropImageFilter.html) to crop your image after rotation.
I am aware of sub-pixel shapes, such as Rectangle2D.Double, Ellipse2D.Double and Line2D.Double - but I couldn't find information about drawing an Image / BufferedImage with sub-pixel accuracy.
Perhaps something that would look like this - Image2D.Double?
Is there any way I can achieve this?
Images may be drawn with an AffineTransform, which can specify scaling and translation with floating point values.
(See drawImage(Image, AffineTransform, ImageObserver) method)
For example, to draw an image scaled to half size and at position (10.5, 10.5), use:
Graphics2D g = ...
BufferedImage myImage = ...
AffineTransform t = new AffineTransform();
t.translate(10.5, 10.5);
t.scale(0.5, 0.5);
g.drawImage(myImage, t, null);
You should ensure that appropriate RenderingHints have been set on the Graphics2D object (set KEY_ANTIALIASING to VALUE_ANTIALIAS_ON for starters).
I am trying to use JAI to perform a rotate task on an image. I can get this working no problem. However, there is severe loss of midtones in the image. The image can be rotated in photoshop without this lack of contrast.
Please see the following 3 images stacked next to each other here, to see what I mean;
http://imgur.com/SYPhZ.jpg
The top image is the original, the middle is rotated in photoshop to prove that it can be done, and the bottom is from the result of my code.
To see the actual images, please see here;
Before rotate: http://imgur.com/eiAOO.jpg
After rotate : http://imgur.com/TTUKS.jpg
You can see the issue most clearly if you load the images in two different tabs, and flick between them.
In terms of code, I load the image as follows;
public void testIt() throws Exception {
File source = new File("c:\\STRIP.jpg");
FileInputStream fis = new FileInputStream(source);
BufferedImage sourceImage = ImageIO.read(fis);
fis.close();
BufferedImage rotatedImage = doRotate(sourceImage, 15);
FileOutputStream output = new FileOutputStream("c:\\STRIP_ROTATED.jpg");
ImageIO.write(rotatedImage, "JPEG", output);
}
and then here is the rotate function;
public BufferedImage doRotate(BufferedImage input, int angle) {
int width = input.getWidth();
int height = input.getHeight();
double radians = Math.toRadians(angle / 10.0);
// Rotate about the input image's centre
AffineTransform rotate = AffineTransform.getRotateInstance(radians, width / 2.0, height / 2.0);
Shape rect = new Rectangle(width, height);
// Work out how big the rotated image would be..
Rectangle bounds = rotate.createTransformedShape(rect).getBounds();
// Shift the rotated image into the centre of the new bounds
rotate.preConcatenate(
AffineTransform.getTranslateInstance((bounds.width - width) / 2.0, (bounds.height - height) / 2.0));
BufferedImage output = new BufferedImage(bounds.width, bounds.height, input.getType());
Graphics2D g2d = (Graphics2D) output.getGraphics();
// Fill the background with white
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(width, height));
RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(hints);
g2d.drawImage(input, rotate, null);
return output;
}
This is apparently a bug in JAI that has existed for a while:
The earliest mention that I was able to find of this issue appears here. That original article points to an old jai-core issue here. Having read that resolution, it appears that there is a root bug that is still open and described here.
Whether or not all of that detective work is relevant to your application, it may be possible to construct a color space that is more tolerant than the default that JAI is using for your test code.
In the absolute worst case, you could write the pixel traversal yourself to create a rotated image. That isn't the optimal solution but I mention it for completeness if you absolutely need a solution to this problem today.