6

Looking for image picker on new flutter web 1.9. I found a way but for less than 1.9, now that is merged dont know how can i achived this. Tried with dart:html but is not working on release! Only on running

3 Answers 3

15

It seems like as for Flutter web 1.10 dev , universal_html package is good candidate for the temporarily vacant position of dart:html:

import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:universal_html/prefer_universal/html.dart' as html;

class ImagePickerLabPage extends StatefulWidget {
  @override
  _ImagePickerLabPageState createState() => _ImagePickerLabPageState();
}

class _ImagePickerLabPageState extends State<ImagePickerLabPage> {
  String name = '';
  String error;
  Uint8List data;

  pickImage() {
    final html.InputElement input = html.document.createElement('input');
    input
      ..type = 'file'
      ..accept = 'image/*';

    input.onChange.listen((e) {
      if (input.files.isEmpty) return;
      final reader = html.FileReader();
      reader.readAsDataUrl(input.files[0]);
      reader.onError.listen((err) => setState(() {
            error = err.toString();
          }));
      reader.onLoad.first.then((res) {
        final encoded = reader.result as String;
        // remove data:image/*;base64 preambule
        final stripped =
            encoded.replaceFirst(RegExp(r'data:image/[^;]+;base64,'), '');

        setState(() {
          name = input.files[0].name;
          data = base64.decode(stripped);
          error = null;
        });
      });
    });

    input.click();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(name),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.open_in_browser),
        onPressed: () {
          pickImage();
        },
      ),
      body: Center(
        child: error != null
            ? Text(error)
            : data != null ? Image.memory(data) : Text('No data...'),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks it's working fine, but how can we keep it's type as Image? I just wanna upload it to firebase, but it's not uploading as Image.
html.InputReader and html.FileReader not importing successfully showing error there. Can you please let us know how to solve it?
@Umair Make sure that you specified correct package in pubspec.yaml, and no other packages in your code imported with html-alias.
Compiler message: lib/main.dart:240:5: Error: Factory redirects to class 'FileReader', which is abstract and can't be instantiated. Target kernel_snapshot failed: Exception: Errors during snapshot creation: null build failed.
@Umair You can create a new question. Show int it your pubspec.yaml and code from lib/main.dart file
|
4

Actually onChange doesn't work well on mobile safari, it need to change addEventListener and also need to append it.

Future<void> _setImage() async {
    final completer = Completer<List<String>>();
    InputElement uploadInput = FileUploadInputElement();
    uploadInput.multiple = true;
    uploadInput.accept = 'image/*';
    uploadInput.click();
    // onChange doesn't work on mobile safari
    uploadInput.addEventListener('change', (e) async {
        // read file content as dataURL
        final files = uploadInput.files;
        Iterable<Future<String>> resultsFutures = files.map((file) {
            final reader = FileReader();
            reader.readAsDataUrl(file);
            reader.onError.listen((error) => completer.completeError(error));
            return reader.onLoad.first.then((_) => reader.result as String);
        });

        final results = await Future.wait(resultsFutures);
        completer.complete(results);
    });
    // need to append on mobile safari
    document.body.append(uploadInput);
    final List<String> images = await completer.future;
    setState(() {
        _uploadedImages = images;
    });
    uploadInput.remove();
}

This also works:

Future<void> _setImage() async {   
    final completer = Completer<List<String>>();
    final InputElement input = document.createElement('input');
    input
      ..type = 'file'
      ..multiple = true
      ..accept = 'image/*';
    input.click();
    // onChange doesn't work on mobile safari
    input.addEventListener('change', (e) async {
      final List<File> files = input.files;
      Iterable<Future<String>> resultsFutures = files.map((file) {
        final reader = FileReader();
        reader.readAsDataUrl(file);
        reader.onError.listen((error) => completer.completeError(error));
        return reader.onLoad.first.then((_) => reader.result as String);
      });
      final results = await Future.wait(resultsFutures);
      completer.complete(results);
    });
    // need to append on mobile safari
    document.body.append(input);
    // input.click(); can be here
    final List<String> images = await completer.future;
    setState(() {
      _uploadedImages = images;
    });
    input.remove();
}

2 Comments

@Bulkin Thank you! saved me as image_picker_web has conflicts with iOS ( for device I use image_picker) and my app runs both on web and device.
holy moly. you are my hero. How on earth did you figure this out? I figured that on mobile web the flutter code was somehow backgrounded during file selection... but I was totally lost on what to change. I need to understand your document.append better
2

why don't you just use: https://pub.dev/packages/image_picker_web

It supports also multiple outputTypes (File, Widget, Uint8List)

2 Comments

I tried this, doesn't work, gives an unknown type on location. If somebody gets it to work, ket me know. It an issue in the package "issues"
but it supports only for web

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.