Graphics2D
类中的 rotate()
和 shear()
方法,它们能让你轻松实现图片的旋转和变形效果
一、旋转方法:rotate()
基本用法
rotate()
方法用于旋转图形或图像。它有两种主要形式:
// 形式1:围绕原点(0,0)旋转
void rotate(double theta)
// 形式2:围绕指定点(x,y)旋转
void rotate(double theta, double x, double y)
参数说明
theta
:旋转角度(弧度值)。注意,Java 中角度通常用弧度表示,而非度数。- 要将度数转为弧度:
Math.toRadians(角度)
- 例如:90 度 =
Math.toRadians(90)
≈ 1.57 弧度
- 要将度数转为弧度:
x, y
:旋转中心点的坐标。如果不指定,默认围绕原点 (0,0) 旋转。-
// 围绕原点旋转45度 g2.rotate(Math.toRadians(45)); g2.drawImage(img, 0, 0, this); // 围绕图片中心旋转90度 int centerX = img.getWidth(this) / 2; int centerY = img.getHeight(this) / 2; g2.rotate(Math.toRadians(90), centerX, centerY); g2.drawImage(img, 0, 0, this);
二、变形(剪切)方法:
shear()
基本用法
shear()
方法用于实现图形或图像的剪切变形,就像把图像 "斜着拉" 一样。 -
void shear(double shx, double shy)
参数说明
shx
:水平方向的剪切因子- 正值:向右倾斜(类似平行四边形向右倒)
- 负值:向左倾斜(类似平行四边形向左倒)
shy
:垂直方向的剪切因子- 正值:向下倾斜(类似平行四边形向下倒)
- 负值:向上倾斜(类似平行四边形向上倒)
-
// 水平方向剪切(向右倾斜) g2.shear(0.5, 0); g2.drawImage(img, 0, 0, this); // 垂直方向剪切(向下倾斜) g2.shear(0, 0.3); g2.drawImage(img, 0, 0, this); // 同时水平和垂直剪切 g2.shear(0.2, 0.2); g2.drawImage(img, 0, 0, this);
三、使用技巧
1. 角度与弧度的转换
Java 中三角函数使用弧度,而我们习惯用度数:
- 度数转弧度:
Math.toRadians(度数)
- 弧度转度数:
Math.toDegrees(弧度)
-
变换是累积的,多次调用会叠加效果:
2. 多次变换的叠加效果
-
// 先旋转45度,再水平剪切 g2.rotate(Math.toRadians(45)); g2.shear(0.3, 0); g2.drawImage(img, 0, 0, this);
3. 重置变换
如果需要清除之前的变换,可以创建新的
Graphics2D
对象或使用setTransform()
方法。 -
// 保存当前变换状态 AffineTransform oldTransform = g2.getTransform(); // 旋转并绘制第一张图片 g2.rotate(Math.toRadians(45), centerX, centerY); g2.drawImage(img1, 50, 50, this); // 恢复变换状态("把玻璃转回原样") g2.setTransform(oldTransform); // 现在绘制第二张图片,它不会旋转 g2.drawImage(img2, 200, 50, this);
-
import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import javax.swing.*; public class TransformDemo extends JPanel { private Image image; public TransformDemo() { // 加载图片 image = new ImageIcon("your-image-path.jpg").getImage(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; // 1. 原始图片 g2.drawImage(image, 50, 50, 100, 100, this); // 2. 旋转45度 g2.rotate(Math.toRadians(45), 200, 100); g2.drawImage(image, 150, 50, 100, 100, this); g2.rotate(-Math.toRadians(45), 200, 100); // 恢复旋转 // 3. 水平剪切 g2.shear(0.3, 0); g2.drawImage(image, 300, 50, 100, 100, this); g2.shear(-0.3, 0); // 恢复剪切 // 4. 垂直剪切 g2.shear(0, 0.3); g2.drawImage(image, 50, 200, 100, 100, this); g2.shear(0, -0.3); // 恢复剪切 // 5. 组合变换:先旋转再剪切 g2.rotate(Math.toRadians(30), 200, 250); g2.shear(0.2, 0.2); g2.drawImage(image, 150, 200, 100, 100, this); g2.shear(-0.2, -0.2); // 先恢复剪切 g2.rotate(-Math.toRadians(30), 200, 250); // 再恢复旋转 } public static void main(String[] args) { JFrame frame = new JFrame("图形变换演示"); frame.add(new TransformDemo()); frame.setSize(500, 400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
****************************************************************************************************
-
旋转和变形的操作实际上是应用在整个 "画布" 上的,而不是单独的图片。
-
一、形象理解
想象你在一块透明的玻璃上画画:
- 画布 = 玻璃
- 图片 = 玻璃上画的图案
-
当你调用
g2.rotate()
或g2.shear()
时,相当于: - 旋转画布:你把整个玻璃旋转了一个角度
- 变形画布:你把玻璃扭曲成了平行四边形
-
这时,玻璃上的所有图案(图片)都会跟着一起旋转或变形!
-
二、为什么这很重要?
1. 旋转中心点的影响
- 如果围绕原点 (0,0) 旋转,图片会围绕窗口左上角旋转
- 如果指定中心点,图片会围绕该点旋转
// 围绕原点旋转(图片会"飞出"窗口) g2.rotate(Math.toRadians(45)); g2.drawImage(img, 50, 50, this); // 围绕图片中心旋转(效果更直观) int centerX = 50 + img.getWidth(this)/2; int centerY = 50 + img.getHeight(this)/2; g2.rotate(Math.toRadians(45), centerX, centerY); g2.drawImage(img, 50, 50, this);
2. 变换的累积效果
- 每次调用变换方法,都会影响后续所有的绘图操作
- 就像你把玻璃转了一下后,再画的任何东西都会是倾斜的
-
// 先旋转画布 g2.rotate(Math.toRadians(30)); // 第一张图片会旋转 g2.drawImage(img1, 50, 50, this); // 第二张图片也会旋转(即使没写rotate代码) g2.drawImage(img2, 200, 50, this);
三、如何控制变换范围?
如果你只想让特定图片旋转,而不影响其他图片,可以:
1. 临时保存和恢复变换状态
// 保存当前变换状态 AffineTransform oldTransform = g2.getTransform(); // 旋转并绘制第一张图片 g2.rotate(Math.toRadians(45), centerX, centerY); g2.drawImage(img1, 50, 50, this); // 恢复变换状态("把玻璃转回原样") g2.setTransform(oldTransform); // 现在绘制第二张图片,它不会旋转 g2.drawImage(img2, 200, 50, this);
2. 只在特定范围内应用变换
-
// 绘制不变换的图片 g2.drawImage(img1, 50, 50, this); // 创建新的Graphics2D对象(相当于拿一块新玻璃) Graphics2D g2Copy = (Graphics2D) g2.create(); // 只在这个副本上应用变换 g2Copy.rotate(Math.toRadians(45), centerX, centerY); g2Copy.drawImage(img2, 200, 50, this); // 释放副本("扔掉用过的玻璃") g2Copy.dispose(); // 原始的g2不受影响,继续绘制其他内容 g2.drawImage(img3, 350, 50, this);
import java.awt.*; import java.awt.image.BufferedImage; import javax.swing.*; public class TransformExplanation extends JPanel { private BufferedImage image; public TransformExplanation() { // 创建一个简单的测试图片 image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); Graphics2D g = image.createGraphics(); g.setColor(Color.RED); g.fillRect(0, 0, 100, 100); g.setColor(Color.WHITE); g.drawString("A", 45, 60); g.dispose(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; // 1. 绘制原始图片(没有变换) g2.drawImage(image, 50, 50, this); g2.drawString("原始图片", 50, 160); // 2. 旋转画布后绘制图片 g2.rotate(Math.toRadians(45), 200, 100); g2.drawImage(image, 150, 50, this); g2.rotate(-Math.toRadians(45), 200, 100); // 恢复旋转 g2.drawString("旋转后的图片", 150, 160); // 3. 变形画布后绘制图片 g2.shear(0.3, 0); g2.drawImage(image, 250, 50, this); g2.shear(-0.3, 0); // 恢复变形 g2.drawString("变形后的图片", 250, 160); // 4. 旋转后绘制多条线(展示整个画布被旋转) g2.rotate(Math.toRadians(30), 100, 250); g2.setColor(Color.BLUE); g2.drawLine(50, 200, 150, 200); g2.drawLine(50, 220, 150, 220); g2.drawLine(50, 240, 150, 240); g2.rotate(-Math.toRadians(30), 100, 250); // 恢复旋转 g2.drawString("旋转后的画布", 50, 300); } public static void main(String[] args) { JFrame frame = new JFrame("变换原理演示"); frame.add(new TransformExplanation()); frame.setSize(500, 400); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
总结
- 变换操作应用于画布,而不是单独的图片
- 一旦应用变换,后续所有绘图操作都会受影响
- 可以通过保存 / 恢复变换状态或创建副本来控制变换范围
- 旋转中心点的选择对效果有很大影响