diff --git a/FlatCAMApp.py b/FlatCAMApp.py index b19cb4a1..8620ed20 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -2007,8 +2007,10 @@ class App(QtCore.QObject): self.image_tool.install(icon=QtGui.QIcon('share/image32.png'), pos=self.ui.menufileimport, separator=True) self.pcb_wizard_tool = PcbWizard(self) - self.pcb_wizard_tool.install(icon=QtGui.QIcon('share/drill32.png'), pos=self.ui.menufileimport, - separator=True) + self.pcb_wizard_tool.install(icon=QtGui.QIcon('share/drill32.png'), pos=self.ui.menufileimport) + + self.pdf_tool = ToolPDF(self) + self.pdf_tool.install(icon=QtGui.QIcon('share/pdf32.png'), pos=self.ui.menufileimport) self.log.debug("Tools are installed.") diff --git a/README.md b/README.md index ced07166..54b860da 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,13 @@ CAD program, and create G-Code for Isolation routing. ================================================= +19.04.2019 + +- started to work on PDF import tool + + 18.04.2019 + - Gerber Editor: added custom mouse cursors for each mode in Add Track Tool - Gerber Editor: Poligonize Tool will first fuse polygons that touch each other and at a second try will create a polygon. The polygon will be automatically moved to Aperture '0' (regions). - Gerber Editor: Region Tool will add regions only in '0' aperture diff --git a/flatcamTools/ToolPDF.py b/flatcamTools/ToolPDF.py new file mode 100644 index 00000000..b2676a3b --- /dev/null +++ b/flatcamTools/ToolPDF.py @@ -0,0 +1,178 @@ +############################################################ +# 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 diff --git a/flatcamTools/__init__.py b/flatcamTools/__init__.py index 6119a4c1..71286c55 100644 --- a/flatcamTools/__init__.py +++ b/flatcamTools/__init__.py @@ -15,5 +15,6 @@ from flatcamTools.ToolNonCopperClear import NonCopperClear from flatcamTools.ToolTransform import ToolTransform from flatcamTools.ToolSolderPaste import SolderPaste from flatcamTools.ToolPcbWizard import PcbWizard +from flatcamTools.ToolPDF import ToolPDF from flatcamTools.ToolShell import FCShell diff --git a/share/pdf32.png b/share/pdf32.png new file mode 100644 index 00000000..f90b13f7 Binary files /dev/null and b/share/pdf32.png differ