设置

I am using a custom RenderBox to draw.
The canvas object in the code below comes from the PaintingContext in the paint method.

绘画

I am trying to render pixels individually by using Canvas.drawRect.
I should point out that these are sometimes larger and sometimes smaller than the pixels on screen they actually occupy.

for (int i = 0; i < width * height; i++) {
  // in this case the rect size is 1
  canvas.drawRect(
      Rect.fromLTWH(index % (width * height), 
          (index / (width * height)).floor(), 1, 1), Paint()..color = colors[i]);
}

存储

我将像素存储为100(上面代码中的colors).我以前try 过不同的嵌套列表,但它们在性能方面没有引起任何明显的差异. 我的Android Emulator测试设备increases by 102 when populating the list with a 103 image上的memory.请注意,它只是暂时增加了282.7MB.大约半分钟后,增量降到153.6MB,并停留在那里(没有任何用户交互).

渲染

在分辨率为999x999的情况下,上面的代码导致GPU max250.1 ms/frame,UI max1835.9 ms/frame,这显然是不可接受的.当试图绘制999x999图像时,UI会冻结两秒钟,考虑到4k视频在同一设备上运行流畅,这应该是小菜一碟(我猜).

中央处理器

我不确定如何使用Android分析器正确跟踪这一点,但虽然是102 the list,即绘制像素(上述指标也是如此),但中央处理器使用率从0%上升到60%.以下是AVD性能设置:

原因

I have no idea where to start since I am not even sure what part of my code causes the freezing. Is it the memory usage? Or the drawing itself?
How would I go about this in general? What am I doing wrong? How should I store these pixels instead.

努力

我试了那么多,但都没有用,所以我只想指出最值得注意的几个:

  • 我试着把List<List<Color>>改成Image from the dart:ui library,希望能用Canvas.drawImage.为此,我try 对我自己的PNG进行编码,但是I have not been able to render more than a single row.然而,看起来这并不会提振业绩.在try 转换9999x9999图像时,我遇到内存不足异常.现在,我想知道视频是如何呈现的,因为如果内存中有几秒钟的话,任何4k视频都会很容易比9999x9999图像占用更多的内存.

  • 我试着实施image计划.然而,在完成它之前,我停了下来,因为我注意到它不是用于Flutter,而是用于HTML.用这个我什么也得不到.

  • 这一点对于我将得出的以下结论非常重要:我try 了104 without storing the pixels,也就是使用Random.nextInt来生成随机 colored颜色 .当try 随机生成999x999图像时,结果是1824.7 ms/framesGPU max2362.7 ms/frameUI max,这更糟糕,特别是在GPU部门.

结论

这是我在try 使用Canvas.drawImage:Canvas.drawRect渲染失败之前得出的结论,因为它甚至不能绘制简单的图像.

你是如何在Flutter 打中做到这一点的?

注意事项

  • 这基本上是what I tried to ask over two months ago(是的,我一直在努力解决这个问题这么长时间),但我认为我当时没有正确地表达自己,我甚至不知道实际的问题是什么.

  • 我能正确渲染的最高分辨率约为10k像素.我至少需要1m个.

  • 我在想,放弃飘浮,转向本土可能是我唯一的 Select .然而,我愿意相信我处理这个问题是完全错误的.我花了大约三个月的时间试图弄清楚这一点,但我没有找到任何能让我有所作为的东西.

推荐答案

解决方案

dart:ui有一个功能,可以很容易地将像素转换成Image:decodeImageFromPixels

当我写这个答案的时候,我根本没有意识到这一点,这就是为什么我写了"Alternative"部分.

Alternative

Thanks to @pslink for reminding me of BMP after I wrote that I had failed to encode my own PNG.
I had looked into it previously, but I thought that it looked to complicated without sufficient documentation. Now, I found this nice article explaining the necessary BMP headers and implemented 32-bit BGRA (ARGB but BGRA is the order of the default mask) by copying Example 2 from the "BMP file format" Wikipedia article. I went through all sources but could not find an original source for this example. Maybe the authors of the Wikipedia article wrote it themselves.

结果

使用Canvas.drawImage和我的999x999像素转换为BMP字节列表中的图像,我得到的是9.9 ms/frameGPU max7.1 ms/frame,which is awesomeUI max

|  ms/frame |  Before (Canvas.drawRect) | After (Canvas.drawImage) |
|-----------|---------------------------|--------------------------|
|  GPU max  | 1824.7                    | 9.9                      |
|  UI max   | 2362.7                    | 7.1                      |

结论

Canvas.drawRect这样的画布操作不应该这样使用.

使用说明

首先,这非常简单,但是,您需要正确填充字节列表,否则,您将收到数据格式不正确且看不到结果的错误,这可能会非常令人沮丧.

由于不能在绘制调用中使用async个操作,因此需要使用prepare your image 101.

在代码中,您需要使用Codec将字节列表转换为图像.

final list = [
            0x42, 0x4d, // 'B', 'M'
            ...];
// make sure that you either know the file size, data size and data offset beforehand
//        or that you edit these bytes afterwards

final Uint8List bytes = Uint8List.fromList(list);

final Codec codec = await instantiateImageCodec(bytes));

final Image image = (await codec.getNextFrame()).image;

You need to pass this image to your drawing widget, e.g. using a FutureBuilder.
Now, you can just use Canvas.drawImage in your draw call.

Dart相关问答推荐

使用 2 个类型参数声明类型StateNotifierProvider,但给出了 1 个类型参数

为什么Dart中的 abs() 函数在没有用括号括起来时返回负数?

如何在 Dart 中设置文本框的值?

Dart JavaScript 与 jQuery 的互操作回调

Flutter:将照片或图像显示为模态弹出窗口

Dart 中使用 ifAbsent 的 Map Update 方法

如何限制TextSpan小部件的文本长度

不推荐使用AnteStorStateofType,请改用findAncestorStateOfType

全局减慢 Flutter 中的动画

GestureDetector onTap 卡

如何导入文件夹中的所有文件?

Dart:打印整数和字符串

如何从列表中的元素创建逗号分隔的字符串

Dart:如何判断变量类型是否为字符串

Cancel stream onData

从 Dart 应用访问 pubspec.yaml 属性

如何在 Dart 中扩展列表?

如何初始化构造函数主体中的最终字段?

dart中的动态和对象有什么区别?

Dart 字符串比较器