From 8246408b3622457e4f3efbe79a4663e9d3d324f4 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Tue, 5 Sep 2023 17:03:36 +0800 Subject: [PATCH] Fix copy Image to Clipboard not works on web --- lib/components/image.dart | 34 +++++++++++++++++++++++------ lib/platform/to_png.dart | 6 ++++++ lib/platform/to_png_none.dart | 5 +++++ pubspec.lock | 40 +++++++++++++++++++++++++++++++++++ pubspec.yaml | 1 + 5 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 lib/platform/to_png.dart create mode 100644 lib/platform/to_png_none.dart diff --git a/lib/components/image.dart b/lib/components/image.dart index 1ab9a5f..b084bd0 100644 --- a/lib/components/image.dart +++ b/lib/components/image.dart @@ -1,16 +1,27 @@ -import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:logging/logging.dart'; import 'package:super_clipboard/super_clipboard.dart'; import 'package:super_context_menu/super_context_menu.dart'; +import '../platform/to_png_none.dart' + if (dart.library.html) '../platform/to_png.dart'; final _log = Logger("ImageWithContextMenu"); +enum ImageFmt { + jpg, + png, + gif, +} + class ImageWithContextMenu extends StatelessWidget { - const ImageWithContextMenu(this.data, {Key? key, this.uri}) : super(key: key); + const ImageWithContextMenu(this.data, + {Key? key, this.uri, this.fmt = ImageFmt.jpg}) + : super(key: key); final Uint8List data; final String? uri; + final ImageFmt fmt; @override Widget build(BuildContext context) { return ContextMenuWidget( @@ -18,12 +29,21 @@ class ImageWithContextMenu extends StatelessWidget { var list = [ MenuAction( title: AppLocalizations.of(context)!.copyImage, - callback: () { - final item = DataWriterItem(); - item.add(Formats.jpeg(data)); - ClipboardWriter.instance.write([item]).catchError((err) { + callback: () async { + try { + final item = DataWriterItem(); + if (!kIsWeb) { + item.add(fmt == ImageFmt.jpg + ? Formats.jpeg(data) + : Formats.png(data)); + } else { + item.add(Formats.png( + fmt == ImageFmt.jpg ? await jpgToPng(data) : data)); + } + await ClipboardWriter.instance.write([item]); + } catch (err) { _log.warning("Failed to copy image to clipboard:", err); - }); + } }) ]; if (uri != null) { diff --git a/lib/platform/to_png.dart b/lib/platform/to_png.dart new file mode 100644 index 0000000..7dcc2ca --- /dev/null +++ b/lib/platform/to_png.dart @@ -0,0 +1,6 @@ +import 'dart:typed_data'; +import 'package:image/image.dart'; + +Future jpgToPng(Uint8List data) async { + return encodePng(decodeJpg(data)!); +} diff --git a/lib/platform/to_png_none.dart b/lib/platform/to_png_none.dart new file mode 100644 index 0000000..6685024 --- /dev/null +++ b/lib/platform/to_png_none.dart @@ -0,0 +1,5 @@ +import 'dart:typed_data'; + +Future jpgToPng(Uint8List data) async { + throw UnimplementedError(); +} diff --git a/pubspec.lock b/pubspec.lock index d7c5cd6..aa6f770 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.2.0" + archive: + dependency: transitive + description: + name: archive + sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e" + url: "https://pub.dev" + source: hosted + version: "3.3.8" args: dependency: transitive description: @@ -382,6 +390,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: "direct main" + description: + name: image + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf + url: "https://pub.dev" + source: hosted + version: "4.0.17" infinite_scroll_pagination: dependency: "direct main" description: @@ -558,6 +574,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" pixel_snap: dependency: transitive description: @@ -582,6 +606,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.6" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" pool: dependency: transitive description: @@ -915,6 +947,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8a3fd27..2ebfb7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: flutter_web_plugins: sdk: flutter go_router: ^10.1.0 + image: ^4.0.17 infinite_scroll_pagination: ^4.0.0 intl: any json_annotation: ^4.8.1