#coding: utf-8
import ui
import photos
class PointView(ui.View):
def __init__(self):
self.bounds = (0,0,16,16)
self.hidden = True
self.touch_enabled = False
def draw(self):
contour = ui.Path.oval(0,0,self.width, self.height)
ui.set_color('#FF7349')
contour.fill()
oval = ui.Path.oval(4,4,self.width - 8, self.height - 8)
ui.set_color('#FF8B3F')
oval.fill()
class CropArea(ui.View):
def __init__(self):
self.hidden = True
self.touch_enabled = False
self.background_color = (1,0.54,0.24,0.3)
self.bounds = (0,0,2,2)
class DragView (ui.View):
def __init__(self):
self.background_color = (1,1,1,0)
self.crop_area = CropArea()
self.indicator_start = PointView()
self.indicator_end = PointView()
self.crop_pixels = ui.Label(number_of_lines=1, background_color=(1,0.54,0.24,1.0))
self.crop_pixels.hidden = True
self.crop_pixels.text_color = '#383838'
self.crop_pixels.height = 20
self.crop_pixels.alignment = ui.ALIGN_CENTER
self.add_subview(self.crop_pixels)
self.add_subview(self.crop_area)
self.add_subview(self.indicator_start)
def draw(self):
self.crop_button = ui.ButtonItem(title='Crop', enabled=False, action=self.crop_action)
self.superview.right_button_items = [self.crop_button]
self.clear_button = ui.ButtonItem(title='Clear', enabled=False, action=self.clear_action)
self.superview.left_button_items = [self.clear_button]
self.spinner = ui.ActivityIndicator()
self.spinner.style = ui.ACTIVITY_INDICATOR_STYLE_WHITE_LARGE
self.spinner.center = self.center
self.superview.add_subview(self.spinner)
def touch_began(self, touch):
self.remove_subview(self.indicator_end)
self.crop_button.enabled = False
self.clear_button.enabled = False
self.crop_area.bounds = (0,0,2,2)
self.indicator_start.center = touch.location
self.indicator_start.hidden = False
self.crop_area.x = touch.location[0]
self.crop_area.y = touch.location[1]
self.crop_area.hidden = False
self.crop_pixels.hidden = True
def touch_moved(self, touch):
loc = touch.location
if loc[0] < self.indicator_start.center[0]:
self.crop_area.x = loc[0]
if loc[1] < self.indicator_start.center[1]:
self.crop_area.y = loc[1]
self.crop_area.width = abs(loc[0] - self.indicator_start.center[0])
self.crop_area.height = abs(loc[1] - self.indicator_start.center[1])
self.crop_pixels.hidden = False
self.crop_pixels.text = '%i x %i' % self.current_crop_size()
self.crop_pixels.x = self.crop_area.x
self.crop_pixels.y = self.crop_area.y + self.crop_area.height
def touch_ended(self, touch):
self.add_subview(self.indicator_end)
self.indicator_end.center = touch.location
self.indicator_end.hidden = False
self.crop_button.enabled = True
self.clear_button.enabled = True
def clear_action(self, sender):
self.crop_button.enabled = False
self.indicator_end.hidden = True
self.crop_area.hidden = True
self.indicator_start.hidden = True
def crop_action(self, sender):
self.spinner.start()
the_image = self.superview.image_view.image
iw, ih = the_image.size
fx, fy, fw, fh = self.crop_area.frame
scale = min(iw/self.width, ih/self.height)
dw, dh, dx, dy = fw * scale, fh * scale, fx * scale, fy * scale
with ui.ImageContext(dw,dh) as ctx:
with ui.ImageContext(iw,ih) as cropx:
the_image.clip_to_mask(dx,dy,dw,dh)
the_image.draw()
le_crop = cropx.get_image()
ui.concat_ctm(ui.Transform.translation(-dx, -dy))
le_crop.draw()
self.cropped_image = ctx.get_image()
self.show_crop = ui.ImageView()
self.show_crop.image = self.cropped_image
self.show_crop.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
self.show_crop.flex = 'TBLR'
self.spinner.stop()
save_image = ui.ButtonItem(title='Save Image', action=self.save_to_camera_roll)
self.show_crop.right_button_items = [save_image]
self.show_crop.present('sheet')
def save_to_camera_roll(self, sender):
saved_photo = photos.save_image(self.cropped_image)
if saved_photo:
self.show_crop.close()
def current_crop_size(self):
iw, ih = self.superview.image_view.image.size
fx, fy, fw, fh = self.crop_area.frame
scale = min(iw/self.width, ih/self.height)
dw, dh = fw * scale, fh * scale
return dw,dh
class DemoView (ui.View):
def __init__(self):
self.image_view = ui.ImageView(frame=self.bounds)
self.image_view.content_mode = ui.CONTENT_SCALE_ASPECT_FIT
self.image_view.flex = 'WH'
self.image_view.background_color = '#383838'
self.add_subview(self.image_view)
self.drag_view = DragView()
self.add_subview(self.drag_view)
def set_image(self, img):
self.image_view.image = img
self.layout()
def layout(self):
if self.image_view.image:
w, h = self.width, self.height
iw, ih = self.image_view.image.size
scale = min(w/iw, h/ih)
dw, dh = iw * scale, ih * scale
x, y = (w - dw) * 0.5, (h - dh) * 0.5
self.drag_view.frame = (x, y, dw, dh)
img = ui.Image.from_data(photos.pick_image(raw_data=True))
if img:
v = DemoView()
v.set_image(img)
v.present()
There are no comments yet.
I'm not 100% sure that it's working correctly on my retina iPad Mini though. Am I right to assume that it's supposed to be possible to adjust the orange selection rectangle using its little circular handles? And also to move the rectangle by tapping and dragging within it? Neither of those things work for me as every tap starts the creation of a new rectangle (i.e. No adjusting or moving the existing rectangle). Maybe that wasn't even your intention, but maybe it's a bug. I thought you might like to know anyway.
Thanks again for producing this great workflow.
Cheers!
Alan.