Commit 35706230 by tanghuan

微信小程序卡片分享指令处理

1 parent 89a67320
...@@ -3,7 +3,8 @@ import 'dart:io'; ...@@ -3,7 +3,8 @@ import 'dart:io';
import 'package:appframe/config/constant.dart'; import 'package:appframe/config/constant.dart';
import 'package:appframe/services/dispatcher.dart'; import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/file_type_util.dart'; import 'package:appframe/utils/file_type_util.dart';
import 'package:appframe/utils/thumbnail_util.dart'; import 'package:appframe/utils/image_util.dart';
import 'package:appframe/utils/video_util.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:image_size_getter/file_input.dart'; import 'package:image_size_getter/file_input.dart';
import 'package:image_size_getter/image_size_getter.dart'; import 'package:image_size_getter/image_size_getter.dart';
...@@ -64,10 +65,9 @@ class ChooseFileHandler extends MessageHandler { ...@@ -64,10 +65,9 @@ class ChooseFileHandler extends MessageHandler {
// 通过image_size_getter获取图片尺寸 // 通过image_size_getter获取图片尺寸
var sizeResult = ImageSizeGetter.getSizeResult(FileInput(originalFile)); var sizeResult = ImageSizeGetter.getSizeResult(FileInput(originalFile));
var size = sizeResult.size; var size = sizeResult.size;
imgWidth = sizeResult.size.width; imgWidth = size.width;
imgHeight = sizeResult.size.height; imgHeight = size.height;
final tempDir = await getTemporaryDirectory(); imgThumbFilePath = await ImageUtil.genTempThumbnail(originalFile.path);
imgThumbFilePath = await ThumbnailUtil.genTempThumbnail(originalFile, tempDir);
} }
double? videoWidth, videoHeight; double? videoWidth, videoHeight;
...@@ -82,7 +82,8 @@ class ChooseFileHandler extends MessageHandler { ...@@ -82,7 +82,8 @@ class ChooseFileHandler extends MessageHandler {
controller.dispose(); controller.dispose();
final tempDir = await getTemporaryDirectory(); final tempDir = await getTemporaryDirectory();
videoThumbFilePath = await ThumbnailUtil.genVideoThumbnail(originalFile.path, tempDir); final thumbnailPath = '${tempDir.path}/video_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';
videoThumbFilePath = await VideoUtil.genVideoThumbnail(originalFile.path, thumbnailPath);
} }
// 返回临时文件信息 // 返回临时文件信息
......
import 'dart:io';
import 'package:appframe/config/locator.dart'; import 'package:appframe/config/locator.dart';
import 'package:appframe/services/dispatcher.dart'; import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/image_util.dart';
import 'package:dio/dio.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
class ShareHandler extends MessageHandler { class ShareHandler extends MessageHandler {
@override @override
...@@ -9,17 +15,43 @@ class ShareHandler extends MessageHandler { ...@@ -9,17 +15,43 @@ class ShareHandler extends MessageHandler {
throw Exception('参数错误'); throw Exception('参数错误');
} }
var weapp = params['weapp'] as Map<String, dynamic>?; var weapp = params['weapp'];
if (weapp is! Map<String, dynamic>) {
throw Exception('参数错误');
}
var title = weapp['title'] as String? ?? '';
var imageUrl = weapp['imageUrl'] as String? ?? '';
var path = weapp['path'] as String? ?? '';
var appid = weapp['appid'] as String? ?? '';
var desc = weapp['desc'] as String? ?? '';
var envVersion = weapp['envVersion'] as String? ?? '';
if (title.isEmpty || imageUrl.isEmpty || path.isEmpty || appid.isEmpty) {
throw Exception('参数错误');
}
// 1 将图片下载到本机
var imagePath = await _downloadToTemporaryDirectory(imageUrl);
// 2 对图片生成缩略图
// 微信官方要求小程序卡片缩略图数据不能大于 128K,否则分享失败,因此要生成缩略图处理
var thumbPath = await ImageUtil.genTempThumbnail(imagePath, width: 640, quality: 14);
// 3 读取缩略图为Uint8List
var thumbData = await File(thumbPath!).readAsBytes();
try { try {
var model = WeChatShareMiniProgramModel(
webPageUrl: imageUrl,
miniProgramType: _getWXMiniProgramType(envVersion),
userName: appid,
path: path,
title: title,
description: desc,
thumbData: thumbData,
);
Fluwx fluwx = getIt.get<Fluwx>(); Fluwx fluwx = getIt.get<Fluwx>();
return await fluwx.share(WeChatShareMiniProgramModel( return await fluwx.share(model);
title: weapp?['title'] as String,
webPageUrl: weapp?['imageUrl'] as String,
path: weapp?['path'] as String,
userName: weapp?['appid'] as String,
miniProgramType: _getWXMiniProgramType(weapp?['envVersion'] as String?),
));
} catch (e) { } catch (e) {
print(e); print(e);
return false; return false;
...@@ -38,4 +70,31 @@ class ShareHandler extends MessageHandler { ...@@ -38,4 +70,31 @@ class ShareHandler extends MessageHandler {
return WXMiniProgramType.preview; return WXMiniProgramType.preview;
} }
} }
///
/// 将http资源下载到临时目录
/// 返回下载后的路径
///
Future<String> _downloadToTemporaryDirectory(String url) async {
// 要保存的文件名和扩展名
String saveFileName = path.basenameWithoutExtension(url);
String ext = path.extension(url);
// 临时目录
var dir = await getTemporaryDirectory();
// 要保存的路径
var targetPath = path.join(dir.path, '$saveFileName.$ext');
// 如果文件存在,则在文件名后添加数字
int i = 1;
while (File(targetPath).existsSync()) {
targetPath = path.join(dir.path, '$saveFileName($i).$ext');
i++;
}
final resp = await Dio().download(url, targetPath);
if (resp.statusCode != 200) {
throw Exception('文件下载失败');
}
return targetPath;
}
} }
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:path_provider/path_provider.dart';
class ImageUtil {
/// 使用 ffmpeg_kit_flutter_new 生成指定图片的缩略图
///
/// [imagePath] 原始图片路径
/// [width] 缩略图宽度,默认值为320
/// [quality] JPEG 输出质量 (1-32,数值越小质量越高),默认值为18
/// 返回缩略图路径
static Future<String?> genTempThumbnail(String imagePath, {int width = 320, int quality = 18}) async {
try {
// 检查源文件是否存在
final imageFile = File(imagePath);
if (!await imageFile.exists()) {
print('源图片文件不存在: $imagePath');
return null;
}
// 创建临时文件路径用于存储缩略图
final tempDir = await getTemporaryDirectory();
final thumbnailPath = '${tempDir.path}/thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';
// 使用 FFmpeg 生成缩略图
// 构建 FFmpeg 命令行参数
String cmd = '-i "$imagePath" ' // 指定输入文件路径
'-vf scale=$width:-1:flags=lanczos ' // 设置缩略图宽度,高度等比缩放,使用 Lanczos 算法提高质量
'-q:v $quality ' // 设置 JPEG 输出质量 (1-32,数值越小质量越高)
'-y ' // 覆盖已存在的输出文件
// '-pix_fmt yuvj420p ' // 指定像素格式以提高兼容性
'"$thumbnailPath"'; // 指定输出文件路径
// 执行 FFmpeg 命令
final session = await FFmpegKit.execute(cmd);
final returnCode = await session.getReturnCode();
// 检查执行结果
if (ReturnCode.isSuccess(returnCode)) {
return thumbnailPath;
} else {
print('生成图片缩略图失败: ${await session.getFailStackTrace()}');
return null;
}
} catch (e) {
print('生成图片缩略图出错: $e');
return null;
}
}
}
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
/// 缩略图工具类
///
class ThumbnailUtil {
/// 在指定目录下生成缩略图
/// 返回缩略图路径
static Future<String?> genTempThumbnail(File imageFile, Directory dir) async {
try {
// 缩略图路径
final tempPath = dir.path;
final targetPath = '$tempPath/thumbnail_${DateTime.now().millisecondsSinceEpoch}.jpg';
// 压缩生成缩略图文件
final compressedFile = await FlutterImageCompress.compressAndGetFile(imageFile.absolute.path, targetPath);
return compressedFile!.path;
} catch (e) {
print('生成缩略图出错: $e');
return null;
}
}
/// 为视频文件生成缩略图
/// 返回缩略图路径
static Future<String?> genVideoThumbnail(String videoPath, Directory dir) async {
try {
final thumbnailPath = '${dir.path}/video_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';
// 使用 ffmpeg_kit_flutter_new 生成视频缩略图
// 构建FFmpeg命令行参数
String cmd = '-i "$videoPath" ' // 指定输入文件路径
'-ss 1 ' // 从视频第1秒处截取画面
'-vframes 1 ' // 只截取一帧画面
'-vf scale=128:-1 ' // 设置缩略图宽度为128像素,高度按比例缩放
'-y ' // 覆盖已存在的输出文件
'"$thumbnailPath"'; // 指定输出文件路径
final session = await FFmpegKit.execute(cmd);
final returnCode = await session.getReturnCode();
if (ReturnCode.isSuccess(returnCode)) {
return thumbnailPath;
} else {
print('生成视频缩略图失败: ${await session.getFailStackTrace()}');
return null;
}
} catch (e) {
print('生成视频缩略图出错: $e');
return null;
}
}
}
...@@ -68,4 +68,36 @@ class VideoUtil { ...@@ -68,4 +68,36 @@ class VideoUtil {
final returnCode = await session.getReturnCode(); final returnCode = await session.getReturnCode();
return ReturnCode.isSuccess(returnCode); return ReturnCode.isSuccess(returnCode);
} }
/// 为视频文件生成缩略图
/// [videoPath] 要生成缩略图的视频文件路径
/// [thumbnailPath] 要生成的缩略图文件路径
/// 返回缩略图路径
static Future<String?> genVideoThumbnail(String videoPath, String thumbnailPath) async {
try {
// final thumbnailPath = '${dir.path}/video_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg';
// 使用 ffmpeg_kit_flutter_new 生成视频缩略图
// 构建FFmpeg命令行参数
String cmd = '-i "$videoPath" ' // 指定输入文件路径
'-ss 1 ' // 从视频第1秒处截取画面
'-vframes 1 ' // 只截取一帧画面
'-vf scale=128:-1 ' // 设置缩略图宽度为128像素,高度按比例缩放
'-y ' // 覆盖已存在的输出文件
'"$thumbnailPath"'; // 指定输出文件路径
final session = await FFmpegKit.execute(cmd);
final returnCode = await session.getReturnCode();
if (ReturnCode.isSuccess(returnCode)) {
return thumbnailPath;
} else {
print('生成视频缩略图失败: ${await session.getFailStackTrace()}');
return null;
}
} catch (e) {
print('生成视频缩略图出错: $e');
return null;
}
}
} }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!