From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / OSX / iosgrabimage.m
1 /* xscreensaver, Copyright (c) 1992-2014 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] cStringUsingEncoding:NSISOLatin1StringEncoding];
77     }
78   }
79
80   [d->assets release];
81   [d->library release];
82
83   d->callback (img, fn, [img size].width, [img size].height, d->closure);
84   free (d);
85 }
86
87
88 void
89 ios_load_random_image (void (*callback) (void *uiimage, const char *fn,
90                                          int width, int height,
91                                          void *closure),
92                        void *closure)
93 {
94   ios_loader_data *d = (ios_loader_data *) calloc (1, sizeof(*d));
95   d->callback = callback;
96   d->closure = closure;
97
98   d->library = [[[ALAssetsLibrary alloc] init] retain];
99   d->assets = [[NSMutableArray array] retain];
100
101   // The closures passed in here are called later, after we have returned.
102   //
103   [d->library enumerateGroupsWithTypes: ALAssetsGroupAll
104               usingBlock: ^(ALAssetsGroup *group, BOOL *stop) {
105     NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
106     if ([name length]) {
107       [group enumerateAssetsUsingBlock: ^(ALAsset *asset, NSUInteger index,
108                                           BOOL *stop) {
109         if ([[asset valueForProperty: ALAssetPropertyType]
110               isEqual: ALAssetTypePhoto]) {
111           [d->assets addObject:asset];
112         }
113       }];
114     }
115
116     if (! group) {   // done
117       ios_random_image_done (d, YES);
118     }
119   } failureBlock:^(NSError *error) {
120     // E.g., ALAssetsLibraryErrorDomain: "The user has denied the
121     // application access to their media."
122     NSLog(@"reading Photo Library: %@", error);
123     ios_random_image_done (d, NO);
124   }];
125 }
126
127 #endif  // USE_IPHONE - whole file