Skip to content

Instantly share code, notes, and snippets.

Created Apr 10, 2018
What would you like to do?
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)
def touch_ended(self, touch):
# Send the current path to the SketchView:
if callable(self.action):
# Clear the view (the path has now been rendered
# into the SketchView's image view):
self.path = None
def draw(self):
if self.path:
# 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
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:
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:
img = ctx.get_image()
console.hud_alert('No Image', 'error')
'''I have modified the 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 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):
def stroke(self):
w = 20
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)
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) = 'Sketch'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment