Merge pull request #2 from brendabell/feature/add-passap-deco

Feature/add passap deco
pull/3/head
Brenda 2016-12-30 11:08:33 -05:00 zatwierdzone przez GitHub
commit 07b182bfb3
12 zmienionych plików z 17654 dodań i 266 usunięć

1
__init__.py 100644
Wyświetl plik

@ -0,0 +1 @@
# intentionally empty

Wyświetl plik

@ -0,0 +1,62 @@
#!/bin/bash
#
# chkconfig: 2345 75 35
# description: knittingtools
SERVICE=knittingtools
# Source function library.
. /etc/init.d/functions
lockfile=/var/lock/${SERVICE}.lock
procname=/path/to/knittingtools/venv/bin/python
scriptname=/path/to/knittingtools/server.py
pidfile=/var/run/${SERVICE}.pid
RETVAL=0
prog="knittingtools"
start () {
if [ -f "$pidfile" ]; then
checkpid `cat $pidfile` && return 0
fi
echo -n $"Starting $prog: "
$procname $scriptname 1>/dev/null 2>&1 &
RETVAL=$?
PID=$!
echo $PID
echo $PID >$pidfile
echo
[ $RETVAL -eq 0 ] && touch $lockfile
return $RETVAL
}
stop () {
RETVAL=0
if [ -f "${pidfile}" ]; then
echo -n $"Stopping $prog: "
killproc -p ${pidfile} $procname
RETVAL=$?
echo
fi
[ $RETVAL -eq 0 ] && rm -f $lockfile
return $RETVAL
}
restart () {
stop
start
}
# See how we were called.
case "$1" in
start|stop|restart)
$1 ;;
status)
status -p ${pidfile} $procname ;;
condrestart)
test ! -f $lockfile || restart ;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart}"
exit 2
esac

Wyświetl plik

@ -1,14 +1,16 @@
import cairosvg
import cgi
from os import curdir
import os
import sys
import time
import traceback
from modules.pcgenerator import PCGenerator
def pcgenerator_get(handler):
f = open("{}/templates/{}".format(
curdir,
f = open("{}/../templates/{}".format(
os.path.dirname(os.path.realpath(__file__)),
"pcgenerator.html"))
try:
@ -21,6 +23,8 @@ def pcgenerator_get(handler):
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
handler.wfile.write(
"<h1>Aw, snap! We seem to have a problem.</h1><p><b>")
handler.wfile.write(
@ -30,7 +34,6 @@ def pcgenerator_get(handler):
"<a href='http://www.ravelry.com/people/beebell'>beebell on Ravelry</a>. "
"It will be helpful if you include the pattern you uploaded to help me "
"diagnose the issue.")
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
finally:
f.close()
@ -38,47 +41,66 @@ def pcgenerator_get(handler):
def pcgenerator_post(handler):
try:
ctype, pdict = cgi.parse_header(handler.headers.getheader('content-type'))
ctype, pdict = cgi.parse_header(handler.headers.getheader('Content-Type'))
if ctype == 'multipart/form-data':
query=cgi.parse_multipart(handler.rfile, pdict)
upfilecontent = query.get('upfile')
if len(upfilecontent[0]) > 2500:
if len(upfilecontent[0]) > 4000:
handler.send_response(302)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write("Sorry. Your file cannot exceed 2500 bytes!")
else:
horz_repeat = query.get('horz')
machine_type = query.get('machine')
vert_repeat = query.get('vert')
cell_height = query.get('rowheight')
cell_width = query.get('colwidth')
convert_to_png = query.get('png', [''])[0] == 'png'
generator = PCGenerator(
handler,
upfilecontent[0],
float(cell_height[0]),
float(cell_width[0]),
int(horz_repeat[0]),
machine_type[0],
int(vert_repeat[0]))
result = generator.generate()
handler.send_response(200)
handler.send_header('Content-type', 'image/svg+xml')
handler.send_header("Content-Disposition", "attachment; filename=punchcard.svg")
filename_template = 'attachment; filename="punchcard-{}.{}"'
if convert_to_png:
result = cairosvg.svg2png(bytestring=result)
handler.send_header('Content-type', 'image/png')
handler.send_header('Content-Disposition', filename_template.format(int(time.time()), "png"))
else:
handler.send_header('Content-type', 'image/svg+xml')
handler.send_header('Content-Disposition', filename_template.format(int(time.time()), "svg"))
handler.end_headers()
handler.wfile.write(result)
return
except ValueError as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
handler.send_response(302)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write(
"<h1>Aw, snap!</h1><p>")
"<h1>Aw, snap! We seem to have a problem.</h1><p><b>")
handler.wfile.write(
repr(traceback.format_exception(exc_type, exc_value,exc_traceback)))
handler.wfile.write(e)
handler.wfile.write(
"</b><p>Please report this error via private message to "
"<a href='http://www.ravelry.com/people/beebell'>beebell on Ravelry</a>. "
"It will be helpful if you include the pattern you uploaded to help me "
"diagnose the issue.")
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
handler.send_response(302)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
@ -91,12 +113,11 @@ def pcgenerator_post(handler):
"<a href='http://www.ravelry.com/people/beebell'>beebell on Ravelry</a>. "
"It will be helpful if you include the pattern you uploaded to help me "
"diagnose the issue.")
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
def calculator_get(handler):
f = open("{}/templates/{}".format(
curdir,
f = open("{}/../templates/{}".format(
os.path.dirname(os.path.realpath(__file__)),
"calculator.html"))
try:
@ -109,6 +130,8 @@ def calculator_get(handler):
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
handler.wfile.write(
"<h1>Aw, snap! We seem to have a problem.</h1><p><b>")
handler.wfile.write(
@ -118,15 +141,14 @@ def calculator_get(handler):
"<a href='http://www.ravelry.com/people/beebell'>beebell on Ravelry</a>. "
"It will be helpful if you include the pattern you uploaded to help me "
"diagnose the issue.")
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
finally:
f.close()
def index_get(handler):
f = open("{}/templates/{}".format(
curdir,
"index.html"))
f = open("{}/../templates/{}".format(
os.path.dirname(os.path.realpath(__file__)),
"index.html"))
try:
handler.send_response(200)
@ -138,6 +160,8 @@ def index_get(handler):
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
handler.wfile.write(
"<h1>Aw, snap! We seem to have a problem.</h1><p><b>")
handler.wfile.write(
@ -147,7 +171,6 @@ def index_get(handler):
"<a href='http://www.ravelry.com/people/beebell'>beebell on Ravelry</a>. "
"It will be helpful if you include the pattern you uploaded to help me "
"diagnose the issue.")
handler.log_error("%s", traceback.format_exception(exc_type, exc_value,exc_traceback))
finally:
f.close()

23
logging.conf 100644
Wyświetl plik

@ -0,0 +1,23 @@
[loggers]
keys=root
[handlers]
keys=fileHandler
[formatters]
keys=fileFormatter
[logger_root]
level=DEBUG
handlers=fileHandler
[handler_fileHandler]
args=('/var/log/knittingtools.log', 'a')
backupCount: 7
class=logging.handlers.RotatingFileHandler
formatter=fileFormatter
level=DEBUG
[formatter_fileFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

Wyświetl plik

@ -1,70 +1,130 @@
import svgwrite
# default values
# number of overlapping blank rows at the top of the card
blank_rows = 2
# machine specs
specs = {
'12-stitch-br-sr': {
'card_width': 142,
'blank_rows': 2,
'row_height': 5.0,
'stitch_width': 9.0,
'pattern_hole_radius': 3.5,
'pattern_hole_xoffset': 22.5,
'clip_hole_radius': 3.5,
'clip_hole_xoffset': 5.0,
'clip_hole_yoffset': 5.0,
'tractor_hole_radius': 3.0,
'tractor_hole_xoffset': 12.5,
'tractor_hole_yoffset': 2.5,
'stitches': 12,
'corner_offset': 2,
},
'24-stitch-br-sr': {
'card_width': 142,
'blank_rows': 2,
'row_height': 5.0,
'stitch_width': 4.5,
'pattern_hole_radius': 3.5,
'pattern_hole_xoffset': 17.5,
'clip_hole_radius': 3.5,
'clip_hole_xoffset': 5.0,
'clip_hole_yoffset': 5.0,
'tractor_hole_radius': 3.0,
'tractor_hole_xoffset': 12.0,
'tractor_hole_yoffset': 2.5,
'stitches': 24,
'corner_offset': 2,
},
'40-stitch-deco': {
'card_width': 242,
'blank_rows': 3,
'row_height': (305.0 / 58.0),
'stitch_width': 5.0,
'pattern_hole_radius': 3.0,
'pattern_hole_xoffset': 22.0,
'clip_hole_radius': 3.0,
'clip_hole_xoffset': 2.0,
'clip_hole_yoffset': 5.5,
'tractor_hole_radius': 2.5,
'tractor_hole_xoffset': 12.5,
'tractor_hole_yoffset': 5.5,
'stitches': 40,
'corner_offset': 0,
},
}
# width of the side margin in mm
side_margin = 17.0
# height of one row on the card in mm
row_height = 5.0
class Layout:
# width of one stitch on the card in mm
stitch_width = 4.5
#stitch_width = 9.0
def __init__(self, machine_id, stitches, rows, horz_repeat, vert_repeat):
# radius of a pattern hole in mm
pattern_hole_radius = 3.5
# total width of the cut card
self.card_width = specs[machine_id]['card_width']
# radius of a clip hole in mm
clip_hole_radius = 3.0
# number of overlapping blank rows at the top of the card
self.blank_rows = specs[machine_id]['blank_rows']
# radius of a sprocket hole in mm
sprocket_hole_radius = 3.5
# height of one row on the card in mm
self.row_height = specs[machine_id]['row_height']
# drawing stroke width
stroke_width='.1'
# width of one stitch on the card in mm
self.stitch_width = specs[machine_id]['stitch_width']
# fill color
fill_color = 'white'
# radius of a pattern hole in mm
self.pattern_hole_radius = specs[machine_id]['pattern_hole_radius']
# stroke_color
stroke_color = 'black'
# offset of the first pattern hole from the left edge of the card in mm
self.pattern_hole_xoffset = specs[machine_id]['pattern_hole_xoffset']
card_width = 0
card_height = 0
card_rows = 0
card_stitches = 0
# radius of a clip hole in mm
self.clip_hole_radius = specs[machine_id]['clip_hole_radius']
class PCGenerator:
# offset of a clip hole from the left/right edge of the card in mm
self.clip_hole_xoffset = specs[machine_id]['clip_hole_xoffset']
def __init__(self, data, cell_height, cell_width, horz_repeat, vert_repeat):
global row_height
global stitch_width
# offset of a clip hole from the top/bottom edges of the card in mm
self.clip_hole_yoffset = specs[machine_id]['clip_hole_yoffset']
self.data = data.split()
self.horz_repeat = horz_repeat
self.vert_repeat = vert_repeat
row_height = cell_height
stitch_width = cell_width
# radius of a tractor hole in mm
self.tractor_hole_radius = specs[machine_id]['tractor_hole_radius']
def generate(self):
global card_rows
global card_stitches
global card_width
global card_height
# offset of a tractor hole from the left/right edge of the card in mm
self.tractor_hole_xoffset = specs[machine_id]['tractor_hole_xoffset']
card_rows = len(self.data)
card_stitches = len(self.data[0])
if card_rows > 200 or card_stitches > 30:
# offset of a tractor hole from the top/bottom edge of the card in mm
self.tractor_hole_yoffset = specs[machine_id]['tractor_hole_yoffset']
self.corner_offset = specs[machine_id]['corner_offset']
self.card_stitches = stitches
self.card_rows = rows
if self.card_rows > 200 or self.card_stitches > 30:
raise ValueError(
"Your pattern seems to exceed 200 rows and/or 30 stitches. "
"Are you sure you uploaded the right text file?")
card_width = (side_margin * 2) + (card_stitches * self.horz_repeat * stitch_width)
card_height = ((blank_rows * 2) + (card_rows * self.vert_repeat)) * row_height
self.horz_repeat = horz_repeat
self.vert_repeat = vert_repeat
self.card_height = ((self.blank_rows * 2) + (self.card_rows * self.vert_repeat)) * self.row_height
class PCGenerator:
def __init__(self, handler, data, machine_id, vert_repeat):
self.handler = handler
self.data = data.split()
self.layout = Layout(
machine_id,
len(self.data[0]),
len(self.data),
specs[machine_id]['stitches'] / len(self.data[0]),
vert_repeat
)
def generate(self):
diagram = self.create_card()
@ -72,173 +132,143 @@ class PCGenerator:
self.draw_pattern(diagram, self.data, objects)
self.draw_blank_lines(diagram, objects)
self.draw_clip_holes(diagram, objects)
self.draw_sprocket_holes(diagram, objects)
self.draw_tractor_holes(diagram, objects)
# sort the list to optimize cutting
sorted_objects = sorted(objects, key=lambda x: (float(x.attribs['cy']), float(x.attribs['cx'])))
for i in sorted_objects:
diagram.add(i)
return diagram.tostring()
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>{}'.format(diagram.tostring())
def create_card(self):
global card_width
global card_height
diagram = svgwrite.Drawing(
"punchcard.svg",
size=(
'{0}mm'.format(card_width),
'{0}mm'.format(card_height)),
'{0}mm'.format(self.layout.card_width),
'{0}mm'.format(self.layout.card_height)),
viewBox=(
'0 0 {0} {1}'.format(card_width, card_height)),
'0 0 {0} {1}'.format(self.layout.card_width, self.layout.card_height)),
preserveAspectRatio='none')
shape_points = [
(2, 0),
(card_width-2, 0),
(card_width-1, 1),
(card_width-1, 20),
(card_width, 22),
(card_width, card_height-22),
(card_width-1, card_height-20),
(card_width-1, card_height-1),
(card_width-2, card_height),
(2, card_height),
(1, card_height-1),
(1, card_height-20),
(0, card_height-22),
(0, 22),
(1, 20),
(1, 1)]
diagram.add(diagram.polygon(
points=shape_points,
fill=fill_color,
stroke=stroke_color,
stroke_width=stroke_width))
points=self.get_card_shape(),
fill='white',
stroke='black',
stroke_width=.1))
return diagram
def draw_pattern(self, diagram, lines, objects):
global card_rows
global card_stitches
global fill_color
global pattern_hole_radius
global row_color
global row_height
global side_margin
global stitch_width
global stroke_color
global stroke_width
# main body of card
yoffset = 10.0 + (row_height / 2)
for row_repeat in range(self.vert_repeat):
for rows in range(card_rows):
xoffset = side_margin + (stitch_width / 2)
for stitch_repeat in range(self.horz_repeat):
for stitches in range(card_stitches):
yoffset = (self.layout.blank_rows * self.layout.row_height) + (self.layout.row_height / 2)
for row_repeat in range(self.layout.vert_repeat):
for rows in range(self.layout.card_rows):
xoffset = self.layout.pattern_hole_xoffset + (self.layout.pattern_hole_radius / 2)
for stitch_repeat in range(self.layout.horz_repeat):
for stitches in range(self.layout.card_stitches):
if lines[rows][stitches].upper() == 'X':
objects.append(diagram.circle(
center=(xoffset, yoffset),
fill=fill_color,
r = (pattern_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
xoffset += stitch_width
yoffset += row_height
fill='white',
r = (self.layout.pattern_hole_radius / 2),
stroke='black',
stroke_width=.1))
xoffset += self.layout.stitch_width
yoffset += self.layout.row_height
def draw_blank_lines(self, diagram, objects):
global blank_rows
global card_stitches
global fill_color
global pattern_hole_radius
global row_height
global side_margin
global stitch_width
global stroke_color
global stroke_width
# blank rows at top
yoffset = row_height / 2
for rows in range(blank_rows):
xoffset = side_margin + (stitch_width / 2)
for stitch_repeat in range(self.horz_repeat):
for stitches in range(card_stitches):
yoffset = self.layout.row_height / 2
for rows in range(self.layout.blank_rows):
xoffset = self.layout.pattern_hole_xoffset + (self.layout.pattern_hole_radius / 2)
for stitch_repeat in range(self.layout.horz_repeat):
for stitches in range(self.layout.card_stitches):
objects.append(diagram.circle(
center=(xoffset, yoffset),
fill=fill_color,
r = (pattern_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
xoffset += stitch_width
yoffset += row_height
fill='white',
r = (self.layout.pattern_hole_radius / 2),
stroke='black',
stroke_width=.1))
xoffset += self.layout.stitch_width
yoffset += self.layout.row_height
# blank rows at bottom
yoffset = (card_height - (row_height * blank_rows)) + (row_height / 2)
for rows in range(blank_rows):
xoffset = side_margin + (stitch_width / 2)
for stitch_repeat in range(self.horz_repeat):
for stitches in range(card_stitches):
yoffset = (self.layout.card_height - (self.layout.row_height * self.layout.blank_rows)) + (self.layout.row_height / 2)
for rows in range(self.layout.blank_rows):
xoffset = self.layout.pattern_hole_xoffset + (self.layout.pattern_hole_radius / 2)
for stitch_repeat in range(self.layout.horz_repeat):
for stitches in range(self.layout.card_stitches):
objects.append(diagram.circle(
center=(xoffset, yoffset),
fill=fill_color,
r = (pattern_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
xoffset += stitch_width
yoffset += row_height
fill='white',
r = (self.layout.pattern_hole_radius / 2),
stroke='black',
stroke_width=.1))
xoffset += self.layout.stitch_width
yoffset += self.layout.row_height
def draw_clip_holes(self, diagram, objects):
global card_height
global clip_hole_radius
global fill_color
global row_height
global side_margin
global stitch_width
global stroke_color
global stroke_width
left_xoffset = side_margin + (stitch_width / 2) - 6.0
right_xoffset = (card_width - side_margin - (stitch_width / 2)) + 6.0
yoffset = row_height / 2
while yoffset < card_height:
# clip holes on left
self.draw_side_holes(
diagram,
objects,
self.layout.clip_hole_xoffset,
self.layout.clip_hole_yoffset,
self.layout.clip_hole_radius)
def draw_tractor_holes(self, diagram, objects):
self.draw_side_holes(
diagram,
objects,
self.layout.tractor_hole_xoffset,
self.layout.tractor_hole_yoffset,
self.layout.tractor_hole_radius)
def draw_side_holes(self, diagram, objects, xoffset, yoffset, radius):
left_xoffset = xoffset + (radius / 2)
right_xoffset = self.layout.card_width - left_xoffset
while yoffset < self.layout.card_height:
# holes on left
objects.append(diagram.circle(
center=(left_xoffset, yoffset),
fill=fill_color,
r = (clip_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
# clip holes on right
fill='white',
r = (radius / 2),
stroke='black',
stroke_width=.1))
# holes on right
objects.append(diagram.circle(
center=(right_xoffset, yoffset),
fill=fill_color,
r = (clip_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
yoffset += row_height
fill='white',
r = (radius / 2),
stroke='black',
stroke_width=.1))
yoffset += self.layout.row_height
def draw_sprocket_holes(self, diagram, objects):
left_xoffset = 6.5
right_xoffset = card_width - 6.5
yoffset = row_height
for row_repeat in range(self.vert_repeat):
for rows in range(((card_rows * self.vert_repeat) + (blank_rows * 2)) / 2):
# sprocket holes on left
objects.append(diagram.circle(
center=(left_xoffset, yoffset),
fill=fill_color,
r = (sprocket_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
# sprocket holes on left
objects.append(diagram.circle(
center=(right_xoffset, yoffset),
fill=fill_color,
r = (sprocket_hole_radius / 2),
stroke=stroke_color,
stroke_width=stroke_width))
yoffset += (row_height * 2)
def get_card_shape(self):
corner_radius = self.layout.corner_offset + 1
return [
(corner_radius, 0),
(self.layout.card_width - corner_radius, 0),
(self.layout.card_width - self.layout.corner_offset, self.layout.corner_offset),
(self.layout.card_width - self.layout.corner_offset, 20),
(self.layout.card_width, 22),
(self.layout.card_width, self.layout.card_height - 22),
(self.layout.card_width - self.layout.corner_offset, self.layout.card_height - 20),
(self.layout.card_width - self.layout.corner_offset, self.layout.card_height - 1),
(self.layout.card_width - corner_radius, self.layout.card_height),
(corner_radius, self.layout.card_height),
( self.layout.corner_offset, self.layout.card_height - self.layout.corner_offset),
( self.layout.corner_offset, self.layout.card_height - 20),
(0, self.layout.card_height - 22),
(0, 22),
( self.layout.corner_offset, 20),
( self.layout.corner_offset, 1)]

Wyświetl plik

@ -1,9 +1,14 @@
import logging
import logging.config
import os
import sys
import traceback
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
from handlers import actions
pcgenerator_actions = {
'get': actions.pcgenerator_get,
'post': actions.pcgenerator_post }
@ -23,44 +28,86 @@ template_map = {
'/pcgenerator/': pcgenerator_actions,
'/calculator': calculator_actions,
'/calculator/': calculator_actions,
'/': index_actions,
'/index': index_actions }
'/knittingtools': index_actions,
'/knittingtools/': index_actions,
'/index': index_actions,
'/index/': index_actions,
'/': index_actions}
logging.config.fileConfig("{0}/{1}".format(os.path.dirname(os.path.realpath(__file__)), 'logging.conf'))
logger = logging.getLogger('root')
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
print self.path
actions = template_map.get(self.path, None)
if actions is None:
self.send_response(404)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('Not found!')
def handle_not_found(self):
self.send_response(404)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(
"<h1>Aw, snap! We seem to have a problem.</h1><p><b>")
self.wfile.write('The request resource was not found on this server.')
actions['get'](self)
def do_GET(self):
try:
actions = template_map.get(self.path, None)
if actions is None:
self.handle_not_found()
return
actions['get'](self)
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.log_error("%s %s\n" % (
exc_type,
exc_value))
logger.debug("path=%s %s",
self.path,
repr(traceback.format_exception(exc_type, exc_value,exc_traceback)))
def do_POST(self):
print self.path
actions = template_map.get(self.path, None)
if actions is None:
self.send_response(404)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('Not found!')
try:
actions = template_map.get(self.path, None)
if actions is None:
self.handle_not_found()
return
actions['post'](self)
actions['post'](self)
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.log_error("%s %s\n" % (
exc_type,
exc_value))
logger.debug("path=%s %s",
self.path,
repr(traceback.format_exception(exc_type, exc_value, exc_traceback)))
def log_request(self, code=None, size=None):
logger.info("%s - - [%s] %s %s %s" % (
self.headers.get('X-Forwarded-For', None) or self.address_string(),
self.log_date_time_string(),
self.requestline,
code or '-',
size or '-'))
def log_error(self, *args):
logger.error(args)
def log_message(self, *args):
logger.info("%s - - [%s] %s" % (
self.headers.get('X-Forwarded-For', None) or self.address_string(),
self.log_date_time_string(),
args))
def main():
try:
server = HTTPServer(('', 8088), MyHandler)
print 'started httpserver...'
logger.info("Starting server...")
server = HTTPServer(('', 8080), MyHandler)
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
logger.info("Stopping server...")
except Exception:
print sys.exc_info()[0]
logger.error(sys.exc_info()[0])
finally:
server.socket.close()

Wyświetl plik

@ -28,11 +28,12 @@
<body>
<h1>Knitting Gauge Calculator</h1>
<a href="/">&lt;Back&gt;</a>
<a href="/knittingtools">[Back To Tools Home]</a>&nbsp;<a href="http://www.brendaabell.com">[Back To My Blog]</a>
<hr>
<p>This app will help you calculate stitches and rows when your gauge differs from the gauge specified on the pattern.
<p>The forms are reactive. I.e., when you enter a value in any field, the other fields will automatically be adjusted for the value you entered. For example, if you enter inches in the "Imperial" column, the equivalent value in centimeters will automatically displayed in the "Metric" column.
<p>IMPORTANT!!! This app is currently considered Beta. As such, there may be bugs. If you see something that doesn't look right, please report the issue using the instructions at the bottom of this page.
<hr>
@ -198,6 +199,7 @@
<p>After you compute the number of stitches or rows required for your gauge, consult the pattern to see if knitting a different size will produce the desired results.
<p style="margin-left: 40px">For example, if the pattern instructs you to cast on 80 stitches for a size medium but your gauge requires you to cast on 90 stitches to achieve the same width, look at the pattern to see if the next larger size specifies a cast on that's closer to 90 stitches. Knitting a larger size at a smaller gauge (or smaller size at a larger gauge) may produce the same result.
<h2>Bugs & Disclaimers</h2>
<p>If you have questions or feedback, please contact <a href="http://www.ravelry.com/people/beebell">beebell on Ravelry</a> via private message or log at issue on <a href="https://github.com/brendabell/knittingtools/issues">GitHub</a>.</p>
</body>

Wyświetl plik

@ -24,16 +24,18 @@
<body>
<h1>Punchcard Generator</h1>
<a href="/">&lt;Back&gt;</a>
<a href="/knittingtools">[Back To Tools Home]</a>&nbsp;<a href="http://www.brendaabell.com">[Back To My Blog]</a>
<hr>
<p>This app will allow you to upload a small text file that contains your pattern represented as a sequence of rows with X's for punched holes and any other character except space for unpunched holes. The program will generate an SVG file that can be imported into the software you use to cut material with your die cutter.
<p>IMPORTANT!!! This app is currently considered Beta. As such, there may be bugs. If you see something that doesn't look right, please report the issue using the instructions at the bottom of this page.
<h2>TL;DR</h2>
<ul>
<li>Select the file to upload.</li>
<li>Enter your punchcard row height and column width in millimeters.</li>
<li>Enter horizontal and vertical repeats if you need them.</li>
<li>Select your machine type.</li>
<li>Enter the # vertical repeats if you need them. The # horizontal repeats will be automatically calculated based on the machine type.</li>
<li>Check "Convert to PNG" if you'd like to download a PNG image instead of SVG.</li>
<li>Click the Upload button.</li>
</ul>In a few seconds, you should see a dialog prompting you for where you want to save your file. If you need more detailed instructions, keep reading below.
@ -43,34 +45,35 @@
method="POST"
enctype="multipart/form-data"
action="/pcgenerator"
onfocus="x.value=horz.value; y.value=vert.value"
oninput="x.value=horz.value; y.value=vert.value">
onfocus="y.value=vert.value"
oninput="y.value=vert.value">
<table>
<tr>
<td style="text-align:right">Select file to upload:<br>&nbsp;</td>
<td colspan="2"><input type="file" name="upfile"><br><small>(maximum file size 2500 characters)<small></td>
<td colspan="2"><input type="file" name="upfile"><br><small>(maximum file size 4000 characters)<small></td>
</tr>
<tr>
<td style="text-align:right">Height of 1 punchcard row (mm):</td>
<td colspan="2"><input type="number" name="rowheight" min="1.0" max="10.0" step="0.1" value="5.0"></td>
<td style="text-align:right">Select machine type:<br>&nbsp;</td>
<td colspan="2">
<select name="machine">
<option value="12-stitch-br-sr">12-stitch Brother/Silver Reed/Studio</option>
<option value="24-stitch-br-sr">24-stitch Brother/Silver Reed/Studio</option>
<option value="40-stitch-deco">40-stitch Passap Deco</option>
</select>
<p><b>NOTICE: Passap Deco support is currently experimental and has not been fully tested.</b>
</td>
</tr>
<tr>
<td style="text-align:right">Width of 1 punchcard column (mm):</td>
<td colspan="2"><input type="number" name="colwidth" min="1.0" max="10.0" step="0.1" value="4.5"></td>
</tr>
<tr>
<td style="text-align:right"># Horizontal repeats (up to 12):</td>
<td colspan="2"><input type="range" id="horz" name="horz" min="1" max="12" step="1" value="1">
<output id="x" name="x" value="1"></output>
<script>x.value=horz.value;</script></td>
</tr>
<tr>
<td style="text-align:right"># Vertical repeats (up to 12):</td>
<td><input type="range" id="vert" name="vert" min="1" max="12" step="1" value="1">
<td style="text-align:right"># Vertical repeats (up to 24):</td>
<td><input type="range" id="vert" name="vert" min="1" max="24" step="1" value="1">
<output id="y" name="y" value="1"></output>
<script>y.value=vert.value;</script></td>
</tr>
<tr>
<td style="test-align:right">Convert to PNG image:</td>
<td><input type="checkbox" name="png" value="png"></td>
</tr>
<tr>
<td></td>
<td colspan="2"><input type="submit" value="Upload"></td>
@ -95,9 +98,11 @@
---x-----x--
</pre>
<p>By default, the generator will do 1 horizontal repeat and 1 vertical repeat. I.e., if your file contains 36 rows with 24 characters per row, the generated file will produce a 24 row x 36 stitch card. You can increase the width and/or length by adjusting the horizontal and/or vertical repeat before clicking the upload button.
<p>The generator will determine the number of horizontal repeats based on the number of characters in your first row and the type of machine. I.e., if row 1 contains 4 characters and you select a 12-stitch machine, the generator will automatically do 3 horizontal repeats: 4 * 3 = 12.
<p>What this means is that you can design a simple 4x4 card and use repeats to make the card as wide or as long as it needs to be in order to work properly. For example, the following text file will generate a 24 row x 48 stitch card if you specify 6 for the horizontal repeat and 12 for the vertical repeat:
<p>By default, the generator will do 1 vertical repeat. I.e., if your file contains 36 rows, the generated file will produce a 36 row card. You can increase the length by adjusting the vertical repeat before clicking the upload button.
<p>What this means is that you can design a simple 4x4 card and use repeats to make the card as wide or as long as it needs to be in order to work properly. For example, the following text file will generate a 24 row x 48 stitch card if you select a 24-stitch machine and specify 12 for the vertical repeat:
<pre>
x-x-
@ -106,29 +111,11 @@
-x-x
</pre>
<p>You'll need to specify the height and width of 1 row and 1 column on the punchcard. You can determine the correct values by measuring the size of the squares on a card that works with your knitting machine. If your card doesn't have squares, you can measure the distance between the centers of two adjacent holes. For reference:
<p>
<table>
<tr>
<th>Knitting Machine</th>
<th style="text-align:center">Row Height<br>(mm)</th>
<th style="text-align:center">Column Width<br>(mm)</th>
</tr>
<tr>
<td>Brother 24-Stitch Standard</td>
<td style="text-align:center">5</td>
<td style="text-align:center">4.5</td>
</tr>
<tr>
<td>Brother 12-Stitch Bulky</td>
<td style="text-align:center">5</td>
<td style="text-align:center">9</td>
</tr>
</table>
<p>The resulting SVG file can be imported into any application that understands SVG. You can also display the SVG in some browsers. Neither the text file or resulting SVG will be saved on this site. Be sure to keep them in a safe location so they don't get lost.
<p>Silhouette users have reported issues importing SVG files or having to resize the SVG in Inkscape before importing. If you have trouble with the SVG file, try checking the Convert To PNG button to see if that helps.
<h2>Bugs & Disclaimers</h2>
<p>This program has only been tested using Sure Cuts A Lot on a Pazzles Creative Mighty. YMMV!
<p>If you have questions or feedback, please contact <a href="http://www.ravelry.com/people/beebell">beebell on Ravelry</a> via private message or log at issue on <a href="https://github.com/brendabell/knittingtools/issues">GitHub</a>.</p>

1
test/__init__.py 100644
Wyświetl plik

@ -0,0 +1 @@
# intentionally empty

Plik diff jest za duży Load Diff

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 753 KiB

Wyświetl plik

@ -0,0 +1,4 @@
-x--
-xxx
xxx-
--x-

17
test/test.py 100644
Wyświetl plik

@ -0,0 +1,17 @@
# invocation: python -m test.test
from modules.pcgenerator import PCGenerator
import cairosvg
pattern='-x--\n-xxx\nxxx-\n--x-\n'
#machine = '12-stitch-br-sr'
#machine = '24-stitch-br-sr'
machine = '40-stitch-deco'
generator = PCGenerator(None, pattern, machine, 10)
result = generator.generate()
text_file = open("{}.svg".format(machine), "w")
text_file.write(result)
text_file.close()
png_file = open("{}.png".format(machine), "w")
cairosvg.svg2png(bytestring=result,write_to=png_file)
png_file.close()