diff --git a/ahb_raster_view.py b/ahb_raster_view.py index 20eef18..082660c 100644 --- a/ahb_raster_view.py +++ b/ahb_raster_view.py @@ -1,5 +1,13 @@ import FreeCAD as App import FreeCADGui as Gui +from datetime import datetime + +def print_verbose(msg): + verbose = False + if verbose: + now = datetime.now() + current_time = now.strftime("%H:%M:%S") + print(current_time, msg) class RasterView: def __init__(self, view): @@ -116,7 +124,7 @@ class RasterView: self.init_image() - print('Rasterizing ' + view.Label + " to " + self.image_file_name + "...") + print_verbose('Rasterizing ' + view.Label + " to " + self.image_file_name + "...") dir = os.path.dirname(self.image_file_name) if not os.path.exists(dir): @@ -127,6 +135,7 @@ class RasterView: objects_to_reset = {} duplicated_parts = {} try: + print_verbose("Preparing scene...") # construct new scene with links to the parts we want sceneGroup = tmp_doc.addObject('App::DocumentObjectGroup', 'Scene') prev_parts = [] @@ -259,20 +268,25 @@ class RasterView: resolution[1] = int(max_res) if fast_render: + print_verbose("Fast rasterization...") composite_img = self._render_lines(tmp_doc, resolution, prev_parts + new_parts, (0.0, 0.0, 0.0), []) else: # render old parts in gray lines + print_verbose("Rendering old parts (gray)...") prev_parts_img = self._render_lines(tmp_doc, resolution, prev_parts, (0.6, 0.6, 0.6), [], fast_render) # render new parts in black lines (old parts can mask them) + print_verbose("Rendering new parts (black)...") new_parts_img = self._render_lines(tmp_doc, resolution, new_parts, (0.0, 0.0, 0.0), prev_parts, fast_render) # create the composite image + print_verbose("Compositing images...") composite_img = prev_parts_img.copy() composite_img.paste(new_parts_img, None, new_parts_img) # Optimize the image to reduce storage size if not fast_render: + print_verbose("Optimizing PNG size...") num_colors = 32 # All-or-nothing alpha: we use a white background and only make pixels fully transparent where alpha is zero, to not loose antialiasing @@ -286,6 +300,7 @@ class RasterView: composite_img = composite_img.quantize(colors=num_colors, dither=Image.Dither.NONE) finally: + print_verbose("Cleaning scene...") #raise Exception("test") # restore properties on objects we have modified for obj, props in objects_to_reset.items(): @@ -302,6 +317,8 @@ class RasterView: # remove the temporary document App.closeDocument(tmp_doc.Name) + print_verbose("Finalizing view...") + # Crop the image, which is also used to deduce the center of the source view original_size = composite_img.size @@ -349,6 +366,8 @@ class RasterView: image.Width = composite_img.size[0] * image_scale / 10.0 * 1.01 image.Height = composite_img.size[1] * image_scale / 10.0 * 1.01 image.recompute() + + print_verbose("Done") def _render_lines(self, doc, resolution, parts, line_color, masking_parts, fast_render = True): import tempfile @@ -358,12 +377,17 @@ class RasterView: # render lines in black, background in red, fill shapes in green # the green band contains the lines images, the red band contains the inverted alpha layer + configured = [] + print_verbose('Preparing objects for line rendering...') for link in doc.findObjects(): if link in parts or link in masking_parts: link.ViewObject.Visibility = True # in current version of freecad, link override material does not allow to override all material properties, for example emissive color, so we have to change material of the linked object for obj in self._flatten_objects_tree([link]): + if obj in configured: continue + configured.append(obj) + if self._should_render(obj) and not fast_render: obj.ViewObject.LineColor = (0.0, 0.0, 0.0, 0.0) if link in parts else (1.0, 0.0, 1.0) obj.ViewObject.ShapeMaterial.AmbientColor = (0.0, 0.0, 0.0, 0.0) @@ -377,6 +401,7 @@ class RasterView: else: link.ViewObject.Visibility = False + print_verbose('Rendering lines...') temp_file_name = tempfile.gettempdir() + "/ahb_temp_image.png" doc_view.saveImage(temp_file_name, resolution[0]+2, resolution[1]+2, "#ff0000") # we add 1 pixel border that we will need to crop later lines_bands_img = self._read_image(temp_file_name) @@ -390,14 +415,20 @@ class RasterView: # Render all shapes with different colors, in order to extract outlines (where color changes) # This is needed because FreeCAD does not render lines on the boundary of curve shapes, such as spheres or cylinders # The technique could be improved by using the depth buffer instead, in order to detect boundaries within the same object + print_verbose('Preparing objects for outline rendering...') step = 8 r = step g = step b = step + configured = [] for link in doc.findObjects(): if link in parts or link in masking_parts: for obj in self._flatten_objects_tree([link]): + if obj in configured: continue + configured.append(obj) + if self._should_render(obj) and obj.TypeId != 'Part::Part2DObjectPython': + configured.append(obj) obj.ViewObject.DisplayMode = 'Shaded' obj.ViewObject.ShapeMaterial.AmbientColor = (0.0, 0.0, 0.0, 0.0) obj.ViewObject.ShapeMaterial.DiffuseColor = (0.0, 0.0, 0.0, 0.0) @@ -416,9 +447,11 @@ class RasterView: else: obj.ViewObject.Visibility = False + print_verbose('Rendering shapes...') doc_view.saveImage(temp_file_name, (resolution[0]+2)*2, (resolution[1]+2)*2, "#ffffff") # shapes are rendered at twice the resolution for antialiasing shapes_img = self._read_image(temp_file_name) + print_verbose('Extracting outlines...') outlines_img = None for x in range(0, 3): for y in range(0, 3): @@ -434,6 +467,7 @@ class RasterView: else: outlines_img.paste(partial_outlines, None, partial_outlines.point(lambda p: 0 if p == 255 else 255)) + print_verbose('Combining lines and outlines...') lines_fullres = lines_img.resize(outlines_img.size, Image.NEAREST) lines_fullres.paste(outlines_img, None, outlines_img.point(lambda p: 255 if p == 0 else 0)) #lines_fullres.paste(255, alpha_fullres.point(lambda p: 255 if p == 0 else 0)) @@ -448,6 +482,7 @@ class RasterView: alpha_img = alpha_img.point(lambda p: 0 if p == 0 else 255) # colorize final image + print_verbose('Colorizing image...') fill_color = (1.0, 1.0, 1.0) result = Image.merge("RGBA", [ all_lines.point(lambda p: int(fill_color[0] * p + line_color[0] * (255.0 - p))), diff --git a/ahb_techdraw_extensions.py b/ahb_techdraw_extensions.py index 7fe1d2c..0f368c3 100644 --- a/ahb_techdraw_extensions.py +++ b/ahb_techdraw_extensions.py @@ -640,6 +640,10 @@ class TechDrawExtensions: def refreshOverlays(self, page, callback = None): import os + for view in page.Views: + if view.TypeId == 'TechDraw::DrawViewPart' and 'Assembly_handbook_RasterView' in view.PropertiesList and view.Assembly_handbook_RasterView: + view.purgeTouched() # make sure we don't trigger rendering of source views (this is awfully slow and doesn't even work for a lot of models) + doc = page.Document for image in page.Views: if image.TypeId == 'TechDraw::DrawViewImage':