From http://www.jwz.org/xscreensaver/xscreensaver-5.36.tar.gz
[xscreensaver] / OSX / grabclient-ios.m
1 /* xscreensaver, Copyright (c) 1992-2016 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 /* This iOS code to choose and return a random image from the user's
13  * photo gallery.
14  *
15  * Much of the following written by:
16  *
17  *  Created by David Oster on 6/23/12.
18  *  Copyright (c) 2012 Google. All rights reserved.
19  *  Licensed under the Apache License, Version 2.0 (the "License");
20  *  you may not use this file except in compliance with the License.
21  *  You may obtain a copy of the License at
22  *
23  *       http://www.apache.org/licenses/LICENSE-2.0
24  *
25  *  Unless required by applicable law or agreed to in writing, software
26  *  distributed under the License is distributed on an "AS IS" BASIS,
27  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28  *  See the License for the specific language governing permissions and
29  *  limitations under the License.
30  */
31
32 #ifdef USE_IPHONE  // whole file
33
34 #import <AssetsLibrary/AssetsLibrary.h>
35 #import "grabscreen.h"
36 #import "yarandom.h"
37
38 /* ALAssetsLibrary is an async API, so we need to fire it off and then
39    call a callback when it's done.  Fortunately, this fits the same
40    interaction model already used in xscreensaver by load_image_async(),
41    so it works out nicely.
42  */
43
44 typedef struct {
45   void (*callback) (void *uiimage, const char *fn, int width, int height,
46                     void *closure);
47   void *closure;
48
49   ALAssetsLibrary *library;
50   NSMutableArray *assets;
51
52 } ios_loader_data;
53
54
55 static void
56 ios_random_image_done (ios_loader_data *d, BOOL ok)
57 {
58   UIImage *img = 0;
59   const char *fn = 0;
60   NSUInteger n = ok ? [d->assets count] : 0;
61   if (n > 0) {
62     ALAsset *asset = [d->assets objectAtIndex: random() % n];
63     ALAssetRepresentation *rep = [asset defaultRepresentation];
64
65     // "fullScreenImage" returns a smaller image than "fullResolutionImage",
66     // but this function still takes a significant fraction of a second,
67     // causing a visible glitch in e.g. "glslideshow".
68     CGImageRef cgi = [rep fullScreenImage];
69     if (cgi) {
70       UIImageOrientation orient = (UIImageOrientation) 
71         [[asset valueForProperty:ALAssetPropertyOrientation] intValue];
72       img = [UIImage imageWithCGImage: cgi
73                      scale: 1
74                      orientation: orient];
75       if (img)
76         fn = [[[rep filename] stringByDeletingPathExtension]
77                cStringUsingEncoding:NSUTF8StringEncoding];
78     }
79   }
80
81   [d->assets release];
82   [d->library release];
83
84   d->callback (img, fn, [img size].width, [img size].height, d->closure);
85   free (d);
86 }
87
88
89 void
90 ios_load_random_image (void (*callback) (void *uiimage, const char *fn,
91                                          int width, int height,
92                                          void *closure),
93                        void *closure)
94 {
95   ios_loader_data *d = (ios_loader_data *) calloc (1, sizeof(*d));
96   d->callback = callback;
97   d->closure = closure;
98
99   d->library = [[[ALAssetsLibrary alloc] init] retain];
100   d->assets = [[NSMutableArray array] retain];
101
102   // The closures passed in here are called later, after we have returned.
103   //
104   [d->library enumerateGroupsWithTypes: ALAssetsGroupAll
105               usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
106     NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
107     if ([name length]) {
108       [group enumerateAssetsUsingBlock: ^(ALAsset *asset, NSUInteger index,
109                                           BOOL *stop) {
110         if ([[asset valueForProperty: ALAssetPropertyType]
111               isEqual: ALAssetTypePhoto]) {
112           [d->assets addObject:asset];
113         }
114       }];
115     }
116
117     if (! group) {   // done
118       ios_random_image_done (d, YES);
119     }
120   } failureBlock:^(NSError *error) {
121     // E.g., ALAssetsLibraryErrorDomain: "The user has denied the
122     // application access to their media."
123     NSLog(@"reading Photo Library: %@", error);
124     ios_random_image_done (d, NO);
125   }];
126 }
127
128 #endif  // USE_IPHONE - whole file