Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/prepare.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 29 additions & 9 deletions lib/src/blurhash.dart
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,39 @@ Future<Uint8List> 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<double> _sRGBLookupTable = _createSRGBLookupTable(256);

List<double> _createSRGBLookupTable(int size) {
final table = List<double>.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 {
// Faster approximation with square roots
final vv = sqrt(v);
final vvv = sqrt(vv);
return ((1.055 * vv * vvv - 0.055) * 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<Uint8List> blurHashDecode({
Expand Down
31 changes: 31 additions & 0 deletions test/blur_hash_widget_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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.';

await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
width: 200,
height: 200,
child: BlurHash(
hash: testHash,
),
),
),
),
),
);

expect(find.byType(BlurHash), findsOneWidget);

final BlurHash blurHash = tester.widget(find.byType(BlurHash));
expect(blurHash.hash, equals(testHash));
expect(blurHash.image, isNull);
});
}