Flutter图像模糊预览插件blurhash_ffi的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter图像模糊预览插件blurhash_ffi的使用

blurhash_ffi 是一个用于Flutter的插件,它实现了基于C语言的FFI(Foreign Function Interface)Blurhash编解码器。该插件支持Android、iOS、Linux、macOS和Windows平台,并且在性能和质量上与官方Blurhash实现相匹配。

blurhash_ffi

使用方法

添加依赖

要在项目中使用blurhash_ffi,首先需要在pubspec.yaml文件中添加依赖:

dependencies:
  blurhash_ffi: ^latest_version # 替换为最新版本号

编解码示例

单步编解码

以下是一个简单的例子,展示了如何在一个步骤中完成图像的编码和解码:

import 'package:blurhash_ffi/blurhash_ffi.dart';
import 'package:flutter/material.dart';

class BlurhashMyImage extends StatelessWidget {
  final String imageUrl;
  const BlurhashMyImage({required this.imageUrl, super.key});

  @override
  Widget build(BuildContext context) {
    return Image(
      image: BlurhashTheImage(
        NetworkImage(imageUrl), // 可以使用任何你想要的ImageProvider。
        decodingHeight: 1920,
        decodingWidth: 1080,
      ),
      alignment: Alignment.center,
      fit: BoxFit.cover,
    );
  }
}

编码

下面是如何从ImageProvider编码生成Blurhash字符串的例子:

import 'package:blurhash_ffi/blurhash_ffi.dart';

void encodeBlurhash() async {
  final imageProvider = NetworkImage('https://picsum.photos/512');
  try {
    final String blurHash = await BlurhashFFI.encode(imageProvider);
    print('Encoded blurhash: $blurHash');
  } catch (e) {
    print('Failed to encode blurhash: $e');
  }
}

解码

有三种方式可以解码Blurhash:

  1. 使用BlurhashFfi小部件

    import 'package:blurhash_ffi/blurhash_ffi.dart';
    
    class BlurHashApp extends StatelessWidget {
      const BlurHashApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(title: const Text("BlurHash")),
          body: const SizedBox.expand(
            child: Center(
              child: AspectRatio(
                aspectRatio: 1.6,
                child: BlurhashFfi(hash: "L5H2EC=PM+yV0g-mq.wG9c010J}I"),
              ),
            ),
          ),
        ),
      );
    }
    
  2. 使用BlurhashFfiImage作为ImageProvider

    import 'package:blurhash_ffi/blurhash_ffi.dart';
    
    final imageProvider = BlurhashFfiImage("L5H2EC=PM+yV0g-mq.wG9c010J}I");
    
    class BlurHashApp2 extends StatelessWidget {
      const BlurHashApp2({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          appBar: AppBar(title: const Text("BlurHash")),
          body: const SizedBox.expand(
            child: Center(
              child: AspectRatio(
                aspectRatio: 1.6,
                child: Image(
                  image: imageProvider,
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ),
        ),
      );
    }
    
  3. 使用静态方法BlurhashFfi.decode返回ui.Image

    import 'package:blurhash_ffi/blurhash_ffi.dart';
    import 'dart:ui' as ui;
    
    void decodeBlurhash() async {
      try {
        final ui.Image image = await BlurhashFFI.decode("L5H2EC=PM+yV0g-mq.wG9c010J}I");
        // 处理解码后的image
      } catch (e) {
        print('Failed to decode blurhash: $e');
      }
    }
    

释放资源

当不再需要进行Blurhash编解码时,记得释放相关资源:

import 'package:blurhash_ffi/blurhash_ffi.dart';

void releaseResources() {
  BlurhashFFi.free();
}

完整示例代码

为了更好地理解如何在实际应用中使用blurhash_ffi,这里提供了一个完整的示例代码,展示了如何选择图片并显示其对应的Blurhash效果:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:blurhash_ffi/blurhash_ffi.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<String>? blurHashResult;
  int selectedImage = -1;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Blurhash FFI Example'),
        ),
        body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(10),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [1, 2, 3].map<Widget>((e) {
                    var assetName = e == 1
                        ? 'assets/images/$e.jpg'
                        : 'assets/images/$e.png';
                    return MaterialButton(
                      padding: EdgeInsets.zero,
                      onPressed: () async {
                        blurHashResult = BlurhashFFI.encode(
                          AssetImage(assetName),
                        );
                        setState(() {
                          selectedImage = e;
                        });
                      },
                      child: ImageSelect(
                        imageProvider: AssetImage(assetName),
                        isSelected: selectedImage == e,
                      ),
                    );
                  }).toList(),
                ),
                if (blurHashResult != null)
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: FutureBuilder(
                      future: blurHashResult,
                      builder: (context, snapshot) => snapshot.hasData
                          ? Text('blurhash: ${snapshot.data}')
                          : const CircularProgressIndicator(),
                    ),
                  ),
                if (blurHashResult != null)
                  Align(
                    alignment: Alignment.center,
                    child: SizedBox(
                      height: 120,
                      width: 120,
                      child: FutureBuilder(
                          future: blurHashResult,
                          builder: (context, snapshot) {
                            if (snapshot.hasData) {
                              return BlurhashFfi(
                                hash: snapshot.data!,
                                decodingWidth: 120,
                                decodingHeight: 120,
                                imageFit: BoxFit.cover,
                                color: Colors.grey,
                                onReady: () => debugPrint('Blurhash ready'),
                                onDisplayed: () =>
                                    debugPrint('Blurhash displayed'),
                                errorBuilder: (context, error, stackTrace) =>
                                    Container(
                                        color: Colors.red,
                                        child: const Center(
                                            child: Text('Error',
                                                style: TextStyle(
                                                    color: Colors.white,
                                                    fontSize: 20,
                                                    fontWeight:
                                                        FontWeight.bold)))),
                              );
                            }
                            return const Center(
                              child: CircularProgressIndicator(),
                            );
                          }),
                    ),
                  )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class ImageSelect extends StatelessWidget {
  final ImageProvider imageProvider;
  final bool isSelected;
  const ImageSelect(
      {super.key, required this.imageProvider, this.isSelected = false});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Container(
        decoration: BoxDecoration(
          border: isSelected ? Border.all(color: Colors.blue, width: 2) : null,
        ),
        child: Image(
          image: imageProvider,
          width: 100,
          height: 100,
        ),
      ),
    );
  }
}

通过上述内容,您可以快速上手blurhash_ffi插件,在您的Flutter应用中实现高效的图像模糊预览功能。更多详细信息和高级用法,请参考官方GitHub仓库


更多关于Flutter图像模糊预览插件blurhash_ffi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图像模糊预览插件blurhash_ffi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用blurhash_ffi插件来实现图像模糊预览的示例代码。这个插件利用Blurhash算法来生成和渲染图像的模糊预览,非常适合在图像加载前显示一个占位符。

步骤1:添加依赖

首先,你需要在pubspec.yaml文件中添加blurhash_ffi依赖:

dependencies:
  flutter:
    sdk: flutter
  blurhash_ffi: ^0.6.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

步骤2:导入依赖并生成Blurhash

你需要一个Blurhash字符串来生成模糊预览。通常,Blurhash字符串是由服务器端生成的,然后与你的图像URL一起返回。为了演示,这里我们假设你已经有了一个Blurhash字符串。

import 'package:flutter/material.dart';
import 'package:blurhash_ffi/blurhash_ffi.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Blurhash FFI Example'),
        ),
        body: Center(
          child: BlurhashDemo(),
        ),
      ),
    );
  }
}

class BlurhashDemo extends StatefulWidget {
  @override
  _BlurhashDemoState createState() => _BlurhashDemoState();
}

class _BlurhashDemoState extends State<BlurhashDemo> {
  // 假设你有一个Blurhash字符串
  final String blurhash = "LHEFNQExQ2lE$x%!x%3uI#ux!p-H7";

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        // 使用BlurhashImageView显示模糊预览
        BlurhashImageView(
          hash: blurhash,
          width: 300,
          height: 300,
          // 你可以在这里添加占位符颜色
          fallbackColor: Colors.grey[300]!,
        ),
        SizedBox(height: 20),
        // 真正的图像加载完成后显示
        Image.network(
          'https://example.com/your-image-url.jpg',  // 替换为实际的图像URL
          width: 300,
          height: 300,
        ),
      ],
    );
  }
}

// 自定义BlurhashImageView组件(如果插件没有直接提供)
class BlurhashImageView extends StatelessWidget {
  final String hash;
  final double width;
  final double height;
  final Color fallbackColor;

  BlurhashImageView({
    required this.hash,
    required this.width,
    required this.height,
    this.fallbackColor = Colors.transparent,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: Size(width, height),
      painter: BlurhashPainter(
        hash: hash,
        size: Size(width, height),
        fallbackColor: fallbackColor,
      ),
    );
  }
}

class BlurhashPainter extends CustomPainter {
  final String hash;
  final Size size;
  final Color fallbackColor;

  BlurhashPainter({
    required this.hash,
    required this.size,
    this.fallbackColor = Colors.transparent,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint();
    final ImageProvider imageProvider = MemoryImage(BlurhashDecoder.decode(hash, size.width, size.height));
    final ImagePainter imagePainter = ImagePainter(imageProvider, size: size);

    // 如果Blurhash解码失败,则使用fallbackColor绘制
    try {
      imagePainter.paint(canvas, size);
    } catch (_) {
      paint.color = fallbackColor;
      canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}

// 注意:BlurhashDecoder是一个假设的类,实际使用中需要查看blurhash_ffi的文档来确定如何解码Blurhash字符串为图像数据。
// 由于blurhash_ffi的API可能会变化,这里只提供了一个大致的实现思路。
// 你可能需要使用Blurhash.decodeToImage或其他API来实现Blurhash的解码。

注意事项

  1. BlurhashDecoder:上面的代码中的BlurhashDecoder是一个假设的类。你需要查阅blurhash_ffi的文档,了解如何正确解码Blurhash字符串为图像数据。
  2. ImagePainter:同样,ImagePainter也是一个示例类。你可能需要使用Flutter提供的CanvasPaint类来手动绘制解码后的图像。
  3. MemoryImage:这个类用于从内存中的图像数据创建ImageProvider。你可能需要根据blurhash_ffi解码后的实际数据类型进行调整。

请确保查阅最新的blurhash_ffi文档,因为API可能会有所变化。希望这个示例能帮助你理解如何在Flutter中使用blurhash_ffi插件来实现图像模糊预览。

回到顶部