diff --git a/src/octoprint/filemanager/analysis.py b/src/octoprint/filemanager/analysis.py index cd4ca7fd..10e512d9 100644 --- a/src/octoprint/filemanager/analysis.py +++ b/src/octoprint/filemanager/analysis.py @@ -186,6 +186,10 @@ class AbstractAnalysisQueue(object): time.sleep(1.0) def _analyze(self, entry, high_priority=False): + if(True): + self._logger.warn("Avoiding analysis of {entry}".format(**locals())) + return + path = entry.absolute_path if path is None or not os.path.exists(path): return diff --git a/src/octoprint/plugins/svgtogcode/__init__.py b/src/octoprint/plugins/svgtogcode/__init__.py index 828646e0..b7b61285 100644 --- a/src/octoprint/plugins/svgtogcode/__init__.py +++ b/src/octoprint/plugins/svgtogcode/__init__.py @@ -345,99 +345,162 @@ class SvgToGcodePlugin(octoprint.plugin.SlicerPlugin, path, _ = os.path.splitext(model_path) machinecode_path = path + ".gco" - if on_progress: - if not on_progress_args: + if on_progress is not None: + if on_progress_args is None: on_progress_args = () - if not on_progress_kwargs: + if on_progress_kwargs is None: on_progress_kwargs = dict() + #on_progress_kwargs["_progress"] = your_plugins_slicing_progress + #on_progress(*on_progress_args, **on_progress_kwargs) self._svgtogcode_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path)) - engine_settings = self._convert_to_engine(profile_path) + direct_call = True + if(direct_call): + ## direct call + from os.path import expanduser + homedir = expanduser("~") + converter_path = homedir+"/mrbeam-inkscape-ext" + + hostname = socket.gethostname() + if("Bucanero" in hostname): + converter_path = '/home/teja/workspace/mrbeam-inkscape-ext' - from os.path import expanduser - homedir = expanduser("~") - executable = homedir + "/mrbeam-inkscape-ext/mrbeam.py" - log_path = homedir + "/.octoprint/logs/svgtogcode.log" - log_enabled = s.get(["debug_logging"]) - - # debugging stuff. TODO remove - hostname = socket.gethostname() - if("Bucanero" in hostname): - executable = homedir + "/workspace/mrbeam-inkscape-ext/mrbeam.py" - - # executable = s.get(["svgtogcode_engine"]) - - if not executable: - return False, "Path to SVG converter is not configured " - - dest_dir, dest_file = os.path.split(machinecode_path) - working_dir, _ = os.path.split(executable) - args = ['python "%s"' % executable, '-f "%s"' % dest_file, '-d "%s"' % dest_dir] - args += ['--no-header=True'] - for k, v in engine_settings.items(): - args += ['"%s=%s"' % (k, str(v))] - fill_enabled = False # disabled as highly experimental - args += ['--fill-areas=%s' % fill_enabled] - args += ['--create-log=%s' % log_enabled, '"--log-filename=%s"' % log_path,'"%s"' % model_path] - - #python ~/mrbeam-inkscape-ext/standalone.py -f output.gcode -d output/path --engraving-laser-speed=300 - # --laser-intensity=1000 --create-log=false path/to/input.svg - - import sarge - command = " ".join(args) - self._logger.info("Running %r in %s" % (command, working_dir)) - try: - p = sarge.run(command, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture()) - p.wait_events() - try: - with self._slicing_commands_mutex: - self._slicing_commands[machinecode_path] = p.commands[0] - - line_seen = False - while p.returncode is None: - line = p.stdout.readline(timeout=0.5) - if not line: - if line_seen: - break - else: - continue - - line_seen = True - self._svgtogcode_logger.debug(line.strip()) - - if on_progress is not None: - pass - finally: - p.close() - - with self._cancelled_jobs_mutex: - if machinecode_path in self._cancelled_jobs: - self._svgtogcode_logger.info("### Cancelled") - raise octoprint.slicing.SlicingCancelled() - - self._svgtogcode_logger.info("### Finished, returncode %d" % p.returncode) - if p.returncode == 0: - return True, None + import sys + sys.path.append(converter_path) + from mrbeam import Laserengraver + + profile = Profile(self._load_profile(profile_path)) + params = profile.convert_to_engine2() + + dest_dir, dest_file = os.path.split(machinecode_path) + params['directory'] = dest_dir + params['file'] = dest_file + params['noheaders'] = "true" # TODO... booleanify + + params['fill_areas'] = False # disabled as highly experimental + if(s.get(["debug_logging"])): + log_path = homedir + "/.octoprint/logs/svgtogcode.log" + params['log_filename'] = log_path else: - self._logger.warn("Could not slice, got return code %r" % p.returncode) - return False, "Got returncode %r" % p.returncode + params['log_filename'] = '' - except octoprint.slicing.SlicingCancelled as e: - raise e - except: - self._logger.exception("Could not slice, got an unknown error") - return False, "Unknown error, please consult the log file" + + print("### params ", params) + try: + engine = Laserengraver(params, model_path) + engine.affect() + + self._svgtogcode_logger.info("### Conversion finished") + return True, None # TODO add analysis about out of working area, ignored elements, invisible elements, text elements + except octoprint.slicing.SlicingCancelled as e: + raise e + except Exception as e: + print e.__doc__ + print e.message + self._logger.exception("Conversion error ({0}): {1}".format(e.__doc__, e.message)) + return False, "Unknown error, please consult the log file" + + finally: + with self._cancelled_jobs_mutex: + if machinecode_path in self._cancelled_jobs: + self._cancelled_jobs.remove(machinecode_path) + with self._slicing_commands_mutex: + if machinecode_path in self._slicing_commands: + del self._slicing_commands[machinecode_path] - finally: - with self._cancelled_jobs_mutex: - if machinecode_path in self._cancelled_jobs: - self._cancelled_jobs.remove(machinecode_path) - with self._slicing_commands_mutex: - if machinecode_path in self._slicing_commands: - del self._slicing_commands[machinecode_path] + self._svgtogcode_logger.info("-" * 40) - self._svgtogcode_logger.info("-" * 40) + else: + ## shell call + engine_settings = self._convert_to_engine(profile_path) + + from os.path import expanduser + homedir = expanduser("~") + executable = homedir + "/mrbeam-inkscape-ext/mrbeam.py" + log_path = homedir + "/.octoprint/logs/svgtogcode.log" + log_enabled = s.get(["debug_logging"]) + + # debugging stuff. TODO remove + hostname = socket.gethostname() + if("Bucanero" in hostname): + executable = homedir + "/workspace/mrbeam-inkscape-ext/mrbeam.py" + + # executable = s.get(["svgtogcode_engine"]) + + if not executable: + return False, "Path to SVG converter is not configured " + + dest_dir, dest_file = os.path.split(machinecode_path) + working_dir, _ = os.path.split(executable) + args = ['python "%s"' % executable, '-f "%s"' % dest_file, '-d "%s"' % dest_dir] + args += ['--no-header=True'] + for k, v in engine_settings.items(): + args += ['"%s=%s"' % (k, str(v))] + fill_enabled = False # disabled as highly experimental + if(fill_enabled): + args += ['--fill-areas'] + if(log_enabled): + args += ['"--log-filename=%s"' % log_path] + args += ['"%s"' % model_path] + + + import sarge + command = " ".join(args) + self._logger.info("Running %r" % (command)) + try: + p = sarge.run(command, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture()) + p.wait_events() + try: + with self._slicing_commands_mutex: + self._slicing_commands[machinecode_path] = p.commands[0] + + line_seen = False + while p.returncode is None: + line = p.stdout.readline(timeout=0.5) + if not line: + if line_seen: + break + else: + continue + + line_seen = True + self._svgtogcode_logger.debug(line.strip()) + + if on_progress is not None: + pass + finally: + p.close() + + with self._cancelled_jobs_mutex: + if machinecode_path in self._cancelled_jobs: + self._svgtogcode_logger.info("### Cancelled") + raise octoprint.slicing.SlicingCancelled() + + + self._svgtogcode_logger.info("### Finished, returncode %d" % p.returncode) + if p.returncode == 0: + return True, None + else: + self._logger.warn("Could not slice, got return code %r" % p.returncode) + return False, "Got returncode %r" % p.returncode + + except octoprint.slicing.SlicingCancelled as e: + raise e + except: + self._logger.exception("Could not slice, got an unknown error") + return False, "Unknown error, please consult the log file" + + finally: + with self._cancelled_jobs_mutex: + if machinecode_path in self._cancelled_jobs: + self._cancelled_jobs.remove(machinecode_path) + with self._slicing_commands_mutex: + if machinecode_path in self._slicing_commands: + del self._slicing_commands[machinecode_path] + + self._svgtogcode_logger.info("-" * 40) + # end if False def cancel_slicing(self, machinecode_path): with self._slicing_commands_mutex: diff --git a/src/octoprint/plugins/svgtogcode/profile.py b/src/octoprint/plugins/svgtogcode/profile.py index 831082a9..ce79e9af 100644 --- a/src/octoprint/plugins/svgtogcode/profile.py +++ b/src/octoprint/plugins/svgtogcode/profile.py @@ -13,14 +13,24 @@ import re defaults = dict( + # general settings + svgDPI = 90, + pierce_time = 0, + + # vector settings speed = 300, intensity = 500, + fill_areas = False, + cross_fill = False, + fill_angle = 0, + fill_spacing = 0.25, + + # pixel settings beam_diameter = 0.25, intensity_white = 0, intensity_black = 500, feedrate_white = 1500, feedrate_black = 250, - pierce_time = 0, img_contrast = 1.0, img_sharpening = 1.0, img_dithering = False @@ -241,3 +251,27 @@ class Profile(object): } return settings + + + def convert_to_engine2(self): + + settings = { + "engraving_laser_speed": self.get_int("speed"), + "laser_intensity": self.get_int("intensity"), + "beam_diameter" : self.get_float("beam_diameter"), + "intensity_white" : self.get_int("intensity_white"), + "intensity_black" : self.get_int("intensity_black"), + "speed_white" : self.get_int("feedrate_white"), + "speed_black" : self.get_int("feedrate_black"), + "pierce_time" : self.get_float("pierce_time"), + "contrast": self.get_float("img_contrast"), + "sharpening": self.get_float("img_sharpening"), + "dithering": self.get_boolean("img_dithering"), + "fill_areas": self.get_boolean("fill_areas"), + "cross_fill": self.get_boolean("cross_fill"), + "fill_angle": self.get_float("fill_angle"), + "fill_spacing": self.get_float("fill_spacing"), + "svgDPI": self.get_float("svgDPI") + } + + return settings diff --git a/src/octoprint/plugins/svgtogcode/static/js/gcode_parser.js b/src/octoprint/plugins/svgtogcode/static/js/gcode_parser.js index 12828286..ac520d7b 100644 --- a/src/octoprint/plugins/svgtogcode/static/js/gcode_parser.js +++ b/src/octoprint/plugins/svgtogcode/static/js/gcode_parser.js @@ -4,7 +4,7 @@ $(function() { self.toolOffsets = [{x: 0, y: 0}]; - self.parse = function(gcode, blockDelimiter, blockCallback ) { + self.parse = function(gcode, pathDelimiter, pathCallback, imgCallback ) { var argChar, numSlice; var x, y, z, pi, pj, pp = 0; @@ -14,6 +14,7 @@ $(function() { var f, lastF = 4000; var extrude = false, extrudeRelative = false, retract = 0; var positionRelative = false; + var withinPixelCode = false; var dcExtrude = false; var assumeNonDC = false; @@ -27,6 +28,29 @@ $(function() { var model = []; for (var i = 0; i < gcode_lines.length; i++) { + var l = gcode_lines[i]; + if(l.startsWith(';Image')) { + withinPixelCode = true; + // ;Image: 24.71x18.58 @ 2.59,1.70 + var re = /;Image: ([-+]?[0-9]*\.?[0-9]+)x([-+]?[0-9]*\.?[0-9]+) @ ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)/; + var match = l.match(re); + if(match){ + var w = parseFloat(match[1]); + var h = parseFloat(match[2]); + var x = parseFloat(match[3]); + var y = parseFloat(match[4]); + if(typeof imgCallback === 'function'){ + imgCallback(x,y,w,h); + } + } + } + if(l.startsWith(';EndImage')) withinPixelCode = false; + + if(withinPixelCode){ + continue; + } + var line = l.split(/[\(;]/)[0]; + x = undefined; y = undefined; z = undefined; @@ -37,7 +61,6 @@ $(function() { retract = 0; extrude = false; - var line = gcode_lines[i].split(/[\(;]/)[0]; var addToModel = false; var convertAndAddToModel = false; @@ -402,15 +425,15 @@ $(function() { prevY = y; } - if (typeof (blockCallback) === 'function' && typeof (blockDelimiter) !== 'undefined' && blockDelimiter.test(line)) { - blockCallback(model); + if (typeof (pathCallback) === 'function' && typeof (pathDelimiter) !== 'undefined' && pathDelimiter.test(line)) { + pathCallback(model); model = model.slice(-1); // keep the last element as start of the next block } } prevZ = z; - if (typeof (blockCallback) === 'function' && model.length > 0) { - blockCallback(model); + if (typeof (pathCallback) === 'function' && model.length > 0) { + pathCallback(model); } }; diff --git a/src/octoprint/plugins/svgtogcode/static/js/working_area.js b/src/octoprint/plugins/svgtogcode/static/js/working_area.js index 0eb2757c..e238e6d5 100644 --- a/src/octoprint/plugins/svgtogcode/static/js/working_area.js +++ b/src/octoprint/plugins/svgtogcode/static/js/working_area.js @@ -165,18 +165,22 @@ $(function(){ } self.loadGcode(file, function(gcode){ - self.parser.parse(gcode, /(m0?3)|(m0?5)/i, function(block){ + var pathCallback = function(path){ var points = []; var intensity = -1; - for (var idx = 0; idx < block.length; idx++) { - var item = block[idx]; + for (var idx = 0; idx < path.length; idx++) { + var item = path[idx]; points.push( [ item.x, item.y ] ); intensity = item.laser; } if(points.length > 0) self.draw_gcode(points, intensity, '#'+previewId); - }); + }; + var imgCallback = function(x,y,w,h){ + self.draw_gcode_img_placeholder(x,y,w,h, '#'+previewId) + }; + self.parser.parse(gcode, /(m0?3)|(m0?5)/i, pathCallback, imgCallback); }); }; @@ -668,6 +672,15 @@ $(function(){ }); snap.select(target).append(p); }; + + self.draw_gcode_img_placeholder = function(x,y,w,h, target){ + var i = snap.rect(x,y,w,h).attr({ + fill: '#AAAAFF', + stroke: 'none' + }); + snap.select(target).append(i); + }; + self.clear_gcode = function(){ // console.log("gcodeprev clear"); snap.select('#gCodePreview').clear();