APP_NEW/lib/Class/Screenshot/screenshot.dart
2025-03-11 21:17:14 +08:00

163 lines
5.4 KiB
Dart

import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:lamiter/Class/Screenshot/screenshot_widget.dart';
import 'package:lamiter/Provider/Diagnosis/Diagnosis_Item/constitution_provider.dart';
import 'package:lamiter/Provider/Diagnosis/Diagnosis_Item/urban_disease_provider.dart';
import 'package:lamiter/Provider/Diagnosis/Diagnosis_Item/posture_issue_provider.dart';
import 'package:lamiter/Provider/Diagnosis/Diagnosis_Item/symptom_provider.dart';
import 'package:lamiter/Provider/Language/language_provider.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class Screenshot {
final List<ScreenshotWidget> children;
final double width = 2024;
const Screenshot({
required this.children,
});
Future<void> screenshot(Locale locale) async {
final pngBytes = await _mergeWidgetsToPng(
children,
locale,
width: width,
pixelRatio: 1,
);
if (pngBytes == null) return;
await ImageGallerySaver.saveImage(
pngBytes,
quality: 60,
);
}
// 合併多個 widget 的 PNG bytes
Future<Uint8List?> _mergeWidgetsToPng(
List<Widget> widgets,
Locale locale, {
required double width,
double pixelRatio = 1.0,
}) async {
final images = <ui.Image>[];
// 渲染每個 widget 成為圖片
for (var widget in widgets) {
final image = await _widgetToImage(widget, width, locale);
if (image == null) return null;
images.add(image);
}
// 計算合併後圖像的總高度
final totalHeight =
images.fold(0.0, (sum, img) => sum + img.height.toDouble());
// 創建畫布
final recorder = ui.PictureRecorder();
final canvas = Canvas(
recorder,
Rect.fromLTWH(0, 0, width * pixelRatio, totalHeight * pixelRatio),
);
// 將圖像逐一繪製到畫布
double currentOffset = 0.0;
for (var image in images) {
final src =
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble());
final dst = Rect.fromLTWH(0, currentOffset * pixelRatio,
width * pixelRatio, image.height.toDouble() * pixelRatio);
canvas.drawImageRect(image, src, dst, Paint());
currentOffset += image.height.toDouble();
}
// 將畫布轉為圖像
final mergedImage = await recorder.endRecording().toImage(
(width * pixelRatio).toInt(), (totalHeight * pixelRatio).toInt());
// 將圖像轉為 PNG bytes
final byteData =
await mergedImage.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List();
}
// 將 widget 轉換為 PNG
Future<ui.Image?> _widgetToImage(
Widget widget, double width, Locale locale) async {
// 創建一個離屏的 RenderRepaintBoundary
final repaintBoundary = RenderRepaintBoundary();
// 創建一個 RenderView 並將 RepaintBoundary 作為子節點
final renderView = RenderView(
child: RenderPositionedBox(
alignment: Alignment.center,
child: repaintBoundary,
),
configuration: ViewConfiguration(
physicalConstraints: BoxConstraints(maxWidth: width),
logicalConstraints: BoxConstraints(maxWidth: width),
devicePixelRatio: 1.0,
),
view: WidgetsBinding.instance.window,
);
// 構建 PipelineOwner
final pipelineOwner = PipelineOwner();
renderView.attach(pipelineOwner);
renderView.prepareInitialFrame();
// pipelineOwner.rootNode = renderView;
// 構建 BuildOwner
final buildOwner = BuildOwner(focusManager: FocusManager());
final constitutionProvider = ConstitutionProvider();
await constitutionProvider.init();
final postureIssueProvider = PostureIssueProvider();
await postureIssueProvider.init();
final symptomProvider = SymptomProvider();
await symptomProvider.init();
final urbanDiseaseProvider = UrbanDiseaseProvider();
await urbanDiseaseProvider.init();
final providerWidgetTree = MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => constitutionProvider),
ChangeNotifierProvider(create: (context) => postureIssueProvider),
ChangeNotifierProvider(create: (context) => symptomProvider),
ChangeNotifierProvider(create: (context) => urbanDiseaseProvider),
ChangeNotifierProvider(create: (context) => LanguageProvider()),
],
child: Localizations(
delegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: locale,
child: widget,
),
);
final renderElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: providerWidgetTree,
).attachToRenderTree(buildOwner);
// 執行布局和繪製
buildOwner.buildScope(renderElement);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
Size size = renderElement.size ?? Size(1, 1);
final pixelRatio = width / size.width;
// 提取圖像
final image = await repaintBoundary.toImage(pixelRatio: pixelRatio);
return image;
}
}