How do I Render Individual Pixels in Flutter?

后端 未结 1 1335
清酒与你
清酒与你 2020-12-06 14:01

Setup

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

Draw

相关标签:
1条回答
  • 2020-12-06 14:38

    Solution

    dart:ui has a function that converts pixels to an Image easily: decodeImageFromPixels

    • Example implementation

    • Issue on performance

    • Does not work in the current master channel

    I was simply not aware of this back when I created this answer, which is why I wrote the "Alternative" section.

    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.

    Results

    Using Canvas.drawImage and my 999x999 pixels converted to an image from a BMP byte list, I get a GPU max of 9.9 ms/frame and a UI max of 7.1 ms/frame, which is awesome!

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

    Conclusion

    Canvas operations like Canvas.drawRect are not meant to be used like that.

    Instructions

    First of, this is quite straight-forward, however, you need to correctly populate the byte list, otherwise, you are going to get an error that your data is not correctly formatted and see no results, which can be quite frustrating.

    You will need to prepare your image before drawing as you cannot use async operations in the paint call.

    In code, you need to use a Codec to transform your list of bytes into an image.

    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.

    0 讨论(0)
提交回复
热议问题