import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.effect.DropShadow; import javafx.scene.image.PixelFormat; import javafx.scene.image.PixelWriter; import javafx.scene.paint.Color; import javafx.stage.Stage; import java.nio.ByteBuffer; import static javafx.application.Application.launch; /** * @author zhaoyong * @Date 2022/1/6 * @Description */ public class ImageOps extends Application { // 图像数据 private static final int IMAGE_WIDTH = 10;//设置图像的宽度 private static final int IMAGE_HEIGHT = 10;//设置图像的长度 private byte imageData[] = new byte[IMAGE_WIDTH * IMAGE_HEIGHT * 3];//创建一个字节型数组 // 绘制表面 (Canvas) private GraphicsContext gc;//创建一个画笔 private Canvas canvas;//创建一个画布 private Group root;//创建一个节点组容器 public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("PixelWriter测试"); root = new Group();//初始化节点组容器对象 canvas = new Canvas(500, 200);//创建衣蛾200*200的宽高画布对象 canvas.setTranslateX(100);//设置画布对象转变位移X canvas.setTranslateY(100);//设置画布对象转变位移Y gc = canvas.getGraphicsContext2D();//创建画布上对应的画笔对象 createImageData(); drawImageData(); primaryStage.setScene(new Scene(root, 400, 400)); primaryStage.show(); } private void createImageData() {//创建一个图片图形 int i = 0; for (int y = 0; y < IMAGE_HEIGHT; y++) { int r = y * 255 / IMAGE_HEIGHT; for (int x = 0; x < IMAGE_WIDTH; x++) { int g = x * 255 / IMAGE_WIDTH; imageData[i] = (byte) r; imageData[i + 1] = (byte) g; i += 3; } } } private void drawImageData() { boolean on = true; PixelWriter pixelWriter = gc.getPixelWriter();//创建一个像素写入器 PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance();//创建一个像素格式 for (int y = 50; y < 150; y += IMAGE_HEIGHT) { for (int x = 50; x < 150; x += IMAGE_WIDTH) { if (on) { pixelWriter.setPixels(x, y, IMAGE_WIDTH, IMAGE_HEIGHT, pixelFormat, imageData, 0, IMAGE_WIDTH * 3); } on = !on; } on = !on; } // 增加阴影效果 gc.applyEffect(new DropShadow(20, 20, 20, Color.GRAY)); root.getChildren().add(canvas);//节点容器组添加画布 } }
这个Demo没有从已有的图片中读取数据,它完全从零开始创建了一个新的WritableImage对象。它绘制了几行带有多种颜色的10*10的矩形,对应的颜色数据被存储在一个像素数组中,表示每个像素的RGB值
两个私有方法createImageData和drawImageData,createImageData方法设置了在每个10*10的矩形中的颜色的RGB值
________________________________________
创建一个快照
javafx.scene.Scene类还提供了一个snapshot方法,它返回一个WritableImage,其中包含了当前展示在你的应用程序场景中内容。当与Java中的ImageIO类配合使用时,你可以将快照存储到文件系统中
import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import javafx.application.Application; import javafx.embed.swing.SwingFXUtils; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.effect.DropShadow; import javafx.scene.image.PixelFormat; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.paint.Color; import javafx.stage.Stage; import javax.imageio.ImageIO; public class ImageTest extends Application { // 图像数据 private static final int IMAGE_WIDTH = 10;//图片宽度 private static final int IMAGE_HEIGHT = 10;//图片高度 private byte imageData[] = new byte[IMAGE_WIDTH * IMAGE_HEIGHT * 3];//创建图形数据字节数组 // 绘制表面 (Canvas) private GraphicsContext gc;//创建画笔 private Canvas canvas;//创建画布 private Group root;//创建节点组容器对象 public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("PixelWriter Test");//设置舞台标题 root = new Group();//初始化节点组对象 canvas = new Canvas(200, 200);//初始化创建画布 canvas.setTranslateX(100);//设置画布位移X canvas.setTranslateY(100);//设置画布位移Y gc = canvas.getGraphicsContext2D();//获取画布上的画笔对象 createImageData();//创建图形数据 drawImageData();//绘画图形 Scene scene = new Scene(root, 400, 400);//创建场景 primaryStage.setScene(scene);//舞台设置场景 primaryStage.show();//舞台展现 // 截取场景的快照 WritableImage writableImage = scene.snapshot(null);//获取场景图像的快照图片 // 将快照作为png图像写入到文件系统中 File outFile = new File("imageops-snapshot.png");//相对程序所在的当前目录创建一个文件对象 try {//将快照写入文件系统存为.png图片 ImageIO.write(SwingFXUtils.fromFXImage(writableImage, null), "png", outFile);//利用图片文件输出流工具将文件写出去并保存到指定目录下 } catch (IOException ex) { System.out.println(ex.getMessage()); } } private void createImageData() { int i = 0; for (int y = 0; y < IMAGE_HEIGHT; y++) { System.out.println("y: " + y); int r = y * 255 / IMAGE_HEIGHT; for (int x = 0; x < IMAGE_WIDTH; x++) { System.out.println("\tx: " + x); int g = x * 255 / IMAGE_WIDTH; imageData[i] = (byte) r; imageData[i + 1] = (byte) g; System.out.println("\t\tR: " + (byte) r); System.out.println("\t\tG: " + (byte) g); i += 3; } } System.out.println("imageData.lengthdrawImageData: " + imageData.length); } private void drawImageData() { boolean on = true; PixelWriter pixelWriter = gc.getPixelWriter(); PixelFormat<ByteBuffer> pixelFormat = PixelFormat.getByteRgbInstance(); for (int y = 50; y < 150; y += IMAGE_HEIGHT) { for (int x = 50; x < 150; x += IMAGE_WIDTH) { if (on) { pixelWriter.setPixels(x, y, IMAGE_WIDTH, IMAGE_HEIGHT, pixelFormat, imageData, 0, IMAGE_WIDTH * 3); } on = !on; } on = !on; } // 增加阴影效果 gc.applyEffect(new DropShadow(20, 20, 20, Color.GRAY));//设置阴影特效 root.getChildren().add(canvas);//节点组上添加画布对象 } }
说明:
调用scene.snapshot(null)创建了一个场景对象的新的快照并将其分配给了新构建的WritableImage。然后(在ImageIO和SwingFXUtils的帮助下)这个图片被写入文件系统并保存为了一个.png图片