diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e8ef40..cdc720e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta ================================================= +5.10.2020 + +- working on adding DPI setting for PNG export in the Film Tool + 26.09.2020 - the Selected Tab is now Properties Tab for FlatCAM objects diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index ebed23d4..fb1fc857 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -461,6 +461,7 @@ class PreferencesUIManager: "tools_film_file_type_radio": self.ui.tools_defaults_form.tools_film_group.file_type_radio, "tools_film_orientation": self.ui.tools_defaults_form.tools_film_group.orientation_radio, "tools_film_pagesize": self.ui.tools_defaults_form.tools_film_group.pagesize_combo, + "tools_film_png_dpi": self.ui.tools_defaults_form.tools_film_group.png_dpi_spinner, # Panelize Tool "tools_panelize_spacing_columns": self.ui.tools_defaults_form.tools_panelize_group.pspacing_columns, diff --git a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py index 419f300d..eff982f8 100644 --- a/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py +++ b/appGUI/preferences/tools/ToolsFilmPrefGroupUI.py @@ -1,7 +1,7 @@ -from PyQt5 import QtWidgets, QtCore, QtGui -from PyQt5.QtCore import Qt, QSettings +from PyQt5 import QtWidgets +from PyQt5.QtCore import QSettings -from appGUI.GUIElements import RadioSet, FCEntry, FCDoubleSpinner, FCCheckBox, FCComboBox, FCColorEntry +from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox, FCColorEntry, FCLabel, FCSpinner from appGUI.preferences.OptionsGroupUI import OptionsGroupUI import gettext @@ -28,7 +28,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): self.decimals = decimals # ## Parameters - self.film_label = QtWidgets.QLabel("%s:" % _("Parameters")) + self.film_label = FCLabel("%s:" % _("Parameters")) self.film_label.setToolTip( _("Create a PCB film from a Gerber or Geometry object.\n" "The file is saved in SVG format.") @@ -40,7 +40,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): self.film_type_radio = RadioSet([{'label': 'Pos', 'value': 'pos'}, {'label': 'Neg', 'value': 'neg'}]) - ftypelbl = QtWidgets.QLabel('%s:' % _('Film Type')) + ftypelbl = FCLabel('%s:' % _('Film Type')) ftypelbl.setToolTip( _("Generate a Positive black film or a Negative film.\n" "Positive means that it will print the features\n" @@ -53,7 +53,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.film_type_radio, 0, 1) # Film Color - self.film_color_label = QtWidgets.QLabel('%s:' % _('Film Color')) + self.film_color_label = FCLabel('%s:' % _('Film Color')) self.film_color_label.setToolTip( _("Set the film color when positive film is selected.") ) @@ -68,7 +68,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): self.film_boundary_entry.set_range(0, 9999.9999) self.film_boundary_entry.setSingleStep(0.1) - self.film_boundary_label = QtWidgets.QLabel('%s:' % _("Border")) + self.film_boundary_label = FCLabel('%s:' % _("Border")) self.film_boundary_label.setToolTip( _("Specify a border around the object.\n" "Only for negative film.\n" @@ -87,7 +87,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): self.film_scale_stroke_entry.set_range(0, 9999.9999) self.film_scale_stroke_entry.setSingleStep(0.1) - self.film_scale_stroke_label = QtWidgets.QLabel('%s:' % _("Scale Stroke")) + self.film_scale_stroke_label = FCLabel('%s:' % _("Scale Stroke")) self.film_scale_stroke_label.setToolTip( _("Scale the line stroke thickness of each feature in the SVG file.\n" "It means that the line that envelope each SVG feature will be thicker or thinner,\n" @@ -96,7 +96,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.film_scale_stroke_label, 3, 0) grid0.addWidget(self.film_scale_stroke_entry, 3, 1) - self.film_adj_label = QtWidgets.QLabel('%s' % _("Film Adjustments")) + self.film_adj_label = FCLabel('%s' % _("Film Adjustments")) self.film_adj_label.setToolTip( _("Sometime the printers will distort the print shape, especially the Laser types.\n" "This section provide the tools to compensate for the print distortions.") @@ -117,7 +117,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): ) grid0.addWidget(self.film_scale_cb, 5, 0, 1, 2) - self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor")) + self.film_scalex_label = FCLabel('%s:' % _("X factor")) self.film_scalex_entry = FCDoubleSpinner() self.film_scalex_entry.set_range(-999.9999, 999.9999) self.film_scalex_entry.set_precision(self.decimals) @@ -126,7 +126,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.film_scalex_label, 6, 0) grid0.addWidget(self.film_scalex_entry, 6, 1) - self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor")) + self.film_scaley_label = FCLabel('%s:' % _("Y factor")) self.film_scaley_entry = FCDoubleSpinner() self.film_scaley_entry.set_range(-999.9999, 999.9999) self.film_scaley_entry.set_precision(self.decimals) @@ -148,7 +148,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): ) grid0.addWidget(self.film_skew_cb, 8, 0, 1, 2) - self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle")) + self.film_skewx_label = FCLabel('%s:' % _("X angle")) self.film_skewx_entry = FCDoubleSpinner() self.film_skewx_entry.set_range(-999.9999, 999.9999) self.film_skewx_entry.set_precision(self.decimals) @@ -157,7 +157,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.film_skewx_label, 9, 0) grid0.addWidget(self.film_skewx_entry, 9, 1) - self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle")) + self.film_skewy_label = FCLabel('%s:' % _("Y angle")) self.film_skewy_entry = FCDoubleSpinner() self.film_skewy_entry.set_range(-999.9999, 999.9999) self.film_skewy_entry.set_precision(self.decimals) @@ -166,7 +166,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.film_skewy_label, 10, 0) grid0.addWidget(self.film_skewy_entry, 10, 1) - self.film_skew_ref_label = QtWidgets.QLabel('%s:' % _("Reference")) + self.film_skew_ref_label = FCLabel('%s:' % _("Reference")) self.film_skew_ref_label.setToolTip( _("The reference point to be used as origin for the skew.\n" "It can be one of the four points of the geometry bounding box.") @@ -198,7 +198,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): {'label': _('Y'), 'value': 'y'}, {'label': _('Both'), 'value': 'both'}], stretch=False) - self.film_mirror_axis_label = QtWidgets.QLabel('%s:' % _("Mirror axis")) + self.film_mirror_axis_label = FCLabel('%s:' % _("Mirror axis")) grid0.addWidget(self.film_mirror_axis_label, 13, 0) grid0.addWidget(self.film_mirror_axis, 13, 1) @@ -213,7 +213,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): {'label': _('PDF'), 'value': 'pdf'} ], stretch=False) - self.file_type_label = QtWidgets.QLabel(_("Film Type:")) + self.file_type_label = FCLabel(_("Film Type:")) self.file_type_label.setToolTip( _("The file type of the saved film. Can be:\n" "- 'SVG' -> open-source vectorial format\n" @@ -224,7 +224,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.file_type_radio, 15, 1) # Page orientation - self.orientation_label = QtWidgets.QLabel('%s:' % _("Page Orientation")) + self.orientation_label = FCLabel('%s:' % _("Page Orientation")) self.orientation_label.setToolTip(_("Can be:\n" "- Portrait\n" "- Landscape")) @@ -237,7 +237,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.orientation_radio, 16, 1) # Page Size - self.pagesize_label = QtWidgets.QLabel('%s:' % _("Page Size")) + self.pagesize_label = FCLabel('%s:' % _("Page Size")) self.pagesize_label.setToolTip(_("A selection of standard ISO 216 page sizes.")) self.pagesize_combo = FCComboBox() @@ -302,6 +302,17 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.pagesize_label, 17, 0) grid0.addWidget(self.pagesize_combo, 17, 1) + # PNG DPI + self.png_dpi_label = FCLabel('%s:' % "PNG DPI") + self.png_dpi_label.setToolTip( + _("Default value is 96 DPI. Change this value to scale the PNG file.") + ) + self.png_dpi_spinner = FCSpinner() + self.png_dpi_spinner.set_range(0, 100000) + + grid0.addWidget(self.png_dpi_label, 19, 0) + grid0.addWidget(self.png_dpi_spinner, 19, 1) + self.layout.addStretch() # Film Tool diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index c6ade3cc..e04f1831 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -1854,6 +1854,7 @@ class GeometryObject(FlatCAMObj, Geometry): return self.multigeo = True + # Object initialization function for app.app_obj.new_object() # RUNNING ON SEPARATE THREAD! def job_init_single_geometry(job_obj, app_obj): @@ -2115,9 +2116,9 @@ class GeometryObject(FlatCAMObj, Geometry): is_first = True if tooluid_key == tool_lst[0] else False is_last = True if tooluid_key == tool_lst[-1] else False res, start_gcode = job_obj.geometry_tool_gcode_gen(tooluid_key, tools_dict, first_pt=(0, 0), - tolerance = tol, + tolerance=tol, is_first=is_first, is_last=is_last, - toolchange = True) + toolchange=True) if res == 'fail': log.debug("GeometryObject.mtool_gen_cncjob() --> generate_from_geometry2() failed") return 'fail' @@ -2303,8 +2304,8 @@ class GeometryObject(FlatCAMObj, Geometry): toolchangexy=toolchangexy, extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy, - pp_geometry_name=ppname_g - ) + pp_geometry_name=ppname_g) + job_obj.source_file = res # tell gcode_parse from which point to start drawing the lines depending on what kind of object is the # source of gcode @@ -2872,13 +2873,13 @@ class GeometryObject(FlatCAMObj, Geometry): self.plot() @staticmethod - def merge(geo_list, geo_final, multigeo=None, fuse_tools=None): + def merge(geo_list, geo_final, multi_geo=None, fuse_tools=None): """ Merges the geometry of objects in grb_list into the geometry of geo_final. :param geo_list: List of GerberObject Objects to join. :param geo_final: Destination GerberObject object. - :param multigeo: if the merged geometry objects are of type MultiGeo + :param multi_geo: if the merged geometry objects are of type MultiGeo :param fuse_tools: If True will try to fuse tools of the same type for the Geometry objects :return: None """ @@ -2908,7 +2909,7 @@ class GeometryObject(FlatCAMObj, Geometry): GeometryObject.merge(geo_list=geo_obj, geo_final=geo_final) # If not list, just append else: - if multigeo is None or multigeo is False: + if multi_geo is None or multi_geo is False: geo_final.multigeo = False else: geo_final.multigeo = True @@ -2966,19 +2967,23 @@ class GeometryObject(FlatCAMObj, Geometry): new_tool_nr = 1 for i_lst in intersect_list: new_solid_geo = [] + last_tool = None for old_tool in i_lst: new_solid_geo += new_tools[old_tool]['solid_geometry'] + last_tool = old_tool - if new_solid_geo: + if new_solid_geo and last_tool: final_tools[new_tool_nr] = \ { - k: deepcopy(new_tools[old_tool][k]) for k in new_tools[old_tool] if k != 'solid_geometry' + k: deepcopy(new_tools[last_tool][k]) for k in new_tools[last_tool] if k != 'solid_geometry' } final_tools[new_tool_nr]['solid_geometry'] = deepcopy(new_solid_geo) new_tool_nr += 1 else: final_tools = new_tools + # if not final_tools: + # return 'fail' geo_final.tools = final_tools @staticmethod diff --git a/appTools/ToolFilm.py b/appTools/ToolFilm.py index c5831819..d01dde8b 100644 --- a/appTools/ToolFilm.py +++ b/appTools/ToolFilm.py @@ -9,7 +9,7 @@ from PyQt5 import QtCore, QtWidgets, QtGui from appTool import AppTool from appGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \ - OptionalHideInputSection, FCComboBox, FCFileSaveDialog, FCButton, FCLabel + OptionalHideInputSection, FCComboBox, FCFileSaveDialog, FCButton, FCLabel, FCSpinner from copy import deepcopy import logging @@ -138,6 +138,8 @@ class Film(AppTool): self.ui.orientation_radio.set_value(self.app.defaults["tools_film_orientation"]) self.ui.pagesize_combo.set_value(self.app.defaults["tools_film_pagesize"]) + self.ui.png_dpi_spinner.set_value(self.app.defaults["tools_film_png_dpi"]) + self.ui.tf_type_obj_combo.set_value('grb') self.ui.tf_type_box_combo.set_value('grb') # run once to update the obj_type attribute in the FCCombobox so the last object is showed in cb @@ -187,8 +189,8 @@ class Film(AppTool): def generate_positive_normal_film(self, name, boxname, factor, ftype='svg'): log.debug("ToolFilm.Film.generate_positive_normal_film() started ...") - scale_factor_x = None - scale_factor_y = None + scale_factor_x = 1 + scale_factor_y = 1 skew_factor_x = None skew_factor_y = None mirror = None @@ -328,8 +330,8 @@ class Film(AppTool): def generate_negative_film(self, name, boxname, factor, ftype='svg'): log.debug("ToolFilm.Film.generate_negative_film() started ...") - scale_factor_x = None - scale_factor_y = None + scale_factor_x = 1 + scale_factor_y = 1 skew_factor_x = None skew_factor_y = None mirror = None @@ -390,7 +392,7 @@ class Film(AppTool): def export_negative(self, obj_name, box_name, filename, boundary, scale_stroke_factor=0.00, - scale_factor_x=None, scale_factor_y=None, + scale_factor_x=1, scale_factor_y=1, skew_factor_x=None, skew_factor_y=None, skew_reference='center', mirror=None, use_thread=True, ftype='svg'): @@ -434,6 +436,12 @@ class Film(AppTool): self.app.inform.emit('[WARNING_NOTCL] %s: %s' % (_("No object Box. Using instead"), obj)) box = obj + new_png_dpi = self.ui.png_dpi_spinner.get_value() + dpi_rate = new_png_dpi / 96 + if dpi_rate != 1: + scale_factor_x += dpi_rate + scale_factor_y += dpi_rate + def make_negative_film(): exported_svg = obj.export_svg(scale_stroke_factor=scale_stroke_factor, scale_factor_x=scale_factor_x, scale_factor_y=scale_factor_y, @@ -513,7 +521,10 @@ class Film(AppTool): try: doc_final = StringIO(doc_final) drawing = svg2rlg(doc_final) - renderPM.drawToFile(drawing, filename, 'PNG') + if new_png_dpi == 96: + renderPM.drawToFile(drawing, filename, 'PNG') + else: + renderPM.drawToFile(drawing, filename, 'PNG', dpi=new_png_dpi) except Exception as e: log.debug("FilmTool.export_negative() --> PNG output --> %s" % str(e)) return 'fail' @@ -566,7 +577,7 @@ class Film(AppTool): def export_positive(self, obj_name, box_name, filename, scale_stroke_factor=0.00, - scale_factor_x=None, scale_factor_y=None, + scale_factor_x=1, scale_factor_y=1, skew_factor_x=None, skew_factor_y=None, skew_reference='center', mirror=None, orientation_val='p', pagesize_val='A4', color_val='black', opacity_val=1.0, use_thread=True, ftype='svg'): @@ -620,6 +631,12 @@ class Film(AppTool): color = color_val transparency_level = opacity_val + new_png_dpi = self.ui.png_dpi_spinner.get_value() + dpi_rate = new_png_dpi / 96 + if dpi_rate != 1: + scale_factor_x += dpi_rate + scale_factor_y += dpi_rate + def make_positive_film(p_size, orientation, color, transparency_level): log.debug("FilmTool.export_positive().make_positive_film()") @@ -692,7 +709,10 @@ class Film(AppTool): try: doc_final = StringIO(doc_final) drawing = svg2rlg(doc_final) - renderPM.drawToFile(drawing, filename, 'PNG') + if new_png_dpi == 96: + renderPM.drawToFile(drawing, filename, 'PNG') + else: + renderPM.drawToFile(drawing, filename, 'PNG', dpi=new_png_dpi) except Exception as e: log.debug("FilmTool.export_positive() --> PNG output --> %s" % str(e)) return 'fail' @@ -1199,6 +1219,20 @@ class FilmUI: self.on_film_type(val='hide') + # PNG DPI + self.png_dpi_label = FCLabel('%s:' % "PNG DPI") + self.png_dpi_label.setToolTip( + _("Default value is 96 DPI. Change this value to scale the PNG file.") + ) + self.png_dpi_spinner = FCSpinner(callback=self.confirmation_message_int) + self.png_dpi_spinner.set_range(0, 100000) + + grid1.addWidget(self.png_dpi_label, 4, 0) + grid1.addWidget(self.png_dpi_spinner, 4, 1) + + self.png_dpi_label.hide() + self.png_dpi_spinner.hide() + # Buttons self.film_object_button = FCButton(_("Save Film")) self.film_object_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png')) @@ -1214,7 +1248,7 @@ class FilmUI: font-weight: bold; } """) - grid1.addWidget(self.film_object_button, 4, 0, 1, 2) + grid1.addWidget(self.film_object_button, 6, 0, 1, 2) self.layout.addStretch() @@ -1254,11 +1288,22 @@ class FilmUI: self.orientation_radio.show() self.pagesize_label.show() self.pagesize_combo.show() + self.png_dpi_label.hide() + self.png_dpi_spinner.hide() + elif val == 'png': + self.png_dpi_label.show() + self.png_dpi_spinner.show() + self.orientation_label.hide() + self.orientation_radio.hide() + self.pagesize_label.hide() + self.pagesize_combo.hide() else: self.orientation_label.hide() self.orientation_radio.hide() self.pagesize_label.hide() self.pagesize_combo.hide() + self.png_dpi_label.hide() + self.png_dpi_spinner.hide() def on_punch_source(self, val): if val == 'pad' and self.punch_cb.get_value(): diff --git a/camlib.py b/camlib.py index f9a09814..2977728f 100644 --- a/camlib.py +++ b/camlib.py @@ -2255,14 +2255,20 @@ class Geometry(object): geom = geom_svg - if scale_factor_x: + if scale_factor_x and not scale_factor_y: geom = affinity.scale(geom_svg, scale_factor_x, 1.0) - if scale_factor_y: + elif not scale_factor_x and scale_factor_y: geom = affinity.scale(geom_svg, 1.0, scale_factor_y) - if skew_factor_x: + elif scale_factor_x and scale_factor_y: + geom = affinity.scale(geom_svg, scale_factor_x, scale_factor_y) + + if skew_factor_x and not skew_factor_y: geom = affinity.skew(geom_svg, skew_factor_x, 0.0, origin=skew_ref) - if skew_factor_y: + elif not skew_factor_x and skew_factor_y: geom = affinity.skew(geom_svg, 0.0, skew_factor_y, origin=skew_ref) + elif skew_factor_x and skew_factor_y: + geom = affinity.skew(geom_svg, skew_factor_x, skew_factor_y, origin=skew_ref) + if mirror: if mirror == 'x': geom = affinity.scale(geom_svg, 1.0, -1.0) diff --git a/defaults.py b/defaults.py index 43661fb8..4cfe289c 100644 --- a/defaults.py +++ b/defaults.py @@ -533,6 +533,7 @@ class FlatCAMDefaults: "tools_film_file_type_radio": 'svg', "tools_film_orientation": 'p', "tools_film_pagesize": 'A4', + "tools_film_png_dpi": 96, # Panel Tool "tools_panelize_spacing_columns": 0.0,