faf234804744d1476efe3afa1bc87e4c13378c69
[xscreensaver] / OSX / iosgrabimage.m
1 /* xscreensaver, Copyright (c) 1992-2012 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, void *closure);
46   void *closure;
47
48   ALAssetsLibrary *library;
49   NSMutableArray *assets;
50
51 } ios_loader_data;
52
53
54 static void
55 ios_random_image_done (ios_loader_data *d, BOOL ok)
56 {
57   UIImage *img = 0;
58   const char *fn = 0;
59   int n = ok ? [d->assets count] : 0;
60   if (n > 0) {
61     ALAsset *asset = [d->assets objectAtIndex: random() % n];
62     ALAssetRepresentation *rep = [asset defaultRepresentation];
63
64     // "fullScreenImage" returns a smaller image than "fullResolutionImage",
65     // but this function still takes a significant fraction of a second,
66     // causing a visible glitch in e.g. "glslideshow".
67     CGImageRef cgi = [rep fullScreenImage];
68     if (cgi) {
69       UIImageOrientation orient = (UIImageOrientation) 
70         [[asset valueForProperty:ALAssetPropertyOrientation] intValue];
71       img = [UIImage imageWithCGImage: cgi
72                      scale: 1
73                      orientation: orient];
74       if (img)
75         fn = [[rep filename] cStringUsingEncoding:NSISOLatin1StringEncoding];
76     }
77   }
78
79   [d->assets release];
80   [d->library release];
81
82   d->callback (img, fn, d->closure);
83   free (d);
84 }
85
86
87 void
88 ios_load_random_image (void (*callback) (void *uiimage, const char *fn,
89                                          void *closure),
90                        void *closure)
91 {
92   ios_loader_data *d = (ios_loader_data *) calloc (1, sizeof(*d));
93   d->callback = callback;
94   d->closure = closure;
95
96   d->library = [[[ALAssetsLibrary alloc] init] retain];
97   d->assets = [[NSMutableArray array] retain];
98
99   // The closures passed in here are called later, after we have returned.
100   //
101   [d->library enumerateGroupsWithTypes: ALAssetsGroupAll
102               usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
103     NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
104     if ([name length]) {
105       [group enumerateAssetsUsingBlock: ^(ALAsset *asset, NSUInteger index,
106                                           BOOL *stop) {
107         if ([[asset valueForProperty: ALAssetPropertyType]
108               isEqual: ALAssetTypePhoto]) {
109           [d->assets addObject:asset];
110         }
111       }];
112     }
113
114     if (! group) {   // done
115       ios_random_image_done (d, YES);
116     }
117   } failureBlock:^(NSError *error) {
118     // E.g., ALAssetsLibraryErrorDomain: "The user has denied the
119     // application access to their media."
120     NSLog(@"reading Photo Library: %@", error);
121     ios_random_image_done (d, NO);
122   }];
123 }
124
125 #endif  // USE_IPHONE - whole file