kelsheikh
kelsheikh

Reputation: 1338

Add text on top of image and share image with button tap

I have been trying to add text on top of an image and then allow the user to share the image. I'm having two issues that I can't seem to figure out.

  1. The text is overflowing off the screen and not wrapping in the TextPainter when adding to Canvas.

  2. I have been trying to share the image using a FloatingActionButton. The issue I am having is sharing an actual image and not image string. I have been using the esys_flutter_share package to try and achieve it but I get an error. I really just want to share the Image that I wrote the text on top of.

Unhandled Exception: type 'Image' is not a subtype of type 'String'

.

Any help is greatly appreciated.

import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:flutter/services.dart' show rootBundle;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var _imageUrl = 'https://imageurl.png';
  var _img;
  var nimg;

  @override
  void initState() {

    _showImg();

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var widget =
    _img != null ? Image.memory(_img) : Text('pleace click button');
    return Scaffold(
      appBar: AppBar(),
      body: Center(child: widget),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {

          final ByteData bytes = await rootBundle.load(nimg);
          await Share.file('esys image', '$nimg', bytes.buffer.asUint8List(), 'image/png');

        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }


  _showImg() async{
    var uri = Uri.parse(_imageUrl);
    var httpClient = HttpClient();
    var request = await httpClient.getUrl(uri);
    var response = await request.close();
    var imageData = <int>[];
    await response.forEach((data) async {
      imageData.addAll(data);
    });

    ui.Image image =
        await decodeImageFromList(Uint8List.fromList(imageData));
    var pictureRecorder = ui.PictureRecorder();
    var canvas = Canvas(pictureRecorder);
    var paint = Paint();
    paint.isAntiAlias = true;

    var src = Rect.fromLTWH(
        0.0, 0.0, image.width.toDouble(), image.height.toDouble());
    var dst = Rect.fromLTWH(
        0.0, 0.0, image.width.toDouble(), image.height.toDouble());
    canvas.drawRect(Rect.fromLTWH(0.0, 0.0, 200.0, 200.0), paint);
    canvas.drawImageRect(image, src, dst, paint);


    //Add text on image
    TextSpan span = new TextSpan(
        style: new TextStyle(color: Colors.white, fontSize: 150.0,
            fontFamily: 'Roboto'), text: "Here is some great text to put on top");
    TextPainter tp = new TextPainter(
        text: span, textDirection: TextDirection.ltr, textAlign: TextAlign.center);
    tp.layout();
    tp.paint(canvas, new Offset(image.width/2 - image.width/2 /2, image.height/2 - image.height/2 /3));


    var pic = pictureRecorder.endRecording();
    ui.Image img = await pic.toImage(image.width, image.height);
    var byteData = await img.toByteData(format: ui.ImageByteFormat.png);
    var buffer = byteData.buffer.asUint8List();

    //Assign image to be shared
    nimg = img;

    //Set the image as the child in the body
    setState(() {
      _img = buffer;
    });
  }

}

Upvotes: 4

Views: 2157

Answers (2)

Jim
Jim

Reputation: 7601

The easiest way to share image with text:

  1. Create a Stack and put Image in it, positioned the Text widget anywhere you want on the image.

  2. Wrap Stack with RepaintBoundary

  3. Screenshot with

RenderRepaintBoundary boundary = _globalKey.currentContext.findRenderObject();
Image image = await boundary.toImage();
  1. Share with esys_flutter_share

PS. Of course you can also use image packages to add text to image.

Upvotes: 4

Sharad Paghadal
Sharad Paghadal

Reputation: 2154

esys_flutter_share is not having capability of sharing both data type at a same time. I have faced this issue and fixed by taking this package in my code and editing it's methods that allows us to share both data type. Here is the edited package files.

How to take packages in local code?

Checkout this answer

The updated code url is this, download it and follow above answer.

Upvotes: 1

Related Questions