Skip to content

Commit

Permalink
Merge pull request #187 from shoebot/jupyter
Browse files Browse the repository at this point in the history
Jupyter
  • Loading branch information
rlafuente committed Oct 10, 2018
2 parents 87e3230 + ddb1b1c commit 07f1b2e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 79 deletions.
6 changes: 5 additions & 1 deletion shoebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import signal
import sys
import threading
import cairocffi as cairo

# TODO - Check if this needs importing here:
# from shoebot.data import MOVETO, RMOVETO, LINETO, RLINETO, CURVETO, RCURVETO, ARC, ELLIPSE, CLOSE, LEFT, RIGHT, ShoebotError, ShoebotScriptError
Expand Down Expand Up @@ -105,7 +106,10 @@ def create_canvas(src, format=None, outputfile=None, multifile=False, buff=None,
title = 'Untitled - Shoebot'
sink = ShoebotWindow(title, show_vars, fullscreen=fullscreen)
else:
if src and os.path.isfile(src):
if src and isinstance(src, cairo.Surface):
outputfile = src
format = 'surface'
elif src and os.path.isfile(src):
outputfile = os.path.splitext(os.path.basename(src))[0] + '.' + (format or 'svg')
else:
outputfile = 'output.svg'
Expand Down
19 changes: 12 additions & 7 deletions shoebot/core/cairo_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,29 @@ class CairoImageSink(DrawQueueSink):
'''
DrawQueueSink that uses cairo contexts as the render context.
'''
def __init__(self, filename=None, format=None, multifile=False, buff=None):
def __init__(self, target=None, format=None, multifile=False, buff=None):
"""
:param filename: output filename
:param format: if filename is specified this is not needed.
:param target: output filename (or cairo surface if format is 'surface')
:param format: if filename is specified this is not needed. Can be 'surface' for Cairo surfaces
:param multifile: If used with filename, then numbered files will be output for each froam.
:param buff: optionally a file like object can be used instead of a filename
this is useful for streaming output.
"""
DrawQueueSink.__init__(self)
if format is None:
if filename is not None:
format = os.path.splitext(filename)[1][1:].lower()
if target is not None and format is not 'surface':
format = os.path.splitext(target)[1][1:].lower()
self.filename = target
elif buff is not None:
raise AttributeError("No format specified, but using buff")
else:
# multifile
self.file_root, self.file_ext = os.path.splitext(filename)
self.buff = buff
self.format = format
self.filename = filename
self.target = target
self.multifile = multifile
self.file_root, self.file_ext = os.path.splitext(filename)

def _output_file(self, frame):
"""
Expand Down Expand Up @@ -84,6 +87,8 @@ def create_rcontext(self, size, frame):
surface = cairo.PSSurface(self._output_file(frame), *size)
elif self.format == 'svg':
surface = cairo.SVGSurface(self._output_file(frame), *size)
elif self.format == 'surface':
surface = self.target
else:
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *size)
return cairo.Context(surface)
Expand Down
61 changes: 49 additions & 12 deletions shoebot/grammar/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,38 +320,75 @@ def files(self, path="*"):
# Taken ipsis verbis from Nodebox
return glob(path)

def snapshot(self, filename=None, surface=None, defer=None, autonumber=False):
def snapshot(self, target=None, defer=None, autonumber=False):
'''Save the contents of current surface into a file or cairo surface/context
:param filename: Filename to save snapshot as, available formats include .png, .ps, .svg
:param surface: If specified will output snapshot to the supplied cairo surface.
:param filename: Can be a filename or a Cairo surface.
:param defer: If true, buffering/threading may be employed however output will not be immediate.
:param autonumber: If true then a number will be appended to the filename.
'''
if autonumber:
file_number=self._frame
file_number = self._frame
else:
file_number=None
if surface:
file_number = None

import cairocffi as cairo
if isinstance(target, cairo.Surface):
# snapshot to Cairo surface
if defer is None:
self._canvas.snapshot(surface, defer)
defer = False
ctx = cairo.Context(target)
# this used to be self._canvas.snapshot, but I couldn't make it work.
# self._canvas.snapshot(target, defer)
# TODO: check if this breaks when taking more than 1 snapshot
self._canvas._drawqueue.render(ctx)
return
elif filename is None:
# If nothing specied, we can see if a filename is available
elif target is None:
# If nothing specified, use a default filename from the script name
script_file = self._namespace.get('__file__')
if script_file:
filename = os.path.splitext(script_file)[0] + '.svg'
file_number=True
target = os.path.splitext(script_file)[0] + '.svg'
file_number = True

if filename:
if target:
# snapshot to file, target is a filename
if defer is None:
self._canvas.snapshot(filename, defer=defer, file_number=file_number)
defer = True
self._canvas.snapshot(target, defer=defer, file_number=file_number)
else:
raise ShoebotError('No image saved')

def show(self, format='png', as_data=False):
'''Returns an Image object of the current surface. Used for displaying
output in Jupyter notebooks. Adapted from the cairo-jupyter project.'''

import cairocffi as cairo
from io import BytesIO

b = BytesIO()

if format == 'png':
from IPython.display import Image
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.WIDTH, self.HEIGHT)
self.snapshot(surface)
surface.write_to_png(b)
b.seek(0)
data = b.read()
if as_data:
return data
else:
return Image(data)
elif format == 'svg':
from IPython.display import SVG
surface = cairo.SVGSurface(b, self.WIDTH, self.HEIGHT)
surface.finish()
b.seek(0)
data = b.read()
if as_data:
return data
else:
return SVG(data)

def ximport(self, libName):
'''
Expand Down
4 changes: 3 additions & 1 deletion shoebot/grammar/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def _run_frame(self, executor, limit=False, iteration=0):
elif self._speed < 0:
self._frame -= 1

def run(self, inputcode, iterations=None, run_forever=False, frame_limiter=False, verbose=False):
def run(self, inputcode, iterations=None, run_forever=False, frame_limiter=False, verbose=False, break_on_error=False):
'''
Executes the contents of a Nodebox/Shoebot script
in current surface's context.
Expand Down Expand Up @@ -288,6 +288,8 @@ def run(self, inputcode, iterations=None, run_forever=False, frame_limiter=False
else:
errmsg = simple_traceback(e, executor.known_good or '')
print >> sys.stderr, errmsg
if break_on_error:
raise

def finish(self):
## For use when using shoebot as a module
Expand Down
58 changes: 0 additions & 58 deletions shoebot/grammar/nodebox.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,64 +245,6 @@ def star(self, startx, starty, points=20, outer=100, inner=50, draw=True, **kwar

return self.endpath(draw)

def obama(self, x=0, y=0, s=1):
self.beginpath()
self.moveto(x+0, y+0)
self.moveto(x+30.155835*s, y+3.3597362999999998*s)
self.curveto(x+22.226585999999998*s, y+3.4767912999999999*s, x+17.558824000000001*s, y+11.938165*s, x+17.099542*s, y+19.025210999999999*s)
self.curveto(x+16.557696*s, y+22.805612999999997*s, x+15.694208*s, y+27.570126999999999*s, x+20.886292999999998*s, y+24.358142999999998*s)
self.curveto(x+22.063617999999998*s, y+23.262867999999997*s, x+16.210089999999997*s, y+25.217665999999998*s, x+20.032938999999999*s, y+22.868894999999998*s)
self.curveto(x+25.583684999999999*s, y+23.357593999999999*s, x+22.084018*s, y+16.985720000000001*s, x+18.091563000000001*s, y+19.354975*s)
self.curveto(x+17.196534*s, y+12.990902999999999*s, x+21.360583000000002*s, y+6.1242342999999995*s, x+28.662463000000002*s, y+7.5544572999999993*s)
self.curveto(x+38.693815999999998*s, y+5.1428252999999993*s, x+39.505282000000001*s, y+14.898575999999998*s, x+40.712510000000002*s, y+15.298545999999998*s)
self.curveto(x+41.478746000000001*s, y+17.796257999999998*s, x+38.611923000000004*s, y+17.259235999999998*s, x+41.188965000000003*s, y+20.135055999999999*s)
self.curveto(x+41.031133000000004*s, y+21.093715*s, x+40.828136000000001*s, y+22.054302999999997*s, x+40.595178000000004*s, y+23.017814999999999*s)
self.curveto(x+37.462203000000002*s, y+22.218651999999999*s, x+39.577568000000007*s, y+20.442938999999999*s, x+35.418173000000003*s, y+21.627851999999997*s)
self.curveto(x+33.602451000000002*s, y+19.520005999999999*s, x+26.432436000000003*s, y+20.067235999999998*s, x+32.427879000000004*s, y+19.574813999999996*s)
self.curveto(x+36.576917000000002*s, y+22.536335999999995*s, x+36.206899000000007*s, y+18.657166999999998*s, x+32.257211000000005*s, y+18.227402999999995*s)
self.curveto(x+30.574708000000005*s, y+18.213692999999996*s, x+25.753600000000006*s, y+17.080653999999996*s, x+26.102409000000005*s, y+20.064142999999994*s)
self.curveto(x+26.629214000000005*s, y+23.430944999999994*s, x+38.445660000000004*s, y+20.437210999999994*s, x+31.723868000000003*s, y+22.684509999999996*s)
self.curveto(x+25.411513000000003*s, y+23.251439999999995*s, x+37.020808000000002*s, y+23.018320999999997*s, x+40.577397000000005*s, y+23.095826999999996*s)
self.curveto(x+39.397572000000004*s, y+27.939184999999995*s, x+37.394660000000002*s, y+32.818625999999995*s, x+35.748844000000005*s, y+37.477711999999997*s)
self.curveto(x+33.876538000000004*s, y+37.505711999999995*s, x+40.912494000000002*s, y+27.210657999999995*s, x+33.551462000000008*s, y+28.513852999999997*s)
self.curveto(x+29.408984000000007*s, y+26.166980999999996*s, x+30.338694000000007*s, y+27.710668999999996*s, x+33.110568000000008*s, y+30.191032999999997*s)
self.curveto(x+33.542732000000008*s, y+33.300877999999997*s, x+27.883396000000008*s, y+31.263332999999996*s, x+24.356592000000006*s, y+31.595176999999996*s)
self.curveto(x+26.592705000000006*s, y+31.132081999999997*s, x+32.999869000000004*s, y+26.980728999999997*s, x+25.889071000000005*s, y+28.137995999999998*s)
self.curveto(x+24.787247000000004*s, y+28.528912999999999*s, x+23.694590000000005*s, y+29.248256999999999*s, x+22.461438000000005*s, y+29.045728999999998*s)
self.curveto(x+19.269951000000006*s, y+27.610359999999996*s, x+20.894864000000005*s, y+31.648117999999997*s, x+23.304124000000005*s, y+31.790200999999996*s)
self.curveto(x+23.016163000000006*s, y+31.879840999999995*s, x+22.756522000000004*s, y+31.999426999999997*s, x+22.532552000000006*s, y+32.155418999999995*s)
self.curveto(x+18.385237000000007*s, y+34.449280999999992*s, x+20.349656000000007*s, y+30.779214999999994*s, x+19.403592000000007*s, y+29.169828999999993*s)
self.curveto(x+13.060974000000007*s, y+29.491880999999992*s, x+17.907451000000005*s, y+36.572479999999992*s, x+20.239166000000008*s, y+40.144177999999997*s)
self.curveto(x+18.873123000000007*s, y+37.739430999999996*s, x+18.08608000000001*s, y+32.890574999999998*s, x+19.360926000000006*s, y+33.977977999999993*s)
self.curveto(x+20.037191000000007*s, y+36.986654999999992*s, x+25.938847000000006*s, y+41.74645499999999*s, x+26.130852000000004*s, y+38.06631999999999*s)
self.curveto(x+20.628474000000004*s, y+36.782302999999992*s, x+27.449303000000004*s, y+35.551605999999992*s, x+29.746934000000003*s, y+35.648064999999988*s)
self.curveto(x+30.410632000000003*s, y+33.076153999999988*s, x+19.772083000000002*s, y+38.383369999999985*s, x+23.268567000000004*s, y+33.779412999999991*s)
self.curveto(x+27.615261000000004*s, y+31.829713999999992*s, x+31.833047000000004*s, y+35.101421999999992*s, x+35.688399000000004*s, y+31.89302799999999*s)
self.curveto(x+35.013363000000005*s, y+37.811202999999992*s, x+31.504216000000003*s, y+45.616307999999989*s, x+24.125476000000006*s, y+44.718296999999993*s)
self.curveto(x+19.661164000000007*s, y+41.819234999999992*s, x+21.309011000000005*s, y+48.927480999999993*s, x+14.919938000000005*s, y+51.24616799999999*s)
self.curveto(x+9.8282387000000053*s, y+53.10291999999999*s, x+5.8473682000000053*s, y+52.883251999999992*s, x+6.0155459000000047*s, y+56.432774999999992*s)
self.curveto(x+12.987418000000005*s, y+55.93589999999999*s, x+13.997744000000004*s, y+56.35166499999999*s, x+21.252523000000004*s, y+55.912477999999993*s)
self.curveto(x+20.898605000000003*s, y+53.130379999999995*s, x+19.688185000000004*s, y+41.857771999999997*s, x+23.656133000000004*s, y+47.023085999999992*s)
self.curveto(x+25.569923000000003*s, y+49.452668999999993*s, x+28.134662000000006*s, y+51.620268999999993*s, x+30.831404000000006*s, y+52.278003999999996*s)
self.curveto(x+28.088531000000007*s, y+53.314066999999994*s, x+28.752400000000005*s, y+58.240187999999996*s, x+30.522060000000007*s, y+56.199688999999992*s)
self.curveto(x+26.248979000000006*s, y+52.41766599999999*s, x+40.622643000000011*s, y+60.60644099999999*s, x+34.287476000000005*s, y+53.45876299999999*s)
self.lineto(x+33.032337000000005*s, y+52.455290999999988*s)
self.curveto(x+38.130551000000004*s, y+52.222700999999986*s, x+42.570123000000009*s, y+42.380979999999987*s, x+42.152545000000003*s, y+48.047831999999985*s)
self.curveto(x+43.123448000000003*s, y+54.821857999999985*s, x+40.010563000000005*s, y+56.547931999999989*s, x+47.969558000000006*s, y+56.614551999999989*s)
self.curveto(x+53.619178000000005*s, y+56.352016999999989*s, x+55.95324500000001*s, y+57.119506999999992*s, x+59.298673000000008*s, y+56.060458999999987*s)
self.curveto(x+58.382843999999999*s, y+46.073152*s, x+39.067419999999998*s, y+53.375225999999998*s, x+43.301012*s, y+37.764923000000003*s)
self.curveto(x+43.428455999999997*s, y+31.694825000000002*s, x+54.123880999999997*s, y+29.681982999999999*s, x+50.010494999999999*s, y+22.514310999999999*s)
self.curveto(x+47.938220999999999*s, y+20.563641000000001*s, x+44.097188000000003*s, y+25.356368*s, x+47.994453*s, y+21.312273999999999*s)
self.curveto(x+50.682201999999997*s, y+9.7576163000000005*s, x+40.191285999999998*s, y+3.6382382999999998*s, x+30.155835*s, y+3.3597362999999998*s)
self.moveto(x+20.239166000000001*s, y+40.144177999999997*s)
self.curveto(x+20.618817*s, y+40.762231*s, x+20.633900000000001*s, y+40.753855999999999*s, x+20.239166000000001*s, y+40.144177999999997*s)
self.moveto(x+48.335794999999997*s, y+25.116951*s)
self.curveto(x+52.603257999999997*s, y+28.884436000000001*s, x+42.579355*s, y+36.129815000000001*s, x+44.680596999999999*s, y+27.957156999999999*s)
self.curveto(x+46.699556999999999*s, y+28.476931999999998*s, x+47.871873000000001*s, y+29.936544999999999*s, x+48.335794999999997*s, y+25.116951*s)
return self.endpath()

easteregg = obama

# Path
# Path functions taken from Nodebox and modified

Expand Down

0 comments on commit 07f1b2e

Please sign in to comment.