Sub6Resources / flutter_html

A Flutter widget for rendering static html as Flutter widgets (Will render over 80 different html tags!)
https://pub.dev/packages/flutter_html
MIT License
1.76k stars 815 forks source link

is local image file supported #478

Closed eliranwong closed 3 years ago

eliranwong commented 3 years ago

First, thanks for developing this useful package. Can you please advise me how the html codes work with local image files, e.g. images stored in user directory? In your example, I can see the image source is online. Is it possible to load image offline?

salvaterra commented 3 years ago

<img src="asset:assets/graphics/art.png">

eliranwong commented 3 years ago

thanks a lot for reply. It works in assets folder. Impressive!

How about if I want to load image file from user directory? what should I put in place of "asset:"?

for example, if I have an image with a full path, myUserDirectoryPath/graphics/art.png ?

erickok commented 3 years ago

That would depend on where the image is. Unless it is in your own private app folder, you won't be able to directly refer to a file.

eliranwong commented 3 years ago

I put image in shared user directory, accessible by users. The assets folder has a problem that I cannot pack the appbundle file and upload to google play store if the file is larger than 150 MB. I have image files, greater than 500MB. So, I need users to put in shared user directory and access image from there.

I got the user directory path by the following codes:

class StorageMx {

// Check if storage permission is granted. static Future checkStoragePermission() async { final permissionResult = await Permission.storage.request(); return (permissionResult.isGranted) ? true : false; }

// get user directory static Future getUserDirectoryPath() async { if (await checkStoragePermission()) { final Directory userDirectory = (Platform.isAndroid) ? await getExternalStorageDirectory() : await getApplicationDocumentsDirectory(); return userDirectory.path; } else { return ""; } }

}

erickok commented 3 years ago

If these files are content your app needs to function, then you should not put them in external storage directory on Android.

eliranwong commented 3 years ago

the images file are not necessary for my app to run.

I am writting a bible app. If users want additional bible maps, they can download to user directory. so the feature is optional. the app does not depends the image file to run.

I want to load those images with flutter_html. is that possible?

ryan-berger commented 3 years ago

@erickok This seems similar to previous issues that have been raised to add your own image URI resolver. I don't believe we have this now, so is this a duplicate of other issues that want to be able to resolve image URIs however they would like?

erickok commented 3 years ago

Yes, I think a custom image resolver would... resolve these type of issues. Something to work on I guess because what the issue creator wants I believe is currently not possible (yet totally reasonable).

ryan-berger commented 3 years ago

Is accessing the filesystem not feasible in Flutter? On the Android side I thought you could set up a storage provider for your app so that you can write to the filesystem, and then when you want to load in images Flutter could fetch the bytes and you could render the raw image.

Also maybe such a fetch would be quite slow with Flutter? Communication between Flutter/Native seems to be something that should be done as little as possible with as little data as possible and isn't built for something larger like image transfer, but most of the Flutter apps I've built don't require much and are mostly just API calls and nothing too Native.

If this really isn't possible and you can't get images from the filesystem with Flutter (for iOS or Android) then I think that the issue should be closed due to it being infeasible.

Otherwise, lets create a new issue or find the "file resolver" issue and reference this issue there so when it gets closed we can close this one as well. I think that it would be a really good feature to have and something that I could look into and shouldn't be to hard to implement

eliranwong commented 3 years ago

Thanks a lot for replies. If local image in shared directory cannot be read directly, can I first covert it to base64 and put in img tag. Does flutter_html support base64 String.

erickok commented 3 years ago

The problem isn't that you can't read files of course on Android. But depending on where the files are and who owns them you can or cannot directly access them via the normal IO. For example, if a photo gets shared to your app, you'll just get a stream handle, and not get an actual file handle.

If you, like the OP, want to download additional (non-elemental) content on the fly, to augment the user experience, I still highly recommend downloading to the apps' protected own storage. This isn't data that you want to share with other apps (logically, regardless of security) and your app can access these files without difficulty.

For flutter_html, we'd still need a mechanism where you can tell how to resolve images. At the moment we support the following:

You can already override loading of images altogether by using a customRenderer for img. We could add explicit support for file: and event content: url's to a friendlier user experience.

Levy787 commented 3 years ago

I'm trying to use the local asset file

<img src="asset:assets/images/retro_logo.png">

but getting a URI error,

The following ArgumentError was thrown resolving an image codec:
Invalid argument(s): No host specified in URI file:///assets/images/logo_retro.png

When the exception was thrown, this was the stack: 
#0      _HttpClient._openUrl (dart:_http/http_impl.dart:2407:9)
#1      _HttpClient.getUrl (dart:_http/http_impl.dart:2328:48)
#2      NetworkImage._loadAsync (package:flutter/src/painting/_network_image_io.dart:89:59)
#3      NetworkImage.load (package:flutter/src/painting/_network_image_io.dart:50:14)
#4      ImageProvider.resolveStreamForKey.<anonymous closure> (package:flutter/src/painting/image_provider.dart:504:13)
...
Image provider: NetworkImage("assets/images/logo_retro.png", scale: 1.0)
Image key: NetworkImage("assets/images/logo_retro.png", scale: 1.0)

It seems like even with the asset: at the the beginning of the img src, it's still trying to get a NetworkImage.

Levy787 commented 3 years ago

I'm trying to use the local asset file

<img src="asset:assets/images/retro_logo.png">

but getting a URI error,

The following ArgumentError was thrown resolving an image codec:
Invalid argument(s): No host specified in URI file:///assets/images/logo_retro.png

When the exception was thrown, this was the stack: 
#0      _HttpClient._openUrl (dart:_http/http_impl.dart:2407:9)
#1      _HttpClient.getUrl (dart:_http/http_impl.dart:2328:48)
#2      NetworkImage._loadAsync (package:flutter/src/painting/_network_image_io.dart:89:59)
#3      NetworkImage.load (package:flutter/src/painting/_network_image_io.dart:50:14)
#4      ImageProvider.resolveStreamForKey.<anonymous closure> (package:flutter/src/painting/image_provider.dart:504:13)
...
Image provider: NetworkImage("assets/images/logo_retro.png", scale: 1.0)
Image key: NetworkImage("assets/images/logo_retro.png", scale: 1.0)

It seems like even with the asset: at the the beginning of the img src, it's still trying to get a NetworkImage.

For anyone having this issue, be sure to give your app a hot restart, it should work fine then.

erickok commented 3 years ago

Identical request to #304. Let's discuss in #497 on an API that would suit you.

erickok commented 3 years ago

With #505 merged you could already do this fairly easily. For example:

  // Some path to where your images are
  final localRoot = "/app/accessible/path/to/images";

  // Handle all paths that start with a / and treat as local
    (attr, _) => attr["src"] != null && attr["src"].startsWith("/wiki"):
        (context, attr, element) {
      final file = File(localRoot + attr["src"]);
      return Image.file(file);
    },

I'm not sure if we need more first-party support beyond this?