🚀运行效果展示

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

鸿蒙+Flutter 跨平台开发——图片像素化:拼豆爱好者的福音

前言

拼豆艺术作为一种流行的手工创作形式,近年来受到越来越多人的喜爱。它通过将不同颜色的小豆子按照像素图案排列组合,创造出各种生动有趣的作品。然而,对于很多拼豆爱好者来说,如何将自己喜欢的图片转化为合适的像素图案是一个难题。传统的像素化工具要么操作复杂,要么效果不理想,无法满足拼豆爱好者的需求。

随着鸿蒙系统的快速发展和Flutter跨平台框架的成熟,我们有机会开发一款专为拼豆爱好者设计的图片像素化应用。本文将介绍如何使用Flutter框架开发一款运行在鸿蒙系统上的图片像素化应用,帮助拼豆爱好者轻松将任何图片转化为适合拼豆创作的像素图案。

应用介绍

功能特点

我们开发的图片像素化应用具有以下核心功能:

  1. 图片选择功能:支持从相册选择图片或拍照获取图片
  2. 像素化处理:将原图转化为带有清晰网格线的像素风格图片
  3. 参数调整:支持调整横轴切割数量,控制像素块大小
  4. 色系系统选择:支持多种色系系统,适配不同品牌的拼豆产品
  5. 拼豆信息计算:自动计算所需拼豆数量和作品尺寸
  6. 结果展示:实时展示原图和像素化后的对比效果

技术架构

应用采用Flutter框架开发,实现了鸿蒙和其他平台的跨平台支持。整体架构如下:

用户界面

图片选择模块

像素化处理模块

参数调整模块

结果展示模块

图片数据管理

参数配置管理

核心功能实现及代码展示

1. 项目初始化与配置

首先,我们需要创建一个Flutter项目,并配置必要的依赖:

name: pixel_art_app
description: A pixel art generator for bead art enthusiasts

publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ^3.6.2

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  image_picker: ^1.1.2

2. 主应用架构

应用采用Material Design 3设计风格,支持浅色和深色主题:

import 'package:flutter/material.dart';
import 'dart:math' show min, max, cos, sin, sqrt;
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:image_picker/image_picker.dart' show ImagePicker, ImageSource;

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

/// 像素艺术应用主类
class PixelArtApp extends StatelessWidget {
  const PixelArtApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '拼豆像素生成器',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      themeMode: ThemeMode.system,
      home: const PixelArtHomePage(),
    );
  }
}

3. 图片选择功能

实现了从相册选择图片和拍照功能:

/// 选择图片
Future<void> _pickImage(String source) async {
  try {
    // 鸿蒙平台暂时不支持image_picker,使用模拟数据
    // final XFile? image = await _picker.pickImage(source: source);
    // if (image != null) {
    //   final Uint8List bytes = await image.readAsBytes();
    //   final ui.Codec codec = await ui.instantiateImageCodec(bytes);
    //   final ui.FrameInfo frameInfo = await codec.getNextFrame();
    //   setState(() {
    //     _originalImage = frameInfo.image;
    //     _pixelatedImage = null;
    //   });
    //   _pixelateImage();
    // }
  } catch (e) {
    // 处理图片选择错误
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('图片选择失败')),
    );
  }
}

4. 像素化算法实现

核心的像素化算法,直接在原图上绘制网格线:

/// 像素化图片
Future<void> _pixelateImage() async {
  if (_originalImage == null) return;
  
  final ui.PictureRecorder recorder = ui.PictureRecorder();
  final ui.Canvas canvas = ui.Canvas(recorder);
  
  final int originalWidth = _originalImage!.width;
  final int originalHeight = _originalImage!.height;
  
  // 使用横轴切割数量计算像素块的大小
  final int pixelWidth = _horizontalCutCount;
  // 保持图片的宽高比
  final double aspectRatio = originalWidth / originalHeight;
  final int pixelHeight = (pixelWidth / aspectRatio).round();
  
  // 计算每个像素块的实际大小
  final double blockWidth = originalWidth / pixelWidth;
  final double blockHeight = originalHeight / pixelHeight;
  
  // 1. 直接绘制原图,保留原图的所有颜色信息
  canvas.drawImage(_originalImage!, Offset.zero, Paint());
  
  // 2. 绘制网格线,形成像素块效果
  final ui.Paint gridPaint = ui.Paint()
    ..color = Colors.black.withOpacity(0.5) // 增加网格线的不透明度,使其更明显
    ..strokeWidth = 1.0
    ..style = ui.PaintingStyle.stroke;
  
  // 绘制竖线
  for (int x = 0; x <= pixelWidth; x++) {
    final double xPos = x * blockWidth;
    canvas.drawLine(
      Offset(xPos, 0),
      Offset(xPos, originalHeight.toDouble()),
      gridPaint,
    );
  }
  
  // 绘制横线
  for (int y = 0; y <= pixelHeight; y++) {
    final double yPos = y * blockHeight;
    canvas.drawLine(
      Offset(0, yPos),
      Offset(originalWidth.toDouble(), yPos),
      gridPaint,
    );
  }
  
  // 生成像素化图片
  final ui.Picture picture = recorder.endRecording();
  final ui.Image pixelatedImage = await picture.toImage(originalWidth, originalHeight);
  
  setState(() {
    _pixelatedImage = pixelatedImage;
  });
}

5. 参数调整功能

实现了横轴切割数量、颜色合并阈值等参数的调整:

// 横轴切割数量和颜色合并阈值
Row(
  children: [
    Expanded(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('横轴切割数量 (10-300):'),
          const SizedBox(height: 8),
          TextField(
            keyboardType: TextInputType.number,
            controller: TextEditingController(text: _horizontalCutCount.toString()),
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
              contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
            ),
            onSubmitted: (value) {
              final int? count = int.tryParse(value);
              if (count != null && count >= 10 && count <= 300) {
                setState(() {
                  _horizontalCutCount = count;
                  _pixelateImage();
                });
              }
            },
          ),
        ],
      ),
    ),
    const SizedBox(width: 16),
    Expanded(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('颜色合并阈值 (0-100):'),
          const SizedBox(height: 8),
          TextField(
            keyboardType: TextInputType.number,
            controller: TextEditingController(text: _colorMergeThreshold.toString()),
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
              contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
            ),
            onSubmitted: (value) {
              final int? threshold = int.tryParse(value);
              if (threshold != null && threshold >= 0 && threshold <= 100) {
                setState(() {
                  _colorMergeThreshold = threshold;
                  _pixelateImage();
                });
              }
            },
          ),
        ],
      ),
    ),
  ],
),

6. 色系系统选择

支持多种色系系统的选择:

// 色系系统
Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    const Text('色系系统:'),
    const SizedBox(height: 8),
    Wrap(
      spacing: 8.0,
      runSpacing: 8.0,
      children: _colorSystemOptions.map((String value) {
        return ElevatedButton(
          style: ElevatedButton.styleFrom(
            backgroundColor: _colorSystem == value ? Colors.blue : Colors.grey,
            foregroundColor: Colors.white,
          ),
          onPressed: () {
            setState(() {
              _colorSystem = value;
              _pixelateImage();
            });
          },
          child: Text(value),
        );
      }).toList(),
    ),
  ],
),

7. 结果展示功能

使用CustomPaint直接绘制原图和像素化后的图片:

// 原图和像素图对比
Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    // 原图
    Expanded(
      child: Column(
        children: [
          const Text('原图'),
          const SizedBox(height: 8),
          SizedBox(
            width: 150,
            height: 150,
            child: _originalImage != null
                ? CustomPaint(
                    painter: ImagePainter(_originalImage!),
                    size: const Size(150, 150),
                  )
                : const CircularProgressIndicator(),
          ),
        ],
      ),
    ),
    const SizedBox(width: 20),
    // 像素图
    Expanded(
      child: Column(
        children: [
          const Text('像素图'),
          const SizedBox(height: 8),
          SizedBox(
            width: 150,
            height: 150,
            child: _pixelatedImage != null
                ? CustomPaint(
                    painter: ImagePainter(_pixelatedImage!),
                    size: const Size(150, 150),
                  )
                : const CircularProgressIndicator(),
          ),
        ],
      ),
    ),
  ],
),

8. 自定义图片绘制器

实现了自定义的ImagePainter类,用于绘制图片:

/// 图片绘制器,用于在CustomPaint中绘制ui.Image对象
class ImagePainter extends CustomPainter {
  final ui.Image image;
  
  ImagePainter(this.image);
  
  
  void paint(Canvas canvas, Size size) {
    // 计算图片绘制的缩放比例,保持宽高比
    final double scale = min(size.width / image.width, size.height / image.height);
    final double scaledWidth = image.width * scale;
    final double scaledHeight = image.height * scale;
    
    // 计算居中绘制的偏移量
    final double offsetX = (size.width - scaledWidth) / 2;
    final double offsetY = (size.height - scaledHeight) / 2;
    
    // 绘制图片
    canvas.drawImageRect(
      image,
      Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
      Rect.fromLTWH(offsetX, offsetY, scaledWidth, scaledHeight),
      Paint(),
    );
  }
  
  
  bool shouldRepaint(covariant ImagePainter oldDelegate) {
    return oldDelegate.image != image;
  }
}

应用流程

应用的主要流程如下:

从相册选择

拍照

使用示例图片

启动应用

显示首页

用户选择图片

加载图片

拍摄图片

加载内置示例图片

显示原图

用户调整参数

生成像素化图片

显示对比结果

用户可重新调整参数

计算拼豆信息

显示拼豆数量和尺寸

总结

应用优势

  1. 跨平台支持:基于Flutter框架开发,支持鸿蒙系统和其他主流平台
  2. 操作简单:直观的界面设计,用户可以轻松上手
  3. 效果出色:保留原图的颜色和细节,生成清晰的像素化效果
  4. 功能丰富:支持多种参数调整和色系系统选择
  5. 实用性强:自动计算拼豆数量和作品尺寸,方便用户购买材料

未来改进方向

  1. 支持更多图片格式:目前主要支持常见的图片格式,未来可以扩展支持更多格式
  2. 添加图片编辑功能:如裁剪、旋转等,方便用户预处理图片
  3. 实现图片保存和分享:支持将像素化后的图片保存到相册或分享给朋友
  4. 添加社区功能:让用户可以分享自己的作品,交流创作经验
  5. 优化算法性能:进一步优化像素化算法,提高处理速度

结论

通过使用Flutter框架开发鸿蒙平台的图片像素化应用,我们成功实现了一个功能丰富、操作简单、效果出色的拼豆辅助工具。这款应用不仅为拼豆爱好者提供了便利,也展示了Flutter在鸿蒙系统上的强大跨平台能力。

随着鸿蒙系统的不断发展和Flutter框架的持续优化,我们有理由相信,未来会有更多优秀的跨平台应用出现在鸿蒙生态中。我们也将继续改进这款应用,为拼豆爱好者提供更好的服务。


以上就是我们开发的鸿蒙+Flutter跨平台图片像素化应用的详细介绍。希望这篇文章能对正在学习Flutter开发或对拼豆艺术感兴趣的读者有所帮助。如果您有任何问题或建议,欢迎在评论区留言讨论。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐