增强预览机制
This commit is contained in:
@@ -179,7 +179,15 @@ Future<Response> _getPhotoPreviewHandler(Request req) async {
|
|||||||
return Response.notFound('Photo not found');
|
return Response.notFound('Photo not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
final file = await vips.generatePreview(photo.filePath);
|
// 从查询参数获取宽度和高度
|
||||||
|
final w = int.tryParse(req.url.queryParameters['w'] ?? '');
|
||||||
|
final h = int.tryParse(req.url.queryParameters['h'] ?? '');
|
||||||
|
|
||||||
|
final file = await vips.generatePreview(
|
||||||
|
photo.filePath,
|
||||||
|
w: w,
|
||||||
|
h: h,
|
||||||
|
);
|
||||||
|
|
||||||
if (!await file.exists()) {
|
if (!await file.exists()) {
|
||||||
return Response.notFound('File not found');
|
return Response.notFound('File not found');
|
||||||
@@ -206,7 +214,7 @@ Future<Response> _getPhotoPreviewHandler(Request req) async {
|
|||||||
return Response.ok(
|
return Response.ok(
|
||||||
streamController.stream,
|
streamController.stream,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': photo.mimeType,
|
'Content-Type': 'image/webp',
|
||||||
'Content-Length': file.statSync().size.toString(),
|
'Content-Length': file.statSync().size.toString(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,25 +7,82 @@ class Vips {
|
|||||||
|
|
||||||
Vips({this.vipsExecuteFile});
|
Vips({this.vipsExecuteFile});
|
||||||
|
|
||||||
Future<File> generatePreview(String imgPath) async {
|
/// 生成图片预览(WebP 格式)
|
||||||
final imgOut =
|
///
|
||||||
"cache/preview/" + basename(imgPath).hashCode.toString() + ".webp";
|
/// [imgPath] 原图路径
|
||||||
|
/// [w] 预览图宽度(可选)
|
||||||
|
/// [h] 预览图高度(可选)
|
||||||
|
///
|
||||||
|
/// 如果同时指定 [w] 和 [h],图片将按比例缩放以适应指定尺寸
|
||||||
|
Future<File> generatePreview(
|
||||||
|
String imgPath, {
|
||||||
|
int? w,
|
||||||
|
int? h,
|
||||||
|
}) async {
|
||||||
|
// 生成缓存文件名:包含原图 hash 和尺寸信息
|
||||||
|
final baseName = basename(imgPath).hashCode.toString();
|
||||||
|
final sizeSuffix = _buildSizeSuffix(w, h);
|
||||||
|
final imgOut = "cache/preview/${baseName}${sizeSuffix}.webp";
|
||||||
final outFile = File(imgOut);
|
final outFile = File(imgOut);
|
||||||
|
|
||||||
|
// 缓存命中:直接返回已存在的预览图
|
||||||
if (outFile.existsSync()) {
|
if (outFile.existsSync()) {
|
||||||
return outFile;
|
return outFile;
|
||||||
}
|
}
|
||||||
final result = await Process.run("vips", [
|
|
||||||
"webpsave",
|
// 确保缓存目录存在
|
||||||
imgPath,
|
await outFile.parent.create(recursive: true);
|
||||||
imgOut,
|
|
||||||
"--Q",
|
// 构建 vips 命令参数
|
||||||
"80",
|
if (w != null || h != null) {
|
||||||
"--smart-subsample",
|
final thumbnailArgs = <String>[
|
||||||
"--strip",
|
"thumbnail",
|
||||||
]);
|
imgPath,
|
||||||
if (result.exitCode == 0) {
|
imgOut,
|
||||||
|
w?.toString() ?? "0",
|
||||||
|
"--height",
|
||||||
|
h?.toString() ?? "0",
|
||||||
|
];
|
||||||
|
|
||||||
|
final thumbnailResult = await Process.run("vips", thumbnailArgs);
|
||||||
|
if (thumbnailResult.exitCode != 0) {
|
||||||
|
print(thumbnailResult.stderr);
|
||||||
|
throw Exception("vips thumbnail failed!");
|
||||||
|
}
|
||||||
return outFile;
|
return outFile;
|
||||||
|
} else {
|
||||||
|
// 不缩放,直接转换为 WebP 格式
|
||||||
|
final args = <String>[
|
||||||
|
"webpsave",
|
||||||
|
imgPath,
|
||||||
|
imgOut,
|
||||||
|
"--Q",
|
||||||
|
"80",
|
||||||
|
"--effort",
|
||||||
|
"6",
|
||||||
|
"--smart-subsample",
|
||||||
|
];
|
||||||
|
|
||||||
|
final result = await Process.run("vips", args);
|
||||||
|
if (result.exitCode == 0) {
|
||||||
|
return outFile;
|
||||||
|
}
|
||||||
|
print(result.stderr);
|
||||||
|
throw Exception("vips image transcode failed!");
|
||||||
}
|
}
|
||||||
throw Exception("vips image transcode failed!");
|
}
|
||||||
|
|
||||||
|
/// 构建尺寸后缀
|
||||||
|
///
|
||||||
|
/// 例如:
|
||||||
|
/// - w=200, h=150 => "_200x150"
|
||||||
|
/// - w=200, h=null => "_200x0"
|
||||||
|
/// - w=null, h=150 => "_0x150"
|
||||||
|
/// - w=null, h=null => ""
|
||||||
|
String _buildSizeSuffix(int? w, int? h) {
|
||||||
|
if (w == null && h == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "_${w ?? 0}x${h ?? 0}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user