From de3a23e82fe2e4c919b393c6cc090ea8296fe22e Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Tue, 17 Nov 2020 20:08:27 +0200 Subject: [PATCH] - fixed PDF Tool such that now it can import more types of files including PDF files made with FlatCAM --- CHANGELOG.md | 1 + appParsers/ParsePDF.py | 6 +- appTools/ToolPDF.py | 142 +++++++++++++++++++++++------------------ requirements.txt | 3 +- setup_ubuntu.sh | 3 +- 5 files changed, 89 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94847445..be45d3be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG for FlatCAM beta - the Follow Geometry outputted by the Follow Tools is now of type multigeo which means that it can be fused with other multigeo object without much pain - Punch Gerber Tool - working on the new manual pads add feature +- fixed PDF Tool such that now it can import more types of files including PDF files made with FlatCAM 16.11.2020 diff --git a/appParsers/ParsePDF.py b/appParsers/ParsePDF.py index 66858f42..2818b9ef 100644 --- a/appParsers/ParsePDF.py +++ b/appParsers/ParsePDF.py @@ -532,7 +532,8 @@ class PdfParser: else: ap_list = [int(k) for k in apertures_dict.keys()] # perhaps it's the only aperture? and in that case we need to start from 10 - ap_list.remove(0) + if 0 in ap_list and len(ap_list) == 1: + ap_list.remove(0) if not ap_list: aperture = 10 else: @@ -874,7 +875,8 @@ class PdfParser: else: ap_list = [int(k) for k in apertures_dict.keys()] # perhaps it's the only aperture? and in that case we need to start from 10 - ap_list.remove(0) + if 0 in ap_list and len(ap_list) == 1: + ap_list.remove(0) if not ap_list: aperture = 10 else: diff --git a/appTools/ToolPDF.py b/appTools/ToolPDF.py index 7be1e293..49de4be5 100644 --- a/appTools/ToolPDF.py +++ b/appTools/ToolPDF.py @@ -13,15 +13,17 @@ from shapely.geometry import Point, MultiPolygon from shapely.ops import unary_union from copy import deepcopy -from io import BytesIO - -import zlib +# from io import BytesIO +# +# import zlib import re import time import logging import traceback import os +from pikepdf import Pdf, parse_content_stream + import gettext import appTranslation as fcTranslate import builtins @@ -128,67 +130,83 @@ class ToolPDF(AppTool): with self.app.proc_container.new('%s...' % _("Parsing")): with open(filename, "rb") as f: - pdf = f.read() + # pdf = f.read() + pdf = Pdf.open(f) - stream_nr = 0 - for s in re.findall(self.stream_re, pdf): - if self.app.abort_flag: - # graceful abort requested by the user - raise grace + page = pdf.pages[0] + decomp_file = '' + for operands, command in parse_content_stream(page): + line = '' + for op in operands: + try: + line += str(op) + ' ' + except Exception as e: + # print(str(e), operands, command) + pass + line += str(command) + decomp_file += line + '\n' + self.pdf_decompressed[short_name] = decomp_file - stream_nr += 1 - log.debug("PDF STREAM: %d\n" % stream_nr) - s = s.strip(b'\r\n') - - # https://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations - # def decompress(data): - # decompressed = zlib.decompressobj( - # -zlib.MAX_WBITS # see above - # ) - # inflated = decompressed.decompress(data) - # inflated += decompressed.flush() - # return inflated - - # Convert 2 Bytes If Python 3 - def C2BIP3(string): - if type(string) == bytes: - return string - else: - return bytes([ord(x) for x in string]) - - def inflate(data): - try: - return zlib.decompress(C2BIP3(data)) - except Exception: - if len(data) <= 10: - raise - oDecompress = zlib.decompressobj(-zlib.MAX_WBITS) - oStringIO = BytesIO() - count = 0 - for byte in C2BIP3(data): - try: - oStringIO.write(oDecompress.decompress(byte)) - count += 1 - except Exception: - break - if len(data) - count <= 2: - return oStringIO.getvalue() - else: - raise - - try: - decomp = inflate(s) - except Exception as e: - decomp = None - log.debug("ToolPDF.open_pdf() -> inflate (decompress) -> %s" % str(e)) - - try: - self.pdf_decompressed[short_name] += (decomp.decode('UTF-8') + '\r\n') - except Exception: - try: - self.pdf_decompressed[short_name] += (decomp.decode('latin1') + '\r\n') - except Exception as e: - log.debug("ToolPDF.open_pdf() -> decoding error -> %s" % str(e)) + # stream_nr = 0 + # for s in re.findall(self.stream_re, pdf): + # if self.app.abort_flag: + # # graceful abort requested by the user + # raise grace + # + # stream_nr += 1 + # log.debug("PDF STREAM: %d\n" % stream_nr) + # s = s.strip(b'\r\n') + # + # # https://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations + # # def decompress(data): + # # decompressed = zlib.decompressobj( + # # -zlib.MAX_WBITS # see above + # # ) + # # inflated = decompressed.decompress(data) + # # inflated += decompressed.flush() + # # return inflated + # + # Convert 2 Bytes If Python 3 + # def C2BIP3(string): + # if type(string) == bytes: + # return string + # else: + # return bytes([ord(x) for x in string]) + # + # def inflate(data): + # try: + # return zlib.decompress(C2BIP3(data)) + # except Exception: + # if len(data) <= 10: + # raise + # oDecompress = zlib.decompressobj(-zlib.MAX_WBITS) + # oStringIO = BytesIO() + # count = 0 + # for byte in C2BIP3(data): + # try: + # oStringIO.write(oDecompress.decompress(byte)) + # count += 1 + # except Exception: + # break + # if len(data) - count <= 2: + # return oStringIO.getvalue() + # else: + # raise + # + # try: + # decomp = inflate(s) + # except Exception as e: + # decomp = None + # log.debug("ToolPDF.open_pdf() -> inflate (decompress) -> %s" % str(e)) + # + # try: + # self.pdf_decompressed[short_name] += (decomp.decode('UTF-8') + '\r\n') + # except Exception: + # try: + # self.pdf_decompressed[short_name] += (decomp.decode('latin1') + '\r\n') + # except Exception as e: + # log.debug("ToolPDF.open_pdf() -> decoding error -> %s" % str(e)) + # self.pdf_decompressed[short_name] = decomp_file if self.pdf_decompressed[short_name] == '': self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Failed to open"), str(filename))) diff --git a/requirements.txt b/requirements.txt index a89fe3ee..72095885 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,4 +28,5 @@ qrcode>=6.1 reportlab>=3.5 svglib gdal -pyserial>=3.4 \ No newline at end of file +pyserial>=3.4 +pikepdf>=2.0 \ No newline at end of file diff --git a/setup_ubuntu.sh b/setup_ubuntu.sh index 854f4815..4fe8a9e1 100644 --- a/setup_ubuntu.sh +++ b/setup_ubuntu.sh @@ -45,6 +45,7 @@ sudo -H python3 -m pip install --upgrade \ pyqt5 \ reportlab \ svglib \ - pyserial + pyserial \ + pikepdf sudo -H easy_install -U distribute