1

I'm trying to get my google map markers to generate icons from firebase storage, I've tried a few things with BitmapDescriptor and Uint8list but fail to understand what is needed to make this work. What is needed to make the markers icons from network images? I've seen this plugin but it doesn't work for web. What do I need to do to make the code below show markers as icons.

deleted old bad example code

I've updated the code attempting to implement Curt's suggestions. I finally have it down to one error that seems I'm very close.

  1. [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, Unable to interpret bytes as a valid image., null, java.lang.IllegalArgumentException: Unable to interpret bytes as a valid image.

When I print the bytes it comes out as a series of numbers, when I print _bitmapDesciptor I unfortunately get "Instance of 'BitmapDescriptor'" which backs up the error message.

What do I need to do to get it to interpret correctly?

import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../models/marker_collect_model.dart';

class ShowMapPublic extends StatefulWidget {
  @override
  _ShowMapState createState() => _ShowMapState();
}

class _ShowMapState extends State<ShowMapPublic> {
  GoogleMapController? controller;
  List<Marker> list = [];
  List<String> listDocuments = [];

  void _onMapCreated(GoogleMapController controllerParam) {
    setState(() {
      controller = controllerParam;
    });
  }

  void readDataFromFirebase() async {
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    CollectionReference<Map<String, dynamic>> collectionReference =
        firestore.collection('2022BHAM');
    collectionReference.snapshots().listen((event) async {
      List<DocumentSnapshot> snapshots = event.docs;
      for (var map in snapshots) {
        Map<String, dynamic> data =
            map.data() as Map<String, dynamic>; // add this line
        MarkerCollectModel model =
            await MarkerCollectModel.fromMap(data); // use data here
        String nameDocument = map.id;
        listDocuments.add(nameDocument);
        Marker marker = await createMarker(model, nameDocument);
        setState(() {
          list.add(marker);
        });
      }
    });
  }

  Future<BitmapDescriptor> _buildMarkerIcon(String pathImage) async {
    // Fetch the PNG
    Image _image = await Image.network(pathImage);

    // Encode the image as a list of ints
    List<int> list = utf8.encode(_image.toString());

    // Convert the int list into an unsigned 8-bit bytelist
    Uint8List bytes = Uint8List.fromList(list);

    // And construct the BitmapDescriptor from the bytelist
    BitmapDescriptor _bitmapDescriptor = BitmapDescriptor.fromBytes(bytes);

    // And return the product
    return _bitmapDescriptor;
  }

  Future<Marker> createMarker(
      MarkerCollectModel markerCollectModel, String nameDocument) async {
    Marker marker;
    marker = Marker(
      markerId: MarkerId(nameDocument),
      icon: await _buildMarkerIcon(markerCollectModel.urlavatar!),
      position: LatLng(markerCollectModel.lat!, markerCollectModel.lng!),
    );
    return marker;
  }

  Set<Marker> myMarkers() {
    return list.toSet();
  }

  // Method
  @override
  void initState() {
    super.initState();
    readDataFromFirebase();
  }

  @override
  Widget build(BuildContext context) {
    CameraPosition cameraPosition =
        CameraPosition(target: LatLng(40.788717, -99.496509), zoom: 2.5);
    return Scaffold(
        backgroundColor: Colors.black,
        body: Center(
            child: Stack(
          children: <Widget>[
            GoogleMap(
              initialCameraPosition: cameraPosition,
              markers: myMarkers(),
              onMapCreated: _onMapCreated,
            ),
          ],
        )));
  }
}

giroprotagonist
  • 138
  • 1
  • 3
  • 15

2 Answers2

1

The icon is supposed to be BitmapDescriptor class. The class can only be initialized with a json, through the BitmapDescriptor.fromJson() constructor. The json is supposed to describe the color of the marker, mostly the color. See the official docs here.

If you have to use an image as an icon, you should use the flutter_map package. It would mean you will have to redo a lot of your code though. This tutorial might help.

Mudassir
  • 725
  • 6
  • 28
  • Thanks for your suggestions, I got it to work with fluttermap pretty quickly but fluttermap seems clunky still compared to google map. I will continue to read about how to do it, I just don't understand how to make it work with my existing setup, still new to programming. I have worked with the link you provided a few days ago and also could not make it work with my existing code though I did get it to function on it's own. – giroprotagonist Oct 23 '21 at 23:06
  • @giroprotagonist - I've made this work with google maps, but it's been a long time ago. Are you still interested in an answer? I'll go dig through old code if you are. – Curt Eckhart Nov 19 '21 at 20:51
  • Hey again @CurtEckhart! I would love to be able to pull it off on google maps. I've since completely rebuilt it with fluttermap as you can see, it looks pretty good but I really want the google map layers for my project. I would certainly appreciate it if it wasn't too much effort thanks. – giroprotagonist Nov 19 '21 at 22:06
  • I've written up an approach that I would use if I had to do this. – Curt Eckhart Nov 19 '21 at 22:33
  • @CurtEckhart I've picked this back up still trying to make it work properly, I have it down to only one error now, would greatly appreciate any suggestions, code is updated up top. – giroprotagonist Oct 27 '22 at 17:14
0

First know that this answer should be read as a solution outline. I didn't implement any of this in actual working code. That being said, it should work. I've put this solution together based on reading the various documentations, and this is what I would try if I were actually going to code it.

Constraint: Per Google documentation, the image being loaded must be encoded (or at least returned) as a PNG.

Solution Plan

BitmapDescriptor provides a FromBytes method that can be used to construct a BitMapDescriptor from a serialized data stream.

Next, observe that Image provides a toString() method that will convert your loaded image into a string.

Then you can convert that string into a Uint8List by leveraging a couple of utility methods.

List<int> list = utf8.encode(source);
Uint8List bytes = Uint8List.fromList(list);

(Shout out to Osama Gamal for providing this part of the solution in a previous answer)

And finally use BitmapDescriptor.FromBytes() to produce the icon data.

Again, assuming that the network image that you load is a PNG as required by BitMapDescriptor, it seems possible to reach your target.

Putting it all together...

I have written this as an async method. There are other ways to wait for the image to come in, but this is easiest for illustration purposes.

You will 'await _buildMarkerIcon(foo)' or '_buildMarkerIcon(foo).then((Bitmap Descriptor bmd) { use it }' as your use case requires.

Good luck and I hope this helps someone.

BitmapDescriptor _buildMarkerIcon(String pathImage) async {
  // Fetch the PNG
  Image _image = await Image.network(pathImage);

  // Encode the image as a list of ints
  List<int> list = utf8.encode(_image.toString());

  // Convert the int list into an unsigned 8-bit bytelist
  Uint8List bytes = Uint8List.fromList(list);

  // And construct the BitmapDescriptor from the bytelist
  BitmapDescriptor _bitmapDescriptor = BitmapDescriptor.fromBytes(bytes);

  // And return the product
  return _bitmapDescriptor;
}
Curt Eckhart
  • 455
  • 5
  • 11
  • Thanks for this great effort Curt, very much appreciated. I've made an edit to my original post showing the now somewhat improperly implemented code and the resulting errors. I will continue to try to wrap my head around it but I think at this point it's my programming experience that's coming up short. Thanks again. – giroprotagonist Nov 20 '21 at 00:00
  • I've picked this back up still trying to make it work properly, I have it down to only one error now, would greatly appreciate any suggestions, code is updated up top. – giroprotagonist Oct 27 '22 at 17:29