前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter 像素编辑器#04 | 导入导出图像

Flutter 像素编辑器#04 | 导入导出图像

作者头像
张风捷特烈
发布2024-05-29 12:11:54
1080
发布2024-05-29 12:11:54
举报
文章被收录于专栏:Android知识点总结
1. 本文目的

本系列,将通过 Flutter 实现一个全平台的像素编辑器应用。源码见开源项目 【pix_editor】。在前三篇中,我们已经完成了一个简易的图像编辑器,并且简单引入了图层的概念,支持切换图层显示不同的像素画面。

本文的目标两个:

1. 支持导入一张图像,将其像素化地展示在界面中:

01.gif
01.gif

2. 像素点可编辑,编辑完成后,可以将图片进行导出到对应文件夹:

02.gif
02.gif
image.png
image.png

2. 图像的导入

图像本质上是由一个个像素点构成的二维空间点阵。在像素编辑器中,每个单元格记录着一份像素信息,我们需要根据网格行列数,对图像的像素信息进行采样。行列数会直接决定当前区域中像素信息相对于原图像的的完整程度。比如下面分别是 16*1632*3264*64 的网格采样同一图像的呈现效果:

16*16

32*32

64*64

当前需求的关键点在于:如何获取原图像的所有像素点信息,然后根据像素点映射生成 PixCell 列表数据进行呈现。此时需要依赖 image类库。 现在在业务逻辑对象 PixPaintLogic 中增加一个 setImage 方法,传入用户选择的文件路径,使用 img.decodeImage 方法解码图片生成 img.Image 对象:

代码语言:javascript
复制
---->[lib/bloc/pix_paint_logic.dart]----
import 'package:image/image.dart' as img;

void setImage(String filePath) async {
  File file = File(filePath);
  img.Image? pixImage = img.decodeImage(await file.readAsBytes());
  if(pixImage==null){
    return;
  }
  setPixByImage(pixImage);
}

setPixByImage 方法中处理核心逻辑:遍历网格的行列数,从 image 中采样对应的像素值。其中 rate 标识格点像素相较于真实像素的坐标缩放比例,也就是像素采样的间隔。将非透明色的像素点,加入到 PixCell 列表中:

代码语言:javascript
复制
void setPixByImage(img.Image image) {
  List<PixCell> cells = [];
  int minSize = min(image.width, image.height);
  int minCount = min(row, column);
  int count = minSize.clamp(0, minCount);
  double rate = minSize / count;
  
  for (int x = 0; x < count; x++) {
    for (int y = 0; y < count; y++) {
      var pixel = image.getPixel((y * rate).toInt(), (x * rate).toInt());
      var color = Color.fromARGB(
          pixel.a.toInt(), pixel.r.toInt(), pixel.g.toInt(), pixel.b.toInt());
      if (color != Colors.transparent) {
        cells.add(PixCell(color: color, position: (y, x)));
      }
    }
  }
  setPixCells(cells);
}

最后通过 setPixCells 方法,将生成的 PixCell 列表加入到状态数据中,并发送更新通知,让画板进行变化:

代码语言:javascript
复制
void setPixCells(List<PixCell> cells) {
  pixCells.clear();
  pixCells.addAll(cells);
  notifyListeners();
  activePixLayer.update();
}

3. 图像的导出

本来是想通过 Canvas 进行绘制导出图片的,但是效果并不理想,因为 Flutter 的 1px 问题,并不适合绘制细小的像素。 image类库 中提供了像素级的操作,直接生成 png 图像:

image.png
image.png

如下所示,先创建一个 pixLayer 网格宽高的 img.Image 图像,通过数为 4 个,默认是 3 没有透明度。然后遍历 pixLayer#pixCells 为生成的 image 对象设置像素信息。最后只需要 img.encodePng(image) 即可进行编码得到字节列表数据:

代码语言:javascript
复制
PixPaintLogic paintLogic = PixPaintScope.read(context);
PixLayer pixLayer = paintLogic.activePixLayer;

final image = img.Image(
  width: pixLayer.row,
  height: pixLayer.column,
  numChannels: 4,
);

for (PixCell pix in pixLayer.pixCells) {
  Color color = pix.color;
  image.setPixelRgba(
    pix.position.$1,
    pix.position.$2,
    color.red,
    color.green,
    color.blue,
    color.alpha,
  );
}

final Uint8List byteData = img.encodePng(image);

有了字节列表数据之后,通过 FilePicker.platform.saveFile 选择保存文件,然后写入文件即可:

代码语言:javascript
复制
String? result = await FilePicker.platform.saveFile(type: FileType.image);
if (result != null) {
  File file = File(result);
  await file.writeAsBytes(byteData);
}

到这里,导入导出图像的功能就基本完成了,这样像素编辑的基本功能就能运转了,但目前只支持正方形的图片,后续会继续优化,支持矩形的网格。可以多多关注 【pix_editor】 的发展。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 本文目的
  • 2. 图像的导入
  • 3. 图像的导出
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档