MoodCanvas/lib/screens/preview/wallpaper_preview_painter.dart
fengshengxiong 91b7eebbf2 接入TopON
2026-01-22 16:34:55 +08:00

159 lines
3.6 KiB
Dart

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:aesthetica_wallpaper/models/recipe.dart';
// 壁纸预览绘制器
class WallpaperPreviewPainter extends CustomPainter {
final ui.Image image;
final Recipe recipe;
WallpaperPreviewPainter({required this.image, required this.recipe});
// 构建颜色矩阵
ColorFilter _buildColorMatrix() {
final double brightness = recipe.brightness;
final double contrast = recipe.contrast;
final double saturation = recipe.saturation;
List<double> matrix = [
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
0,
];
// 应用饱和度
if (saturation != 1.0) {
final sat = saturation;
const lumR = 0.3086;
const lumG = 0.6094;
const lumB = 0.0820;
matrix = [
lumR * (1 - sat) + sat,
lumG * (1 - sat),
lumB * (1 - sat),
0,
0,
lumR * (1 - sat),
lumG * (1 - sat) + sat,
lumB * (1 - sat),
0,
0,
lumR * (1 - sat),
lumG * (1 - sat),
lumB * (1 - sat) + sat,
0,
0,
0,
0,
0,
1,
0,
];
}
// 应用对比度
if (contrast != 1.0) {
final translate = (1.0 - contrast) * 128;
matrix[0] *= contrast;
matrix[5] *= contrast;
matrix[10] *= contrast;
matrix[4] += translate;
matrix[9] += translate;
matrix[14] += translate;
}
// 应用亮度
if (brightness != 0.0) {
final b = brightness * 255;
matrix[4] += b;
matrix[9] += b;
matrix[14] += b;
}
return ColorFilter.matrix(matrix);
}
@override
void paint(Canvas canvas, Size size) {
// 裁剪画布
canvas.clipRect(Offset.zero & size);
// 准备画笔
final Paint paint = Paint()..filterQuality = FilterQuality.low;
// 定义源矩形和目标矩形
final Rect srcRect = Rect.fromLTWH(
0,
0,
image.width.toDouble(),
image.height.toDouble(),
);
final Rect dstRect = Rect.fromLTWH(0, 0, size.width, size.height);
// 应用颜色矩阵
paint.colorFilter = _buildColorMatrix();
// 应用模糊
if (recipe.blur > 0.0) {
paint.imageFilter = ui.ImageFilter.blur(
sigmaX: recipe.blur,
sigmaY: recipe.blur,
);
}
// 绘制图片
canvas.drawImageRect(image, srcRect, dstRect, paint);
// 绘制文字叠加
if (recipe.overlayText.isNotEmpty) {
final textPainter = TextPainter(
text: TextSpan(
text: recipe.overlayText,
style: TextStyle(
fontSize: 32,
color: Color(recipe.textColor),
fontWeight: FontWeight.bold,
),
),
textDirection: ui.TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout(maxWidth: size.width - 40);
final offset = Offset(
(size.width - textPainter.width) / 2,
(size.height - textPainter.height) / 2,
);
textPainter.paint(canvas, offset);
}
}
@override
bool shouldRepaint(covariant WallpaperPreviewPainter oldDelegate) {
return oldDelegate.image != image ||
oldDelegate.recipe.brightness != recipe.brightness ||
oldDelegate.recipe.contrast != recipe.contrast ||
oldDelegate.recipe.saturation != recipe.saturation ||
oldDelegate.recipe.blur != recipe.blur ||
oldDelegate.recipe.overlayText != recipe.overlayText ||
oldDelegate.recipe.textColor != recipe.textColor;
}
}