1/* xscreensaver, Copyright (c) 1992-2019 Jamie Zawinski <jwz@jwz.org>
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation.  No representations are made about the suitability of this
8 * software for any purpose.  It is provided "as is" without express or
9 * implied warranty.
10 */
11
12/* iOS 8+ code to choose and return a random image from the photo library.
13 */
14
15#ifdef USE_IPHONE  // whole file
16
17#import <Photos/Photos.h>
18#import "grabscreen.h"
19#import "yarandom.h"
20
21void
22ios_load_random_image (void (*callback) (void *uiimage, const char *fn,
23                                         int width, int height,
24                                         void *closure),
25                       void *closure,
26                       int width, int height)
27{
28  // If the user has not yet been asked for authoriziation, pop up the
29  // auth dialog now and re-invoke this function once it has been
30  // answered.  The callback will run once there has been a Yes or No.
31  // Otherwise, we'd return right away with colorbars even if the user
32  // then went on to answer Yes.
33  //
34  PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
35  if (status == PHAuthorizationStatusNotDetermined) {
36    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
37      ios_load_random_image (callback, closure, width, height);
38    }];
39    return;
40  }
41
42  // The rest of this is synchronous.
43
44  PHFetchOptions *opt = [[PHFetchOptions new] autorelease];
45  opt.includeAssetSourceTypes = (PHAssetSourceTypeUserLibrary |
46                                 PHAssetSourceTypeCloudShared |
47                                 PHAssetSourceTypeiTunesSynced);
48  PHFetchResult *r = [PHAsset
49                       fetchAssetsWithMediaType: PHAssetMediaTypeImage
50                       options: opt];
51  NSUInteger n = [r count];
52  PHAsset *asset = n ? [r objectAtIndex: random() % n] : NULL;
53
54  __block UIImage *img = 0;
55  __block const char *fn = 0;
56
57  if (asset) {
58    PHImageRequestOptions *opt = [[PHImageRequestOptions alloc] init];
59    opt.synchronous = YES;
60
61    // Get the image bits.
62    //
63    int size = width > height ? width : height;
64    [[PHImageManager defaultManager]
65      requestImageForAsset: asset
66      targetSize: CGSizeMake (size, size)
67      contentMode: PHImageContentModeDefault
68      options: opt
69      resultHandler:^void (UIImage *image, NSDictionary *info) {
70        img = [image retain];
71    }];
72
73    // Get the image name.
74    //
75    [[PHImageManager defaultManager]
76      requestImageDataForAsset: asset
77      options: opt
78      resultHandler:^(NSData *imageData, NSString *dataUTI,
79                      UIImageOrientation orientation,
80                      NSDictionary *info) {
81        // Looks like UIImage is pre-rotated to compensate for 'orientation'.
82        NSString *path = [info objectForKey:@"PHImageFileURLKey"];
83        if (path)
84          fn = [[[path lastPathComponent] stringByDeletingPathExtension]
85                 cStringUsingEncoding:NSUTF8StringEncoding];
86    }];
87  }
88
89  if (img)
90    callback (img, fn, [img size].width, [img size].height, closure);
91  else
92    callback (0, 0, 0, 0, closure);
93}
94
95#endif  // USE_IPHONE - whole file
96