Created
April 10, 2018 13:24
-
-
Save jsbain/48675c9f598a1a8ade648391b429d63c to your computer and use it in GitHub Desktop.
Sketch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
A very simple drawing 'app' that demonstrates | |
custom views and saving images to the camera roll. | |
''' | |
import ui | |
import photos | |
import console | |
# The PathView class is responsible for tracking | |
# touches and drawing the current stroke. | |
# It is used by SketchView. | |
class PathView (ui.View): | |
def __init__(self, frame): | |
self.frame = frame | |
self.flex = 'WH' | |
self.path = None | |
self.action = None | |
def touch_began(self, touch): | |
x, y = touch.location | |
self.path = MyPath()#ui.Path() | |
self.path.line_width = 8.0 | |
self.path.line_join_style = ui.LINE_JOIN_ROUND | |
self.path.line_cap_style = ui.LINE_CAP_ROUND | |
self.path.move_to(x, y) | |
def touch_moved(self, touch): | |
x, y = touch.location | |
self.path.line_to(x, y) | |
self.set_needs_display() | |
def touch_ended(self, touch): | |
# Send the current path to the SketchView: | |
if callable(self.action): | |
self.action(self) | |
# Clear the view (the path has now been rendered | |
# into the SketchView's image view): | |
self.path = None | |
self.set_needs_display() | |
def draw(self): | |
if self.path: | |
self.path.stroke() | |
# The main SketchView contains a PathView for the current | |
# line and an ImageView for rendering completed strokes. | |
# It also manages the 'Clear' and 'Save' ButtonItems that | |
# are shown in the title bar. | |
class SketchView (ui.View): | |
def __init__(self, width=1024, height=1024): | |
self.bg_color = 'white' | |
iv = ui.ImageView(frame=(0, 0, width, height)) | |
pv = PathView(frame=self.bounds) | |
pv.action = self.path_action | |
self.add_subview(iv) | |
self.add_subview(pv) | |
save_button = ui.ButtonItem() | |
save_button.title = 'Save Image' | |
save_button.action = self.save_action | |
clear_button = ui.ButtonItem() | |
clear_button.title = 'Clear' | |
clear_button.tint_color = 'red' | |
clear_button.action = self.clear_action | |
self.right_button_items = [save_button, clear_button] | |
self.image_view = iv | |
def path_action(self, sender): | |
path = sender.path | |
old_img = self.image_view.image | |
width, height = self.image_view.width, self.image_view.height | |
with ui.ImageContext(width, height) as ctx: | |
if old_img: | |
old_img.draw() | |
path.stroke() | |
self.image_view.image = ctx.get_image() | |
def clear_action(self, sender): | |
self.image_view.image = None | |
def save_action(self, sender): | |
if self.image_view.image: | |
# We draw a new image here, so that it has the current | |
# orientation (the canvas is quadratic). | |
with ui.ImageContext(self.width, self.height) as ctx: | |
self.image_view.image.draw() | |
img = ctx.get_image() | |
photos.save_image(img) | |
console.hud_alert('Saved') | |
else: | |
console.hud_alert('No Image', 'error') | |
'''I have modified the Sketch.py code to draw a succession of ovals instead of using path.stroke(), with the intention of using the pencil pressure to change the alpha at different points along the path. In the code below I have kept it constant for simplicity. But the alpha value does not seem to be captured correctly in ctx.get_image(), causing it to change when path_action() is called at the end of the path. Just add the code below to the Sketch.py example, and change the definition in touch_began() to self.path = MyPath() to see the problem when you lift the pencil/finger at the end of the stroke. | |
''' | |
import math | |
def distanceBetween(point1, point2): | |
return math.sqrt((point2[0] - point1[0])**2 + (point2[1] - point1[1])**2) | |
def angleBetween(point1, point2): | |
return math.atan2( point2[0] - point1[0], point2[1] - point1[1] ) | |
class MyPath(): | |
def move_to(self,x,y): | |
self.path = [(x,y)] | |
def line_to(self,x,y): | |
self.path.append((x,y)) | |
def stroke(self): | |
w = 20 | |
ui.set_alpha(0.006) | |
lastPoint = self.path[0] | |
for i in range(1,len(self.path)): | |
currentPoint = self.path[i] | |
dist = distanceBetween(lastPoint, currentPoint) | |
angle = angleBetween(lastPoint, currentPoint) | |
for j in range(int(dist)): | |
x = lastPoint[0] + (math.sin(angle) * j) | |
y = lastPoint[1] + (math.cos(angle) * j) | |
circle = ui.Path.oval(x, y, w, w) | |
circle.fill() | |
lastPoint = currentPoint | |
# We use a square canvas, so that the same image | |
# can be used in portrait and landscape orientation. | |
w, h = ui.get_screen_size() | |
canvas_size = max(w, h) | |
sv = SketchView(canvas_size, canvas_size) | |
sv.name = 'Sketch' | |
sv.present('fullscreen') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment