addWatermark function
给图片添加多行水印(左下角位置)
Implementation
Future<Uint8List> addWatermark({
required Uint8List imageBytes,
required List<String> watermarkLines,
Color watermarkColor = Colors.white,
int watermarkOpacity = 204,
double watermarkFontSize = 18,
Color backgroundColor = Colors.black,
int backgroundOpacity = 178,
EdgeInsets padding = const EdgeInsets.all(18),
}) async {
final normalizedWatermarkOpacity = watermarkOpacity.clamp(0, 255);
final normalizedBackgroundOpacity = backgroundOpacity.clamp(0, 255);
ui.Codec? codec;
ui.Image? image;
Picture? picture;
ui.Image? watermarkedImage;
try {
codec = await instantiateImageCodec(imageBytes);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
image = frameInfo.image;
final double imageWidth = image.width.toDouble();
final double imageHeight = image.height.toDouble();
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawImage(image, Offset.zero, Paint());
final textStyle = TextStyle(
color: watermarkColor.withAlpha(normalizedWatermarkOpacity),
fontSize: watermarkFontSize,
fontFamily: 'System',
);
final String watermarkText = watermarkLines.join('\n');
final textSpan = TextSpan(text: watermarkText, style: textStyle);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: imageWidth * 0.6);
final double x = padding.left;
final double y = (imageHeight - textPainter.height - padding.bottom).clamp(
0.0,
imageHeight,
);
final Offset watermarkPosition = Offset(x, y);
final double backgroundWidth = textPainter.width + padding.horizontal;
final double backgroundHeight = textPainter.height + padding.vertical;
final Rect backgroundRect = Rect.fromLTWH(
watermarkPosition.dx - padding.left,
watermarkPosition.dy - padding.top,
backgroundWidth,
backgroundHeight,
);
final Paint backgroundPaint = Paint()
..color = backgroundColor.withAlpha(normalizedBackgroundOpacity)
..maskFilter = MaskFilter.blur(BlurStyle.normal, 2);
canvas.drawRRect(
RRect.fromRectAndRadius(backgroundRect, Radius.circular(8)),
backgroundPaint,
);
textPainter.paint(canvas, watermarkPosition);
picture = recorder.endRecording();
watermarkedImage = await picture.toImage(image.width, image.height);
final ByteData? byteData = await watermarkedImage.toByteData(
format: ImageByteFormat.png,
);
if (byteData == null) {
throw StateError('Failed to encode watermarked image to PNG bytes.');
}
return byteData.buffer.asUint8List();
} finally {
codec?.dispose();
image?.dispose();
picture?.dispose();
watermarkedImage?.dispose();
}
}