我正在使用自定义RenderBox
绘制。
下面代码中的canvas
对象来自PaintingContext
in the paint
method。
我试图通过使用Canvas.drawRect
单独渲染像素。
我应该指出,它们有时会比实际占用的屏幕上的像素更大,有时也更小。
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]);
}
我将像素存储为List<List<Color>>
(上面代码中的colors
)。我之前尝试过不同的嵌套列表,但它们在性能方面没有引起任何明显的差异。当使用282.7MB
图像填充列表时,我的Android Emulator测试设备上的内存增加了999x999
。请注意,它只会暂时增加282.7MB
。大约半分钟后,增加下降到153.6MB
并停留在那里(没有任何用户交互)。
分辨率为999x999
,上面的代码导致GPU最大值为250.1 ms/frame
,UI最大值为1835.9 ms/frame
,这显然是不可接受的。当试图绘制999x999
图像时,UI会冻结两秒钟,考虑到4k视频在同一台设备上运行顺畅,这应该是小菜一碟(我猜)。
我不确定如何使用Android分析器正确跟踪这个,但在填充或更改列表时,即绘制像素(也是上述指标的情况),CPU使用率从0%
到60%
。以下是AVD性能设置:
我不知道从哪里开始,因为我甚至不确定我的代码的哪一部分会导致冻结。它是内存使用情况吗?还是绘图本身? 我一般会如何处理这个问题?我究竟做错了什么?我应该如何存储这些像素。
我已经尝试了很多,根本没有帮助,我会尽力指出最值得注意的:
List<List<Color>>
转换为Image
from the dart:ui
library,希望使用Canvas.drawImage
。为了做到这一点,我尝试编码我自己的PNG,但I have not been able to render more than a single row。但是,它看起来并不会提升性能。当试图转换9999x9999
图像时,我遇到了内存不足异常。现在,我想知道视频是如何呈现的,因为任何4k视频都会比9999x9999
图像容易占用更多内存,如果它在内存中的几秒钟。image
包。但是,我在完成它之前停止了,因为我注意到它不是用于Flutter而是用于HTML。我不会使用它获得任何东西。Random.nextInt
生成随机颜色。当试图随机生成999x999
图像时,这导致GPU最大值为1824.7 ms/frames
,UI最大值为2362.7 ms/frame
,这更糟糕,尤其是在GPU部门。这是我在尝试使用Canvas.drawImage
渲染失败之前达到的结论:Canvas.drawRect
不是为此任务而制作的,因为它甚至无法绘制简单的图像。
你是如何在Flutter做到这一点的?
10k
像素。我至少需要1m
。感谢@pslink在我写完之后提醒我BMP
我没有编码我自己的PNG
。
我以前曾调查过它,但我认为如果没有足够的文档,它看起来很复杂。现在,我发现this nice article解释了必要的BMP
标头,并通过复制Example 2 from the "BMP file format" Wikipedia article实现了32位BGRA(ARGB,但BGRA是默认掩码的顺序)。我浏览了所有来源,但找不到此示例的原始来源。也许维基百科文章的作者自己写了这篇文章。
使用Canvas.drawImage
和我的999x999
像素转换为BMP
字节列表中的图像,我获得了GPU最大值9.9 ms/frame
和UI最大值7.1 ms/frame
,这太棒了!
| ms/frame | Before (Canvas.drawRect) | After (Canvas.drawImage) |
|-----------|---------------------------|--------------------------|
| GPU max | 1824.7 | 9.9 |
| UI max | 2362.7 | 7.1 |
像Canvas.drawRect
这样的画布操作不应该像这样使用。
首先,这是非常简单的,但是,您需要正确填充字节列表,否则,您将得到一个错误,您的数据格式不正确并且看不到任何结果,这可能非常令人沮丧。
您需要在绘图前准备好图像,因为您无法在绘图调用中使用async
操作。
在代码中,您需要使用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;
您需要将此图像传递给绘图窗口小部件,例如使用FutureBuilder
。
现在,您可以在绘制调用中使用Canvas.drawImage
。