扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
在操作二维或三维的图形图像上,长期以来人们总结出了一些常用的变换矩阵,这些矩阵就像公式和定理一样被开发人员使用,楼主可以把这些矩阵当成公式来记忆,就像我们小时候背加法、乘法口诀一样。
城中网站建设公司创新互联建站,城中网站设计制作,有大型网站制作公司丰富经验。已为城中上千提供企业网站建设服务。企业网站搭建\成都外贸网站建设要多少钱,请找那个售后服务好的城中做网站的公司定做!
如果楼主想了解得更深入一些,请往下看:
[ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
[ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
[ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
上面的式子是jdk文档中复制过来的,就是变换时的运算过程,也就是说变换后的坐标x'、y'是由一个3*3的矩阵与原坐标x、y相乘得出的,其中的m00~m12就是AffineTransform构造方法中的六个参数,另外,式子中的最后一行是固定的。
矩阵乘法就不用说了吧,最后得出的结果就是上式中的最后一列,可能写成下面这样会更容易理解:
x' = m00x + m01y + m02
y' = m10x + m11y + m12
看出什么了吗?其实这就是二维平面直角坐标系中的两个很简单的二元一次方程而已,方程定义的就是横纵坐标变换的规则。
以水平翻转为例,水平翻转是以图形/图像的垂直中线为轴来翻转的,因此任何一个点(x,y)变换后的坐标应该是y坐标不变,x坐标变为-x+width-1,即(-x+width-1,y),之所以减1是因为垂直中轴上的点不应该改变。
理解了上面的变换过程之后,将结果带入上面的两个二元一次方程,可以得出
m00=-1、m01=0、m02=width-1
m10=0、m11=1、m12=0
正好是你给的代码中的六个值(AffineTransform构造方法中的参数顺序为m00、m10、m01、m11、m02、m12)
其他几个变换道理是一样的
程序实现思路: 在javafx中Node对象有一个effect属性,可以用于实现各种特效。PerspectiveTransform特效可以使Node对象实现透视变换。因此我们可以通过计算透视变换中每个点的位置来实现3D翻转特效。
实现步骤: 1、定义FlipView对象。包含以下属性:
复制代码 代码如下:
//正面视图
public Node frontNode;
//反面视图
public Node backNode;
//是否翻转
boolean flipped = false;
//翻转角度
DoubleProperty time = new SimpleDoubleProperty(Math.PI / 2);
//正面翻转特效
PerspectiveTransform frontEffect = new PerspectiveTransform();
//反面翻转特效
PerspectiveTransform backEffect = new PerspectiveTransform();
create方法返回需要显示的内容:
复制代码 代码如下:
private void create() {
time.addListener(new ChangeListener() {
@Override
public void changed(ObservableValue? extends Number arg0,
Number arg1, Number arg2) {
setPT(frontEffect, time.get());
setPT(backEffect, time.get());
}
});
anim.getKeyFrames().addAll(frame1, frame2);
backNode.visibleProperty().bind(
Bindings.when(time.lessThan(0)).then(true).otherwise(false));
frontNode.visibleProperty().bind(
Bindings.when(time.lessThan(0)).then(false).otherwise(true));
setPT(frontEffect, time.get());
setPT(backEffect, time.get());
frontNode.setEffect(frontEffect);
backNode.setEffect(backEffect);
getChildren().addAll(backNode, frontNode);
}
以上代码需要注意的是: 随着time值的变化frontEffect和backEffect的值也会随着变换。 2、PerspectiveTransform特效的实现使用了Math.sin()和Math.cos()方法模拟3D角度变换。 具体实现如下:
复制代码 代码如下:
private void setPT(PerspectiveTransform pt, double t) {
double width = 200;
double height = 200;
double radius = width / 2;
double back = height / 10;
pt.setUlx(radius - Math.sin(t) * radius);
pt.setUly(0 - Math.cos(t) * back);
pt.setUrx(radius + Math.sin(t) * radius);
pt.setUry(0 + Math.cos(t) * back);
pt.setLrx(radius + Math.sin(t) * radius);
pt.setLry(height - Math.cos(t) * back);
pt.setLlx(radius - Math.sin(t) * radius);
pt.setLly(height + Math.cos(t) * back);
}
3、角度变换在1秒的时间内从3.14/2变换到-3.14/2。
复制代码 代码如下:
KeyFrame frame1 = new KeyFrame(Duration.ZERO, new KeyValue(time,
Math.PI / 2, Interpolator.LINEAR));
KeyFrame frame2 = new KeyFrame(Duration.seconds(1),
new EventHandler() {
@Override
public void handle(ActionEvent event) {
flipped = !flipped;
}
}, new KeyValue(time, -Math.PI / 2, Interpolator.LINEAR));
4、FlipView对象的创建:通过构造函数可以很方便的创建FlipView对象.
复制代码 代码如下:
ImageView image1 = new ImageView(new Image(getClass()
.getResourceAsStream("lion1.png")));
ImageView image2 = new ImageView(new Image(getClass()
.getResourceAsStream("lion2.png")));
FlipView flip = new FlipView(image1, image2);
废话不多说直接上代码:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
public class ImageChange {
public static InputStream rotateImg(BufferedImage image, int degree, Color bgcolor) throws IOException {
int iw = image.getWidth();//原始图象的宽度
int ih = image.getHeight();//原始图象的高度
int w = 0;
int h = 0;
int x = 0;
int y = 0;
degree = degree % 360;
if (degree 0)
degree = 360 + degree;//将角度转换到0-360度之间
double ang = Math.toRadians(degree);//将角度转为弧度
/**
*确定旋转后的图象的高度和宽度
*/
if (degree == 180 || degree == 0 || degree == 360) {
w = iw;
h = ih;
} else if (degree == 90 || degree == 270) {
w = ih;
h = iw;
} else {
int d = iw + ih;
w = (int) (d * Math.abs(Math.cos(ang)));
h = (int) (d * Math.abs(Math.sin(ang)));
}
x = (w / 2) - (iw / 2);//确定原点坐标
y = (h / 2) - (ih / 2);
BufferedImage rotatedImage = new BufferedImage(w, h, image.getType());
Graphics2D gs = (Graphics2D)rotatedImage.getGraphics();
if(bgcolor==null){
rotatedImage = gs.getDeviceConfiguration().createCompatibleImage(w, h, Transparency.TRANSLUCENT);
}else{
gs.setColor(bgcolor);
gs.fillRect(0, 0, w, h);//以给定颜色绘制旋转后图片的背景
}
AffineTransform at = new AffineTransform();
at.rotate(ang, w / 2, h / 2);//旋转图象
at.translate(x, y);
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
op.filter(image, rotatedImage);
image = rotatedImage;
ByteArrayOutputStream byteOut= new ByteArrayOutputStream();
ImageOutputStream iamgeOut = ImageIO.createImageOutputStream(byteOut);
ImageIO.write(image, "png", iamgeOut);
InputStream inputStream = new ByteArrayInputStream(byteOut.toByteArray());
return inputStream;
}
}
重载渲染控件的paintComponent(Graphics
g)方法.
设你当前图像实例为img,已初始化,需要旋转的角度为ang
public
void
paintComponent(Graphics
g){
super.paintCompoent(g);
Graphics2D
g2d
=
(Graphics2D)g;
g2d.rotate(-angle);
g2d.drawImage(img,0,0,this.getWidth(),this.getHeight(),null);
}
Graphics,Graphics2D
类中有对当前描绘环境进行仿射变换的方法,包括translate,scale,rotate,也可以直接设置仿射变换矩阵,利用这点就可以根据所需要的实现方式来进行描绘.
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流