159 lines
3.6 KiB
Dart
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;
|
|
}
|
|
}
|