diff options
| -rw-r--r-- | requirements.txt | 2 | ||||
| -rw-r--r-- | schemas_json/messages.yaml | 5 | ||||
| -rw-r--r-- | src_js/opcut/common.js | 5 | ||||
| -rw-r--r-- | src_js/opcut/vt.js | 2 | ||||
| -rw-r--r-- | src_py/opcut/common.py | 13 | ||||
| -rw-r--r-- | src_py/opcut/main.py | 23 | ||||
| -rw-r--r-- | src_py/opcut/output.py | 206 | ||||
| -rw-r--r-- | src_py/opcut/server.py | 12 |
8 files changed, 159 insertions, 109 deletions
diff --git a/requirements.txt b/requirements.txt index dd3a7ab..d458021 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,4 @@ pyyaml jsonschema aiohttp flake8 -reportlab +pycairo diff --git a/schemas_json/messages.yaml b/schemas_json/messages.yaml index 44b8c3a..7a4d210 100644 --- a/schemas_json/messages.yaml +++ b/schemas_json/messages.yaml @@ -35,12 +35,17 @@ definitions: required: - result - output_type + - panel properties: result: "$ref": "opcut://result.yaml#" output_type: enum: - PDF + panel: + type: + - "null" + - string response: type: object required: diff --git a/src_js/opcut/common.js b/src_js/opcut/common.js index 323fc76..48ba8d0 100644 --- a/src_js/opcut/common.js +++ b/src_js/opcut/common.js @@ -21,10 +21,11 @@ export function calculate() { } -export function generateOutput(output_type) { +export function generateOutput(output_type, panel) { const msg = { output_type: output_type, - result: r.get('result') + result: r.get('result'), + panel: panel }; send(generateOutputUrl, msg).then(msg => parseGenerateOutputResponse(msg, output_type)); } diff --git a/src_js/opcut/vt.js b/src_js/opcut/vt.js index 139ca33..a2c8c3b 100644 --- a/src_js/opcut/vt.js +++ b/src_js/opcut/vt.js @@ -149,7 +149,7 @@ function rightPanel() { ['div.toolbar', ['button', { on: { - click: () => common.generateOutput('PDF') + click: () => common.generateOutput('PDF', null) }}, ['span.fa.fa-file-pdf-o'], ' PDF' diff --git a/src_py/opcut/common.py b/src_py/opcut/common.py index 184537f..3f24109 100644 --- a/src_py/opcut/common.py +++ b/src_py/opcut/common.py @@ -3,6 +3,8 @@ import enum from opcut import util +mm = 72 / 25.4 + Params = util.namedtuple( 'Params', ['cut_width', 'float'], @@ -44,10 +46,21 @@ Unused = util.namedtuple( ['x', 'float'], ['y', 'float']) +OutputSettings = util.namedtuple( + 'OutputSettings', + ['pagesize', 'Tuple[float,float]', (210 * mm, 297 * mm)], + ['margin_top', 'float', 10 * mm], + ['margin_bottom', 'float', 20 * mm], + ['margin_left', 'float', 10 * mm], + ['margin_right', 'float', 10 * mm]) + Method = enum.Enum('Method', [ 'GREEDY', 'FORWARD_GREEDY']) +OutputType = enum.Enum('OutputType', [ + 'PDF']) + class UnresolvableError(Exception): """Exception raised when Result is not solvable""" diff --git a/src_py/opcut/main.py b/src_py/opcut/main.py index 6758267..7e39212 100644 --- a/src_py/opcut/main.py +++ b/src_py/opcut/main.py @@ -77,15 +77,16 @@ def output(args): args: command line argument """ + if not args.output_path: + return with open(args.result_path, 'r', encoding='utf-8') as f: result_json_data = yaml.safe_load(f) opcut.json_validator.validate(result_json_data, 'opcut://result.yaml#') result = common.json_data_to_result(result_json_data) - - if args.output_pdf_path: - pdf_bytes = opcut.output.generate_pdf(result) - with open(args.output_pdf_path, 'wb') as f: - f.write(pdf_bytes) + output_bytes = opcut.output.generate_output(result, args.output_type, + args.output_panel_id) + with open(args.output_path, 'wb') as f: + f.write(output_bytes) def _create_parser(): @@ -129,8 +130,16 @@ def _create_parser(): help="calculate result file path " "(specified by opcut://result.yaml#)") p.add_argument( - '--output-pdf', default=None, metavar='path', - dest='output_pdf_path', help="optional PDF output file path") + '--output-type', dest='output_type', type=common.OutputType, + default=common.OutputType.PDF, + choices=list(map(lambda x: x.name, common.OutputType)), + help="output type (default PDF)") + p.add_argument( + '--output-panel', default=None, metavar='panel_id', + dest='output_panel_id', help="output panel id") + p.add_argument( + '--output', default=None, metavar='path', dest='output_path', + help="optional output file path") return parser diff --git a/src_py/opcut/output.py b/src_py/opcut/output.py index 311585e..a66b90f 100644 --- a/src_py/opcut/output.py +++ b/src_py/opcut/output.py @@ -1,108 +1,130 @@ import io -from reportlab.pdfgen import canvas -from reportlab.lib.units import mm +import cairo -from opcut import util +from opcut import common -def generate_pdf(result, pagesize_mm=(210, 297), - margin_top_mm=10, margin_bottom_mm=20, - margin_left_mm=10, margin_right_mm=10): - """Generate PDF output +def generate_output(result, output_type, panel_id=None, + settings=common.OutputSettings()): + """Generate output Args: - result (opcut.common.Result): result - pagesize (Tuple[float,float]): page size as (with, height) in mm - margin_top_mm (float): margin top in mm - margin_bottom_mm (float): margin bottom in mm - margin_left_mm (float): margin left in mm - margin_right_mm (float): margin right in mm + result (common.Result): result + output_type (common.OutputType): output type + panel_id (Optional[str]): panel id (None represents all panels) + settings (common.OutputSettings): output settings Returns: bytes """ - pagesize = tuple(map(lambda x: x * mm, pagesize_mm)) - margin = _Margin(top=margin_top_mm * mm, - right=margin_right_mm * mm, - bottom=margin_bottom_mm * mm, - left=margin_left_mm * mm) ret = io.BytesIO() - c = canvas.Canvas(ret, pagesize=pagesize) - c.setFillColorRGB(0.9, 0.9, 0.9) - for panel in result.params.panels: - _pdf_write_panel(c, pagesize, margin, result, panel) - c.save() + with cairo.PDFSurface(ret, settings.pagesize[0], + settings.pagesize[1]) as surface: + ctx = cairo.Context(surface) + # TODO return ret.getvalue() -def generate_csv(result): - """Generate CSV output - - Args: - result (opcut.common.Result): result - - Returns: - bytes - - """ - return b'' - - -_Margin = util.namedtuple('_Margin', 'top', 'right', 'bottom', 'left') - - -def _pdf_write_panel(c, pagesize, margin, result, panel): - if (panel.width / panel.height > - (pagesize[0] - margin.left - margin.right) / - (pagesize[1] - margin.top - margin.bottom)): - scale = ( - (pagesize[0] - (margin.left + margin.right) * mm) / - panel.width) - else: - scale = ( - (pagesize[1] - (margin.top + margin.bottom) * mm) / - panel.height) - width = panel.width * scale - height = panel.height * scale - x0 = ((pagesize[0] - width) * margin.left / - (margin.left + margin.right)) - y0 = ((pagesize[1] - height) * margin.bottom / - (margin.top + margin.bottom)) - c.setFillColorRGB(0.5, 0.5, 0.5) - c.rect(x0, y0, width, height, stroke=1, fill=1) - for used in result.used: - if used.panel != panel: - continue - _pdf_write_used(c, x0, y0, scale, result, used) - for unused in result.unused: - if unused.panel != panel: - continue - _pdf_write_unused(c, x0, y0, scale, result, unused) - c.setFillColorRGB(0, 0, 0) - c.drawCentredString(pagesize[0] / 2, margin.bottom / 2, - panel.id) - c.showPage() - - -def _pdf_write_used(c, x0, y0, scale, result, used): - width = used.item.width * scale - height = used.item.height * scale - if used.rotate: - width, height = height, width - x = used.x * scale + x0 - y = (used.panel.height - used.y) * scale + y0 - height - c.setFillColorRGB(1, 1, 1) - c.rect(x, y, width, height, stroke=0, fill=1) - c.setFillColorRGB(0, 0, 0) - c.drawCentredString(x + width / 2, y + height / 2 - 6, used.item.id) - - -def _pdf_write_unused(c, x0, y0, scale, result, unused): - width = unused.width * scale - height = unused.height * scale - x = unused.x * scale + x0 - y = (unused.panel.height - unused.y) * scale + y0 - height - c.setFillColorRGB(0.9, 0.9, 0.9) - c.rect(x, y, width, height, stroke=0, fill=1) +# def generate_pdf(result, pagesize_mm=(210, 297), +# margin_top_mm=10, margin_bottom_mm=20, +# margin_left_mm=10, margin_right_mm=10): +# """Generate PDF output +# +# Args: +# result (opcut.common.Result): result +# pagesize (Tuple[float,float]): page size as (with, height) in mm +# margin_top_mm (float): margin top in mm +# margin_bottom_mm (float): margin bottom in mm +# margin_left_mm (float): margin left in mm +# margin_right_mm (float): margin right in mm +# +# Returns: +# bytes +# +# """ +# pagesize = tuple(map(lambda x: x * mm, pagesize_mm)) +# margin = _Margin(top=margin_top_mm * mm, +# right=margin_right_mm * mm, +# bottom=margin_bottom_mm * mm, +# left=margin_left_mm * mm) +# ret = io.BytesIO() +# c = canvas.Canvas(ret, pagesize=pagesize) +# c.setFillColorRGB(0.9, 0.9, 0.9) +# for panel in result.params.panels: +# _pdf_write_panel(c, pagesize, margin, result, panel) +# c.save() +# return ret.getvalue() +# +# +# def generate_csv(result): +# """Generate CSV output +# +# Args: +# result (opcut.common.Result): result +# +# Returns: +# bytes +# +# """ +# return b'' +# +# +# _Margin = util.namedtuple('_Margin', 'top', 'right', 'bottom', 'left') +# +# +# def _pdf_write_panel(c, pagesize, margin, result, panel): +# if (panel.width / panel.height > +# (pagesize[0] - margin.left - margin.right) / +# (pagesize[1] - margin.top - margin.bottom)): +# scale = ( +# (pagesize[0] - (margin.left + margin.right) * mm) / +# panel.width) +# else: +# scale = ( +# (pagesize[1] - (margin.top + margin.bottom) * mm) / +# panel.height) +# width = panel.width * scale +# height = panel.height * scale +# x0 = ((pagesize[0] - width) * margin.left / +# (margin.left + margin.right)) +# y0 = ((pagesize[1] - height) * margin.bottom / +# (margin.top + margin.bottom)) +# c.setFillColorRGB(0.5, 0.5, 0.5) +# c.rect(x0, y0, width, height, stroke=1, fill=1) +# for used in result.used: +# if used.panel != panel: +# continue +# _pdf_write_used(c, x0, y0, scale, result, used) +# for unused in result.unused: +# if unused.panel != panel: +# continue +# _pdf_write_unused(c, x0, y0, scale, result, unused) +# c.setFillColorRGB(0, 0, 0) +# c.drawCentredString(pagesize[0] / 2, margin.bottom / 2, +# panel.id) +# c.showPage() +# +# +# def _pdf_write_used(c, x0, y0, scale, result, used): +# width = used.item.width * scale +# height = used.item.height * scale +# if used.rotate: +# width, height = height, width +# x = used.x * scale + x0 +# y = (used.panel.height - used.y) * scale + y0 - height +# c.setFillColorRGB(1, 1, 1) +# c.rect(x, y, width, height, stroke=0, fill=1) +# c.setFillColorRGB(0, 0, 0) +# c.drawCentredString(x + width / 2, y + height / 2 - 6, used.item.id) +# +# +# def _pdf_write_unused(c, x0, y0, scale, result, unused): +# width = unused.width * scale +# height = unused.height * scale +# x = unused.x * scale + x0 +# y = (unused.panel.height - unused.y) * scale + y0 - height +# c.setFillColorRGB(0.9, 0.9, 0.9) +# c.rect(x, y, width, height, stroke=0, fill=1) +# diff --git a/src_py/opcut/server.py b/src_py/opcut/server.py index 02fc161..60b2623 100644 --- a/src_py/opcut/server.py +++ b/src_py/opcut/server.py @@ -68,8 +68,10 @@ async def _generate_output_handler(executor, request): opcut.json_validator.validate( msg, 'opcut://messages.yaml#/definitions/generate_output/request') result = common.json_data_to_result(msg['result']) - output_type = msg['output_type'] - output = await executor(_ext_generate_output, result, output_type) + output_type = common.OutputType[msg['output_type']] + panel = msg['panel'] + output = await executor(_ext_generate_output, result, output_type, + panel) output_json_data = base64.b64encode(output).decode('utf-8') except asyncio.CancelledError: raise @@ -82,7 +84,5 @@ def _ext_calculate(params, method): return opcut.csp.calculate(params, method) -def _ext_generate_output(result, output_type): - if output_type == 'PDF': - return opcut.output.generate_pdf(result) - raise ValueError('output_type {} not supported'.format(output_type)) +def _ext_generate_output(result, output_type, panel): + return opcut.output.generate_output(result, output_type, panel) |
