@ -3,43 +3,44 @@ from tkinter import filedialog
from tkinter . ttk import Notebook
from PIL import Image , ImageTk
import subprocess, os, time
import os
from Renderer import Renderer
from Svg2GcodeConverter import Svg2GcodeConverter
from GCodeRenderer import Renderer
from Svg2GcodeConverter import Svg2GcodeConverter , triangulate_lengths , untriangulate_lengths
from ImageConverter import ImageConverter
from Simulator import Simulator
class Settings :
def __init__ ( self ) :
# Height at which the pen touches and draws on the surface
self . touch_height = 12
# How far to raise the pen tip to raise it off the page
self . raise_height = 2
# The inherent offset from true 0 we have from the pen bracket
self . head_x_offset = 50
# XY movement speed
self . speed = 1000
# Whether we render lift markers
self . lift_markers = False
# ============ HARDCODED VALUES ===========
# X and Y offsets to place the image on A11 paper
self . offset_x = 70 + self . head_x_offset
self . offset_y = 2 0
# Canvas size
self . canvas_x = 200
self . canvas_y = 200
# Bed dimensions to fit A11 paper
self . bed_max_x = 300 - 70 + self . head_x_offset + 20 # 20 is to adjust for the misalignment of print bed
self . bed_min_x = self . offset_x
self . bed_max_y = 280
self . bed_min_y = 20
# The position of the pulley centers in relation to the top left and right of the canvas
self . left_pulley_x_offset = - 40
self . right_pulley_x_offset = 40
self . pulley_y_droop = 60
self . bed_actual_x = 300
self . bed_actual_y = 300
# Diameter of the inner portion of the pulley in millimeters
self . pulley_diameter = 45
# Feed rates
self . speed = 1000
# Whether we render lift markers
self . lift_markers = False
self . lift_counter = 0
# ============ CALCULATED VALUES ===========
self . distance_between_centers = abs ( self . left_pulley_x_offset ) + self . canvas_x + self . right_pulley_x_offset
# Main GUI class and program entry point
class Tracer ( Tk ) :
def update_highpass_value ( self , value ) :
@ -48,6 +49,9 @@ class Tracer(Tk):
def update_blur_value ( self , value ) :
self . blur = value
def update_turd_value ( self , value ) :
self . turd = value
def __init__ ( self ) :
super ( ) . __init__ ( )
@ -58,15 +62,21 @@ class Tracer(Tk):
if not os . path . exists ( " tmp " ) :
os . makedirs ( " tmp " )
# Settings for the printer are loaded, TODO: Customize for our dual motor printer
self . settings = Settings ( )
# Image filename which we are converting
self . filename = None
# GCODE -> SVG,PNG renderer
self . cairo_renderer = Renderer ( self . settings )
# SVG -> GCODE converter
self . gcode_converter = Svg2GcodeConverter ( self . settings )
self . highpass_filter = 0
self . blur = 0
# FILE -> SVG converter
self . image_converter = ImageConverter ( )
self . image_converter_settings = ImageConverter . ConverterSettings ( )
self . label = None
self . pix = None
@ -74,38 +84,55 @@ class Tracer(Tk):
self . image_ref = None
# Initialize TK
self . geometry ( " {} x {} " . format ( 500, 5 00) )
self . geometry ( " {} x {} " . format ( 800, 8 00) )
self . n = Notebook ( self , width = 400 , height = 400 )
self . n . pack ( fill = BOTH , expand = 1 )
self . tab_bar = Notebook ( self , width = 400 , height = 400 )
self . tab_bar . pack ( fill = BOTH , expand = 1 )
self . f1 = Frame ( self . n )
self . f2 = Frame ( self . n )
self . converted_image_tab = Frame ( self . tab_bar )
self . original_image_tab = Frame ( self . tab_bar )
self . rightframe = Frame ( self )
self . rightframe . pack ( side = RIGHT )
self . button = Button ( self . rightframe , text = " Select Image " , command = self . file_select_callback )
self . button . pack ( )
self . centerframe = Frame ( self )
self . centerframe . pack ( side = BOTTOM )
self . image_select_button = Button ( self . rightframe , text = " Select Image " , command = self . file_select_callback )
self . image_select_button . pack ( )
self . button = Button ( self . rightframe , text = " Re-Render " , command = self . render )
self . button . pack ( )
self . rerender_button = Button ( self . rightframe , text = " Re-Render " , command = self . render )
self . rerender_button . pack ( )
self . render_simulation_button = Button ( self . rightframe , text = " Render Simulation " , command = self . render_simulation )
self . render_simulation_button . pack ( )
self . lift_markers_checkbox = Checkbutton ( self . rightframe , text = " Lift Markers " , command = self . cairo_renderer . toggle_flip_markers )
self . lift_markers_checkbox . pack ( )
self . highpass_slider = Scale ( self . rightframe , command = self . update_highpass_value , resolution = 0.1 , to = 15 )
self . highpass_slider . set ( self . highpass_filter )
self . highpass_label = Label ( self . centerframe , text = " Highpass filter " , fg = " black " )
self . highpass_label . pack ( )
self . highpass_slider = Scale ( self . centerframe , command = self . update_highpass_value , resolution = 0.0 , to = 15 , orient = HORIZONTAL )
self . highpass_slider . set ( self . image_converter_settings . highpass_filter )
self . highpass_slider . pack ( )
self . blur_slider = Scale ( self . rightframe , command = self . update_blur_value , resolution = 0.1 , to = 5 )
self . blur_slider . set ( self . blur )
self . blur_label = Label ( self . centerframe , text = " Blur " , fg = " black " )
self . blur_label . pack ( )
self . blur_slider = Scale ( self . centerframe , command = self . update_blur_value , resolution = 0.0 , to = 5 , orient = HORIZONTAL )
self . blur_slider . set ( self . image_converter_settings . blur )
self . blur_slider . pack ( )
self . turd_label = Label ( self . centerframe , text = " Turds " , fg = " black " )
self . turd_label . pack ( )
self . turd_slider = Scale ( self . centerframe , command = self . update_turd_value , resolution = 0.0 , to = 5 , orient = HORIZONTAL )
self . turd_slider . set ( self . image_converter_settings . turd )
self . turd_slider . pack ( )
# Start TK
self . mainloop ( )
def file_select_callback ( self ) :
filepath = filedialog . askopenfilename ( initialdir = " . " , title = " Select file " ,
filetypes = ( ( " jpeg files " , " *.jpg " ) , ( " all files " , " *.* " ) ) )
@ -120,14 +147,14 @@ class Tracer(Tk):
self . render ( )
def render ( self ) :
self . convert_image( self . filename )
self . image_converter. convert_image( self . filename , self . image_converter_settings )
self . gcode_converter . convert_gcode ( )
self . cairo_renderer . clear_screen ( )
self . cairo_renderer . render_gcode ( )
self . f1 . pack_forget ( )
self . f2 . pack_forget ( )
self . converted_image_tab . pack_forget ( )
self . original_image_tab . pack_forget ( )
if self . label is not None :
self . label . pack_forget ( )
@ -139,61 +166,26 @@ class Tracer(Tk):
# scale = self.winfo_width() / pil_image.width
# pil_image = pil_image.resize((int(scale * pil_image.width), int(scale * pil_image.height)))
self . image_ref = ImageTk . PhotoImage ( pil_image )
self . label = Label ( self . f1 , image = self . image_ref )
self . n. add ( self . f1 , text = " Converted " )
self . label = Label ( self . converted_image_tab , image = self . image_ref )
self . tab_bar. add ( self . converted_image_tab , text = " Converted " )
self . label . pack ( expand = True , fill = " both " )
self . pic = ImageTk . PhotoImage ( file = " input-images/ {} " . format ( self . filename ) )
self . label1 = Label ( self . f2 , image = self . pic )
self . n. add ( self . f2 , text = " Original " )
self . label1 = Label ( self . original_image_tab , image = self . pic )
self . tab_bar. add ( self . original_image_tab , text = " Original " )
self . label1 . pack ( expand = True , fill = " both " )
def render_simulation ( self ) :
# This function takes a file and runs it through mogrify, mkbitmap, and finally potrace.
# The flow of the intermediate files is
# input_file.extension : The input file
# input_file.bmp : The input file converted to bmp
# input_file-n.bmp : The bmp file after running through some filters
# input_file.svg : The output svg render
def convert_image ( self , file_name ) :
base_name = file_name . split ( " . " ) [ 0 ]
print ( " Converting input file [ {} ] " . format ( file_name ) )
print ( " Running mogrify... " )
start = time . time ( )
subprocess . call ( [ " mogrify " , " -format " , " bmp " , " input-images/ {} " . format ( file_name ) ] )
print ( " Run took [ {:.2f} ] seconds " . format ( time . time ( ) - start ) )
print ( " Running mkbitmap... " )
start = time . time ( )
mkbitmap_args = [ " mkbitmap " , " input-images/ {} .bmp " . format ( base_name ) ,
" -o " , " input-images/ {} -n.pbm " . format ( base_name ) ]
if self . highpass_filter > 0 :
mkbitmap_args . append ( [ " -f " , self . highpass_filter ] )
if self . blur > 0 :
mkbitmap_args . append ( [ " -b " , self . blur ] )
subprocess . call ( mkbitmap_args )
print ( " Run took [ {:.2f} ] seconds " . format ( time . time ( ) - start ) )
simulator = Simulator ( )
simulator . render ( )
print ( " Running potrace... " )
start = time . time ( )
subprocess . call ( [ " potrace " ,
#"-t", "0.1",
" -z " , " white " ,
" -b " , " svg " ,
" input-images/ {} -n.pbm " . format ( base_name ) ,
" --rotate " , " 0 " ,
" -o " , " tmp/conversion-output.svg " ,
] )
print ( " Run took [ {:.2f} ] seconds \n " . format ( time . time ( ) - start ) )
settings = Settings ( )
print ( triangulate_lengths ( settings , ( 150 , 0 ) ) )
# print(triangulate_lengths(settings, (300, 300)))
if __name__ == " __main__ " :
Tracer ( )
Tracer ( )