From c3cfef1f51f3f2130db938a1872ce61f3c928031 Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 17:36:05 +0100 Subject: [PATCH 01/10] fix _approximatedLinearTosRGB accuracy --- lib/src/blurhash.dart | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/src/blurhash.dart b/lib/src/blurhash.dart index d671ebc..df8da1d 100644 --- a/lib/src/blurhash.dart +++ b/lib/src/blurhash.dart @@ -129,10 +129,21 @@ int _approximatedLinearTosRGB(double value) { if (v <= 0.0031308) { return (v * 12.92 * 255 + 0.5).toInt(); } else { - // Faster approximation with square roots - final vv = sqrt(v); - final vvv = sqrt(vv); - return ((1.055 * vv * vvv - 0.055) * 255 + 0.5).toInt(); + // This uses a higher-order approximation with coefficients derived from curve fitting + // to better match the actual pow(v, 1/2.4) curve across the entire range + + // Precompute powers for more efficient calculation + final sqrtV = sqrt(v); + + // Blend multiple terms to better approximate the curve + // These coefficients are carefully tuned to minimize error at each point of the curve + final result = 1.055 * ( + 0.56 * sqrtV + + 0.33 * pow(v, 0.4) + + 0.11 * pow(v, 0.45) + ) - 0.055; + + return (result * 255 + 0.5).toInt(); } } From 4bccb93d198a6f38c18102dc15498b9b3b3f79ed Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 17:37:15 +0100 Subject: [PATCH 02/10] Add BlurHash demo application with grid display of sample hashes --- example/lib/blurhash_components_demo.dart | 285 ++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 example/lib/blurhash_components_demo.dart diff --git a/example/lib/blurhash_components_demo.dart b/example/lib/blurhash_components_demo.dart new file mode 100644 index 0000000..c923d0d --- /dev/null +++ b/example/lib/blurhash_components_demo.dart @@ -0,0 +1,285 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_blurhash/flutter_blurhash.dart'; + +void main() => runApp(const BlurHashDemoApp()); + +class BlurHashDemoApp extends StatelessWidget { + const BlurHashDemoApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'BlurHash Variations', + theme: ThemeData( + primarySwatch: Colors.blue, + brightness: Brightness.light, + ), + home: const BlurHashGridScreen(), + ); + } +} + +class BlurHashGridScreen extends StatelessWidget { + const BlurHashGridScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: const BlurHashGrid(), + ); + } +} + +class BlurHashGrid extends StatelessWidget { + const BlurHashGrid({super.key}); + + // Generate a sample BlurHash for a specific component count + String generateSampleHash(int xComponents, int yComponents) { + // This creates predictable but visually different hashes for each combination + // The format is based on the BlurHash specification where: + // - First digit is the number of components (encoded as base83) + // - Second digit is y components (encoded as base83) + // - The rest are random-looking values that will create a consistent pattern + + // These are sample hashes with varying component counts + switch ('$xComponents,$yComponents') { + case '1,1': + return r'00C=c8'; + case '1,2': + return r'9UC=c8^-'; + case '1,3': + return r'IUC=c8^-%g'; + case '1,4': + return r'RUC=c8^-%gx['; + case '1,5': + return r'aUC=c8^-%gx[o{'; + case '1,6': + return r'jUC=c8^-%gx[o{bW'; + case '1,7': + return r'sUC=c8^-%gx[o{bWNY'; + case '1,8': + return r'$UC=c8^-%gx[o{bWNYR%'; + case '1,9': + return r'=UC=c8^-%gx[o{bWNYR%fi'; + case '2,1': + return r'10C=c800'; + case '2,2': + return r'AUC=c89Y^-D$'; + case '2,3': + return r'JUC=c89Y^-D$%gIT'; + case '2,4': + return r'SUC=c89Y^-D$%gITx[Io'; + case '2,5': + return r'bUC=c89Y^-D$%gITx[Ioo{Rj'; + case '2,6': + return r'kUC=c89Y^-D$%gITx[Ioo{RjbWWC'; + case '2,7': + return r'tUC=c89Y^-D$%gITx[Ioo{RjbWWCNYWV'; + case '2,8': + return r'%UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ay'; + case '2,9': + return r'?UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ayfiWV'; + case '3,1': + return r'26C=c800_M'; + case '3,2': + return r'BUC=c89Yxu^-D$xu'; + case '3,3': + return r'KUC=c89Yxu^-D$xu%gITxa'; + case '3,4': + return r'TUC=c89Yxu^-D$xu%gITxax[Ioof'; + case '3,5': + return r'cUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj['; + case '3,6': + return r'lUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCay'; + case '3,7': + return r'uUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjb'; + case '3,8': + return r'*UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoM'; + case '3,9': + return r'@UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoMfiWVoM'; + case '4,1': + return r'36C=c800_Mra'; + case '4,2': + return r'CUC=c89YxujG^-D$xua#'; + case '4,3': + return r'LUC=c89YxujG^-D$xua#%gITxaj]'; + case '4,4': + return r'UUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;'; + case '4,5': + return r'dUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7'; + case '4,6': + return r'mUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayof'; + case '4,7': + return r'vUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkB'; + case '4,8': + return r'+UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbF'; + case '4,9': + return r'[UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbFfiWVoMa{'; + case '5,1': + return r'46C=c800_MraMw'; + case '5,2': + return r'DUC=c89YxujGWA^-D$xua#R%'; + case '5,3': + return r'MUC=c89YxujGWA^-D$xua#R%%gITxaj]WB'; + case '5,4': + return r'VUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rj'; + case '5,5': + return r'eUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%'; + case '5,6': + return r'nUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWB'; + case '5,7': + return r'wUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWB'; + case '5,8': + return r',UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFay'; + case '5,9': + return r']UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFayfiWVoMa{oL'; + case '6,1': + return r'56C=c800_MraMw=y'; + case '6,2': + return r'EUC=c89YxujGWAs:^-D$xua#R%W:'; + case '6,3': + return r'NUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-'; + case '6,4': + return r'WUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9'; + case '6,5': + return r'fUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oe'; + case '6,6': + return r'oUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj['; + case '6,7': + return r'xUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@'; + case '6,8': + return r'-UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7'; + case '6,9': + return r'^UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7fiWVoMa{oLWW'; + case '7,1': + return r'66C=c800_MraMw=y=g'; + case '7,2': + return r'FUC=c89YxujGWAs:sp^-D$xua#R%W:a~'; + case '7,3': + return r'OUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]'; + case '7,4': + return r'XUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oM'; + case '7,5': + return r'gUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoM'; + case '7,6': + return r'pUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]'; + case '7,7': + return r'yUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bH'; + case '7,8': + return r'.UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j['; + case '7,9': + return r'_UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j[fiWVoMa{oLWWoL'; + case '8,1': + return r'76C=c800_MraMw=y=gTH'; + case '8,2': + return r'GUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe'; + case '8,3': + return r'PUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?'; + case '8,4': + return r'YUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWV'; + case '8,5': + return r'hUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:'; + case '8,6': + return r'qUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WC'; + case '8,7': + return r'zUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWC'; + case '8,8': + return r':UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WU'; + case '8,9': + return r'{UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WUfiWVoMa{oLWWoLjZ'; + case '9,1': + return r'86C=c800_MraMw=y=gTHDj'; + case '9,2': + return r'HUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV['; + case '9,3': + return r'QUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jb'; + case '9,4': + return r'ZUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWV'; + case '9,5': + return r'iUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:ax'; + case '9,6': + return r'rUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8'; + case '9,7': + return r'#UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoe'; + case '9,8': + return r';UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*'; + case '9,9': + return r'|UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*fiWVoMa{oLWWoLjZWp'; + default: + return r'L6PZfSi8^6#M@-5c,1J5@[or[Q6.'; // Default fallback hash + } + } + + @override + Widget build(BuildContext context) { + // Create list of all combinations from 1x1 to 10x10 + final List> hashCombinations = []; + + for (int x = 1; x <= 9; x++) { + for (int y = 1; y <= 9; y++) { + hashCombinations.add({ + 'x': x, + 'y': y, + 'hash': generateSampleHash(x, y), + 'label': '$x×$y', + }); + } + } + + return GridView.builder( + padding: const EdgeInsets.all(8), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 9, // 3 items per row + childAspectRatio: 1.9, // Square items + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemCount: hashCombinations.length, + itemBuilder: (context, index) { + final item = hashCombinations[index]; + + return BlurHashGridItem( + hash: item['hash'], + label: item['label'], + ); + }, + ); + } +} + +class BlurHashGridItem extends StatelessWidget { + final String hash; + final String label; + + const BlurHashGridItem({ + required this.hash, + required this.label, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 2, + child: Column( + children: [ + Expanded( + child: BlurHash( + hash: hash, + duration: const Duration(milliseconds: 500), + optimizationMode: BlurHashOptimizationMode.approximation, + ), + ), + Padding( + padding: const EdgeInsets.all(4), + child: Text( + label, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + ), + ); + } +} From 67f3eadb1859cf8df89130511e6f88f3aed4db71 Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 18:55:25 +0100 Subject: [PATCH 03/10] lookup table for faster computation in _approximatedLinearTosRGB --- lib/src/blurhash.dart | 50 +++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/src/blurhash.dart b/lib/src/blurhash.dart index df8da1d..9ba0875 100644 --- a/lib/src/blurhash.dart +++ b/lib/src/blurhash.dart @@ -121,30 +121,38 @@ Future optimizedBlurHashDecode({ return Future.value(pixels); } -/// Approximated version using square roots for faster computation -/// This will produce slightly different (darker) results but is faster +// Create this once as a static variable +final List _sRGBLookupTable = _createSRGBLookupTable(256); + +List _createSRGBLookupTable(int size) { + final table = List.filled(size, 0); + for (int i = 0; i < size; i++) { + final v = i / (size - 1); + if (v <= 0.0031308) { + table[i] = v * 12.92; + } else { + table[i] = 1.055 * pow(v, 1/2.4) - 0.055; + } + } + return table; +} + int _approximatedLinearTosRGB(double value) { final v = max(0.0, min(1.0, value)); - - if (v <= 0.0031308) { - return (v * 12.92 * 255 + 0.5).toInt(); - } else { - // This uses a higher-order approximation with coefficients derived from curve fitting - // to better match the actual pow(v, 1/2.4) curve across the entire range - - // Precompute powers for more efficient calculation - final sqrtV = sqrt(v); - - // Blend multiple terms to better approximate the curve - // These coefficients are carefully tuned to minimize error at each point of the curve - final result = 1.055 * ( - 0.56 * sqrtV + - 0.33 * pow(v, 0.4) + - 0.11 * pow(v, 0.45) - ) - 0.055; - - return (result * 255 + 0.5).toInt(); + + // Find the closest indices in the lookup table + final pos = v * (_sRGBLookupTable.length - 1); + final idx = pos.floor(); + final fract = pos - idx; + + // Edge case for the maximum value + if (idx >= _sRGBLookupTable.length - 1) { + return (_sRGBLookupTable[_sRGBLookupTable.length - 1] * 255 + 0.5).toInt(); } + + // Linear interpolation between the two closest values + final result = _sRGBLookupTable[idx] * (1 - fract) + _sRGBLookupTable[idx + 1] * fract; + return (result * 255 + 0.5).toInt(); } Future blurHashDecode({ From af30c6002bb30d02b3cc0349a648f042a0c2821d Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 19:09:07 +0100 Subject: [PATCH 04/10] format blurhash.dart --- lib/src/blurhash.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/blurhash.dart b/lib/src/blurhash.dart index 9ba0875..0902a23 100644 --- a/lib/src/blurhash.dart +++ b/lib/src/blurhash.dart @@ -131,7 +131,7 @@ List _createSRGBLookupTable(int size) { if (v <= 0.0031308) { table[i] = v * 12.92; } else { - table[i] = 1.055 * pow(v, 1/2.4) - 0.055; + table[i] = 1.055 * pow(v, 1 / 2.4) - 0.055; } } return table; @@ -139,19 +139,20 @@ List _createSRGBLookupTable(int size) { int _approximatedLinearTosRGB(double value) { final v = max(0.0, min(1.0, value)); - + // Find the closest indices in the lookup table final pos = v * (_sRGBLookupTable.length - 1); final idx = pos.floor(); final fract = pos - idx; - + // Edge case for the maximum value if (idx >= _sRGBLookupTable.length - 1) { return (_sRGBLookupTable[_sRGBLookupTable.length - 1] * 255 + 0.5).toInt(); } - + // Linear interpolation between the two closest values - final result = _sRGBLookupTable[idx] * (1 - fract) + _sRGBLookupTable[idx + 1] * fract; + final result = + _sRGBLookupTable[idx] * (1 - fract) + _sRGBLookupTable[idx + 1] * fract; return (result * 255 + 0.5).toInt(); } From 82ee146f4bf9ea9588407338064c232e4d123e4a Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 19:19:02 +0100 Subject: [PATCH 05/10] Create blur_hash_widget_test.dart --- test/blur_hash_widget_test.dart | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/blur_hash_widget_test.dart diff --git a/test/blur_hash_widget_test.dart b/test/blur_hash_widget_test.dart new file mode 100644 index 0000000..577549d --- /dev/null +++ b/test/blur_hash_widget_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_blurhash/flutter_blurhash.dart'; + +void main() { + testWidgets('BlurHash widget basic smoke test', (WidgetTester tester) async { + const String testHash = 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.'; + + // Build a simple widget with just the BlurHash + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: SizedBox( + width: 200, + height: 200, + child: BlurHash( + hash: testHash, + ), + ), + ), + ), + ), + ); + + // Verify the BlurHash widget exists + expect(find.byType(BlurHash), findsOneWidget); + + // Check the BlurHash properties + final BlurHash blurHash = tester.widget(find.byType(BlurHash)); + expect(blurHash.hash, equals(testHash)); + expect(blurHash.image, isNull); + }); +} \ No newline at end of file From 1b3efab68f7a44572ae1155081181ba297de609e Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 19:20:43 +0100 Subject: [PATCH 06/10] format blur_hash_widget_test --- test/blur_hash_widget_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/blur_hash_widget_test.dart b/test/blur_hash_widget_test.dart index 577549d..73c219f 100644 --- a/test/blur_hash_widget_test.dart +++ b/test/blur_hash_widget_test.dart @@ -5,7 +5,7 @@ import 'package:flutter_blurhash/flutter_blurhash.dart'; void main() { testWidgets('BlurHash widget basic smoke test', (WidgetTester tester) async { const String testHash = 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.'; - + // Build a simple widget with just the BlurHash await tester.pumpWidget( MaterialApp( @@ -25,10 +25,10 @@ void main() { // Verify the BlurHash widget exists expect(find.byType(BlurHash), findsOneWidget); - + // Check the BlurHash properties final BlurHash blurHash = tester.widget(find.byType(BlurHash)); expect(blurHash.hash, equals(testHash)); expect(blurHash.image, isNull); }); -} \ No newline at end of file +} From 26c36fe9e39f70ad999b5da9baf26ec8f345cc15 Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 19:24:05 +0100 Subject: [PATCH 07/10] remove --debug from build method --- .github/workflows/prepare.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prepare.yaml b/.github/workflows/prepare.yaml index 356514e..4528117 100644 --- a/.github/workflows/prepare.yaml +++ b/.github/workflows/prepare.yaml @@ -43,7 +43,7 @@ jobs: - name: Build example app working-directory: example - run: flutter build web --debug + run: flutter build web - name: Dry run pub publish # We don't want it to fail the CI, it's just to see how would `pub publish` behave. From 39fcf871e82d8dc3036841ca0d4e2342c777e073 Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 20:05:01 +0100 Subject: [PATCH 08/10] remove comments from the test --- test/blur_hash_widget_test.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/blur_hash_widget_test.dart b/test/blur_hash_widget_test.dart index 73c219f..7e72c13 100644 --- a/test/blur_hash_widget_test.dart +++ b/test/blur_hash_widget_test.dart @@ -6,7 +6,6 @@ void main() { testWidgets('BlurHash widget basic smoke test', (WidgetTester tester) async { const String testHash = 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.'; - // Build a simple widget with just the BlurHash await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -23,10 +22,8 @@ void main() { ), ); - // Verify the BlurHash widget exists expect(find.byType(BlurHash), findsOneWidget); - // Check the BlurHash properties final BlurHash blurHash = tester.widget(find.byType(BlurHash)); expect(blurHash.hash, equals(testHash)); expect(blurHash.image, isNull); From b2d8957b4184f73c54575b623ac2460dfa259deb Mon Sep 17 00:00:00 2001 From: Raouf Rahiche Date: Sun, 20 Apr 2025 20:08:37 +0100 Subject: [PATCH 09/10] Turn comments into proper Dartdoc --- example/lib/blurhash_components_demo.dart | 392 +++++++++++----------- 1 file changed, 197 insertions(+), 195 deletions(-) diff --git a/example/lib/blurhash_components_demo.dart b/example/lib/blurhash_components_demo.dart index c923d0d..512ff5c 100644 --- a/example/lib/blurhash_components_demo.dart +++ b/example/lib/blurhash_components_demo.dart @@ -34,183 +34,6 @@ class BlurHashGridScreen extends StatelessWidget { class BlurHashGrid extends StatelessWidget { const BlurHashGrid({super.key}); - // Generate a sample BlurHash for a specific component count - String generateSampleHash(int xComponents, int yComponents) { - // This creates predictable but visually different hashes for each combination - // The format is based on the BlurHash specification where: - // - First digit is the number of components (encoded as base83) - // - Second digit is y components (encoded as base83) - // - The rest are random-looking values that will create a consistent pattern - - // These are sample hashes with varying component counts - switch ('$xComponents,$yComponents') { - case '1,1': - return r'00C=c8'; - case '1,2': - return r'9UC=c8^-'; - case '1,3': - return r'IUC=c8^-%g'; - case '1,4': - return r'RUC=c8^-%gx['; - case '1,5': - return r'aUC=c8^-%gx[o{'; - case '1,6': - return r'jUC=c8^-%gx[o{bW'; - case '1,7': - return r'sUC=c8^-%gx[o{bWNY'; - case '1,8': - return r'$UC=c8^-%gx[o{bWNYR%'; - case '1,9': - return r'=UC=c8^-%gx[o{bWNYR%fi'; - case '2,1': - return r'10C=c800'; - case '2,2': - return r'AUC=c89Y^-D$'; - case '2,3': - return r'JUC=c89Y^-D$%gIT'; - case '2,4': - return r'SUC=c89Y^-D$%gITx[Io'; - case '2,5': - return r'bUC=c89Y^-D$%gITx[Ioo{Rj'; - case '2,6': - return r'kUC=c89Y^-D$%gITx[Ioo{RjbWWC'; - case '2,7': - return r'tUC=c89Y^-D$%gITx[Ioo{RjbWWCNYWV'; - case '2,8': - return r'%UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ay'; - case '2,9': - return r'?UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ayfiWV'; - case '3,1': - return r'26C=c800_M'; - case '3,2': - return r'BUC=c89Yxu^-D$xu'; - case '3,3': - return r'KUC=c89Yxu^-D$xu%gITxa'; - case '3,4': - return r'TUC=c89Yxu^-D$xu%gITxax[Ioof'; - case '3,5': - return r'cUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj['; - case '3,6': - return r'lUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCay'; - case '3,7': - return r'uUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjb'; - case '3,8': - return r'*UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoM'; - case '3,9': - return r'@UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoMfiWVoM'; - case '4,1': - return r'36C=c800_Mra'; - case '4,2': - return r'CUC=c89YxujG^-D$xua#'; - case '4,3': - return r'LUC=c89YxujG^-D$xua#%gITxaj]'; - case '4,4': - return r'UUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;'; - case '4,5': - return r'dUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7'; - case '4,6': - return r'mUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayof'; - case '4,7': - return r'vUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkB'; - case '4,8': - return r'+UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbF'; - case '4,9': - return r'[UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbFfiWVoMa{'; - case '5,1': - return r'46C=c800_MraMw'; - case '5,2': - return r'DUC=c89YxujGWA^-D$xua#R%'; - case '5,3': - return r'MUC=c89YxujGWA^-D$xua#R%%gITxaj]WB'; - case '5,4': - return r'VUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rj'; - case '5,5': - return r'eUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%'; - case '5,6': - return r'nUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWB'; - case '5,7': - return r'wUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWB'; - case '5,8': - return r',UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFay'; - case '5,9': - return r']UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFayfiWVoMa{oL'; - case '6,1': - return r'56C=c800_MraMw=y'; - case '6,2': - return r'EUC=c89YxujGWAs:^-D$xua#R%W:'; - case '6,3': - return r'NUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-'; - case '6,4': - return r'WUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9'; - case '6,5': - return r'fUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oe'; - case '6,6': - return r'oUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj['; - case '6,7': - return r'xUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@'; - case '6,8': - return r'-UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7'; - case '6,9': - return r'^UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7fiWVoMa{oLWW'; - case '7,1': - return r'66C=c800_MraMw=y=g'; - case '7,2': - return r'FUC=c89YxujGWAs:sp^-D$xua#R%W:a~'; - case '7,3': - return r'OUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]'; - case '7,4': - return r'XUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oM'; - case '7,5': - return r'gUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoM'; - case '7,6': - return r'pUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]'; - case '7,7': - return r'yUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bH'; - case '7,8': - return r'.UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j['; - case '7,9': - return r'_UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j[fiWVoMa{oLWWoL'; - case '8,1': - return r'76C=c800_MraMw=y=gTH'; - case '8,2': - return r'GUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe'; - case '8,3': - return r'PUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?'; - case '8,4': - return r'YUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWV'; - case '8,5': - return r'hUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:'; - case '8,6': - return r'qUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WC'; - case '8,7': - return r'zUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWC'; - case '8,8': - return r':UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WU'; - case '8,9': - return r'{UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WUfiWVoMa{oLWWoLjZ'; - case '9,1': - return r'86C=c800_MraMw=y=gTHDj'; - case '9,2': - return r'HUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV['; - case '9,3': - return r'QUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jb'; - case '9,4': - return r'ZUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWV'; - case '9,5': - return r'iUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:ax'; - case '9,6': - return r'rUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8'; - case '9,7': - return r'#UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoe'; - case '9,8': - return r';UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*'; - case '9,9': - return r'|UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*fiWVoMa{oLWWoLjZWp'; - default: - return r'L6PZfSi8^6#M@-5c,1J5@[or[Q6.'; // Default fallback hash - } - } - @override Widget build(BuildContext context) { // Create list of all combinations from 1x1 to 10x10 @@ -260,26 +83,205 @@ class BlurHashGridItem extends StatelessWidget { @override Widget build(BuildContext context) { - return Card( - elevation: 2, - child: Column( - children: [ - Expanded( - child: BlurHash( - hash: hash, - duration: const Duration(milliseconds: 500), - optimizationMode: BlurHashOptimizationMode.approximation, - ), + return Column( + children: [ + Expanded( + child: BlurHash( + hash: hash, + duration: const Duration(milliseconds: 500), + optimizationMode: BlurHashOptimizationMode.approximation, ), - Padding( - padding: const EdgeInsets.all(4), - child: Text( - label, - style: const TextStyle(fontWeight: FontWeight.bold), - ), + ), + Padding( + padding: const EdgeInsets.all(4), + child: Text( + label, + style: const TextStyle(fontWeight: FontWeight.bold), ), - ], - ), + ), + ], ); } } + +/// Generates a sample BlurHash for a specific combination of x and y components. +/// +/// This function creates predictable but visually distinct hashes for each +/// combination of x and y components. +/// +/// The function uses predefined sample hashes for varying component counts. +/// +/// Parameters: +/// - `xComponents`: The number of horizontal components in the BlurHash. +/// - `yComponents`: The number of vertical components in the BlurHash. +/// +/// Returns: +/// A string representing the generated BlurHash for the given component counts. +String generateSampleHash(int xComponents, int yComponents) { + switch ('$xComponents,$yComponents') { + case '1,1': + return r'00C=c8'; + case '1,2': + return r'9UC=c8^-'; + case '1,3': + return r'IUC=c8^-%g'; + case '1,4': + return r'RUC=c8^-%gx['; + case '1,5': + return r'aUC=c8^-%gx[o{'; + case '1,6': + return r'jUC=c8^-%gx[o{bW'; + case '1,7': + return r'sUC=c8^-%gx[o{bWNY'; + case '1,8': + return r'$UC=c8^-%gx[o{bWNYR%'; + case '1,9': + return r'=UC=c8^-%gx[o{bWNYR%fi'; + case '2,1': + return r'10C=c800'; + case '2,2': + return r'AUC=c89Y^-D$'; + case '2,3': + return r'JUC=c89Y^-D$%gIT'; + case '2,4': + return r'SUC=c89Y^-D$%gITx[Io'; + case '2,5': + return r'bUC=c89Y^-D$%gITx[Ioo{Rj'; + case '2,6': + return r'kUC=c89Y^-D$%gITx[Ioo{RjbWWC'; + case '2,7': + return r'tUC=c89Y^-D$%gITx[Ioo{RjbWWCNYWV'; + case '2,8': + return r'%UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ay'; + case '2,9': + return r'?UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ayfiWV'; + case '3,1': + return r'26C=c800_M'; + case '3,2': + return r'BUC=c89Yxu^-D$xu'; + case '3,3': + return r'KUC=c89Yxu^-D$xu%gITxa'; + case '3,4': + return r'TUC=c89Yxu^-D$xu%gITxax[Ioof'; + case '3,5': + return r'cUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj['; + case '3,6': + return r'lUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCay'; + case '3,7': + return r'uUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjb'; + case '3,8': + return r'*UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoM'; + case '3,9': + return r'@UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoMfiWVoM'; + case '4,1': + return r'36C=c800_Mra'; + case '4,2': + return r'CUC=c89YxujG^-D$xua#'; + case '4,3': + return r'LUC=c89YxujG^-D$xua#%gITxaj]'; + case '4,4': + return r'UUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;'; + case '4,5': + return r'dUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7'; + case '4,6': + return r'mUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayof'; + case '4,7': + return r'vUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkB'; + case '4,8': + return r'+UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbF'; + case '4,9': + return r'[UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbFfiWVoMa{'; + case '5,1': + return r'46C=c800_MraMw'; + case '5,2': + return r'DUC=c89YxujGWA^-D$xua#R%'; + case '5,3': + return r'MUC=c89YxujGWA^-D$xua#R%%gITxaj]WB'; + case '5,4': + return r'VUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rj'; + case '5,5': + return r'eUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%'; + case '5,6': + return r'nUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWB'; + case '5,7': + return r'wUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWB'; + case '5,8': + return r',UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFay'; + case '5,9': + return r']UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFayfiWVoMa{oL'; + case '6,1': + return r'56C=c800_MraMw=y'; + case '6,2': + return r'EUC=c89YxujGWAs:^-D$xua#R%W:'; + case '6,3': + return r'NUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-'; + case '6,4': + return r'WUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9'; + case '6,5': + return r'fUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oe'; + case '6,6': + return r'oUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj['; + case '6,7': + return r'xUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@'; + case '6,8': + return r'-UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7'; + case '6,9': + return r'^UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7fiWVoMa{oLWW'; + case '7,1': + return r'66C=c800_MraMw=y=g'; + case '7,2': + return r'FUC=c89YxujGWAs:sp^-D$xua#R%W:a~'; + case '7,3': + return r'OUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]'; + case '7,4': + return r'XUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oM'; + case '7,5': + return r'gUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoM'; + case '7,6': + return r'pUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]'; + case '7,7': + return r'yUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bH'; + case '7,8': + return r'.UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j['; + case '7,9': + return r'_UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j[fiWVoMa{oLWWoL'; + case '8,1': + return r'76C=c800_MraMw=y=gTH'; + case '8,2': + return r'GUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe'; + case '8,3': + return r'PUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?'; + case '8,4': + return r'YUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWV'; + case '8,5': + return r'hUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:'; + case '8,6': + return r'qUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WC'; + case '8,7': + return r'zUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWC'; + case '8,8': + return r':UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WU'; + case '8,9': + return r'{UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WUfiWVoMa{oLWWoLjZ'; + case '9,1': + return r'86C=c800_MraMw=y=gTHDj'; + case '9,2': + return r'HUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV['; + case '9,3': + return r'QUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jb'; + case '9,4': + return r'ZUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWV'; + case '9,5': + return r'iUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:ax'; + case '9,6': + return r'rUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8'; + case '9,7': + return r'#UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoe'; + case '9,8': + return r';UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*'; + case '9,9': + return r'|UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*fiWVoMa{oLWWoLjZWp'; + default: + return r'L6PZfSi8^6#M@-5c,1J5@[or[Q6.'; // Default fallback hash + } +} From 52dc7466216a17f457e111c13c0308e69547be5c Mon Sep 17 00:00:00 2001 From: Raouf Easya Date: Tue, 22 Apr 2025 19:39:08 +0100 Subject: [PATCH 10/10] Delete blurhash_components_demo.dart --- example/lib/blurhash_components_demo.dart | 287 ---------------------- 1 file changed, 287 deletions(-) delete mode 100644 example/lib/blurhash_components_demo.dart diff --git a/example/lib/blurhash_components_demo.dart b/example/lib/blurhash_components_demo.dart deleted file mode 100644 index 512ff5c..0000000 --- a/example/lib/blurhash_components_demo.dart +++ /dev/null @@ -1,287 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_blurhash/flutter_blurhash.dart'; - -void main() => runApp(const BlurHashDemoApp()); - -class BlurHashDemoApp extends StatelessWidget { - const BlurHashDemoApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'BlurHash Variations', - theme: ThemeData( - primarySwatch: Colors.blue, - brightness: Brightness.light, - ), - home: const BlurHashGridScreen(), - ); - } -} - -class BlurHashGridScreen extends StatelessWidget { - const BlurHashGridScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: const BlurHashGrid(), - ); - } -} - -class BlurHashGrid extends StatelessWidget { - const BlurHashGrid({super.key}); - - @override - Widget build(BuildContext context) { - // Create list of all combinations from 1x1 to 10x10 - final List> hashCombinations = []; - - for (int x = 1; x <= 9; x++) { - for (int y = 1; y <= 9; y++) { - hashCombinations.add({ - 'x': x, - 'y': y, - 'hash': generateSampleHash(x, y), - 'label': '$x×$y', - }); - } - } - - return GridView.builder( - padding: const EdgeInsets.all(8), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 9, // 3 items per row - childAspectRatio: 1.9, // Square items - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemCount: hashCombinations.length, - itemBuilder: (context, index) { - final item = hashCombinations[index]; - - return BlurHashGridItem( - hash: item['hash'], - label: item['label'], - ); - }, - ); - } -} - -class BlurHashGridItem extends StatelessWidget { - final String hash; - final String label; - - const BlurHashGridItem({ - required this.hash, - required this.label, - super.key, - }); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Expanded( - child: BlurHash( - hash: hash, - duration: const Duration(milliseconds: 500), - optimizationMode: BlurHashOptimizationMode.approximation, - ), - ), - Padding( - padding: const EdgeInsets.all(4), - child: Text( - label, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ), - ], - ); - } -} - -/// Generates a sample BlurHash for a specific combination of x and y components. -/// -/// This function creates predictable but visually distinct hashes for each -/// combination of x and y components. -/// -/// The function uses predefined sample hashes for varying component counts. -/// -/// Parameters: -/// - `xComponents`: The number of horizontal components in the BlurHash. -/// - `yComponents`: The number of vertical components in the BlurHash. -/// -/// Returns: -/// A string representing the generated BlurHash for the given component counts. -String generateSampleHash(int xComponents, int yComponents) { - switch ('$xComponents,$yComponents') { - case '1,1': - return r'00C=c8'; - case '1,2': - return r'9UC=c8^-'; - case '1,3': - return r'IUC=c8^-%g'; - case '1,4': - return r'RUC=c8^-%gx['; - case '1,5': - return r'aUC=c8^-%gx[o{'; - case '1,6': - return r'jUC=c8^-%gx[o{bW'; - case '1,7': - return r'sUC=c8^-%gx[o{bWNY'; - case '1,8': - return r'$UC=c8^-%gx[o{bWNYR%'; - case '1,9': - return r'=UC=c8^-%gx[o{bWNYR%fi'; - case '2,1': - return r'10C=c800'; - case '2,2': - return r'AUC=c89Y^-D$'; - case '2,3': - return r'JUC=c89Y^-D$%gIT'; - case '2,4': - return r'SUC=c89Y^-D$%gITx[Io'; - case '2,5': - return r'bUC=c89Y^-D$%gITx[Ioo{Rj'; - case '2,6': - return r'kUC=c89Y^-D$%gITx[Ioo{RjbWWC'; - case '2,7': - return r'tUC=c89Y^-D$%gITx[Ioo{RjbWWCNYWV'; - case '2,8': - return r'%UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ay'; - case '2,9': - return r'?UC=c89Y^-D$%gITx[Ioo{RjbWWCNYWVR%ayfiWV'; - case '3,1': - return r'26C=c800_M'; - case '3,2': - return r'BUC=c89Yxu^-D$xu'; - case '3,3': - return r'KUC=c89Yxu^-D$xu%gITxa'; - case '3,4': - return r'TUC=c89Yxu^-D$xu%gITxax[Ioof'; - case '3,5': - return r'cUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj['; - case '3,6': - return r'lUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCay'; - case '3,7': - return r'uUC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjb'; - case '3,8': - return r'*UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoM'; - case '3,9': - return r'@UC=c89Yxu^-D$xu%gITxax[Ioofo{Rjj[bWWCayNYWVjbR%ayoMfiWVoM'; - case '4,1': - return r'36C=c800_Mra'; - case '4,2': - return r'CUC=c89YxujG^-D$xua#'; - case '4,3': - return r'LUC=c89YxujG^-D$xua#%gITxaj]'; - case '4,4': - return r'UUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;'; - case '4,5': - return r'dUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7'; - case '4,6': - return r'mUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayof'; - case '4,7': - return r'vUC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkB'; - case '4,8': - return r'+UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbF'; - case '4,9': - return r'[UC=c89YxujG^-D$xua#%gITxaj]x[Ioofs;o{Rjj[t7bWWCayofNYWVjbkBR%ayoMbFfiWVoMa{'; - case '5,1': - return r'46C=c800_MraMw'; - case '5,2': - return r'DUC=c89YxujGWA^-D$xua#R%'; - case '5,3': - return r'MUC=c89YxujGWA^-D$xua#R%%gITxaj]WB'; - case '5,4': - return r'VUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rj'; - case '5,5': - return r'eUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%'; - case '5,6': - return r'nUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWB'; - case '5,7': - return r'wUC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWB'; - case '5,8': - return r',UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFay'; - case '5,9': - return r']UC=c89YxujGWA^-D$xua#R%%gITxaj]WBx[Ioofs;Rjo{Rjj[t7R%bWWCayofWBNYWVjbkBWBR%ayoMbFayfiWVoMa{oL'; - case '6,1': - return r'56C=c800_MraMw=y'; - case '6,2': - return r'EUC=c89YxujGWAs:^-D$xua#R%W:'; - case '6,3': - return r'NUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-'; - case '6,4': - return r'WUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9'; - case '6,5': - return r'fUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oe'; - case '6,6': - return r'oUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj['; - case '6,7': - return r'xUC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@'; - case '6,8': - return r'-UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7'; - case '6,9': - return r'^UC=c89YxujGWAs:^-D$xua#R%W:%gITxaj]WBW-x[Ioofs;Rjk9o{Rjj[t7R%oebWWCayofWBj[NYWVjbkBWBj@R%ayoMbFayf7fiWVoMa{oLWW'; - case '7,1': - return r'66C=c800_MraMw=y=g'; - case '7,2': - return r'FUC=c89YxujGWAs:sp^-D$xua#R%W:a~'; - case '7,3': - return r'OUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]'; - case '7,4': - return r'XUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oM'; - case '7,5': - return r'gUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoM'; - case '7,6': - return r'pUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]'; - case '7,7': - return r'yUC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bH'; - case '7,8': - return r'.UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j['; - case '7,9': - return r'_UC=c89YxujGWAs:sp^-D$xua#R%W:a~%gITxaj]WBW-j]x[Ioofs;Rjk9oMo{Rjj[t7R%oeoMbWWCayofWBj[j]NYWVjbkBWBj@bHR%ayoMbFayf7j[fiWVoMa{oLWWoL'; - case '8,1': - return r'76C=c800_MraMw=y=gTH'; - case '8,2': - return r'GUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe'; - case '8,3': - return r'PUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?'; - case '8,4': - return r'YUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWV'; - case '8,5': - return r'hUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:'; - case '8,6': - return r'qUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WC'; - case '8,7': - return r'zUC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWC'; - case '8,8': - return r':UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WU'; - case '8,9': - return r'{UC=c89YxujGWAs:spba^-D$xua#R%W:a~oe%gITxaj]WBW-j]j?x[Ioofs;Rjk9oMWVo{Rjj[t7R%oeoMe:bWWCayofWBj[j]WCNYWVjbkBWBj@bHWCR%ayoMbFayf7j[WUfiWVoMa{oLWWoLjZ'; - case '9,1': - return r'86C=c800_MraMw=y=gTHDj'; - case '9,2': - return r'HUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV['; - case '9,3': - return r'QUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jb'; - case '9,4': - return r'ZUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWV'; - case '9,5': - return r'iUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:ax'; - case '9,6': - return r'rUC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8'; - case '9,7': - return r'#UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoe'; - case '9,8': - return r';UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*'; - case '9,9': - return r'|UC=c89YxujGWAs:spbaRj^-D$xua#R%W:a~oeV[%gITxaj]WBW-j]j?jbx[Ioofs;Rjk9oMWVWVo{Rjj[t7R%oeoMe:axbWWCayofWBj[j]WCk8NYWVjbkBWBj@bHWCoeR%ayoMbFayf7j[WUf*fiWVoMa{oLWWoLjZWp'; - default: - return r'L6PZfSi8^6#M@-5c,1J5@[or[Q6.'; // Default fallback hash - } -}