From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / OSX / grabclient-ios.m
1 /* xscreensaver, Copyright (c) 1992-2017 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
21 void
22 ios_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];
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;
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