DylanVann / react-native-fast-image

🚩 FastImage, performant React Native image component.
MIT License
8.16k stars 1.5k forks source link

Won't display assets-library URIs on iOS #314

Open airlaser opened 5 years ago

airlaser commented 5 years ago

Using CameraRoll in react native gives a URI formatted as assets-library://asset/asset.... This used to work with this library. It still works with react's Image tag. However, this library now shows a blank image instead. Not sure which build caused it as I'm having trouble rolling back.

vreality64 commented 5 years ago

I've had same problem and wondering what is root cause 🤔

@MacKentoch says the reason is new xcode build system. (#300) However i'm using legacy build system.

My solution is same with @airlaser (using RN Image component) However FlatList have memory leak issue if they used with RN Image. (Ref) If anyone have trouble by using FlatList with react-native-fast-image to load asset-library URI, they really eager to fixed this issue including me.

Or is there another solution for this?

prcbass commented 5 years ago

I am also seeing this issue.

Using legacy build system with XCode 9.4.1

Tried v5.1.0 and v5.0.10 with no success.

Gadigg commented 5 years ago

Just upgraded fast-image and started having this issue... using the newest Xcode and latest releases of react and react native :\

vreality64 commented 5 years ago

I've some researched about this issue and conclude it's SDWebImage's problem. because they does not support PHAsset which is can handle assets-library protocol.

Please check below comments. react-native-fast-image is currently using SDWebImage@4.2.2 and SDWebImage@5.x is still beta yet. (I found current version through Podfile.lock but not sure)

Maybe we can add PHAsset support in 5.x or by a seperate Pods commented on 25 Jan 2018 in SDWebImage repository

Release status of SDWebImage 5.0.0-beta3 was released on 30 Aug 2018.

However ReactNative's Image is supporting assets-library. they have logic for assets-library not like SDWebImage@4.x's local image handling logic which always returns nil about assets-library image.

I think this should be supported by implementing own assets-library handling or upgrading SDWebImage@5.x which is now supporting through SDWebImagePhotosPlugin.

@DylanVann Can you follow up this issue?

tronginc commented 5 years ago

I have the same problem. But I have solved this issue. You may need add width and height to style.

{ this.state.image ? <Image style={{height: 100, width: 100}} source={{uri: this.state.image}} /> : null }
minimaluminium commented 5 years ago

@vreality64 You've done some good research. Seems like SDWebImage 5.0.0 is not that far. Hopefully, react-native-fast-image will be updated once the new version gets released.

vreality64 commented 5 years ago

Now It's possible through latest version react-native-fast-image@6.x by using SDWebImagePhotosPlugin. In react-native-fast-image@6.x, SDWebimage was upgraded to 5.x~ 🕺

thank you @dreampiggy

dreampiggy commented 5 years ago

@vreality64 Actually. It supports for Photos framework (Asset Library has been deprecated).

So you need to query the local identifier and format it like photos://asset/#{original_local_identifier}

I don't test whether the old Asset Library URL format is supported or not :)

vreality64 commented 5 years ago

@dreampiggy Thank you for explanation, I understand. Rewrite local identifier. That's all I have to do for now.

I think It would be best to use Photos Framework instead of AssetLibrary in ReactNative. I hope so be soon 🤣

bobber205 commented 4 years ago

@vreality64 do you have any examples on getting this to build? Simply importing it into a RN project and running pod install clearly isn't enough because I keep getting

Module 'SDWebImage' not found

when building my project.

billdami commented 4 years ago

@vreality64 or anyone else, are you successfully using FastImage with getPhotos() results from @react-native-community/cameraroll? It sounds like FastImage now supports this, but you have to "rewrite the local identifier", do you have an example of that?

For example, camera roll is currently returning me URIs like ph://F2A9F582-BA45-4308-924E-6D146B784A09/L0/001, is that all the data you need to rewrite it into the format required by FastImage?

dreampiggy commented 4 years ago

@billdami For Phoots library, Apple have their own format (called local identifier). FastImage on iOS is backed by SDWebImage, and it have one Photos Support plugin SDWebImagePhotosPlugin. You need to try that.

But that plugin, use the PHAsset object to construct URL, not the simple raw URL. You need the FastImage or custom plugin to provide that object instead, or you can provide the raw local identifier.

Any demo (combined with JavaScript client code, the FastImage library) to test ? I can try to figure out whether it's possible to get that photos pipeline works

dreampiggy commented 4 years ago

Is this ph://F2A9F582-BA45-4308-924E-6D146B784A09/L0/001

actually something returned from Apple's API ? Or this ph:// is that @react-native-community/cameraroll framework, who hard-coded the prefix ?

I check the SDWebImagePhotosPlugin, the local identifier does not have this ph:// prefix, just looks like this:

image

These two string is supported by us for now. But it looks different from those with ph://

Our SDWebImagePhotosPlugin use the custom prefix photos://, but not ph://, if it was hard-coded by react-native-community/cameraroll, we should be unified to use the same URL scheme.

dreampiggy commented 4 years ago

Hard-coded, not anything that generated from Apple :)

https://github.com/react-native-community/react-native-cameraroll/blob/03bc028efe2bf4b603feb25ba3943ec1760f7fe0/ios/RNCCameraRollManager.m#L258

Can anyone communicate with that react-native-community/cameraroll framework maintainer ? Or can we unify to use the same prefix ? If we're not unified, there will always be issues to communicate between different third-party framework who use Photos Library.

dreampiggy commented 4 years ago

I can just compromise to change the SDWebImagePhotosPlugin, from using photos:// to ph://, which is compatible with that react-native-community generated URL. But this is not always a best solution for future maintain. Until there is one Common and Formal Standard for all Photos Library URL format.

dreampiggy commented 4 years ago

@billdami Try to use this branch code instead. Add this to Podfile

pod 'SDWebImagePhotosPlugin', :git => 'https://github.com/dreampiggy/SDWebImagePhotosPlugin.git', :branch => 'change_compatible_with_ph_scheme_react_native'

Then, setup the loader in AppDelegate. See readme of that SDWebImagePhotosPlugin

// Add multiple loaders with Photos Asset support
SDImageLoadersManager.shared.addLoader(SDWebImagePhotosLoader.shared)
SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared
billdami commented 4 years ago

@dreampiggy thanks very much for the response and investigation into this. I will give your branch a try and let you know.

Also, is it possible to configure and use SDWebImagePhotosPlugin/FastImage to render images from the Photos Library/react-native-community/cameraroll with a much smaller image size than the original photo resolution?

dreampiggy commented 4 years ago

@dreampiggy thanks very much for the response and investigation into this. I will give your branch a try and let you know.

Also, is it possible to configure and use SDWebImagePhotosPlugin/FastImage to render images from the Photos Library/react-native-community/cameraroll with a much smaller image size than the original photo resolution?

SDWebImagwPhotosPlugin provide a API to configurate the targetSize contentMode, but it’s available in Objective-C/Swift native API. I don’t test if this available to React world. If not, maybe you need to write your own wrapper of native bridge, or ask for some help for FastImage. I can provide native support (but not React help :()

dreampiggy commented 4 years ago

There are one global configuration of that target size and content mode, you can limit the size. But it’s not appliable for single image request(for example, photos 1 use 1024x768, photos 2 use 3480x2160).

Just check out SDWebImagePhotosPlugin’s readme. All usage are here

dreampiggy commented 4 years ago

@billdami SDWebImagePhotosPlugin v1.0.0 now compatible with that react-native-community/cameraroll.

You can just integrate that plugin (with CocoaPods or Carthage), put the setup code on AppDelegate.m, then using the URL string from cameraroll (like this ph://F2A9F582-BA45-4308-924E-6D146B784A09/L0/001) on FastImage.

@import SDWebImage;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Register the Photos URL support
    [SDImageLoadersManager.sharedManager addLoader:SDImagePhotosLoader.sharedLoader];
    SDWebImageManager.defaultImageLoader = SDImageLoadersManager.sharedManager;
    return YES;
}

And I should mentioned something here: Asset Library (assets-library://) already deprecated from iOS 9.0, and does not works in iOS 13+. It may previouslly work because of Asset Library URL with iOS native URL loading system. But now, you must migrate to use Photos framework instead. Which use a identifier but not a URL format to query image and video.

r0b0t3d commented 4 years ago

I can load images from cameraroll with FastImage but got memory issue when scrolling down to load more photos

Message from debugger: Terminated due to memory issue
  pod 'SDWebImage', '~> 5.0'
  pod 'SDWebImagePhotosPlugin', '~> 1.0'
dreampiggy commented 4 years ago

I can load images from cameraroll with FastImage but got memory issue when scrolling down to load more photos

Message from debugger: Terminated due to memory issue
  pod 'SDWebImage', '~> 5.0'
  pod 'SDWebImagePhotosPlugin', '~> 1.0'

@r0b0t3d Did you check something documentation of SDWebImagePhotosPlugin-Memory Warning ? Which allows some customization about image loading size.

For iPhone X+ devices, the Camera pixel size is higher than 4000x 4000, so it's better to limit the size. You can change the default image pixel size using the APIs. For example like this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Add multiple loaders with Photos Asset support
    [SDImageLoadersManager.sharedManager addLoader:SDWebImagePhotosLoader.sharedLoader];
    // Limit default query pixel size (only 1000x1000)
    SDWebImagePhotosLoader.sharedLoader.imageRequestOptions.sd_targetSize = CGSizeMake(1000, 1000); 
    SDWebImageManager.defaultImageLoader = SDImageLoadersManager.sharedManager;

    return YES;
}
dreampiggy commented 4 years ago

SDWebImage on iOS also support customization through context option, to control on each image request level (not global on manager level, we support both cases because of our user...). But seems the react-native-fast-image does not expose the bridge to JavaScript size ?

When using the context option to control each different image request, you can do it in native code as well (see SDWebImage wiki) Hopeful react-native-fast-image can introduce this as well as Glide on Android ?

 SDWebImageManager.sharedManager.optionsProcessor = [SDWebImageOptionsProcessor optionsProcessorWithBlock:^SDWebImageOptionsResult * _Nullable(NSURL * _Nullable url, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
    SDWebImageMutableContext *mutableContext = [NSDictionary dictionaryWithDictionary:context];
    // Limit size depends on different context or url
    PHImageRequestOptions *imageRequestOptions = PHImageRequestOptions new];
    imageRequestOptions.sd_targetSize = CGSizeMake(1000, 1000);
    if (somethingINeedToUseSmallerPixel()) {
        imageRequestOptions.sd_targetSize = CGSizeMake(500, 500);
    }
    mutableContext[SDWebImageContextPhotosImageRequestOptions] = imageRequestOptions;
     context = [mutableContext copy];

    return [[SDWebImageOptionsResult alloc] initWithOptions:options context:context];
 }];
dreampiggy commented 4 years ago

@dreampiggy thanks very much for the response and investigation into this. I will give your branch a try and let you know.

Also, is it possible to configure and use SDWebImagePhotosPlugin/FastImage to render images from the Photos Library/react-native-community/cameraroll with a much smaller image size than the original photo resolution?

@billdami Sorry that I didn't reply that time. You can do this in the global control, see my comment here: https://github.com/DylanVann/react-native-fast-image/issues/314#issuecomment-581758849

Actually I want to change a proper size to use instead of original pixel size, but I have no idea how a framework should do, because it all depends on your usage.

If you use a imageView which in detail page, just want to showing full pixel image to let user view the full-screen image, the original pixel size should work.

If you use a imageView cell in list page, just want to showing the thumbnail image, then the size should be much lower.

However, this context it not visible to SDWebImage, until you provide .thumbnailPixelSize, .imageRequestOption or other context option to me. Sadly react-native-fast-image does not pass these options to the JavaScript bridge