Загрузить изображение из SharedPreferences в pdf в Flutter

#image #flutter #pdf #sharedpreferences

#изображение #flutter #PDF #sharedpreferences

Вопрос:

Мне нужно загрузить изображение из SharedPreferences в документ pdf. Изображение загружается нормально при обычном использовании, но я не знаю, как заставить его загружаться в PDF. Когда я пытаюсь загрузить его как обычное изображение, я получаю «Необработанное исключение: тип «Изображение» не является подтипом типа «PdfImage»»

Вот как я обычно его использую.

 import 'package:flutter/material.dart';
import 'package:flutter_settings_screens/flutter_settings_screens.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:MyApp/SharedPrefUtility.dart';

Future<void> initSettings() async {
  await Settings.init(
    cacheProvider: SharePreferenceCache(),
  );
}

class ProfilePage extends StatefulWidget {
  @override
  _ProfilePageState createState() => _ProfilePageState();
}

class _ProfilePageState extends State<ProfilePage> {
  Image logo;

  pickImage(ImageSource source) async {
    final _image = await ImagePicker.pickImage(source: ImageSource.gallery);

    if (_image != null) {
      setState(() {
        logo = Image.file(_image);
      });
      ImageSharedPrefs.saveImageToPrefs(
          ImageSharedPrefs.base64String(_image.readAsBytesSync()));
    } else {
      print('Error picking image!');
    }
  }

  loadImageFromPrefs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    final imageKeyValue = prefs.getString(IMAGE_KEY);
    if (imageKeyValue != null) {
      final imageString = await ImageSharedPrefs.loadImageFromPrefs();
      setState(() {
        logo = ImageSharedPrefs.imageFrom64BaseString(imageString);
      });
    }
  }

  @override
  void initState() {
    super.initState();
    loadImageFromPrefs();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.red,
        title: Text('Profile Settings'),
      ),
      body: Center(
        child: ListView(
          children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                ClipRect(
                  child: Container(
                    width: 300,
                    height: 300,
                    child: logo == null ? Text('No image selected.') : logo,
                  ),
                ),
                RaisedButton(
                  onPressed: () {
                    pickImage(ImageSource.gallery);
                  },
                  child: Text('Pick Company Logo'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
  

С помощью SharedPrefUtility.dart

 import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';

const IMAGE_KEY = 'IMAGE_KEY';

class ImageSharedPrefs {
  static Future<bool> saveImageToPrefs(String value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    return await prefs.setString(IMAGE_KEY, value);
  }


  static Future<String> loadImageFromPrefs() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getString(IMAGE_KEY);
  }

  static String base64String(Uint8List data) {
    return base64Encode(data);
  }

  static imageFrom64BaseString(String base64String) {
    return Image.memory(
      base64Decode(base64String),
      fit: BoxFit.contain,
    );
  }
}
  

Любые предложения были бы замечательными.

Ответ №1:

davey06 дал ответ на GitHub

    final imageString = await ImageSharedPrefs.loadImageFromPrefs(); 
// Create a PDF document.
final document = pw.Document();

// Add page to the PDF
document.addPage(pw.Page(build: (context) {
  return pw.Center(
    child: pw.Image(
      PdfImage.file(document.document, bytes: base64Decode(imageString)),
    ),
  );
}));

// Return the PDF file content
return document.save();
  

https://github.com/DavBfr/dart_pdf/issues/477

Комментарии:

1. Вы должны пометить свой собственный ответ как правильный, чтобы он не отображался как неотвеченный для других

Ответ №2:

«Необработанное исключение: тип «Изображение» не является подтипом типа «PdfImage»» — в нем говорится, что вам нужно преобразовать изображение в PdfImage

 import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart ' as pw;

pdf = pw.Document();
PdfImage pdfImage = PdfImage.fromImage(pdf.document, image: logo);

pdf.addPage(
  pw.Page(
    pageFormat: PdfPageFormat.a4,
    build: (context) {
      return pw.Image(arcPdfImage, fit: pw.BoxFit.contain);
    },
  ),
);
  

Комментарии:

1. Привет. Спасибо за быстрый ответ. Я все еще не могу заставить его работать. У меня уже есть рабочий PDF-файл с изображениями из папки assets и из кэша, и все работает на 100%. Мне просто нужно также загрузить изображение из SharedPreferences. Я думал, что это должно быть что-то вроде final logo = ImageSharedPrefs.imageFrom64BaseString(ожидает ImageSharedPrefs.loadImageFromPrefs()); Но я получаю указанную ошибку.

Ответ №3:

Я использую изображения, взятые из моих ресурсов, для создания PDF таким образом:

 PdfImage _logo = PdfImage.file(
    doc.document,
    bytes: (await rootBundle.load('assets/client-logo.png')).buffer.asUint8List(),
  );

//later, during widget tree creation 
pw.Image(_logo, width: 180); 
         
  

Это не совсем то, что вы делаете, но я думаю, что это достаточно близко. Класс PdfImage может принимать в качестве входных данных любой Uint8List для bytes аргумента, поэтому вы должны иметь возможность использовать тот же ввод, который вы используете для base64String метода, который вы определили для ImageSharedPrefs

Комментарии:

1. Привет. Спасибо. Я использую это для изображений из моей папки assets, я также загружаю изображение из кэша. Все работает нормально, кроме изображения из общих настроек. rootBundle можно использовать только для изображений, которые существуют, так сказать, до запуска приложения. Изображение, которое находится в общих настройках, имеет строковый формат, поэтому я пытаюсь преобразовать его так, чтобы pdf мог его прочитать.

2. @Fenix вы пытались показать изображение из настроек в стандартном виджете Flutter, например Image ? Если вы можете управлять этим, скажем, с помощью именованного конструктора Image.memory() , который принимает в качестве входных данных Uint8List, вы должны иметь возможность использовать тот же ввод для PdfImage

3. Привет. Да, я пытаюсь это сделать, но пока никаких результатов. Я уверен, что должен быть способ сделать это, я просто еще не нашел его.