nick zoum - 8 months ago 38

Java Question

Is there any way to bend a

`BufferedImage`

I thought that if I crop the image into smaller pieces and rotate them then i would essentially bend the image but it doesn't seem to work.

Here is the method i created:

`/**`

* This is a recursive method that will accept an image the point where the bending will start and the point where the bending will end, as well as the angle of bending

*

* @param original:the original image

* @param startingPoint: the point where the bending should start

* @param endingPoint: the point where the bending should end

* @param radiands: the angle

* @return the bent image

*/

public static BufferedImage getBentImage(BufferedImage original, int startingPoint, int endingPoint, double radians) {

if (startingPoint >= endingPoint)

return original;

int type = BufferedImage.TYPE_INT_ARGB;

int width = original.getWidth();

int height = original.getHeight();

BufferedImage crop = original.getSubimage(0, 0, startingPoint, height);

BufferedImage crop0 = original.getSubimage(startingPoint, 0, width - startingPoint, height);

BufferedImage bendCrop = new BufferedImage(width, height, type);

BufferedImage image = new BufferedImage(width, height, type);

AffineTransform rotation = new AffineTransform();

rotation.translate(0, 0);

rotation.rotate(radians);

Graphics2D g = bendCrop.createGraphics();

g.drawImage(crop0, rotation, null);

g.dispose();

g = image.createGraphics();

g.drawImage(crop, 0, 0, null);

g.drawImage(bendCrop, startingPoint, 0, null);

g.dispose();

return getBentImage(image, startingPoint + 1, endingPoint, radians);

}

This is the original Image:

And this is the result of this

`getBentImage(image, 200, 220, Math.toRadians(1))`

I was expecting something closer to:

Any ideas on how to actually implement a

`getBentImage()`

Answer

As suggested in the comments, a simple approach is to divide the image into 3 parts:

- Identical to the original.
- Bent according to the bending transformation.
- Constant diagonal continuation.

Here is a quick and a bit messy example that shows the original shape and the resulting shape below it. I just used a label icon for the images instead of doing custom painting. (Also I didn't adhere to the Java naming conventions with `final`

variables because it's math and not typical coding.)

Since there are quite a few variables in the calculation code, I added a sketch at the end that shows what the variables represent.

```
public class Main extends JFrame {
static BufferedImage image;
public static void main(String[] args) {
try {
image = ImageIO.read(ClassLoader.getSystemResource("img.png"));
} catch (IOException e) {
e.printStackTrace();
}
new Main();
}
public Main() {
getContentPane().setLayout(new BorderLayout(5, 10));
BufferedImage img2 = transform(15, 100, 300);
JLabel label1 = new JLabel(new ImageIcon(image));
label1.setHorizontalAlignment(JLabel.LEFT);
label1.setOpaque(true);
label1.setBackground(Color.YELLOW);
add(label1, BorderLayout.NORTH);
JLabel label2 = new JLabel(new ImageIcon(img2));
label2.setHorizontalAlignment(JLabel.LEFT);
label2.setOpaque(true);
label2.setBackground(Color.CYAN);
add(label2);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
static BufferedImage transform(int t, int x1, int x2) {
final double TH = Math.toRadians(t);
final int D = x2 - x1;
final int W = image.getWidth();
final int H = image.getHeight();
final int dD = (int) (D / (2 * TH) * Math.sin(2 * TH));
final int dH = (int) (D / TH * Math.pow(Math.sin(TH), 2));
final int pH = (int) ((W - x2) * Math.tan(2 * TH));
final int width = W - (D - dD);
final int height = (int) (H + dH + pH);
System.out.println(W + " " + H + " -> " + width + " " + height);
BufferedImage img2 = new BufferedImage(width, height, image.getType());
for (int x = 0; x < x1; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
img2.setRGB(x, y, rgb);
}
}
for (int x = x1; x < x2; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
int dx = (int) (D / (2 * TH) * Math.sin(2 * (x-x1) * TH / D));
int dy = (int) (D / TH * Math.pow(Math.sin((x-x1) * TH / D), 2));
img2.setRGB(x1 + dx, y + dy, rgb);
}
}
for (int x = x2; x < W; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
int dp = (int) ((x - x2) * Math.tan(2 * TH));
img2.setRGB(x - (D - dD), y + dH + dp, rgb);
}
}
return img2;
}
}
```

As for the calculations, I'll leave it for you as homework; it's just geometry/trigonometry which belongs on Math.SE more than on SO. If you can't figure it out I'll give you a direction.

Note that this method might not be fast at all and could certainly be optimized, I'll leave that to you also.