motion-image-editor 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/project/controllers/image_editor_controller.rb +162 -86
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 226472c295b2d57d3bd62e85792534346b931730
|
4
|
+
data.tar.gz: 08016d9fb24343fbac4d2247ba543756f957617e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3721b52b59c18805e7b4d7ca69807fc854536ecf340da76670d9c1dfc6405600e04ac6874a7acada985310c99e15e27241981f21d0ca19eba8c762fa91c5cc5
|
7
|
+
data.tar.gz: f2bfa5a4e7a5226cbc930b3172d40e04821269d6b200a7472bdcad2ae9b4cf5e9bb4fcc04b10fecf1fa515bab63c169a0dbb31d5c2775b71021a2d9183612678
|
@@ -3,12 +3,15 @@ class Motion; class ImageEditorController < UIViewController
|
|
3
3
|
MINIMUM_SCALE = 1
|
4
4
|
MAXIMUM_SCALE = 3
|
5
5
|
|
6
|
-
attr_reader :
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
attr_reader :source_image, :crop_rect, :output_width
|
7
|
+
attr_writer :rotation_enabled, :enforce_bounds
|
8
|
+
|
9
|
+
def initWithNibName(nib, bundle: bundle)
|
10
|
+
super.tap do |controller|
|
11
|
+
controller.rotation_enabled = true
|
12
|
+
controller.enforce_bounds = false
|
13
|
+
end
|
14
|
+
end
|
12
15
|
|
13
16
|
def viewDidLoad
|
14
17
|
super
|
@@ -20,6 +23,14 @@ class Motion; class ImageEditorController < UIViewController
|
|
20
23
|
setup_constraints
|
21
24
|
end
|
22
25
|
|
26
|
+
def viewDidAppear(animated)
|
27
|
+
super
|
28
|
+
|
29
|
+
image_view.image = preview_image
|
30
|
+
|
31
|
+
reset
|
32
|
+
end
|
33
|
+
|
23
34
|
def add_subviews
|
24
35
|
view.addSubview(crop_view)
|
25
36
|
view.insertSubview(image_view, belowSubview: crop_view)
|
@@ -46,6 +57,53 @@ class Motion; class ImageEditorController < UIViewController
|
|
46
57
|
views: { 'crop' => crop_view }))
|
47
58
|
end
|
48
59
|
|
60
|
+
def source_image=(image)
|
61
|
+
if image != source_image
|
62
|
+
@source_image = image
|
63
|
+
@preview_image = nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def crop_rect=(rect)
|
68
|
+
@crop_rect = rect
|
69
|
+
|
70
|
+
crop_view.crop_rect = rect
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_gesture_state?(state)
|
74
|
+
case state
|
75
|
+
when UIGestureRecognizerStateEnded || UIGestureRecognizerStateCancelled
|
76
|
+
new_scale = bounded_scale(scale)
|
77
|
+
|
78
|
+
delta_x = scale_center.x - image_view.bounds.size.width / 2.0
|
79
|
+
delta_y = scale_center.y - image_view.bounds.size.height / 2.0
|
80
|
+
|
81
|
+
transform = CGAffineTransformTranslate(image_view.transform, delta_x, delta_y)
|
82
|
+
|
83
|
+
transform = CGAffineTransformScale(transform, new_scale / scale , new_scale / scale)
|
84
|
+
|
85
|
+
transform = CGAffineTransformTranslate(transform, -delta_x, -delta_y)
|
86
|
+
|
87
|
+
view.userInteractionEnabled = false
|
88
|
+
|
89
|
+
UIView.animateWithDuration(
|
90
|
+
ANIMATION_DURATION,
|
91
|
+
delay: 0,
|
92
|
+
options: UIViewAnimationOptionCurveEaseOut,
|
93
|
+
animations: -> { image_view.transform = transform },
|
94
|
+
completion: -> (finished) {
|
95
|
+
view.userInteractionEnabled = true
|
96
|
+
@scale = new_scale
|
97
|
+
})
|
98
|
+
|
99
|
+
check_bounds if enforce_bounds?
|
100
|
+
|
101
|
+
false
|
102
|
+
else
|
103
|
+
true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
49
107
|
def process(&block)
|
50
108
|
view.userInteractionEnabled = false
|
51
109
|
|
@@ -74,19 +132,6 @@ class Motion; class ImageEditorController < UIViewController
|
|
74
132
|
end
|
75
133
|
end
|
76
134
|
|
77
|
-
def crop_rect=(rect)
|
78
|
-
@crop_rect = rect
|
79
|
-
|
80
|
-
crop_view.crop_rect = rect
|
81
|
-
end
|
82
|
-
|
83
|
-
def scale_reset_orientations
|
84
|
-
[ UIImageOrientationUpMirrored,
|
85
|
-
UIImageOrientationDownMirrored,
|
86
|
-
UIImageOrientationLeftMirrored,
|
87
|
-
UIImageOrientationRightMirrored ]
|
88
|
-
end
|
89
|
-
|
90
135
|
def transform_image(transform, source_image: source_image, source_size: source_size, source_orientation: source_orientation, output_width: output_width, crop_rect: crop_rect, image_view_size: image_view_size)
|
91
136
|
aspect = crop_rect.size.height / crop_rect.size.width
|
92
137
|
output_size = CGSizeMake(output_width, output_width * aspect)
|
@@ -145,14 +190,6 @@ class Motion; class ImageEditorController < UIViewController
|
|
145
190
|
CGBitmapContextCreateImage(context)
|
146
191
|
end
|
147
192
|
|
148
|
-
def viewDidAppear(animated)
|
149
|
-
super
|
150
|
-
|
151
|
-
image_view.image = preview_image
|
152
|
-
|
153
|
-
reset
|
154
|
-
end
|
155
|
-
|
156
193
|
def reset(options = {})
|
157
194
|
animated = options.fetch(:animated, false)
|
158
195
|
|
@@ -163,8 +200,8 @@ class Motion; class ImageEditorController < UIViewController
|
|
163
200
|
crop_aspect = crop_rect.size.height / crop_rect.size.width
|
164
201
|
|
165
202
|
if source_aspect > crop_aspect
|
166
|
-
|
167
|
-
|
203
|
+
w = crop_rect.size.width
|
204
|
+
h = source_aspect * w
|
168
205
|
else
|
169
206
|
h = crop_rect.size.height
|
170
207
|
w = h / source_aspect
|
@@ -189,7 +226,53 @@ class Motion; class ImageEditorController < UIViewController
|
|
189
226
|
end
|
190
227
|
end
|
191
228
|
|
192
|
-
|
229
|
+
def check_bounds
|
230
|
+
y_offset = 0
|
231
|
+
x_offset = 0
|
232
|
+
|
233
|
+
if image_view.frame.origin.x > crop_rect.origin.x
|
234
|
+
x_offset = -(image_view.frame.origin.x - crop_rect.origin.x)
|
235
|
+
new_right_x = CGRectGetMaxX(image_view.frame) + x_offset
|
236
|
+
|
237
|
+
if new_right_x < CGRectGetMaxX(crop_rect)
|
238
|
+
x_offset = CGRectGetMaxX(crop_rect) - CGRectGetMaxX(image_view.frame)
|
239
|
+
end
|
240
|
+
elsif CGRectGetMaxX(image_view.frame) < CGRectGetMaxX(crop_rect)
|
241
|
+
x_offset = CGRectGetMaxX(crop_rect) - CGRectGetMaxX(image_view.frame)
|
242
|
+
new_left_x = image_view.frame.origin.x + x_offset
|
243
|
+
|
244
|
+
if new_left_x > crop_rect.origin.x
|
245
|
+
x_offset = crop_rect.origin.x - image_view.frame.origin.x
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
if image_view.frame.origin.y > crop_rect.origin.y
|
250
|
+
y_offset = -(image_view.frame.origin.y - crop_rect.origin.y)
|
251
|
+
new_bottom_y = CGRectGetMaxY(image_view.frame) + y_offset
|
252
|
+
|
253
|
+
if new_bottom_y < CGRectGetMaxY(crop_rect)
|
254
|
+
y_offset = CGRectGetMaxY(crop_rect) - CGRectGetMaxY(image_view.frame)
|
255
|
+
end
|
256
|
+
elsif CGRectGetMaxY(image_view.frame) < CGRectGetMaxY(crop_rect)
|
257
|
+
y_offset = CGRectGetMaxY(crop_rect) - CGRectGetMaxY(image_view.frame)
|
258
|
+
new_top_y = image_view.frame.origin.y + y_offset
|
259
|
+
|
260
|
+
if new_top_y > crop_rect.origin.y
|
261
|
+
y_offset = crop_rect.origin.y - image_view.frame.origin.y
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
if x_offset || y_offset
|
266
|
+
view.userInteractionEnabled = false
|
267
|
+
transform = CGAffineTransformTranslate(image_view.transform, x_offset / scale, y_offset / scale)
|
268
|
+
UIView.animateWithDuration(
|
269
|
+
ANIMATION_DURATION,
|
270
|
+
delay: 0,
|
271
|
+
options: UIViewAnimationOptionCurveEaseOut,
|
272
|
+
animations: -> { image_view.transform = transform },
|
273
|
+
completion: -> (finished) { view.userInteractionEnabled = true })
|
274
|
+
end
|
275
|
+
end
|
193
276
|
|
194
277
|
def touchesBegan(touches, withEvent: event)
|
195
278
|
handle_touches(event.allTouches)
|
@@ -221,48 +304,19 @@ class Motion; class ImageEditorController < UIViewController
|
|
221
304
|
end
|
222
305
|
end
|
223
306
|
|
224
|
-
def handle_state?(state)
|
225
|
-
if state == UIGestureRecognizerStateEnded
|
226
|
-
new_scale = bounded_scale(scale)
|
227
|
-
|
228
|
-
delta_x = scale_center.x - image_view.bounds.size.width / 2.0
|
229
|
-
delta_y = scale_center.y - image_view.bounds.size.height / 2.0
|
230
|
-
|
231
|
-
transform = CGAffineTransformTranslate(image_view.transform, delta_x, delta_y)
|
232
|
-
|
233
|
-
transform = CGAffineTransformScale(transform, new_scale / scale , new_scale / scale)
|
234
|
-
|
235
|
-
transform = CGAffineTransformTranslate(transform, -delta_x, -delta_y)
|
236
|
-
|
237
|
-
view.userInteractionEnabled = false
|
238
|
-
|
239
|
-
UIView.animateWithDuration(
|
240
|
-
ANIMATION_DURATION,
|
241
|
-
delay: 0,
|
242
|
-
options: UIViewAnimationOptionCurveEaseOut,
|
243
|
-
animations: -> { image_view.transform = transform },
|
244
|
-
completion: -> (finished) {
|
245
|
-
view.userInteractionEnabled = true
|
246
|
-
@scale = new_scale
|
247
|
-
})
|
248
|
-
|
249
|
-
false
|
250
|
-
else
|
251
|
-
true
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
307
|
def handle_pan(recognizer)
|
256
|
-
|
257
|
-
|
308
|
+
if handle_gesture_state? recognizer.state
|
309
|
+
translation = recognizer.translationInView(image_view)
|
310
|
+
transform = CGAffineTransformTranslate(image_view.transform, translation.x, translation.y)
|
258
311
|
|
259
|
-
|
312
|
+
image_view.transform = transform
|
260
313
|
|
261
|
-
|
314
|
+
recognizer.setTranslation(CGPointZero, inView: crop_view)
|
315
|
+
end
|
262
316
|
end
|
263
317
|
|
264
318
|
def handle_pinch(recognizer)
|
265
|
-
if
|
319
|
+
if handle_gesture_state? recognizer.state
|
266
320
|
if recognizer.state == UIGestureRecognizerStateBegan
|
267
321
|
@scale_center = @touch_center
|
268
322
|
end
|
@@ -283,22 +337,37 @@ class Motion; class ImageEditorController < UIViewController
|
|
283
337
|
end
|
284
338
|
|
285
339
|
def handle_rotation(recognizer)
|
286
|
-
|
287
|
-
|
340
|
+
if rotation_enabled? && handle_gesture_state?(recognizer.state)
|
341
|
+
delta_x = touch_center.x - image_view.bounds.size.width / 2
|
342
|
+
delta_y = touch_center.y - image_view.bounds.size.height / 2
|
288
343
|
|
289
|
-
|
290
|
-
|
291
|
-
|
344
|
+
transform = CGAffineTransformTranslate(image_view.transform, delta_x, delta_y)
|
345
|
+
transform = CGAffineTransformRotate(transform, recognizer.rotation)
|
346
|
+
transform = CGAffineTransformTranslate(transform, -delta_x, -delta_y)
|
292
347
|
|
293
|
-
|
348
|
+
image_view.transform = transform
|
294
349
|
|
295
|
-
|
350
|
+
recognizer.rotation = 0
|
351
|
+
end
|
296
352
|
end
|
297
353
|
|
298
354
|
def handle_tap(recognizer)
|
299
355
|
reset(animated: true)
|
300
356
|
end
|
301
357
|
|
358
|
+
def bounded_scale(scale)
|
359
|
+
return scale if (MINIMUM_SCALE..MAXIMUM_SCALE).include? scale
|
360
|
+
|
361
|
+
scale < MINIMUM_SCALE ? MINIMUM_SCALE : MAXIMUM_SCALE
|
362
|
+
end
|
363
|
+
|
364
|
+
def scale_reset_orientations
|
365
|
+
[ UIImageOrientationUpMirrored,
|
366
|
+
UIImageOrientationDownMirrored,
|
367
|
+
UIImageOrientationLeftMirrored,
|
368
|
+
UIImageOrientationRightMirrored ]
|
369
|
+
end
|
370
|
+
|
302
371
|
def pan_recognizer
|
303
372
|
@pan_recognizer ||= UIPanGestureRecognizer.alloc.initWithTarget(self, action: 'handle_pan:').tap do |recognizer|
|
304
373
|
recognizer.cancelsTouchesInView = false
|
@@ -326,19 +395,6 @@ class Motion; class ImageEditorController < UIViewController
|
|
326
395
|
end
|
327
396
|
end
|
328
397
|
|
329
|
-
def source_image=(image)
|
330
|
-
if image != source_image
|
331
|
-
@source_image = image
|
332
|
-
@preview_image = nil
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
def bounded_scale(scale)
|
337
|
-
return scale if (MINIMUM_SCALE..MAXIMUM_SCALE).include? scale
|
338
|
-
|
339
|
-
scale < MINIMUM_SCALE ? MINIMUM_SCALE : MAXIMUM_SCALE
|
340
|
-
end
|
341
|
-
|
342
398
|
def preview_image
|
343
399
|
@preview_image ||= source_image.resizedImageToFitInSize(view.bounds.size, scaleIfSmaller: false)
|
344
400
|
end
|
@@ -355,7 +411,27 @@ class Motion; class ImageEditorController < UIViewController
|
|
355
411
|
end
|
356
412
|
end
|
357
413
|
|
414
|
+
def scale
|
415
|
+
@scale ||= 1
|
416
|
+
end
|
417
|
+
|
418
|
+
def touch_center
|
419
|
+
@touch_center ||= CGPointZero
|
420
|
+
end
|
421
|
+
|
422
|
+
def scale_center
|
423
|
+
@scale_center ||= CGPointZero
|
424
|
+
end
|
425
|
+
|
358
426
|
def prefersStatusBarHidden
|
359
427
|
true
|
360
428
|
end
|
429
|
+
|
430
|
+
def rotation_enabled?
|
431
|
+
!!@rotation_enabled
|
432
|
+
end
|
433
|
+
|
434
|
+
def enforce_bounds?
|
435
|
+
!!@enforce_bounds
|
436
|
+
end
|
361
437
|
end; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion-image-editor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devon Blandin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: motion-cocoapods
|