1- // Copyright 2013 The Flutter Authors
2- // Use of this source code is governed by a BSD-style license that can be
3- // found in the LICENSE file.
4-
51import 'dart:developer' ;
6-
72import 'package:flutter/foundation.dart' ;
83import 'package:flutter/material.dart' ;
94import 'package:http/http.dart' as http;
105import 'package:vector_graphics/vector_graphics.dart' ;
11- import 'package:vector_graphics_compiler/vector_graphics_compiler.dart' ;
6+ import 'package:vector_graphics_compiler/vector_graphics_compiler.dart' show encodeSvg ;
127
138void main () {
149 runApp (const MyApp ());
1510}
1611
12+ const String _svgDropShadow = '''
13+ <!-- Feature: Classic Drop Shadow via feGaussianBlur, feOffset, and feMerge -->
14+ <svg width="400" height="200" viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg">
15+ <defs>
16+ <filter id="drop-shadow" x="-20%" y="-20%" width="140%" height="140%">
17+ <!-- 1. Blur the original graphic source alpha channel -->
18+ <feGaussianBlur in="SourceAlpha" stdDeviation="6" result="blur" />
19+ <!-- 2. Shift the blurred shadow down and right -->
20+ <feOffset in="blur" dx="5" dy="8" result="offsetBlur"/>
21+ <!-- 3. Layer the original graphic on top of the shadow -->
22+ <feMerge>
23+ <feMergeNode in="offsetBlur" />
24+ <feMergeNode in="SourceGraphic" />
25+ </feMerge>
26+ </filter>
27+ </defs>
28+
29+ <rect x="50" y="40" width="300" height="100" rx="15" fill="#4F46E5" filter="url(#drop-shadow)" />
30+ </svg>
31+ ''' ;
32+
33+ const String _svgNeonText = '''
34+ <!-- Feature: Glowing Neon Text Effect using multiple layered feGaussianBlur outputs -->
35+ <svg width="500" height="200" viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg">
36+ <defs>
37+ <filter id="neon-glow" x="-50%" y="-50%" width="200%" height="200%">
38+ <!-- Blur the graphic significantly to create the wide background glow -->
39+ <feGaussianBlur in="SourceGraphic" stdDeviation="12" result="blur1" />
40+ <!-- Create a sharper, more intense core glow -->
41+ <feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur2" />
42+
43+ <!-- Merge the layers: wide glow, sharp glow, then crisp original text -->
44+ <feMerge>
45+ <feMergeNode in="blur1" />
46+ <feMergeNode in="blur2" />
47+ <feMergeNode in="SourceGraphic" />
48+ </feMerge>
49+ </filter>
50+ </defs>
51+
52+ <rect width="100%" height="100%" fill="#0B0F19" />
53+ <text x="50%" y="55%" dominant-baseline="middle" text-anchor="middle" fill="#FFF" stroke="#FF2E93" stroke-width="2" font-family="Courier New" font-size="64" font-weight="bold" filter="url(#neon-glow)">
54+ OPEN 24/7
55+ </text>
56+ </svg>
57+ ''' ;
58+
59+ const String _svgMeshGradient = '''
60+ <!-- Feature: Smooth UI Background Gradient ("Mesh" Style) via high stdDeviation blur -->
61+ <svg width="600" height="400" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg">
62+ <defs>
63+ <!-- High standard deviation blends the distinct shapes seamlessly -->
64+ <filter id="heavy-blur">
65+ <feGaussianBlur stdDeviation="80" />
66+ </filter>
67+ </defs>
68+
69+ <!-- Base background color -->
70+ <rect width="100%" height="100%" fill="#0F172A" />
71+
72+ <!-- Blurring container holding the colored blobs -->
73+ <g filter="url(#heavy-blur)">
74+ <circle cx="150" cy="120" r="130" fill="#38BDF8" opacity="0.6" />
75+ <circle cx="450" cy="280" r="160" fill="#EC4899" opacity="0.5" />
76+ <circle cx="300" cy="200" r="110" fill="#6366F1" opacity="0.6" />
77+ </g>
78+ </svg>
79+ ''' ;
80+
81+ const String _svgGlassmorphism = '''
82+ <!-- Feature: Glassmorphism / Frosted Glass Panel overlay using clipped feGaussianBlur shapes -->
83+ <svg width="500" height="350" viewBox="0 0 500 350" xmlns="http://www.w3.org/2000/svg">
84+ <defs>
85+ <!-- A standard background blur filter -->
86+ <filter id="glass-blur">
87+ <feGaussianBlur stdDeviation="20" />
88+ </filter>
89+
90+ <!-- Clip path to match our UI card dimensions -->
91+ <clipPath id="card-shape">
92+ <rect x="100" y="75" width="300" height="200" rx="20" />
93+ </clipPath>
94+ </defs>
95+
96+ <!-- Colorful backdrop layer -->
97+ <rect width="100%" height="100%" fill="#1E1E2F" />
98+ <circle cx="160" cy="130" r="90" fill="#FF5E62" />
99+ <circle cx="360" cy="220" r="100" fill="#FF9966" />
100+
101+ <!-- The Frosted Glass Card Technique -->
102+ <!-- 1. Duplicate background layer clipped and heavily blurred -->
103+ <g clip-path="url(#card-shape)">
104+ <rect width="100%" height="100%" fill="#1E1E2F" />
105+ <circle cx="160" cy="130" r="90" fill="#FF5E62" filter="url(#glass-blur)" />
106+ <circle cx="360" cy="220" r="100" fill="#FF9966" filter="url(#glass-blur)" />
107+
108+ <!-- 2. Semi-transparent white tint fill for the frosted appearance -->
109+ <rect x="100" y="75" width="300" height="200" fill="#FFFFFF" opacity="0.07" />
110+ </g>
111+
112+ <!-- 3. Crisp white border stroke overlaying the card to establish depth -->
113+ <rect x="100" y="75" width="300" height="200" rx="20" fill="none" stroke="#FFFFFF" stroke-width="1.5" opacity="0.25" />
114+ </svg>
115+ ''' ;
116+
117+ const String _svgMotionBlur = '''
118+ <!-- Feature: Directional Motion Blur using decoupled axes in stdDeviation="X Y" -->
119+ <svg width="500" height="150" viewBox="0 0 500 150" xmlns="http://www.w3.org/2000/svg">
120+ <defs>
121+ <!-- stdDeviation="Horizontal Vertical". Setting vertical to 0 creates a horizontal streak -->
122+ <filter id="motion-blur-x" x="-50%" y="0%" width="200%" height="100%">
123+ <feGaussianBlur stdDeviation="25 0" />
124+ </filter>
125+ </defs>
126+
127+ <rect width="100%" height="100%" fill="#111827" />
128+
129+ <!-- The trailing motion streak -->
130+ <circle cx="300" cy="75" r="30" fill="#F59E0B" filter="url(#motion-blur-x)" opacity="0.8" />
131+
132+ <!-- The crisp leading object -->
133+ <circle cx="360" cy="75" r="30" fill="#F59E0B" />
134+ </svg>
135+ ''' ;
136+
17137/// The main example app widget.
18138class MyApp extends StatelessWidget {
19139 /// Creates a new [MyApp] .
@@ -23,12 +143,70 @@ class MyApp extends StatelessWidget {
23143 Widget build (BuildContext context) {
24144 return MaterialApp (
25145 title: 'Vector Graphics Demo' ,
26- theme: ThemeData (primarySwatch: Colors .blue),
27- home: const Scaffold (
28- body: Center (
29- child: VectorGraphic (
30- loader: NetworkSvgLoader (
31- 'https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg' ,
146+ theme: ThemeData .dark (),
147+ home: Scaffold (
148+ appBar: AppBar (title: const Text ('Filter & Mask Gallery' )),
149+ body: const SingleChildScrollView (
150+ child: Padding (
151+ padding: EdgeInsets .all (16.0 ),
152+ child: Column (
153+ crossAxisAlignment: CrossAxisAlignment .start,
154+ children: [
155+ Text ('0. Original Ghostscript Tiger (Network SVG Loader)' , style: TextStyle (fontWeight: FontWeight .bold)),
156+ SizedBox (height: 8 ),
157+ SizedBox (
158+ height: 200 ,
159+ width: 200 ,
160+ child: VectorGraphic (
161+ loader: NetworkSvgLoader (
162+ 'https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg' ,
163+ ),
164+ ),
165+ ),
166+ Divider (height: 32 ),
167+ Text ('1. Classic Drop Shadow (feGaussianBlur, feOffset, feMerge)' , style: TextStyle (fontWeight: FontWeight .bold)),
168+ SizedBox (height: 8 ),
169+ SizedBox (
170+ height: 200 ,
171+ width: 400 ,
172+ child: DecoratedBox (
173+ decoration: BoxDecoration (color: Colors .white),
174+ child: VectorGraphic (loader: _StringSvgLoader (_svgDropShadow)),
175+ ),
176+ ),
177+ Divider (height: 32 ),
178+ Text ('2. Glowing Neon Text (Multiple feGaussianBlur, feMerge)' , style: TextStyle (fontWeight: FontWeight .bold)),
179+ SizedBox (height: 8 ),
180+ SizedBox (
181+ height: 200 ,
182+ width: 500 ,
183+ child: VectorGraphic (loader: _StringSvgLoader (_svgNeonText)),
184+ ),
185+ Divider (height: 32 ),
186+ Text ('3. Smooth UI Background Gradient (Mesh style blur on Group)' , style: TextStyle (fontWeight: FontWeight .bold)),
187+ SizedBox (height: 8 ),
188+ SizedBox (
189+ height: 400 ,
190+ width: 600 ,
191+ child: VectorGraphic (loader: _StringSvgLoader (_svgMeshGradient)),
192+ ),
193+ Divider (height: 32 ),
194+ Text ('4. Glassmorphism (Clipped group with blur)' , style: TextStyle (fontWeight: FontWeight .bold)),
195+ SizedBox (height: 8 ),
196+ SizedBox (
197+ height: 350 ,
198+ width: 500 ,
199+ child: VectorGraphic (loader: _StringSvgLoader (_svgGlassmorphism)),
200+ ),
201+ Divider (height: 32 ),
202+ Text ('5. Directional Motion Blur (stdDeviation="25 0")' , style: TextStyle (fontWeight: FontWeight .bold)),
203+ SizedBox (height: 8 ),
204+ SizedBox (
205+ height: 150 ,
206+ width: 500 ,
207+ child: VectorGraphic (loader: _StringSvgLoader (_svgMotionBlur)),
208+ ),
209+ ],
32210 ),
33211 ),
34212 ),
@@ -37,6 +215,37 @@ class MyApp extends StatelessWidget {
37215 }
38216}
39217
218+ class _StringSvgLoader extends BytesLoader {
219+ const _StringSvgLoader (this .svg);
220+ final String svg;
221+
222+ @override
223+ Future <ByteData > loadBytes (BuildContext ? context) async {
224+ return compute (
225+ (String svgStr) {
226+ final Uint8List compiledBytes = encodeSvg (
227+ xml: svgStr,
228+ debugName: 'custom-svg' ,
229+ enableClippingOptimizer: false ,
230+ enableMaskingOptimizer: false ,
231+ enableOverdrawOptimizer: false ,
232+ );
233+ return ByteData .sublistView (compiledBytes);
234+ },
235+ svg,
236+ debugLabel: 'Load String Bytes' ,
237+ );
238+ }
239+
240+ @override
241+ int get hashCode => svg.hashCode;
242+
243+ @override
244+ bool operator == (Object other) {
245+ return other is _StringSvgLoader && other.svg == svg;
246+ }
247+ }
248+
40249/// A [BytesLoader] that converts a network URL into encoded SVG data.
41250class NetworkSvgLoader extends BytesLoader {
42251 /// Creates a [NetworkSvgLoader] that loads an SVG from [url] .
@@ -60,7 +269,7 @@ class NetworkSvgLoader extends BytesLoader {
60269 );
61270 task.finish ();
62271 // sendAndExit will make sure this isn't copied.
63- return compiledBytes.buffer. asByteData ( );
272+ return ByteData . sublistView (compiledBytes );
64273 },
65274 url,
66275 debugLabel: 'Load Bytes' ,
0 commit comments