Jump to content

Anteino

Dormant
  • Posts

    10
  • Joined

  • Last visited

Everything posted by Anteino

  1. So the fallback error is actually gone but I still get the uncaught error: 2018-06-22 16:07:43,416 - INFO - [MainThread] cura.Machines.ContainerNode.getContainer [39]: Lazy-loading container [makerpoint_plaht_ultimaker2_extended_plus_0.8_mm] 2018-06-22 16:07:43,474 - INFO - [MainThread] cura.Settings.MachineManager._updateQualityWithMaterial [1128]: Updating quality/quality_changes due to material change 2018-06-22 16:07:43,483 - DEBUG - [MainThread] cura.Settings.MachineManager._updateQualityWithMaterial [1135]: Current quality type = [fast] 2018-06-22 16:07:43,490 - INFO - [MainThread] cura.Settings.MachineManager._updateQualityWithMaterial [1161]: The current quality type [fast] is not available, switching to [draft] instead 2018-06-22 16:07:43,498 - INFO - [MainThread] cura.Machines.ContainerNode.getContainer [39]: Lazy-loading container [um2p_plaht_0.8_draft] 2018-06-22 16:07:43,503 - DEBUG - [MainThread] LocalContainerProvider.LocalContainerProvider.loadContainer [53]: Loading container um2p_plaht_0.8_draft 2018-06-22 16:07:43,531 - DEBUG - [MainThread] UM.Settings.ContainerRegistry.addContainer [355]: Container [um2p_plaht_0.8_draft] added. 2018-06-22 16:07:43,542 - DEBUG - [MainThread] cura.Machines.Models.CustomQualityProfilesDropDownMenuModel._update [15]: Updating CustomQualityProfilesDropDownMenuModel. 2018-06-22 16:07:43,549 - INFO - [MainThread] cura.Machines.QualityManager.getQualityChangesGroups [186]: Cannot find node for machine def [ultimaker2_plus] in QualityChanges lookup table 2018-06-22 16:07:43,557 - DEBUG - [MainThread] cura.Machines.Models.QualityProfilesDropDownMenuModel._update [50]: Updating QualityProfilesDropDownMenuModel. 2018-06-22 16:07:43,609 - CRITICAL - [MainThread] cura.CrashHandler.__init__ [66]: An uncaught error has occurred! 2018-06-22 16:07:43,618 - CRITICAL - [MainThread] cura.CrashHandler.__init__ [69]: Traceback (most recent call last): 2018-06-22 16:07:43,625 - CRITICAL - [MainThread] cura.CrashHandler.__init__ [69]: File "X:\3.3\build\inst\lib\python3.5\site-packages\cura\Machines\Models\QualityProfilesDropDownMenuModel.py", line 70, in _update 2018-06-22 16:07:43,632 - CRITICAL - [MainThread] cura.CrashHandler.__init__ [69]: File "X:\3.3\build\inst\lib\python3.5\site-packages\cura\Machines\Models\QualityProfilesDropDownMenuModel.py", line 97, in _fetchLayerHeight 2018-06-22 16:07:43,640 - CRITICAL - [MainThread] cura.CrashHandler.__init__ [69]: AttributeError: 'NoneType' object has no attribute 'getContainer' 2018-06-22 16:07:43,802 - DEBUG - [MainThread] LocalContainerProvider.LocalContainerProvider.loadContainer [53]: Loading container ultimaker2_plus 2018-06-22 16:07:44,134 - DEBUG - [MainThread] UM.Settings.ContainerRegistry.addContainer [355]: Container [ultimaker2_plus] added. Cura works fine (without crashes at least) untill I add the .inst.cfg profiles. For example the draft profile that is loaded by default: [general] version = 3 name = Fast definition = ultimaker2_plus [metadata] setting_version = 4 type = quality quality_type = draft weight = -1 material = makerpoint_plaht variant = 0.8 mm [values] cool_fan_full_at_height = =layer_height_0 + 2 * layer_height cool_min_speed = 2 infill_sparse_density = 100 infill_line_width = =round(line_width * 0.75 / 0.75, 2) infill_pattern = cubic line_width = =machine_nozzle_size * 0.9375 machine_nozzle_cool_down_speed = 0.75 machine_nozzle_heat_up_speed = 1.6 material_final_print_temperature = =max(-273.15, material_print_temperature - 5) material_initial_print_temperature = =max(-273.15, material_print_temperature) material_print_temperature = =default_material_print_temperature + 10 speed_print = 45 top_bottom_thickness = =layer_height * 6 wall_line_width = =round(line_width * 0.75 / 0.75, 2) wall_thickness = =wall_line_width_0 + wall_line_width_x cool_fan_speed_max = =100 layer_height = 0.2 prime_tower_enable = False wall_line_width_x = =round(wall_line_width * 0.75 / 0.75, 2) gradual_infill_step_height = =3 * layer_height retract_at_layer_change = False support_angle = 70 support_line_width = =line_width * 0.75 support_xy_distance = =wall_line_width_0 * 1.5
  2. Yea I kinda figured that is how to add global profiles. So I just copied my makerpoint_plaht.xml.fdm_material to generic_plaht.xml.fdm_material. In the generic file I changed the brand and color to Generic. Still crashes though at 0.8 mm nozzle when I add the material based qualities for 0.3 mm and 0.4 mm to the quality folder of the ultimaker2_plus.
  3. Yes, thank you. I did that actually. But the cura.log says my HT-PLA doesn't have a fallback material, which is obviously true because Ultimaker doesn't have an HT-PLA material. The thing that comes closest is Tough PLA I'd say but that is not supported on the Ultimaker 2+. So I added 3 material based qualities (.inst.cfg files) for the UM2E+ so far. It's for the 0.8 mm variant with the qualities draft (0.2 mm ), verydraft (0.3 mm) and superdraft (0.4 mm). I'd like to maintain Ultimaker standards as much as possible to not get confused. When I select 0.8 mm with the draft quality and HT-PLA all is fine and dandy. When I select 0.3 mm layerthickness or higher Cura immediately crashes. Even though I wrote profiles for those exact layerheights. I think it must have something to do with 0.2 mm already being supported natively, but 0.3 mm and above are not.
  4. I did some research and indeed you're right. I'm not making the global profiles. I understand this is done by making a generic_material.xml.fdm_material file. However, when I do this I still keep getting errors like this: Exception: When trying to deserialize fdmextruder #2, we received an unknown ID (um2p_plaht_0.8_draft) for container How would I go about properly implementing a new printing material? Could you give me some advice maybe, because I have been tinkering with this for hours now.
  5. I know, that's what I'm doing ?. I'm trying to add my own printing materials as native.
  6. Alright, yea, cool. That explains a lot. So if I want to make a completely "new" plugin I should dig deeper in Cura. For now I'll stick to your advice and base it on the LegacyProfileReader plugin. That's good advice, thanks ?
  7. I created a tool to make new profiles. It lets you select from existing profiles and export to XML. Using excel you can then edit the profile and import it to the cura directories so the profiles will be recognized as native. Note that with this tool you can make nozzle diameter + layerheight specific printing profiles. This is not only recommendable, but also helps avoiding the compatibility warnings on UM3 and S5. Maybe such a tool already exists but I couldn't find exactly what I needed. This tool helps me make new profiles in a very organized way. Also it helps to see relations between printing profiles created by Ultimaker. You can extrapolate these to your own printing filament to match the quality of Ultimakers native settings. To export a profile from your Cura install, first click open. Then choose a name for the XML that will represent your "profile bundle". Click export. Open the XML to edit your profiles. Next, in the tool, click import and choose your file. Now restart Cura and you should be ready to go. Currently only supports UM2+, UM2E+, UM3, UM3E and UM S5 but more printers could easily be added manually in the code. GitHub repo: https://github.com/Anteino/Cura-profile-maker
  8. Hi all, I would like to make a plugin to import files with the extensions .fdm_material and .inst.cfg to import material- and printing profiles as native in Cura. I basically copied the ImageReader plugin and changed the extensions. The plugin is found but it's still saying that the cfg extension is not supported. What am I missing here? __init__.py: # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from . import ProfileImporter from UM.i18n import i18nCatalog i18n_catalog = i18nCatalog("cura") def getMetaData(): return { "p_reader": [ { "extension": "fdm_material", "description": i18n_catalog.i18nc("@item:inlistbox", "Material profile") }, { "extension": "cfg", "description": i18n_catalog.i18nc("@item:inlistbox", "Printing profile") } ] } def register(app): return { "p_reader": ProfileImporter.ProfileImporter() } ConfigUI.qml: // Copyright (c) 2015 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.1 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 import UM 1.1 as UM UM.Dialog { width: minimumWidth; minimumWidth: 350 * screenScaleFactor; height: minimumHeight; minimumHeight: 250 * screenScaleFactor; title: catalog.i18nc("@title:window", "Convert Image...") GridLayout { UM.I18nCatalog{id: catalog; name:"cura"} anchors.fill: parent; Layout.fillWidth: true columnSpacing: 16 * screenScaleFactor rowSpacing: 4 * screenScaleFactor columns: 1 UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","The maximum distance of each pixel from \"Base.\"") Row { width: parent.width Label { text: catalog.i18nc("@action:label","Height (mm)") width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } TextField { id: peak_height objectName: "Peak_Height" validator: RegExpValidator {regExp: /^-?\d{1,3}([\,|\.]\d*)?$/} width: 180 * screenScaleFactor onTextChanged: { manager.onPeakHeightChanged(text) } } } } UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","The base height from the build plate in millimeters.") Row { width: parent.width Label { text: catalog.i18nc("@action:label","Base (mm)") width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } TextField { id: base_height objectName: "Base_Height" validator: RegExpValidator {regExp: /^\d{1,3}([\,|\.]\d*)?$/} width: 180 * screenScaleFactor onTextChanged: { manager.onBaseHeightChanged(text) } } } } UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","The width in millimeters on the build plate.") Row { width: parent.width Label { text: catalog.i18nc("@action:label","Width (mm)") width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } TextField { id: width objectName: "Width" focus: true validator: RegExpValidator {regExp: /^[1-9]\d{0,2}([\,|\.]\d*)?$/} width: 180 * screenScaleFactor onTextChanged: { manager.onWidthChanged(text) } } } } UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","The depth in millimeters on the build plate") Row { width: parent.width Label { text: catalog.i18nc("@action:label","Depth (mm)") width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } TextField { id: depth objectName: "Depth" focus: true validator: RegExpValidator {regExp: /^[1-9]\d{0,2}([\,|\.]\d*)?$/} width: 180 * screenScaleFactor onTextChanged: { manager.onDepthChanged(text) } } } } UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","By default, white pixels represent high points on the mesh and black pixels represent low points on the mesh. Change this option to reverse the behavior such that black pixels represent high points on the mesh and white pixels represent low points on the mesh.") Row { width: parent.width //Empty label so 2 column layout works. Label { text: "" width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } ComboBox { id: image_color_invert objectName: "Image_Color_Invert" model: [ catalog.i18nc("@item:inlistbox","Lighter is higher"), catalog.i18nc("@item:inlistbox","Darker is higher") ] width: 180 * screenScaleFactor onCurrentIndexChanged: { manager.onImageColorInvertChanged(currentIndex) } } } } UM.TooltipArea { Layout.fillWidth:true height: childrenRect.height text: catalog.i18nc("@info:tooltip","The amount of smoothing to apply to the image.") Row { width: parent.width Label { text: catalog.i18nc("@action:label","Smoothing") width: 150 * screenScaleFactor anchors.verticalCenter: parent.verticalCenter } Item { width: 180 * screenScaleFactor height: 20 * screenScaleFactor Layout.fillWidth: true Slider { id: smoothing objectName: "Smoothing" maximumValue: 100.0 stepSize: 1.0 width: 180 onValueChanged: { manager.onSmoothingChanged(value) } } } } } } rightButtons: [ Button { id:ok_button text: catalog.i18nc("@action:button","OK"); onClicked: { manager.onOkButtonClicked() } enabled: true }, Button { id:cancel_button text: catalog.i18nc("@action:button","Cancel"); onClicked: { manager.onCancelButtonClicked() } enabled: true } ] } plugin.json: { "name": "Profile importer", "author": "Anteino", "version": "1", "description": "Import .xml.fdm_material material profiles and .inst.cfg printer profiles as native in Cura.", "api": 4, "i18n-catalog": "cura" } ProfileImporter.py: # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import numpy from PyQt5.QtGui import QImage, qRed, qGreen, qBlue from PyQt5.QtCore import Qt from UM.Mesh.MeshReader import MeshReader from UM.Mesh.MeshBuilder import MeshBuilder from UM.Math.Vector import Vector from UM.Job import Job from UM.Logger import Logger from .ProfileImporterUI import ProfileImporterUI from cura.Scene.CuraSceneNode import CuraSceneNode as SceneNode class ProfileImporter(MeshReader): def __init__(self): super(ProfileImporter, self).__init__() self._supported_extensions = [".cfg", ".fdm_material"] self._ui = ProfileImporterUI(self) def preRead(self, file_name, *args, **kwargs): img = QImage(file_name) if img.isNull(): Logger.log("e", "Image is corrupt.") return MeshReader.PreReadResult.failed width = img.width() depth = img.height() largest = max(width, depth) width = width / largest * self._ui.default_width depth = depth / largest * self._ui.default_depth self._ui.setWidthAndDepth(width, depth) self._ui.showConfigUI() self._ui.waitForUIToClose() if self._ui.getCancelled(): return MeshReader.PreReadResult.cancelled return MeshReader.PreReadResult.accepted def read(self, file_name): size = max(self._ui.getWidth(), self._ui.getDepth()) return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.image_color_invert) def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, image_color_invert): scene_node = SceneNode() mesh = MeshBuilder() img = QImage(file_name) if img.isNull(): Logger.log("e", "Image is corrupt.") return None width = max(img.width(), 2) height = max(img.height(), 2) aspect = height / width if img.width() < 2 or img.height() < 2: img = img.scaled(width, height, Qt.IgnoreAspectRatio) base_height = max(base_height, 0) peak_height = max(peak_height, -base_height) xz_size = max(xz_size, 1) scale_vector = Vector(xz_size, peak_height, xz_size) if width > height: scale_vector = scale_vector.set(z=scale_vector.z * aspect) elif height > width: scale_vector = scale_vector.set(x=scale_vector.x / aspect) if width > max_size or height > max_size: scale_factor = max_size / width if height > width: scale_factor = max_size / height width = int(max(round(width * scale_factor), 2)) height = int(max(round(height * scale_factor), 2)) img = img.scaled(width, height, Qt.IgnoreAspectRatio) width_minus_one = width - 1 height_minus_one = height - 1 Job.yieldThread() texel_width = 1.0 / (width_minus_one) * scale_vector.x texel_height = 1.0 / (height_minus_one) * scale_vector.z height_data = numpy.zeros((height, width), dtype=numpy.float32) for x in range(0, width): for y in range(0, height): qrgb = img.pixel(x, y) avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255) height_data[y, x] = avg Job.yieldThread() if image_color_invert: height_data = 1 - height_data for _ in range(0, blur_iterations): copy = numpy.pad(height_data, ((1, 1), (1, 1)), mode= "edge") height_data += copy[1:-1, 2:] height_data += copy[1:-1, :-2] height_data += copy[2:, 1:-1] height_data += copy[:-2, 1:-1] height_data += copy[2:, 2:] height_data += copy[:-2, 2:] height_data += copy[2:, :-2] height_data += copy[:-2, :-2] height_data /= 9 Job.yieldThread() height_data *= scale_vector.y height_data += base_height heightmap_face_count = 2 * height_minus_one * width_minus_one total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2 mesh.reserveFaceCount(total_face_count) # initialize to texel space vertex offsets. # 6 is for 6 vertices for each texel quad. heightmap_vertices = numpy.zeros((width_minus_one * height_minus_one, 6, 3), dtype = numpy.float32) heightmap_vertices = heightmap_vertices + numpy.array([[ [0, base_height, 0], [0, base_height, texel_height], [texel_width, base_height, texel_height], [texel_width, base_height, texel_height], [texel_width, base_height, 0], [0, base_height, 0] ]], dtype = numpy.float32) offsetsz, offsetsx = numpy.mgrid[0: height_minus_one, 0: width - 1] offsetsx = numpy.array(offsetsx, numpy.float32).reshape(-1, 1) * texel_width offsetsz = numpy.array(offsetsz, numpy.float32).reshape(-1, 1) * texel_height # offsets for each texel quad heightmap_vertex_offsets = numpy.concatenate([offsetsx, numpy.zeros((offsetsx.shape[0], offsetsx.shape[1]), dtype=numpy.float32), offsetsz], 1) heightmap_vertices += heightmap_vertex_offsets.repeat(6, 0).reshape(-1, 6, 3) # apply height data to y values heightmap_vertices[:, 0, 1] = heightmap_vertices[:, 5, 1] = height_data[:-1, :-1].reshape(-1) heightmap_vertices[:, 1, 1] = height_data[1:, :-1].reshape(-1) heightmap_vertices[:, 2, 1] = heightmap_vertices[:, 3, 1] = height_data[1:, 1:].reshape(-1) heightmap_vertices[:, 4, 1] = height_data[:-1, 1:].reshape(-1) heightmap_indices = numpy.array(numpy.mgrid[0:heightmap_face_count * 3], dtype=numpy.int32).reshape(-1, 3) mesh._vertices[0:(heightmap_vertices.size // 3), :] = heightmap_vertices.reshape(-1, 3) mesh._indices[0:(heightmap_indices.size // 3), :] = heightmap_indices mesh._vertex_count = heightmap_vertices.size // 3 mesh._face_count = heightmap_indices.size // 3 geo_width = width_minus_one * texel_width geo_height = height_minus_one * texel_height # bottom mesh.addFaceByPoints(0, 0, 0, 0, 0, geo_height, geo_width, 0, geo_height) mesh.addFaceByPoints(geo_width, 0, geo_height, geo_width, 0, 0, 0, 0, 0) # north and south walls for n in range(0, width_minus_one): x = n * texel_width nx = (n + 1) * texel_width hn0 = height_data[0, n] hn1 = height_data[0, n + 1] hs0 = height_data[height_minus_one, n] hs1 = height_data[height_minus_one, n + 1] mesh.addFaceByPoints(x, 0, 0, nx, 0, 0, nx, hn1, 0) mesh.addFaceByPoints(nx, hn1, 0, x, hn0, 0, x, 0, 0) mesh.addFaceByPoints(x, 0, geo_height, nx, 0, geo_height, nx, hs1, geo_height) mesh.addFaceByPoints(nx, hs1, geo_height, x, hs0, geo_height, x, 0, geo_height) # west and east walls for n in range(0, height_minus_one): y = n * texel_height ny = (n + 1) * texel_height hw0 = height_data[n, 0] hw1 = height_data[n + 1, 0] he0 = height_data[n, width_minus_one] he1 = height_data[n + 1, width_minus_one] mesh.addFaceByPoints(0, 0, y, 0, 0, ny, 0, hw1, ny) mesh.addFaceByPoints(0, hw1, ny, 0, hw0, y, 0, 0, y) mesh.addFaceByPoints(geo_width, 0, y, geo_width, 0, ny, geo_width, he1, ny) mesh.addFaceByPoints(geo_width, he1, ny, geo_width, he0, y, geo_width, 0, y) mesh.calculateNormals(fast=True) scene_node.setMeshData(mesh.build()) return scene_node ProfileImporterUI.py: # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os import threading from PyQt5.QtCore import Qt, pyqtSignal, QObject from UM.FlameProfiler import pyqtSlot from UM.Application import Application from UM.PluginRegistry import PluginRegistry from UM.Logger import Logger from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") class ProfileImporterUI(QObject): show_config_ui_trigger = pyqtSignal() def __init__(self, image_reader): super(ProfileImporterUI, self).__init__() self.image_reader = image_reader self._ui_view = None self.show_config_ui_trigger.connect(self._actualShowConfigUI) self.default_width = 120 self.default_depth = 120 self._aspect = 1 self._width = self.default_width self._depth = self.default_depth self.base_height = 1 self.peak_height = 10 self.smoothing = 1 self.image_color_invert = False; self._ui_lock = threading.Lock() self._cancelled = False self._disable_size_callbacks = False def setWidthAndDepth(self, width, depth): self._aspect = width / depth self._width = width self._depth = depth def getWidth(self): return self._width def getDepth(self): return self._depth def getCancelled(self): return self._cancelled def waitForUIToClose(self): self._ui_lock.acquire() self._ui_lock.release() def showConfigUI(self): self._ui_lock.acquire() self._cancelled = False self.show_config_ui_trigger.emit() def _actualShowConfigUI(self): self._disable_size_callbacks = True if self._ui_view is None: self._createConfigUI() self._ui_view.show() self._ui_view.findChild(QObject, "Width").setProperty("text", str(self._width)) self._ui_view.findChild(QObject, "Depth").setProperty("text", str(self._depth)) self._disable_size_callbacks = False self._ui_view.findChild(QObject, "Base_Height").setProperty("text", str(self.base_height)) self._ui_view.findChild(QObject, "Peak_Height").setProperty("text", str(self.peak_height)) self._ui_view.findChild(QObject, "Smoothing").setProperty("value", self.smoothing) def _createConfigUI(self): if self._ui_view is None: Logger.log("d", "Creating ProfileImporter config UI") path = os.path.join(PluginRegistry.getInstance().getPluginPath("ProfileImporter"), "ConfigUI.qml") self._ui_view = Application.getInstance().createQmlComponent(path, {"manager": self}) self._ui_view.setFlags(self._ui_view.flags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowMinimizeButtonHint & ~Qt.WindowMaximizeButtonHint); self._disable_size_callbacks = False @pyqtSlot() def onOkButtonClicked(self): self._cancelled = False self._ui_view.close() self._ui_lock.release() @pyqtSlot() def onCancelButtonClicked(self): self._cancelled = True self._ui_view.close() self._ui_lock.release() @pyqtSlot(str) def onWidthChanged(self, value): if self._ui_view and not self._disable_size_callbacks: if len(value) > 0: self._width = float(value.replace(",", ".")) else: self._width = 0 self._depth = self._width / self._aspect self._disable_size_callbacks = True self._ui_view.findChild(QObject, "Depth").setProperty("text", str(self._depth)) self._disable_size_callbacks = False @pyqtSlot(str) def onDepthChanged(self, value): if self._ui_view and not self._disable_size_callbacks: if len(value) > 0: self._depth = float(value.replace(",", ".")) else: self._depth = 0 self._width = self._depth * self._aspect self._disable_size_callbacks = True self._ui_view.findChild(QObject, "Width").setProperty("text", str(self._width)) self._disable_size_callbacks = False @pyqtSlot(str) def onBaseHeightChanged(self, value): if (len(value) > 0): self.base_height = float(value.replace(",", ".")) else: self.base_height = 0 @pyqtSlot(str) def onPeakHeightChanged(self, value): if (len(value) > 0): self.peak_height = float(value.replace(",", ".")) else: self.peak_height = 0 @pyqtSlot(float) def onSmoothingChanged(self, value): self.smoothing = int(value) @pyqtSlot(int) def onImageColorInvertChanged(self, value): self.image_color_invert = (value == 1) Of course you can't interpret a .cfg file as an image. But even when removing the rudimentary code from ImageReader the file is not recognized.. :s Any help would be greatly appreciated ?
×
×
  • Create New...