############################################################ # FlatCAM: 2D Post-processing for Manufacturing # # http://flatcam.org # # File Author: Marius Adrian Stanciu (c) # # Date: 3/10/2019 # # MIT Licence # ############################################################ from FlatCAMTool import FlatCAMTool from FlatCAMObj import * import math import numpy as np import scipy.interpolate import zlib import re import gettext import FlatCAMTranslation as fcTranslate fcTranslate.apply_language('strings') import builtins if '_' not in builtins.__dict__: _ = gettext.gettext class ToolPDF(FlatCAMTool): ''' Parse a PDF file. Reference here: https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf Return a list of geometries ''' toolName = _("PDF Import Tool") def __init__(self, app): FlatCAMTool.__init__(self, app) self.app = app self.step_per_circles = self.app.defaults["gerber_circle_steps"] self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S) # detect 'w' command self.strokewidth_re = re.compile(r'^(\d+\.?\d*)\s*w$') # detect 're' command self.rect_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sre$') # detect 'm' command self.start_path_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sm$') # detect 'l' command self.draw_line_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sl') # detect 'c' command self.draw_arc_3pt_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sc$') # detect 'v' command self.draw_arc_2pt_23_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sv$') # detect 'y' command self.draw_arc_2pt_13_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sy$') # detect 'h' command self.end_path_re = re.compile(r'^h$') self.pdf_parsed = '' def run(self, toggle=True): self.app.report_usage("ToolPDF()") # if toggle: # # if the splitter is hidden, display it, else hide it but only if the current widget is the same # if self.app.ui.splitter.sizes()[0] == 0: # self.app.ui.splitter.setSizes([1, 1]) # else: # try: # if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName: # self.app.ui.splitter.setSizes([0, 1]) # except AttributeError: # pass # else: # if self.app.ui.splitter.sizes()[0] == 0: # self.app.ui.splitter.setSizes([1, 1]) # # FlatCAMTool.run(self) self.set_tool_ui() self.on_open_pdf_click() # self.app.ui.notebook.setTabText(2, "PDF Tool") def install(self, icon=None, separator=None, **kwargs): FlatCAMTool.install(self, icon, separator, shortcut='ALT+Q', **kwargs) def set_tool_ui(self): pass def on_open_pdf_click(self): """ File menu callback for opening an PDF file. :return: None """ self.app.report_usage("ToolPDF.on_open_pdf_click()") self.app.log.debug("ToolPDF.on_open_pdf_click()") _filter_ = "Adobe PDF Files (*.pdf);;" \ "All Files (*.*)" try: filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), directory=self.app.get_last_folder(), filter=_filter_) except TypeError: filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), filter=_filter_) filenames = [str(filename) for filename in filenames] if len(filenames) == 0: self.app.inform.emit(_("[WARNING_NOTCL] Open PDF cancelled.")) else: for filename in filenames: if filename != '': self.app.worker_task.emit({'fcn': self.open_pdf, 'params': [filename]}) def open_pdf(self, filename): def obj_init(grb_obj, app_obj): with open(filename, "rb") as f: pdf = f.read() for s in re.findall(self.stream_re, pdf): s = s.strip(b'\r\n') try: self.pdf_parsed += zlib.decompress(s).decode('UTF-8') except: pass grb_obj.solid_geometry = [self.bezier_to_linestring(0, 0, 0, 0)] with self.app.proc_container.new(_("Opening PDF.")): # obj_init() self.parse_pdf() ret = self.app.new_object("geometry", "bla", obj_init, autoselected=False) # Register recent file self.app.file_opened.emit("geometry", "bla") # # Object name # name = outname or filename.split('/')[-1].split('\\')[-1] # # ret = self.new_object("excellon", name, obj_init, autoselected=False) # if ret == 'fail': # self.inform.emit(_('[ERROR_NOTCL] Open Excellon file failed. Probable not an Excellon file.')) # return # # # Register recent file # self.file_opened.emit("excellon", filename) # # # GUI feedback # self.inform.emit(_("[success] Opened: %s") % filename) # # self.progress.emit(100) def parse_pdf(self): for pline in self.pdf_parsed: pass def bezier_to_linestring(self, start, stop, c1, c2): """ From here: https://gis.stackexchange.com/questions/106937/python-library-or-algorithm-to-generate-arc-geometry-from-three-coordinate-pairs :return: LineString geometry """ coords = np.array([[0, 0], [25, 10], [33, 39], [53, 53]]) # equation Bezier, page 184 PDF 1.4 reference # https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf # R(t) = P0*(1 - t) ** 3 + P1*3*t*(1 - 5) ** 2 + P2 * 3*(1 - t) * t ** 2 + P3*t ** 3 domain = [] i = 0 while i <=1: domain.append(i) for i in domain: return even_line