From 423aae59b1f9a2d98a1584f81bbf3596caaa3860 Mon Sep 17 00:00:00 2001 From: Nicolas Gruber Date: Thu, 11 May 2023 16:57:17 +0200 Subject: [PATCH] implemented making a pdf from DetailPage.dart and croping image to 1:1 format --- lib/AddPage.dart | 27 ++++++++++++++- lib/DetailPage.dart | 57 ++++++++++++++++++++++++++++++- pubspec.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++- pubspec.yaml | 3 ++ 4 files changed, 166 insertions(+), 3 deletions(-) diff --git a/lib/AddPage.dart b/lib/AddPage.dart index cfe5410..5c3dd7a 100644 --- a/lib/AddPage.dart +++ b/lib/AddPage.dart @@ -1,8 +1,10 @@ import 'dart:io'; +import 'dart:math'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:image/image.dart' as img; class AddScreen extends StatefulWidget { @@ -35,6 +37,27 @@ class _AddScreenState extends State { return fileSize <= maxSizeInBytes; } + Future _cropImage(File imageFile) async { + final originalImage = img.decodeImage(await imageFile.readAsBytes()); + + if (originalImage != null) { + int originSize = min(originalImage.width, originalImage.height); + final croppedImage = img.copyCrop( + originalImage, + x: (originalImage.width - originSize)~/2, + y: (originalImage.height - originSize)~/2, + width: originSize, + height: originSize + ); + final newPath = imageFile.path.substring(0, imageFile.path.lastIndexOf('/')); + final newFile = File('$newPath/cropped.jpg'); + await newFile.writeAsBytes(img.encodePng(croppedImage)); + return newFile; + } else { + throw Exception('Unable to decode image file.'); + } + } + Future _getImage(ImageSource source) async { final pickedFile = await ImagePicker().pickImage(source: source); @@ -42,8 +65,9 @@ class _AddScreenState extends State { final tempFile = File(pickedFile.path); final bool isValid = await isFileSizeValid(tempFile, 10); if (isValid) { + File croppedFile = await _cropImage(tempFile); // Bild zuschneiden setState(() { - _imageFile = tempFile; + _imageFile = croppedFile; }); } else { ScaffoldMessenger.of(context).showSnackBar( @@ -53,6 +77,7 @@ class _AddScreenState extends State { } } + Future addNewElementToFirestore(String title, String description, File imageFile, {required Function(bool) onComplete}) async { String collectionName; if (_selectedIndex == 0) { diff --git a/lib/DetailPage.dart b/lib/DetailPage.dart index 74d97eb..7d0ae5a 100644 --- a/lib/DetailPage.dart +++ b/lib/DetailPage.dart @@ -1,5 +1,9 @@ -import 'package:cached_network_image/cached_network_image.dart'; +import 'dart:typed_data'; +import 'package:pdf/widgets.dart' as pdfWidgets; +import 'package:printing/printing.dart'; import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:cached_network_image/cached_network_image.dart'; class DetailPage extends StatelessWidget { final String title; @@ -15,11 +19,62 @@ class DetailPage extends StatelessWidget { required this.imageUrl, }) : super(key: key); + + Future _printPdf() async { + final pdf = pdfWidgets.Document(); + final image = await _loadNetworkImage(imageUrl); + + pdf.addPage( + pdfWidgets.MultiPage( + build: (context) => [ + pdfWidgets.Center( + child: pdfWidgets.SizedBox( + width: double.infinity, // Die Breite auf die maximal mögliche Breite setzen + child: pdfWidgets.AspectRatio( + aspectRatio: 1, // Sie können das Seitenverhältnis entsprechend Ihrem Bild anpassen + child: pdfWidgets.Image(image), + ), + ), + ), + pdfWidgets.Text( + title, + style: pdfWidgets.TextStyle( + fontSize: 20, + fontWeight: pdfWidgets.FontWeight.bold // Titel fett + ) + ), + pdfWidgets.Text(datum, style: const pdfWidgets.TextStyle(fontSize: 14, )), + pdfWidgets.Paragraph(text: description, style: const pdfWidgets.TextStyle(fontSize: 12)), + ], + ), + ); + await Printing.sharePdf(bytes: await pdf.save(), filename: '$title.pdf'); + } + + Future _loadNetworkImage(String url) async { + final response = await http.get(Uri.parse(url)); + + if (response.statusCode != 200) { + throw Exception('Failed to load network image.'); + } + + final Uint8List bytes = response.bodyBytes; + final imageProvider = pdfWidgets.MemoryImage(bytes); + + return imageProvider; + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), + actions: [ + IconButton( + icon: const Icon(Icons.picture_as_pdf), + onPressed: _printPdf, + ), + ], ), body: SingleChildScrollView( child: Column( diff --git a/pubspec.lock b/pubspec.lock index a63eef7..e53bb1f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" + barcode: + dependency: transitive + description: + name: barcode + sha256: "52570564684bbb0240a9f1fdb6bad12adc5e0540103c1c96d6dd550bd928b1c9" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + bidi: + dependency: transitive + description: + name: bidi + sha256: dc00274c7edabae2ab30c676e736ea1eb0b1b7a1b436cb5fe372e431ccb39ab0 + url: "https://pub.dev" + source: hosted + version: "2.0.6" boolean_selector: dependency: transitive description: @@ -312,6 +328,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.16" + image_cropper: + dependency: "direct main" + description: + name: image_cropper + sha256: "710ab4b7953e9ce1d27d833f741e5f8f3afb0b0ba3556dc0b844741b5f55c2b3" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: "09e93a8ec0435adcaa23622ac090442872f18145d70b9ff605ffedcf97d56255" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: "62349e3aab63873ea9b9ab9f69d036ab8a0d74b3004beec4303981386cb9273f" + url: "https://pub.dev" + source: hosted + version: "3.0.3" image_picker: dependency: "direct main" description: @@ -416,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.2" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" path_provider: dependency: transitive description: @@ -464,6 +512,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.6" + pdf: + dependency: "direct main" + description: + name: pdf + sha256: "586d3debf5432e5377044754032cfa53ab45e9abf371d4865e9ad5019570e246" + url: "https://pub.dev" + source: hosted + version: "3.10.1" + pdf_widget_wrapper: + dependency: transitive + description: + name: pdf_widget_wrapper + sha256: "754867bf32c4683da29ccc6bf31250905431fb0818a7258c153e21cd627b3212" + url: "https://pub.dev" + source: hosted + version: "1.0.0" pedantic: dependency: transitive description: @@ -504,6 +568,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.7.3" + printing: + dependency: "direct main" + description: + name: printing + sha256: "6aa86779d51f1c60608defee7b231e1133ab9b00f63b3b71abfa85cb39898571" + url: "https://pub.dev" + source: hosted + version: "5.10.4" process: dependency: transitive description: @@ -512,6 +584,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.4" + qr: + dependency: transitive + description: + name: qr + sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" rxdart: dependency: transitive description: @@ -647,4 +727,4 @@ packages: version: "6.2.2" sdks: dart: ">=2.19.0 <3.0.0" - flutter: ">=3.3.0" + flutter: ">=3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 292470e..79d708c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,9 @@ dependencies: change_app_package_name: ^1.1.0 cached_network_image: ^3.2.3 image: ^4.0.16 + pdf: ^3.10.1 + printing: ^5.10.4 + image_cropper: ^3.0.3 dev_dependencies: