1、JavaFX实现水波效果JavaFX实现水波效果public class JfxRipper extends Application private final double MAX_WIDTH = 400.0; private final double MAX_HEIGHT = 400.0; private static AnimationTimer timer; private static AnimationTimer rainTimer; private FileChooser fc; private double scaleRate; private int maxRainSize,
2、 maxRainPower, stoneSize, stonePower; private int imgWidth, imgHeight; int arrWaveCurrent;/ 当前帧各点波动能量数据 int arrWaveNext;/ 下一帧各点波动能量数据 private Image img; private WritableImage imgRipper; private ImageView imgView; Override public void init() throws Exception fc = new FileChooser(); /添加文件类型过滤 fc.getEx
3、tensionFilters().add( new FileChooser.ExtensionFilter(图片文件, *.jpg;*.png;*.jpeg;*.bmp); img = new Image(getClass().getClassLoader().getResourceAsStream(images/红花.jpg); imgWidth = (int) img.getWidth(); imgHeight = (int) img.getHeight(); /波纹效果计算需要遍历图片每个像素,图片尺寸过大会导致运行速度极慢,故按比例缩小 if (imgWidth MAX_WIDTH |
4、 imgHeight MAX_HEIGHT) double sx = MAX_WIDTH / imgWidth; double sy = MAX_HEIGHT / imgHeight; scaleRate = sx sy ? sy : sx; img = scaleImg(img, imgWidth, imgHeight, scaleRate); imgWidth = (int) (scaleRate * (double) imgWidth); imgHeight = (int) (scaleRate * (double) imgHeight); maxRainSize = 4; maxRai
5、nPower = 60; stoneSize = 5; stonePower = 128; else /雨点和石子大小根据图片尺寸的大小稍作调整 maxRainSize = 3; maxRainPower = 50; stoneSize = 4; stonePower = 108; imgRipper = new WritableImage(imgWidth, imgHeight); arrWaveCurrent = new intimgWidth * imgHeight; arrWaveNext = new intimgWidth * imgHeight; imgView = new Ima
6、geView(); imgView.setOnMousePressed(new EventHandler() Override public void handle(Event event) MouseEvent e = (MouseEvent) event; dropStone(int) e.getX(), (int) e.getY(), stoneSize, stonePower); ); timer = new AnimationTimer() Override public void handle(long now) genRipper(); imgView.setImage(imgR
7、ipper); ; rainTimer = new AnimationTimer() Override public void handle(long now) rain(); imgView.setImage(imgRipper); ; /* * 模拟下雨,随机抛出不同大小和位置的石子 */ protected void rain() int x = (int) (Math.random() * imgWidth); int y = (int) (Math.random() * imgHeight); int rainSize = (int) (Math.random() * maxRain
8、Size); int power = (int) (Math.random() * maxRainPower) + maxRainPower; dropStone(x, y, rainSize, power); Override public void start(Stage primaryStage) throws Exception Group root = new Group(); VBox vb = new VBox(10); root.getChildren().add(vb); imgView.setImage(img); Scene scene = new Scene(root)
9、; primaryStage.setScene(scene); HBox hb = new HBox(10); Button rainControl = new Button(停止下雨); rainControl.setOnAction(ActionEvent event) - if (开始下雨.equals(rainControl.getText() rainTimer.start(); rainControl.setText(停止下雨); else rainTimer.stop(); rainControl.setText(开始下雨); ); Button changePic = new
10、Button(更换图片); changePic.setOnAction(ActionEvent event) - File f = fc.showOpenDialog(primaryStage); if (null != f) /将默认目录设置为上次访问过的目录 fc.setInitialDirectory(f.getParentFile(); /Image imgTmp = null; try img = new Image(new FileInputStream(f); /Desktop.getDesktop().open(f); catch (Exception e) e.printSt
11、ackTrace(); if (img != null) imgWidth = (int) img.getWidth(); imgHeight = (int) img.getHeight(); if (imgWidth MAX_WIDTH | imgHeight MAX_HEIGHT) double sx = MAX_WIDTH / imgWidth; double sy = MAX_HEIGHT / imgHeight; scaleRate = sx sy ? sy : sx; img = scaleImg(img, imgWidth, imgHeight, scaleRate); imgW
12、idth = (int) (scaleRate * (double) imgWidth); imgHeight = (int) (scaleRate * (double) imgHeight); maxRainSize = 4; maxRainPower = 60; stoneSize = 5; stonePower = 128; else maxRainSize = 3; maxRainPower = 50; stoneSize = 4; stonePower = 108; imgRipper = new WritableImage(imgWidth, imgHeight); arrWave
13、Current = new intimgWidth * imgHeight; arrWaveNext = new intimgWidth * imgHeight; imgView.setFitHeight(imgHeight); imgView.setFitWidth(imgWidth); primaryStage.setWidth(imgWidth); imgView.setImage(img); primaryStage.setHeight(imgHeight + 40); ); Button exit = new Button(退出); exit.setOnAction(ActionEv
14、ent event) - primaryStage.close(); ); hb.getChildren().addAll(rainControl, changePic, exit); vb.getChildren().addAll(imgView, hb); primaryStage.setWidth(imgWidth); hb.setAlignment(Pos.CENTER); scene.setFill(Color.BLUEVIOLET); primaryStage.initStyle(StageStyle.TRANSPARENT); timer.start(); rainTimer.s
15、tart(); primaryStage.show(); /* * 水波算法,原作者Imagic */ public void genRipper() PixelReader readImg = img.getPixelReader(); PixelWriter writeRipper = imgRipper.getPixelWriter(); int index = imgWidth; int indexPreX = index - 1; int indexNextX = index + 1; int indexPreY = index - imgWidth; int indexNextY
16、= index + imgWidth; for (int y = 1; y imgHeight - 1; y+) for (int x = 1; x 1) - arrWaveNextindex; / 波能衰减 1/32 arrWaveNextindex -= arrWaveNextindex 5; / 计算出偏移象素和原始象素的内存地址偏移量 : int xoffset = x2 - x1; int yoffset = x4 - x3; int offset = imgWidth * yoffset + xoffset; int posY = index / imgWidth; int pos
17、X = index - posY * imgWidth; int newY = (index + offset) / imgWidth; int newX = (index + offset) - newY * imgWidth; / 判断坐标是否在窗口范围内 if (index + offset 0 & index + offset imgWidth * imgHeight) writeRipper.setColor(posX, posY, readImg.getColor(newX, newY); else writeRipper.setColor(posX, posY, readImg.
18、getColor(posX, posY); / 交换波能数据缓冲区 int temp = arrWaveCurrent; arrWaveCurrent = arrWaveNext; arrWaveNext = temp; /* * 模拟向水中投石子 * * param x:石子位置X坐标 * param y:石子位置y坐标 * param stoneSize:石子半径 * param power:波能大小 */ private void dropStone(int x, int y, int stoneSize, int power) int minPosX = x - stoneSize,
19、maxPosX = x + stoneSize; int minPosY = y - stoneSize, maxPosY = y + stoneSize; minPosX = minPosX 0 ? 0 : minPosX; minPosY = minPosY imgWidth ? imgWidth : maxPosX; maxPosY = maxPosY imgHeight ? imgHeight : maxPosY; int value = stoneSize * stoneSize; for (int posx = minPosX; posx maxPosX; posx+) for (
20、int posy = minPosY; posy maxPosY; posy+) if (posx - x) * (posx - x) + (posy - y) * (posy - y) value) arrWaveCurrentposy * imgWidth + posx = -power; /* * 按比例缩小图片 * 缩小图片算法:x0 = x / sx, y0 = y / sy。x0,y0分别为原图水平和垂直索引, * sx,sy分别为水平和垂直缩小比例 * param src:原始图片 * param imgW:原始图片宽度 * param imgH:原始图片长度 * param r
21、ate:缩小后的图片不原图片尺寸的比例 * return 缩小后的图片 */ private Image scaleImg(Image src, int imgW, int imgH, double rate) int width = (int) (double) imgW * rate); int height = (int) (double) imgH * rate); WritableImage imgScaled = new WritableImage(width, height); PixelReader readSrc = src.getPixelReader(); PixelWr
22、iter writeDest = imgScaled.getPixelWriter(); for (int x = 0; x width; x+) for (int y = 0; y height; y+) writeDest.setColor(x, y, readSrc.getColor(int) (x / rate), (int) (y / rate); return imgScaled; public static void main(String args) launch(args); 里面用到了行序优先一维数组存储二维数组时两个数组索引之间的算术关系公式。设一维数组索引为index,二维数组行索引为x,列索引为y,均从0开始,每行存储元素个数为width,则: y = int(index / width),int为取整函数,如int(1.1)和int(1.9)都等于1 x= index - y * width index = width * y + x 截图:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1