(imageView);
172 | mContext = context;
173 | this.rotate = rotate;
174 | }
175 |
176 | /**
177 | * Actual download method.
178 | */
179 | @Override
180 | protected Bitmap doInBackground(Integer... params) {
181 | try {
182 | position = params[0];
183 | if (isCancelled()) {
184 | return null;
185 | }
186 | Bitmap thumb = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), position, 12345,
187 | MediaStore.Images.Thumbnails.MINI_KIND, null);
188 | if (isCancelled()) {
189 | return null;
190 | }
191 | if (thumb == null) {
192 | return null;
193 | } else {
194 | if (isCancelled()) {
195 | return null;
196 | } else {
197 | if (rotate != 0) {
198 | Matrix matrix = new Matrix();
199 | matrix.setRotate(rotate);
200 | thumb = Bitmap.createBitmap(thumb, 0, 0, thumb.getWidth(), thumb.getHeight(), matrix, true);
201 | }
202 | return thumb;
203 | }
204 | }
205 | }catch(OutOfMemoryError error) {
206 | clearCache();
207 | return null;
208 | }
209 |
210 | }
211 |
212 | private void setInvisible() {
213 | // Log.d("COLLAGE", "Setting something invisible...");
214 | if (imageViewReference != null) {
215 | final ImageView imageView = imageViewReference.get();
216 | BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
217 | if (this == bitmapDownloaderTask) {
218 | imageView.setVisibility(View.GONE);
219 | imageView.setClickable(false);
220 | imageView.setEnabled(false);
221 | }
222 | }
223 | }
224 |
225 | /**
226 | * Once the image is downloaded, associates it to the imageView
227 | */
228 | @Override
229 | protected void onPostExecute(Bitmap bitmap) {
230 | if (isCancelled()) {
231 | bitmap = null;
232 | }
233 | addBitmapToCache(position, bitmap);
234 | if (imageViewReference != null) {
235 | ImageView imageView = imageViewReference.get();
236 | BitmapFetcherTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
237 | if (this == bitmapDownloaderTask) {
238 | imageView.setImageBitmap(bitmap);
239 | Animation anim = AnimationUtils.loadAnimation(imageView.getContext(), android.R.anim.fade_in);
240 | imageView.setAnimation(anim);
241 | anim.start();
242 | }
243 | } else {
244 | setInvisible();
245 | }
246 | }
247 | }
248 |
249 | /**
250 | * A fake Drawable that will be attached to the imageView while the download
251 | * is in progress.
252 | *
253 | *
254 | * Contains a reference to the actual download task, so that a download task
255 | * can be stopped if a new binding is required, and makes sure that only the
256 | * last started download process can bind its result, independently of the
257 | * download finish order.
258 | *
259 | */
260 | static class DownloadedDrawable extends ColorDrawable {
261 | private final WeakReference bitmapDownloaderTaskReference;
262 | private long origId;
263 |
264 | public DownloadedDrawable(Context mContext, BitmapFetcherTask bitmapDownloaderTask, long origId) {
265 | super(Color.TRANSPARENT);
266 | bitmapDownloaderTaskReference = new WeakReference(bitmapDownloaderTask);
267 | this.origId = origId;
268 | }
269 |
270 | public long getOrigId() {
271 | return origId;
272 | }
273 |
274 | public BitmapFetcherTask getBitmapDownloaderTask() {
275 | return bitmapDownloaderTaskReference.get();
276 | }
277 | }
278 |
279 | /*
280 | * Cache-related fields and methods.
281 | *
282 | * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the
283 | * Garbage Collector.
284 | */
285 |
286 | private static final int HARD_CACHE_CAPACITY = 100;
287 | private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds
288 |
289 | // Hard cache, with a fixed maximum capacity and a life duration
290 | private final HashMap sHardBitmapCache = new LinkedHashMap(
291 | HARD_CACHE_CAPACITY / 2, 0.75f, true) {
292 | @Override
293 | protected boolean removeEldestEntry(LinkedHashMap.Entry eldest) {
294 | if (size() > HARD_CACHE_CAPACITY) {
295 | // Entries push-out of hard reference cache are transferred to
296 | // soft reference cache
297 | sSoftBitmapCache.put(eldest.getKey(), new SoftReference(eldest.getValue()));
298 | return true;
299 | } else
300 | return false;
301 | }
302 | };
303 |
304 | // Soft cache for bitmaps kicked out of hard cache
305 | private final static ConcurrentHashMap> sSoftBitmapCache = new ConcurrentHashMap>(
306 | HARD_CACHE_CAPACITY / 2);
307 |
308 | private final Handler purgeHandler = new Handler();
309 |
310 | private final Runnable purger = new Runnable() {
311 | public void run() {
312 | clearCache();
313 | }
314 | };
315 |
316 | /**
317 | * Adds this bitmap to the cache.
318 | *
319 | * @param bitmap
320 | * The newly downloaded bitmap.
321 | */
322 | private void addBitmapToCache(Integer position, Bitmap bitmap) {
323 | if (bitmap != null) {
324 | synchronized (sHardBitmapCache) {
325 | sHardBitmapCache.put(position, bitmap);
326 | }
327 | }
328 | }
329 |
330 | /**
331 | * @param position
332 | * The URL of the image that will be retrieved from the cache.
333 | * @return The cached bitmap or null if it was not found.
334 | */
335 | private Bitmap getBitmapFromCache(Integer position) {
336 | // First try the hard reference cache
337 | synchronized (sHardBitmapCache) {
338 | final Bitmap bitmap = sHardBitmapCache.get(position);
339 | if (bitmap != null) {
340 | // Log.d("CACHE ****** ", "Hard hit!");
341 | // Bitmap found in hard cache
342 | // Move element to first position, so that it is removed last
343 | return bitmap;
344 | }
345 | }
346 |
347 | // Then try the soft reference cache
348 | SoftReference bitmapReference = sSoftBitmapCache.get(position);
349 | if (bitmapReference != null) {
350 | final Bitmap bitmap = bitmapReference.get();
351 | if (bitmap != null) {
352 | // Bitmap found in soft cache
353 | // Log.d("CACHE ****** ", "Soft hit!");
354 | return bitmap;
355 | } else {
356 | // Soft reference has been Garbage Collected
357 | sSoftBitmapCache.remove(position);
358 | }
359 | }
360 |
361 | return null;
362 | }
363 |
364 | /**
365 | * Clears the image cache used internally to improve performance. Note that
366 | * for memory efficiency reasons, the cache will automatically be cleared
367 | * after a certain inactivity delay.
368 | */
369 | public void clearCache() {
370 | sHardBitmapCache.clear();
371 | sSoftBitmapCache.clear();
372 | }
373 |
374 | /**
375 | * Allow a new delay before the automatic cache clear is done.
376 | */
377 | private void resetPurgeTimer() {
378 | // purgeHandler.removeCallbacks(purger);
379 | // purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);
380 | }
381 | }
382 |
--------------------------------------------------------------------------------
/src/ios/ELCImagePicker/Resources/ELCAlbumPickerController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1024
5 | 10F569
6 | 804
7 | 1038.29
8 | 461.00
9 |
13 |
17 |
21 |
30 |
31 | YES
32 |
33 | IBFilesOwner
34 | IBCocoaTouchFramework
35 |
36 |
37 | IBFirstResponder
38 | IBCocoaTouchFramework
39 |
40 |
41 |
42 | 274
43 | {320, 416}
44 |
45 |
46 | 3
47 | MQA
48 |
49 | NO
50 | YES
51 | NO
52 |
53 |
54 | NO
55 |
56 | IBCocoaTouchFramework
57 | NO
58 | 1
59 | 0
60 | YES
61 | 44
62 | 22
63 | 22
64 |
65 |
66 |
67 |
68 | YES
69 |
70 |
71 | view
72 |
73 |
74 |
75 | 5
76 |
77 |
78 |
79 | dataSource
80 |
81 |
82 |
83 | 6
84 |
85 |
86 |
87 | delegate
88 |
89 |
90 |
91 | 7
92 |
93 |
94 |
95 |
96 | YES
97 |
98 | 0
99 |
100 |
101 |
102 |
103 |
104 | -1
105 |
106 |
107 | File's Owner
108 |
109 |
110 | -2
111 |
112 |
113 |
114 |
115 | 4
116 |
117 |
118 |
119 |
120 |
121 |
122 | YES
123 |
124 | YES
125 | -1.CustomClassName
126 | -2.CustomClassName
127 | 4.IBEditorWindowLastContentRect
128 | 4.IBPluginDependency
129 |
130 |
131 | YES
132 | AlbumPickerController
133 | UIResponder
134 | {{329, 504}, {320, 480}}
135 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
136 |
137 |
138 |
139 | YES
140 |
141 |
142 | YES
143 |
144 |
145 |
146 |
147 | YES
148 |
149 |
150 | YES
151 |
152 |
153 |
154 | 7
155 |
156 |
157 |
158 | YES
159 |
160 | AlbumPickerController
161 | UITableViewController
162 |
163 | IBProjectSource
164 | Classes/AlbumPickerController.h
165 |
166 |
167 |
168 |
169 | YES
170 |
171 | NSObject
172 |
173 | IBFrameworkSource
174 | Foundation.framework/Headers/NSError.h
175 |
176 |
177 |
178 | NSObject
179 |
180 | IBFrameworkSource
181 | Foundation.framework/Headers/NSFileManager.h
182 |
183 |
184 |
185 | NSObject
186 |
187 | IBFrameworkSource
188 | Foundation.framework/Headers/NSKeyValueCoding.h
189 |
190 |
191 |
192 | NSObject
193 |
194 | IBFrameworkSource
195 | Foundation.framework/Headers/NSKeyValueObserving.h
196 |
197 |
198 |
199 | NSObject
200 |
201 | IBFrameworkSource
202 | Foundation.framework/Headers/NSKeyedArchiver.h
203 |
204 |
205 |
206 | NSObject
207 |
208 | IBFrameworkSource
209 | Foundation.framework/Headers/NSObject.h
210 |
211 |
212 |
213 | NSObject
214 |
215 | IBFrameworkSource
216 | Foundation.framework/Headers/NSRunLoop.h
217 |
218 |
219 |
220 | NSObject
221 |
222 | IBFrameworkSource
223 | Foundation.framework/Headers/NSThread.h
224 |
225 |
226 |
227 | NSObject
228 |
229 | IBFrameworkSource
230 | Foundation.framework/Headers/NSURL.h
231 |
232 |
233 |
234 | NSObject
235 |
236 | IBFrameworkSource
237 | Foundation.framework/Headers/NSURLConnection.h
238 |
239 |
240 |
241 | NSObject
242 |
243 | IBFrameworkSource
244 | UIKit.framework/Headers/UIAccessibility.h
245 |
246 |
247 |
248 | NSObject
249 |
250 | IBFrameworkSource
251 | UIKit.framework/Headers/UINibLoading.h
252 |
253 |
254 |
255 | NSObject
256 |
257 | IBFrameworkSource
258 | UIKit.framework/Headers/UIResponder.h
259 |
260 |
261 |
262 | UIResponder
263 | NSObject
264 |
265 |
266 |
267 | UIScrollView
268 | UIView
269 |
270 | IBFrameworkSource
271 | UIKit.framework/Headers/UIScrollView.h
272 |
273 |
274 |
275 | UISearchBar
276 | UIView
277 |
278 | IBFrameworkSource
279 | UIKit.framework/Headers/UISearchBar.h
280 |
281 |
282 |
283 | UISearchDisplayController
284 | NSObject
285 |
286 | IBFrameworkSource
287 | UIKit.framework/Headers/UISearchDisplayController.h
288 |
289 |
290 |
291 | UITableView
292 | UIScrollView
293 |
294 | IBFrameworkSource
295 | UIKit.framework/Headers/UITableView.h
296 |
297 |
298 |
299 | UITableViewController
300 | UIViewController
301 |
302 | IBFrameworkSource
303 | UIKit.framework/Headers/UITableViewController.h
304 |
305 |
306 |
307 | UIView
308 |
309 | IBFrameworkSource
310 | UIKit.framework/Headers/UITextField.h
311 |
312 |
313 |
314 | UIView
315 | UIResponder
316 |
317 | IBFrameworkSource
318 | UIKit.framework/Headers/UIView.h
319 |
320 |
321 |
322 | UIViewController
323 |
324 | IBFrameworkSource
325 | UIKit.framework/Headers/UINavigationController.h
326 |
327 |
328 |
329 | UIViewController
330 |
331 | IBFrameworkSource
332 | UIKit.framework/Headers/UIPopoverController.h
333 |
334 |
335 |
336 | UIViewController
337 |
338 | IBFrameworkSource
339 | UIKit.framework/Headers/UISplitViewController.h
340 |
341 |
342 |
343 | UIViewController
344 |
345 | IBFrameworkSource
346 | UIKit.framework/Headers/UITabBarController.h
347 |
348 |
349 |
350 | UIViewController
351 | UIResponder
352 |
353 | IBFrameworkSource
354 | UIKit.framework/Headers/UIViewController.h
355 |
356 |
357 |
358 |
359 | 0
360 | IBCocoaTouchFramework
361 |
362 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS
363 |
364 |
365 |
366 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
367 |
368 |
369 | YES
370 | ../ELCImagePickerDemo.xcodeproj
371 | 3
372 | 123
373 |
374 |
375 |
--------------------------------------------------------------------------------
/src/ios/ELCImagePicker/Resources/ELCAssetTablePicker.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1024
5 | 10F569
6 | 804
7 | 1038.29
8 | 461.00
9 |
10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
11 | 123
12 |
13 |
14 | YES
15 |
16 |
17 |
18 | YES
19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
20 |
21 |
22 | YES
23 |
24 | YES
25 |
26 |
27 | YES
28 |
29 |
30 |
31 | YES
32 |
33 | IBFilesOwner
34 | IBCocoaTouchFramework
35 |
36 |
37 | IBFirstResponder
38 | IBCocoaTouchFramework
39 |
40 |
41 |
42 | 274
43 | {320, 436}
44 |
45 |
46 | 3
47 | MQA
48 |
49 | YES
50 |
51 | NO
52 |
53 | IBCocoaTouchFramework
54 | YES
55 | 1
56 | 0
57 | YES
58 | 44
59 | 22
60 | 22
61 |
62 |
63 |
64 |
65 | YES
66 |
67 |
68 | view
69 |
70 |
71 |
72 | 3
73 |
74 |
75 |
76 | dataSource
77 |
78 |
79 |
80 | 4
81 |
82 |
83 |
84 | delegate
85 |
86 |
87 |
88 | 5
89 |
90 |
91 |
92 |
93 | YES
94 |
95 | 0
96 |
97 |
98 |
99 |
100 |
101 | -1
102 |
103 |
104 | File's Owner
105 |
106 |
107 | -2
108 |
109 |
110 |
111 |
112 | 2
113 |
114 |
115 |
116 |
117 |
118 |
119 | YES
120 |
121 | YES
122 | -1.CustomClassName
123 | -2.CustomClassName
124 | 2.IBEditorWindowLastContentRect
125 | 2.IBPluginDependency
126 |
127 |
128 | YES
129 | AssetTablePicker
130 | UIResponder
131 | {{0, 526}, {320, 480}}
132 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
133 |
134 |
135 |
136 | YES
137 |
138 |
139 | YES
140 |
141 |
142 |
143 |
144 | YES
145 |
146 |
147 | YES
148 |
149 |
150 |
151 | 5
152 |
153 |
154 |
155 | YES
156 |
157 | AssetTablePicker
158 | UITableViewController
159 |
160 | dismiss:
161 | id
162 |
163 |
164 | dismiss:
165 |
166 | dismiss:
167 | id
168 |
169 |
170 |
171 | YES
172 |
173 | YES
174 | parent
175 | selectedAssetsLabel
176 |
177 |
178 | YES
179 | id
180 | UILabel
181 |
182 |
183 |
184 | YES
185 |
186 | YES
187 | parent
188 | selectedAssetsLabel
189 |
190 |
191 | YES
192 |
193 | parent
194 | id
195 |
196 |
197 | selectedAssetsLabel
198 | UILabel
199 |
200 |
201 |
202 |
203 | IBProjectSource
204 | Classes/ELCImagePickerController.h
205 |
206 |
207 |
208 |
209 | YES
210 |
211 | NSObject
212 |
213 | IBFrameworkSource
214 | Foundation.framework/Headers/NSError.h
215 |
216 |
217 |
218 | NSObject
219 |
220 | IBFrameworkSource
221 | Foundation.framework/Headers/NSFileManager.h
222 |
223 |
224 |
225 | NSObject
226 |
227 | IBFrameworkSource
228 | Foundation.framework/Headers/NSKeyValueCoding.h
229 |
230 |
231 |
232 | NSObject
233 |
234 | IBFrameworkSource
235 | Foundation.framework/Headers/NSKeyValueObserving.h
236 |
237 |
238 |
239 | NSObject
240 |
241 | IBFrameworkSource
242 | Foundation.framework/Headers/NSKeyedArchiver.h
243 |
244 |
245 |
246 | NSObject
247 |
248 | IBFrameworkSource
249 | Foundation.framework/Headers/NSObject.h
250 |
251 |
252 |
253 | NSObject
254 |
255 | IBFrameworkSource
256 | Foundation.framework/Headers/NSRunLoop.h
257 |
258 |
259 |
260 | NSObject
261 |
262 | IBFrameworkSource
263 | Foundation.framework/Headers/NSThread.h
264 |
265 |
266 |
267 | NSObject
268 |
269 | IBFrameworkSource
270 | Foundation.framework/Headers/NSURL.h
271 |
272 |
273 |
274 | NSObject
275 |
276 | IBFrameworkSource
277 | Foundation.framework/Headers/NSURLConnection.h
278 |
279 |
280 |
281 | NSObject
282 |
283 | IBFrameworkSource
284 | UIKit.framework/Headers/UIAccessibility.h
285 |
286 |
287 |
288 | NSObject
289 |
290 | IBFrameworkSource
291 | UIKit.framework/Headers/UINibLoading.h
292 |
293 |
294 |
295 | NSObject
296 |
297 | IBFrameworkSource
298 | UIKit.framework/Headers/UIResponder.h
299 |
300 |
301 |
302 | UILabel
303 | UIView
304 |
305 | IBFrameworkSource
306 | UIKit.framework/Headers/UILabel.h
307 |
308 |
309 |
310 | UIResponder
311 | NSObject
312 |
313 |
314 |
315 | UIScrollView
316 | UIView
317 |
318 | IBFrameworkSource
319 | UIKit.framework/Headers/UIScrollView.h
320 |
321 |
322 |
323 | UISearchBar
324 | UIView
325 |
326 | IBFrameworkSource
327 | UIKit.framework/Headers/UISearchBar.h
328 |
329 |
330 |
331 | UISearchDisplayController
332 | NSObject
333 |
334 | IBFrameworkSource
335 | UIKit.framework/Headers/UISearchDisplayController.h
336 |
337 |
338 |
339 | UITableView
340 | UIScrollView
341 |
342 | IBFrameworkSource
343 | UIKit.framework/Headers/UITableView.h
344 |
345 |
346 |
347 | UITableViewController
348 | UIViewController
349 |
350 | IBFrameworkSource
351 | UIKit.framework/Headers/UITableViewController.h
352 |
353 |
354 |
355 | UIView
356 |
357 | IBFrameworkSource
358 | UIKit.framework/Headers/UITextField.h
359 |
360 |
361 |
362 | UIView
363 | UIResponder
364 |
365 | IBFrameworkSource
366 | UIKit.framework/Headers/UIView.h
367 |
368 |
369 |
370 | UIViewController
371 |
372 | IBFrameworkSource
373 | UIKit.framework/Headers/UINavigationController.h
374 |
375 |
376 |
377 | UIViewController
378 |
379 | IBFrameworkSource
380 | UIKit.framework/Headers/UIPopoverController.h
381 |
382 |
383 |
384 | UIViewController
385 |
386 | IBFrameworkSource
387 | UIKit.framework/Headers/UISplitViewController.h
388 |
389 |
390 |
391 | UIViewController
392 |
393 | IBFrameworkSource
394 | UIKit.framework/Headers/UITabBarController.h
395 |
396 |
397 |
398 | UIViewController
399 | UIResponder
400 |
401 | IBFrameworkSource
402 | UIKit.framework/Headers/UIViewController.h
403 |
404 |
405 |
406 |
407 | 0
408 | IBCocoaTouchFramework
409 |
410 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS
411 |
412 |
413 |
414 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
415 |
416 |
417 | YES
418 | ../ELCImagePickerDemo.xcodeproj
419 | 3
420 | 123
421 |
422 |
423 |
--------------------------------------------------------------------------------
/src/ios/ELCImagePicker/Resources/ELCAssetPicker.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1024
5 | 10F569
6 | 804
7 | 1038.29
8 | 461.00
9 |
10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
11 | 123
12 |
13 |
14 | YES
15 |
16 |
17 |
18 | YES
19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
20 |
21 |
22 | YES
23 |
24 | YES
25 |
26 |
27 | YES
28 |
29 |
30 |
31 | YES
32 |
33 | IBFilesOwner
34 | IBCocoaTouchFramework
35 |
36 |
37 | IBFirstResponder
38 | IBCocoaTouchFramework
39 |
40 |
41 |
42 | 274
43 |
44 | YES
45 |
46 |
47 | 268
48 | {320, 416}
49 |
50 |
51 | 1
52 | MSAxIDEAA
53 |
54 | YES
55 | YES
56 | IBCocoaTouchFramework
57 |
58 |
59 | {320, 416}
60 |
61 |
62 | 3
63 | MQA
64 |
65 | 2
66 |
67 |
68 |
69 |
70 | NO
71 |
72 | IBCocoaTouchFramework
73 |
74 |
75 |
76 |
77 | YES
78 |
79 |
80 | view
81 |
82 |
83 |
84 | 3
85 |
86 |
87 |
88 | scrollview
89 |
90 |
91 |
92 | 7
93 |
94 |
95 |
96 |
97 | YES
98 |
99 | 0
100 |
101 |
102 |
103 |
104 |
105 | 1
106 |
107 |
108 | YES
109 |
110 |
111 |
112 |
113 |
114 | -1
115 |
116 |
117 | File's Owner
118 |
119 |
120 | -2
121 |
122 |
123 |
124 |
125 | 6
126 |
127 |
128 | YES
129 |
130 |
131 |
132 |
133 |
134 |
135 | YES
136 |
137 | YES
138 | -1.CustomClassName
139 | -2.CustomClassName
140 | 1.IBEditorWindowLastContentRect
141 | 1.IBPluginDependency
142 | 6.IBPluginDependency
143 | 6.IBViewBoundsToFrameTransform
144 |
145 |
146 | YES
147 | AssetPicker
148 | UIResponder
149 | {{575, 376}, {320, 480}}
150 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
151 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
152 |
153 | P4AAAL+AAAAAAAAAw88AAA
154 |
155 |
156 |
157 |
158 | YES
159 |
160 |
161 | YES
162 |
163 |
164 |
165 |
166 | YES
167 |
168 |
169 | YES
170 |
171 |
172 |
173 | 15
174 |
175 |
176 |
177 | YES
178 |
179 | AssetPicker
180 | UIViewController
181 |
182 | dismiss:
183 | id
184 |
185 |
186 | dismiss:
187 |
188 | dismiss:
189 | id
190 |
191 |
192 |
193 | YES
194 |
195 | YES
196 | parent
197 | scrollview
198 | selectedAssetsLabel
199 |
200 |
201 | YES
202 | id
203 | UIScrollView
204 | UILabel
205 |
206 |
207 |
208 | YES
209 |
210 | YES
211 | parent
212 | scrollview
213 | selectedAssetsLabel
214 |
215 |
216 | YES
217 |
218 | parent
219 | id
220 |
221 |
222 | scrollview
223 | UIScrollView
224 |
225 |
226 | selectedAssetsLabel
227 | UILabel
228 |
229 |
230 |
231 |
232 | IBProjectSource
233 | Classes/ELCImagePickerController.h
234 |
235 |
236 |
237 |
238 | YES
239 |
240 | NSObject
241 |
242 | IBFrameworkSource
243 | Foundation.framework/Headers/NSError.h
244 |
245 |
246 |
247 | NSObject
248 |
249 | IBFrameworkSource
250 | Foundation.framework/Headers/NSFileManager.h
251 |
252 |
253 |
254 | NSObject
255 |
256 | IBFrameworkSource
257 | Foundation.framework/Headers/NSKeyValueCoding.h
258 |
259 |
260 |
261 | NSObject
262 |
263 | IBFrameworkSource
264 | Foundation.framework/Headers/NSKeyValueObserving.h
265 |
266 |
267 |
268 | NSObject
269 |
270 | IBFrameworkSource
271 | Foundation.framework/Headers/NSKeyedArchiver.h
272 |
273 |
274 |
275 | NSObject
276 |
277 | IBFrameworkSource
278 | Foundation.framework/Headers/NSObject.h
279 |
280 |
281 |
282 | NSObject
283 |
284 | IBFrameworkSource
285 | Foundation.framework/Headers/NSRunLoop.h
286 |
287 |
288 |
289 | NSObject
290 |
291 | IBFrameworkSource
292 | Foundation.framework/Headers/NSThread.h
293 |
294 |
295 |
296 | NSObject
297 |
298 | IBFrameworkSource
299 | Foundation.framework/Headers/NSURL.h
300 |
301 |
302 |
303 | NSObject
304 |
305 | IBFrameworkSource
306 | Foundation.framework/Headers/NSURLConnection.h
307 |
308 |
309 |
310 | NSObject
311 |
312 | IBFrameworkSource
313 | UIKit.framework/Headers/UIAccessibility.h
314 |
315 |
316 |
317 | NSObject
318 |
319 | IBFrameworkSource
320 | UIKit.framework/Headers/UINibLoading.h
321 |
322 |
323 |
324 | NSObject
325 |
326 | IBFrameworkSource
327 | UIKit.framework/Headers/UIResponder.h
328 |
329 |
330 |
331 | UILabel
332 | UIView
333 |
334 | IBFrameworkSource
335 | UIKit.framework/Headers/UILabel.h
336 |
337 |
338 |
339 | UIResponder
340 | NSObject
341 |
342 |
343 |
344 | UIScrollView
345 | UIView
346 |
347 | IBFrameworkSource
348 | UIKit.framework/Headers/UIScrollView.h
349 |
350 |
351 |
352 | UISearchBar
353 | UIView
354 |
355 | IBFrameworkSource
356 | UIKit.framework/Headers/UISearchBar.h
357 |
358 |
359 |
360 | UISearchDisplayController
361 | NSObject
362 |
363 | IBFrameworkSource
364 | UIKit.framework/Headers/UISearchDisplayController.h
365 |
366 |
367 |
368 | UIView
369 |
370 | IBFrameworkSource
371 | UIKit.framework/Headers/UITextField.h
372 |
373 |
374 |
375 | UIView
376 | UIResponder
377 |
378 | IBFrameworkSource
379 | UIKit.framework/Headers/UIView.h
380 |
381 |
382 |
383 | UIViewController
384 |
385 | IBFrameworkSource
386 | UIKit.framework/Headers/UINavigationController.h
387 |
388 |
389 |
390 | UIViewController
391 |
392 | IBFrameworkSource
393 | UIKit.framework/Headers/UIPopoverController.h
394 |
395 |
396 |
397 | UIViewController
398 |
399 | IBFrameworkSource
400 | UIKit.framework/Headers/UISplitViewController.h
401 |
402 |
403 |
404 | UIViewController
405 |
406 | IBFrameworkSource
407 | UIKit.framework/Headers/UITabBarController.h
408 |
409 |
410 |
411 | UIViewController
412 | UIResponder
413 |
414 | IBFrameworkSource
415 | UIKit.framework/Headers/UIViewController.h
416 |
417 |
418 |
419 |
420 | 0
421 | IBCocoaTouchFramework
422 |
423 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS
424 |
425 |
426 |
427 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
428 |
429 |
430 | YES
431 | ../ELCImagePickerDemo.xcodeproj
432 | 3
433 | 123
434 |
435 |
436 |
--------------------------------------------------------------------------------
/src/android/Library/src/MultiImageChooserActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, David Erosa
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | *
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDIN G NEGLIGENCE OR OTHERWISE)
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 | * POSSIBILITY OF SUCH DAMAGE
26 | *
27 | * Code modified by Andrew Stephan for Sync OnSet
28 | *
29 | */
30 |
31 | package com.synconset;
32 |
33 | import java.net.URI;
34 | import java.io.File;
35 | import java.io.FileOutputStream;
36 | import java.io.IOException;
37 | import java.io.OutputStream;
38 | import java.util.ArrayList;
39 | import java.util.HashMap;
40 | import java.util.Iterator;
41 | import java.util.Map;
42 | import java.util.Map.Entry;
43 | import java.util.Set;
44 |
45 | import com.synconset.FakeR;
46 | import android.app.Activity;
47 | import android.app.ActionBar;
48 | import android.app.AlertDialog;
49 | import android.app.LoaderManager;
50 | import android.app.ProgressDialog;
51 | import android.content.Context;
52 | import android.content.CursorLoader;
53 | import android.content.DialogInterface;
54 | import android.content.Intent;
55 | import android.content.Loader;
56 | import android.database.Cursor;
57 | import android.graphics.Bitmap;
58 | import android.graphics.BitmapFactory;
59 | import android.graphics.Color;
60 | import android.graphics.Matrix;
61 | import android.net.Uri;
62 | import android.os.AsyncTask;
63 | import android.os.Bundle;
64 | import android.provider.MediaStore;
65 | import android.util.Log;
66 | import android.util.SparseBooleanArray;
67 | import android.view.Display;
68 | import android.view.LayoutInflater;
69 | import android.view.View;
70 | import android.view.ViewGroup;
71 | import android.widget.AbsListView;
72 | import android.widget.AbsListView.OnScrollListener;
73 | import android.widget.AdapterView;
74 | import android.widget.AdapterView.OnItemClickListener;
75 | import android.widget.BaseAdapter;
76 | import android.widget.GridView;
77 | import android.widget.ImageView;
78 | import android.widget.TextView;
79 |
80 | public class MultiImageChooserActivity extends Activity implements OnItemClickListener,
81 | LoaderManager.LoaderCallbacks {
82 | private static final String TAG = "ImagePicker";
83 |
84 | public static final int NOLIMIT = -1;
85 | public static final String MAX_IMAGES_KEY = "MAX_IMAGES";
86 | public static final String WIDTH_KEY = "WIDTH";
87 | public static final String HEIGHT_KEY = "HEIGHT";
88 | public static final String QUALITY_KEY = "QUALITY";
89 |
90 | private ImageAdapter ia;
91 |
92 | private Cursor imagecursor, actualimagecursor;
93 | private int image_column_index, image_column_orientation, actual_image_column_index, orientation_column_index;
94 | private int colWidth;
95 |
96 | private static final int CURSORLOADER_THUMBS = 0;
97 | private static final int CURSORLOADER_REAL = 1;
98 |
99 | private Map fileNames = new HashMap();
100 |
101 | private SparseBooleanArray checkStatus = new SparseBooleanArray();
102 |
103 | private int maxImages;
104 | private int maxImageCount;
105 |
106 | private int desiredWidth;
107 | private int desiredHeight;
108 | private int quality;
109 |
110 | private GridView gridView;
111 |
112 | private final ImageFetcher fetcher = new ImageFetcher();
113 |
114 | private int selectedColor = 0xff32b2e1;
115 | private boolean shouldRequestThumb = true;
116 |
117 | private FakeR fakeR;
118 |
119 | private ProgressDialog progress;
120 |
121 | @Override
122 | public void onCreate(Bundle savedInstanceState) {
123 | super.onCreate(savedInstanceState);
124 | fakeR = new FakeR(this);
125 | setContentView(fakeR.getId("layout", "multiselectorgrid"));
126 | fileNames.clear();
127 |
128 | maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT);
129 | desiredWidth = getIntent().getIntExtra(WIDTH_KEY, 0);
130 | desiredHeight = getIntent().getIntExtra(HEIGHT_KEY, 0);
131 | quality = getIntent().getIntExtra(QUALITY_KEY, 0);
132 | maxImageCount = maxImages;
133 |
134 | Display display = getWindowManager().getDefaultDisplay();
135 | int width = display.getWidth();
136 |
137 | colWidth = width / 4;
138 |
139 | gridView = (GridView) findViewById(fakeR.getId("id", "gridview"));
140 | gridView.setOnItemClickListener(this);
141 | gridView.setOnScrollListener(new OnScrollListener() {
142 | private int lastFirstItem = 0;
143 | private long timestamp = System.currentTimeMillis();
144 |
145 | @Override
146 | public void onScrollStateChanged(AbsListView view, int scrollState) {
147 | if (scrollState == SCROLL_STATE_IDLE) {
148 | shouldRequestThumb = true;
149 | ia.notifyDataSetChanged();
150 | }
151 | }
152 |
153 | @Override
154 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
155 | float dt = System.currentTimeMillis() - timestamp;
156 | if (firstVisibleItem != lastFirstItem) {
157 | double speed = 1 / dt * 1000;
158 | lastFirstItem = firstVisibleItem;
159 | timestamp = System.currentTimeMillis();
160 |
161 | // Limit if we go faster than a page a second
162 | shouldRequestThumb = speed < visibleItemCount;
163 | }
164 | }
165 | });
166 |
167 | ia = new ImageAdapter(this);
168 | gridView.setAdapter(ia);
169 |
170 | LoaderManager.enableDebugLogging(false);
171 | getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this);
172 | getLoaderManager().initLoader(CURSORLOADER_REAL, null, this);
173 | setupHeader();
174 | updateAcceptButton();
175 | progress = new ProgressDialog(this);
176 | progress.setTitle("Processing Images");
177 | progress.setMessage("This may take a few moments");
178 | }
179 |
180 | @Override
181 | public void onItemClick(AdapterView> arg0, View view, int position, long id) {
182 | String name = getImageName(position);
183 | int rotation = getImageRotation(position);
184 |
185 | if (name == null) {
186 | return;
187 | }
188 | boolean isChecked = !isChecked(position);
189 | if (maxImages == 0 && isChecked) {
190 | isChecked = false;
191 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
192 | builder.setTitle("Maximum " + maxImageCount + " Photos");
193 | builder.setMessage("You can only select " + maxImageCount + " photos at a time.");
194 | builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
195 | public void onClick(DialogInterface dialog, int which) {
196 | dialog.cancel();
197 | }
198 | });
199 | AlertDialog alert = builder.create();
200 | alert.show();
201 | } else if (isChecked) {
202 | fileNames.put(name, new Integer(rotation));
203 | if (maxImageCount == 1) {
204 | this.selectClicked(null);
205 | } else {
206 | maxImages--;
207 | ImageView imageView = (ImageView)view;
208 | if (android.os.Build.VERSION.SDK_INT>=16) {
209 | imageView.setImageAlpha(128);
210 | } else {
211 | imageView.setAlpha(128);
212 | }
213 | view.setBackgroundColor(selectedColor);
214 | }
215 | } else {
216 | fileNames.remove(name);
217 | maxImages++;
218 | ImageView imageView = (ImageView)view;
219 | if (android.os.Build.VERSION.SDK_INT>=16) {
220 | imageView.setImageAlpha(255);
221 | } else {
222 | imageView.setAlpha(255);
223 | }
224 | view.setBackgroundColor(Color.TRANSPARENT);
225 | }
226 |
227 | checkStatus.put(position, isChecked);
228 | updateAcceptButton();
229 | }
230 |
231 | @Override
232 | public Loader onCreateLoader(int cursorID, Bundle arg1) {
233 | CursorLoader cl = null;
234 |
235 | ArrayList img = new ArrayList();
236 | switch (cursorID) {
237 |
238 | case CURSORLOADER_THUMBS:
239 | img.add(MediaStore.Images.Media._ID);
240 | img.add(MediaStore.Images.Media.ORIENTATION);
241 | break;
242 | case CURSORLOADER_REAL:
243 | img.add(MediaStore.Images.Thumbnails.DATA);
244 | img.add(MediaStore.Images.Media.ORIENTATION);
245 | break;
246 | default:
247 | break;
248 | }
249 |
250 | cl = new CursorLoader(MultiImageChooserActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
251 | img.toArray(new String[img.size()]), null, null, "DATE_MODIFIED DESC");
252 | return cl;
253 | }
254 |
255 | @Override
256 | public void onLoadFinished(Loader loader, Cursor cursor) {
257 | if (cursor == null) {
258 | // NULL cursor. This usually means there's no image database yet....
259 | return;
260 | }
261 |
262 | switch (loader.getId()) {
263 | case CURSORLOADER_THUMBS:
264 | imagecursor = cursor;
265 | image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
266 | image_column_orientation = imagecursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION);
267 | ia.notifyDataSetChanged();
268 | break;
269 | case CURSORLOADER_REAL:
270 | actualimagecursor = cursor;
271 | String[] columns = actualimagecursor.getColumnNames();
272 | actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
273 | orientation_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION);
274 | break;
275 | default:
276 | break;
277 | }
278 | }
279 |
280 | @Override
281 | public void onLoaderReset(Loader loader) {
282 | if (loader.getId() == CURSORLOADER_THUMBS) {
283 | imagecursor = null;
284 | } else if (loader.getId() == CURSORLOADER_REAL) {
285 | actualimagecursor = null;
286 | }
287 | }
288 |
289 | public void cancelClicked(View ignored) {
290 | setResult(RESULT_CANCELED);
291 | finish();
292 | }
293 |
294 | public void selectClicked(View ignored) {
295 | ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))).setEnabled(false);
296 | getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(false);
297 | progress.show();
298 | Intent data = new Intent();
299 | if (fileNames.isEmpty()) {
300 | this.setResult(RESULT_CANCELED);
301 | progress.dismiss();
302 | finish();
303 | } else {
304 | new ResizeImagesTask().execute(fileNames.entrySet());
305 | }
306 | }
307 |
308 |
309 | /*********************
310 | * Helper Methods
311 | ********************/
312 | private void updateAcceptButton() {
313 | ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview")))
314 | .setEnabled(fileNames.size() != 0);
315 | getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(fileNames.size() != 0);
316 | }
317 |
318 | private void setupHeader() {
319 | // From Roman Nkk's code
320 | // https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW
321 | // Inflate a "Done/Discard" custom action bar view
322 | /*
323 | * Copyright 2013 The Android Open Source Project
324 | *
325 | * Licensed under the Apache License, Version 2.0 (the "License");
326 | * you may not use this file except in compliance with the License.
327 | * You may obtain a copy of the License at
328 | *
329 | * http://www.apache.org/licenses/LICENSE-2.0
330 | *
331 | * Unless required by applicable law or agreed to in writing, software
332 | * distributed under the License is distributed on an "AS IS" BASIS,
333 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
334 | * See the License for the specific language governing permissions and
335 | * limitations under the License.
336 | */
337 | LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService(
338 | LAYOUT_INFLATER_SERVICE);
339 | final View customActionBarView = inflater.inflate(fakeR.getId("layout", "actionbar_custom_view_done_discard"), null);
340 | customActionBarView.findViewById(fakeR.getId("id", "actionbar_done")).setOnClickListener(new View.OnClickListener() {
341 | @Override
342 | public void onClick(View v) {
343 | // "Done"
344 | selectClicked(null);
345 | }
346 | });
347 | customActionBarView.findViewById(fakeR.getId("id", "actionbar_discard")).setOnClickListener(new View.OnClickListener() {
348 | @Override
349 | public void onClick(View v) {
350 | finish();
351 | }
352 | });
353 |
354 | // Show the custom action bar view and hide the normal Home icon and title.
355 | final ActionBar actionBar = getActionBar();
356 | actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM
357 | | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
358 | actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
359 | ViewGroup.LayoutParams.MATCH_PARENT));
360 | }
361 |
362 | private String getImageName(int position) {
363 | actualimagecursor.moveToPosition(position);
364 | String name = null;
365 |
366 | try {
367 | name = actualimagecursor.getString(actual_image_column_index);
368 | } catch (Exception e) {
369 | return null;
370 | }
371 | return name;
372 | }
373 |
374 | private int getImageRotation(int position) {
375 | actualimagecursor.moveToPosition(position);
376 | int rotation = 0;
377 |
378 | try {
379 | rotation = actualimagecursor.getInt(orientation_column_index);
380 | } catch (Exception e) {
381 | return rotation;
382 | }
383 | return rotation;
384 | }
385 |
386 | public boolean isChecked(int position) {
387 | boolean ret = checkStatus.get(position);
388 | return ret;
389 | }
390 |
391 |
392 | /*********************
393 | * Nested Classes
394 | ********************/
395 | private class SquareImageView extends ImageView {
396 | public SquareImageView(Context context) {
397 | super(context);
398 | }
399 |
400 | @Override
401 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
402 | super.onMeasure(widthMeasureSpec, widthMeasureSpec);
403 | }
404 | }
405 |
406 |
407 | private class ImageAdapter extends BaseAdapter {
408 | private final Bitmap mPlaceHolderBitmap;
409 |
410 | public ImageAdapter(Context c) {
411 | Bitmap tmpHolderBitmap = BitmapFactory.decodeResource(getResources(), fakeR.getId("drawable", "loading_icon"));
412 | mPlaceHolderBitmap = Bitmap.createScaledBitmap(tmpHolderBitmap, colWidth, colWidth, false);
413 | if (tmpHolderBitmap != mPlaceHolderBitmap) {
414 | tmpHolderBitmap.recycle();
415 | tmpHolderBitmap = null;
416 | }
417 | }
418 |
419 | public int getCount() {
420 | if (imagecursor != null) {
421 | return imagecursor.getCount();
422 | } else {
423 | return 0;
424 | }
425 | }
426 |
427 | public Object getItem(int position) {
428 | return position;
429 | }
430 |
431 | public long getItemId(int position) {
432 | return position;
433 | }
434 |
435 | // create a new ImageView for each item referenced by the Adapter
436 | public View getView(int pos, View convertView, ViewGroup parent) {
437 |
438 | if (convertView == null) {
439 | ImageView temp = new SquareImageView(MultiImageChooserActivity.this);
440 | temp.setScaleType(ImageView.ScaleType.CENTER_CROP);
441 | convertView = (View)temp;
442 | }
443 |
444 | ImageView imageView = (ImageView)convertView;
445 | imageView.setImageBitmap(null);
446 |
447 | final int position = pos;
448 |
449 | if (!imagecursor.moveToPosition(position)) {
450 | return imageView;
451 | }
452 |
453 | if (image_column_index == -1) {
454 | return imageView;
455 | }
456 |
457 | final int id = imagecursor.getInt(image_column_index);
458 | final int rotate = imagecursor.getInt(image_column_orientation);
459 | if (isChecked(pos)) {
460 | if (android.os.Build.VERSION.SDK_INT>=16) {
461 | imageView.setImageAlpha(128);
462 | } else {
463 | imageView.setAlpha(128);
464 | }
465 | imageView.setBackgroundColor(selectedColor);
466 | } else {
467 | if (android.os.Build.VERSION.SDK_INT>=16) {
468 | imageView.setImageAlpha(255);
469 | } else {
470 | imageView.setAlpha(255);
471 | }
472 | imageView.setBackgroundColor(Color.TRANSPARENT);
473 | }
474 | if (shouldRequestThumb) {
475 | fetcher.fetch(Integer.valueOf(id), imageView, colWidth, rotate);
476 | }
477 |
478 | return imageView;
479 | }
480 | }
481 |
482 |
483 | private class ResizeImagesTask extends AsyncTask>, Void, ArrayList> {
484 | private Exception asyncTaskError = null;
485 |
486 | @Override
487 | protected ArrayList doInBackground(Set>... fileSets) {
488 | Set> fileNames = fileSets[0];
489 | ArrayList al = new ArrayList();
490 | try {
491 | Iterator> i = fileNames.iterator();
492 | Bitmap bmp;
493 | while(i.hasNext()) {
494 | Entry imageInfo = i.next();
495 | File file = new File(imageInfo.getKey());
496 | int rotate = imageInfo.getValue().intValue();
497 | BitmapFactory.Options options = new BitmapFactory.Options();
498 | options.inSampleSize = 1;
499 | options.inJustDecodeBounds = true;
500 | BitmapFactory.decodeFile(file.getAbsolutePath(), options);
501 | int width = options.outWidth;
502 | int height = options.outHeight;
503 | float scale = calculateScale(width, height);
504 | if (scale < 1) {
505 | int finalWidth = (int)(width * scale);
506 | int finalHeight = (int)(height * scale);
507 | int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight);
508 | options = new BitmapFactory.Options();
509 | options.inSampleSize = inSampleSize;
510 | try {
511 | bmp = this.tryToGetBitmap(file, options, rotate, true);
512 | } catch (OutOfMemoryError e) {
513 | options.inSampleSize = calculateNextSampleSize(options.inSampleSize);
514 | try {
515 | bmp = this.tryToGetBitmap(file, options, rotate, false);
516 | } catch (OutOfMemoryError e2) {
517 | throw new IOException("Unable to load image into memory.");
518 | }
519 | }
520 | } else {
521 | try {
522 | bmp = this.tryToGetBitmap(file, null, rotate, false);
523 | } catch(OutOfMemoryError e) {
524 | options = new BitmapFactory.Options();
525 | options.inSampleSize = 2;
526 | try {
527 | bmp = this.tryToGetBitmap(file, options, rotate, false);
528 | } catch(OutOfMemoryError e2) {
529 | options = new BitmapFactory.Options();
530 | options.inSampleSize = 4;
531 | try {
532 | bmp = this.tryToGetBitmap(file, options, rotate, false);
533 | } catch (OutOfMemoryError e3) {
534 | throw new IOException("Unable to load image into memory.");
535 | }
536 | }
537 | }
538 | }
539 |
540 | file = this.storeImage(bmp, file.getName());
541 | al.add(Uri.fromFile(file).toString());
542 | }
543 | return al;
544 | } catch(IOException e) {
545 | try {
546 | asyncTaskError = e;
547 | for (int i = 0; i < al.size(); i++) {
548 | URI uri = new URI(al.get(i));
549 | File file = new File(uri);
550 | file.delete();
551 | }
552 | } catch(Exception exception) {
553 | // the finally does what we want to do
554 | } finally {
555 | return new ArrayList();
556 | }
557 | }
558 | }
559 |
560 | @Override
561 | protected void onPostExecute(ArrayList al) {
562 | Intent data = new Intent();
563 |
564 | if (asyncTaskError != null) {
565 | Bundle res = new Bundle();
566 | res.putString("ERRORMESSAGE", asyncTaskError.getMessage());
567 | data.putExtras(res);
568 | setResult(RESULT_CANCELED, data);
569 | } else if (al.size() > 0) {
570 | Bundle res = new Bundle();
571 | res.putStringArrayList("MULTIPLEFILENAMES", al);
572 | if (imagecursor != null) {
573 | res.putInt("TOTALFILES", imagecursor.getCount());
574 | }
575 | data.putExtras(res);
576 | setResult(RESULT_OK, data);
577 | } else {
578 | setResult(RESULT_CANCELED, data);
579 | }
580 |
581 | progress.dismiss();
582 | finish();
583 | }
584 |
585 | private Bitmap tryToGetBitmap(File file, BitmapFactory.Options options, int rotate, boolean shouldScale) throws IOException, OutOfMemoryError {
586 | Bitmap bmp;
587 | if (options == null) {
588 | bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
589 | } else {
590 | bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
591 | }
592 | if (bmp == null) {
593 | throw new IOException("The image file could not be opened.");
594 | }
595 | if (options != null && shouldScale) {
596 | float scale = calculateScale(options.outWidth, options.outHeight);
597 | bmp = this.getResizedBitmap(bmp, scale);
598 | }
599 | if (rotate != 0) {
600 | Matrix matrix = new Matrix();
601 | matrix.setRotate(rotate);
602 | bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
603 | }
604 | return bmp;
605 | }
606 |
607 | /*
608 | * The following functions are originally from
609 | * https://github.com/raananw/PhoneGap-Image-Resizer
610 | *
611 | * They have been modified by Andrew Stephan for Sync OnSet
612 | *
613 | * The software is open source, MIT Licensed.
614 | * Copyright (C) 2012, webXells GmbH All Rights Reserved.
615 | */
616 | private File storeImage(Bitmap bmp, String fileName) throws IOException {
617 | int index = fileName.lastIndexOf('.');
618 | String name = fileName.substring(0, index);
619 | String ext = fileName.substring(index);
620 | File file = File.createTempFile("tmp_" + name, ext);
621 | OutputStream outStream = new FileOutputStream(file);
622 | if (ext.compareToIgnoreCase(".png") == 0) {
623 | bmp.compress(Bitmap.CompressFormat.PNG, quality, outStream);
624 | } else {
625 | bmp.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
626 | }
627 | outStream.flush();
628 | outStream.close();
629 | return file;
630 | }
631 |
632 | private Bitmap getResizedBitmap(Bitmap bm, float factor) {
633 | int width = bm.getWidth();
634 | int height = bm.getHeight();
635 | // create a matrix for the manipulation
636 | Matrix matrix = new Matrix();
637 | // resize the bit map
638 | matrix.postScale(factor, factor);
639 | // recreate the new Bitmap
640 | Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
641 | return resizedBitmap;
642 | }
643 | }
644 |
645 | private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
646 | // Raw height and width of image
647 | final int height = options.outHeight;
648 | final int width = options.outWidth;
649 | int inSampleSize = 1;
650 |
651 | if (height > reqHeight || width > reqWidth) {
652 | final int halfHeight = height / 2;
653 | final int halfWidth = width / 2;
654 |
655 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both
656 | // height and width larger than the requested height and width.
657 | while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
658 | inSampleSize *= 2;
659 | }
660 | }
661 |
662 | return inSampleSize;
663 | }
664 |
665 | private int calculateNextSampleSize(int sampleSize) {
666 | double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2));
667 | return (int)Math.pow(logBaseTwo + 1, 2);
668 | }
669 |
670 | private float calculateScale(int width, int height) {
671 | float widthScale = 1.0f;
672 | float heightScale = 1.0f;
673 | float scale = 1.0f;
674 | if (desiredWidth > 0 || desiredHeight > 0) {
675 | if (desiredHeight == 0 && desiredWidth < width) {
676 | scale = (float)desiredWidth/width;
677 | } else if (desiredWidth == 0 && desiredHeight < height) {
678 | scale = (float)desiredHeight/height;
679 | } else {
680 | if (desiredWidth > 0 && desiredWidth < width) {
681 | widthScale = (float)desiredWidth/width;
682 | }
683 | if (desiredHeight > 0 && desiredHeight < height) {
684 | heightScale = (float)desiredHeight/height;
685 | }
686 | if (widthScale < heightScale) {
687 | scale = widthScale;
688 | } else {
689 | scale = heightScale;
690 | }
691 | }
692 | }
693 |
694 | return scale;
695 | }
696 | }
697 |
--------------------------------------------------------------------------------