2

I am updated an app from ios7 to ios8 and struggling to get UIImagePicker working to load a picture from the "My Photo Stream" category of photos. The UIImagePicker implementation is standard and I retrieve the URL of the selected photo with:

NSURL *url = [info objectForKey:@"UIImagePickerControllerReferenceURL"];

I then use the new IOS8 APIs for loading this photo:

PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];

This fails to work. The result.count is zero and no image is found. The URL has an different UUID than if I select the photo from "Moments" or "Camera Roll" but looks well formed. (phone is running 8.1):

url NSURL * @"assets-library://asset/asset.JPG?id=4522DBD1-862C-42BE-AF7C-0D6C76CA7590&ext=JPG"

Anyone have some code to load photos from "My Photo Stream" or a way to disable it for the UIImagePicker display?

Using the older ALAssetsLibrary assetForURL API also fails to load these images.

Werner Sharp
  • 121
  • 1
  • 1
  • 6
  • The url is starting with assets-library, so you should use ALAssetsLibrary to get it. – gabbler Oct 27 '14 at 13:26
  • Like I said..."Using the older ALAssetsLibrary assetForURL API also fails to load these images." And the Apple docs for fetchAssetsWithALAssetURLs said it that the URL is "each an asset URL previously retrieved from an ALAsset object." – Werner Sharp Oct 28 '14 at 13:55
  • so the question is "how to load photos from My Photo Stream? – gabbler Oct 28 '14 at 14:10
  • Sure or how on iOS8 do bring up an image picker that shows all available photos and how to load each type. Something weird is going on with 'my photo stream' ones. – Werner Sharp Oct 29 '14 at 12:57
  • Did you ever figure this out? – user3344977 Dec 16 '14 at 02:44
  • We never did figure it out. If the URL fails to load the raw file, we fall back and load it as a UIImage. This doesn't work with our app for PNGs with alpha channel but works fine for JPGs which should be the main format in a photo stream. – Werner Sharp Dec 17 '14 at 14:13
  • Almost half of 2015 and this isn't yet solved? Amazing! – khose Apr 06 '15 at 18:19
  • I got solution check this http://stackoverflow.com/questions/36003835/how-to-get-photo-from-my-photo-stream-album/36004121#36004121 – kb920 Mar 15 '16 at 06:29

5 Answers5

4

I think you can try this to get "my photo stream" album.

PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil];

Photos in My Photo Stream album are uploaded to iCloud and iCloud will manage them efficiently, photos captured within 30 days are there, and I think PHAsset or ALAssetLibrary dealt with locally stored assets. Here is a test I did on my device, I used a imagePicker to get a photo url from stream album, which was

"assets-library://asset/asset.JPG?id=60AE4E50-B835-47EB-B896-5974C21F8C9B&ext=JPG";

And using PHAsset on the same photo I get its localIdentifier:

"60AE4E50-B835-47EB-B896-5974C21F8C9B/L0/001" 

So I think you can strip id from url, and find out which asset's local identifier contains it, then you get the PHAsset you want.

gabbler
  • 13,128
  • 4
  • 29
  • 41
  • Thanks. That does allow you to iterate through the PHAssetCollection and get a list of photos from My Photo Stream but there are no URLs in each PHAsset to match with what UIImagePicker returns for a selected photo in My Photo Stream. Is there a replacement for UIImagePicker in iOS8? – Werner Sharp Oct 29 '14 at 16:47
  • My Photo Stream should appear as an album when you use UIImagePicker,UIImagePicker works on iOS 8, you can use collection view to show the fetched images. I suggest you take a look at the Photos example from Apple. – gabbler Oct 29 '14 at 17:02
  • The Photos example from Apple does not use a UIImagePicker at all. The problem I'm having is the UIImagePicker (which shows the My Photo Stream list) allows selection of this type of Photo but the URL it returns it useless to actually load that file. Neither the new or old API works. These are local Photos on my device so it's not that the image is just in the cloud. – Werner Sharp Oct 29 '14 at 18:45
  • 1
    [info objectForkey:@"UIImagePickerControllerOriginalImage"] will get you the UIImage you want, what you need the url for? – gabbler Oct 30 '14 at 01:18
1

After not finding any answers for this anywhere, I created the following extension to PHAsset which works great as of iOS 8.2 although I assume it's theoretically slow. Even though one of the prior comments says that this is fixed on iOS8.2 beta, the bug was still present for me now that iOS8.2 is released.

import Photos
import UIKit

extension PHAsset {
    class func fetchAssetWithALAssetURL (alURL: NSURL) -> PHAsset? {
        let phPhotoLibrary = PHPhotoLibrary.sharedPhotoLibrary()
        let assetManager = PHImageManager()
        var phAsset : PHAsset?

        let optionsForFetch = PHFetchOptions()
        optionsForFetch.includeHiddenAssets = true

        var fetchResult = PHAsset.fetchAssetsWithALAssetURLs([alURL], options: optionsForFetch)
        if fetchResult?.count > 0 {
            return fetchResult[0] as? PHAsset
        } else {
            var str = alURL.absoluteString!
            let startOfString = advance(find(str, "=")!, 1)
            let endOfString = advance(startOfString, 36)
            let range = Range<String.Index>(start:startOfString, end:endOfString)
            let localIDFragment = str.substringWithRange(range)
            let fetchResultForPhotostream = PHAssetCollection.fetchAssetCollectionsWithType(PHAssetCollectionType.Album, subtype: PHAssetCollectionSubtype.AlbumMyPhotoStream, options: nil)
            if fetchResultForPhotostream?.count > 0 {
                let photostream = fetchResultForPhotostream![0] as PHAssetCollection
                let fetchResultForPhotostreamAssets = PHAsset.fetchAssetsInAssetCollection(photostream, options: optionsForFetch)
                if fetchResultForPhotostreamAssets?.count >= 0 {
                    var stop : Bool = false
                    for var i = 0; i < fetchResultForPhotostreamAssets.count && !stop; i++ {
                        let phAssetBeingCompared = fetchResultForPhotostreamAssets[i] as PHAsset
                        if phAssetBeingCompared.localIdentifier.rangeOfString(localIDFragment, options: nil, range: nil, locale: nil) != nil {
                            phAsset = phAssetBeingCompared
                            stop = true
                        }
                    }
                    return phAsset
                }
            }
            return nil
        }
    }
}
0

Loading an image with a specified URL from My Photo Stream using ALAssetsLibrary is discussed here:

ALAssetsLibrary assetForURL: always returning nil for photos in "My Photo Stream" in iOS 8.1

In short, instead of using assetForURL you have to iterate through all items in a Photo Stream and compare their URL with yours. The link above contains a code example.

It looks awkward, works slower than assetForURL, and it is not so easy to determine if there is no any file with specified URL found, but I did not find any other way to do it (except of migrating to Photos framework).

Community
  • 1
  • 1
Andrew Simontsev
  • 988
  • 7
  • 17
0

For PHAsset, I use

[[PHImageManager defaultManager] requestImageForAsset:imageAsset
                                               targetSize:targetSize
                                              contentMode:PHImageContentModeAspectFit
                                                  options:options
                                            resultHandler:^(UIImage *img, NSDictionary *info)
{ // code for handle image }];

I tried to use requestImageDataForAsset, but it return nil for streamed photos.

Yuchao Zhou
  • 962
  • 13
  • 19
-1

Work for me in 8.0

import Photos

func imageFromAsset(nsurl: NSURL) {
    let asset = PHAsset.fetchAssetsWithALAssetURLs([nsurl], options: nil).firstObject as! PHAsset
    let targetSize = CGSizeMake(300, 300)
    var options = PHImageRequestOptions()

    PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: targetSize, contentMode: PHImageContentMode.AspectFit, options: options, resultHandler: {
        (result, info) in
        // imageE - UIImageView on scene
        self.imageE.image = result
    })
}
gerram
  • 474
  • 6
  • 12
  • @Opticon would like to comment with the following: - **can't comment so I'm asking this way. I implemented this but it always returns a 60x60 aprox. images, no matter what I set in the targetSize. Do you know how I can recover the original photo? Thanks** – Craicerjack Feb 12 '16 at 12:00