By Lingfeng
As a powerful standard format for vector graphics, Scalable Vector Graphics (SVG) has incomparable advantages over bitmaps in terms of image resolution. So, is SVG always the best choice? Not necessarily. This article will explore the performance of SVG in Flutter applications. In addition, it will share the research practices made by the UC Browser core technology team in making better use of SVG in Flutter applications.
In the computing world, many space optimization methods involve reducing the consumption of computing power. For example, a 4K image with a wide variety of colors and shapes can be compressed to 5 kB in size (in fact, if the screen is large enough, you could even see an 8K image). If the 5-kB image is stored in Portable Network Graphic (PNG) format, it will look much smaller and will be pixelated if zoomed in but will be much faster to process.
The two images vary significantly in resolution performance.
To achieve similar resolutions, operating systems usually assist applications in packaging by classifying images with multiple resolutions into user interface (UI) resource packages.
The resource package for the preceding icon is 120 KB in size, with the largest version requiring 4 MB memory capacity to run.
Therefore, SVG is always the best choice, right?
No. Before you analyze the SVG support in Flutter, you may consider the absence of SVG support in various mobile system APIs as a great defect.
However, after you analyze the rasterization cost data, you will understand the concerns about the problems in the systems that can be caused by blindly using the SVG format.
For example, on a mobile phone with the Snapdragon 626 CPU, it takes 34 ms for Flutter to rasterize the preceding SVG image in a 64¡Á64 area. Therefore, one SVG image can completely prevent applications from running smoothly at 60 frames per second (fps). During a test, this rasterization process on an iPhone X took 8 ms to complete, and only two SVG images could be displayed smoothly.
In addition, the need for applying SVG or vector graphics arose after the emergence of the flat UI design trend. When skeuomorphic UI design was the dominant trend, in addition to the speed of rasterization, vector graphics could cause intolerable defects in realistic icons.
For example, after we have performed vectorization by using a more aggressive tracking algorithm, as show on the right in the following figure, the picture of dog looks much like a digital artwork. In addition, the new image version has consumed much more storage space than the PNG format.
Fortunately, when we use flat vector graphics to proceed with projects, we mostly use simple designs to prevent the preceding problem. Therefore, if we can avoid the pitfalls, SVG still can provide excellent performance in many scenarios.
There is an SVG directory in the code of Skia, which is a basic component of Flutter. However, Skia can only serialize images into SVG files. Therefore, you cannot decode or render SVG images with Skia.
Moreover, the current development plan for the framework of Flutter includes no intention to support SVG: https://github.com/flutter/flutter/issues/1831
This makes sense, because large operating systems such as Android and iOS do not support SVG by default.
There is a consensus that the full-featured SVG support not only requires a heavy workload, but also presents potential performance problems. These defects are ambiguously mentioned by the operating systems.
In the previous consultations on SVG, all the recommended solutions included the use of vector fonts. Vector fonts have the following features:
Although much work has been done in exploring SVG, we must admit that the output of vector fonts by far is a practical and efficient solution.
As a powerful standard format for vector graphics, SVG is suitable for certain applications, such as colorful icons, convenient rolling updates, and a wide range of production tools that support this format.
Both operating systems and runtime environments have excluded SVG. However, with the flutter_svg package, Flutter has the capability of rendering and decoding SVG in a simple and fast manner. This indicates the excellent scalability of Flutter and Dart.
The flutter_svg package is easy to use. It has provided interfaces that are similar to the image_provider interface in the framework of Flutter. The following code snippets are used to display SVG images that are from assets and a network respectively.
SvgPicture.asset(
'assets/adsmall.svg',
placeholderBuilder: (BuildContext context) => Container(
child: const CircularProgressIndicator()),
),
SvgPicture.network(
'https://raw.githubusercontent.com/dnfield/flutter_svg/master/example/assets/deborah_ufw/new-camera.svg',
placeholderBuilder: (BuildContext context) => Container(
child: const CircularProgressIndicator()),
),
We must not ignore the potential performance problems of SVG.
The UC Browser core technology team has developed a resource panel to help cope with the potential issues. With this panel, you can easily connect to Flutter applications and view the memory allocation in real time. In addition, you can preview SVG images and obtain their rasterization costs by using the resource panel.
By recording and comparing the rasterization costs of SVG files on real mobile devices, you can easily identify the SVG files with potential problems. As a result, you can make appropriate arrangements for SVG applications.
By comparing the actual rasterization costs, we found that the time consumed by an icon with simple design was 16.66 ms. This is acceptable on mobile devices with the Snapdragon 626 CPU.
As a Dart package, flutter_svg provides the capability of decoding SVG files from networks, assets, and the memory.
The decoded files are not bitmap images like the ui.Image class. Therefore, instead of working with the image cache, the flutter_svg package has implemented its own picture cache. The picture cache stores a class named ui.Picture, which is actually the SkPicture wrapper of Skia Graphics Engine.This class records specific SVG rendering commands in binary mode.
The ui.Picture class does not consume much memory. It is cached to avoid repeatedly parsing XML files.
For example, the following code snippet defines the construction interface of SvgPicture.asset.
SvgPicture.asset(
String assetName, {
Key key,
this.matchTextDirection = false,
AssetBundle bundle,
String package,
this.width,
this.height,
this.fit = BoxFit.contain,
this.alignment = Alignment.center,
this.allowDrawingOutsideViewBox = false,
this.placeholderBuilder,
Color color,
BlendMode colorBlendMode = BlendMode.srcIn,
this.semanticsLabel,
this.excludeFromSemantics = false,
}) : pictureProvider = ExactAssetPicture(
allowDrawingOutsideViewBox == true
? svgStringDecoderOutsideViewBox
: svgStringDecoder,
assetName,
bundle: bundle,
package: package,
colorFilter: _getColorFilter(color, colorBlendMode)),
super(key: key);
The pictures of SvgPicture are updated by stream notifications from the picture provider.
void _resolveImage() {
final PictureStream newStream = widget.pictureProvider
.resolve(createLocalPictureConfiguration(context));
assert(newStream ! = null);
_updateSourceStream(newStream);
}
The stream from the picture provider is populated with ui.Picture by a completer of the picture cache.
// in PictureProvider<T>.resolve
stream.setCompleter(
_cache.putIfAbsent(
key,
() => load(key, onError: onError),
),
);
In the Debug and Profile modes, by adding certain code, you can query all the existing pictures of SvgPicture in the picture cache with developer tools.
The interface that initiates the rasterization process uses the ui.Picture.toImage method. The rasterizer thread is responsible for timing.
Android has provided VectorDrawable, which is a simplified version of SVG. Although the format and properties of this solution is not fully compatible with SVG, a conversion tool is available for resolving this issue. The documents reveal concerns about the performance loss that can be caused by complex SVG images. Reference: https://developer.android.com/studio/write/vector-asset-studio
The current version of Flutter performs the rasterization process once and outputs every frame. This mode is different from the Chromium compositor (cc), which creates bitmaps for each area and then merge these images. In the output step of rasterization in Flutter, if you mark the bitmap pictures of SVG and cache them, you can increase the fps value. However, this method leads to increased memory usage.
At present, it is inconvenient to implement this function by using Dart alone, because RenderPicture is unable to estimate the specific rasterization resolution in the dart.ui thread.
Currently, the resource panel is available within Alibaba Group. Our team is trying to introduce it into the mainline version of Flutter. We welcome you to share your feedback and participate in discussions on this topic.
Alibaba Clouder - September 21, 2020
Hanks - April 21, 2020
Alibaba Clouder - December 22, 2020
Alibaba Clouder - May 17, 2021
XianYu Tech - August 10, 2021
XianYu Tech - August 10, 2021
Provides comprehensive quality assurance for the release of your apps.
Learn MoreAlibaba Cloud (in partnership with Whale Cloud) helps telcos build an all-in-one telecommunication and digital lifestyle platform based on DingTalk.
Learn MoreHelp enterprises build high-quality, stable mobile apps
Learn MoreBuild superapps and corresponding ecosystems on a full-stack platform
Learn More