def _notify_canvas_observers(self, affected_layers): bbox = helpers.Rect() for layer in affected_layers: layer_bbox = layer.get_bbox() bbox.expandToIncludeRect(layer_bbox) for func in self.doc.canvas_observers: func(*bbox)
def get_bbox(self): res = helpers.Rect() for layer in self.layers: # OPTIMIZE: only visible layers... # careful: currently saving assumes that all layers are included bbox = layer.get_bbox() res.expandToIncludeRect(bbox) return res
def flood_fill(self, x, y, color, tolerance=0.1, sample_merged=False, make_new_layer=False): """Flood-fills a point on the current layer with a colour :param x: Starting point X coordinate :param y: Starting point Y coordinate :param color: The RGB color to fill connected pixels with :type color: tuple :param tolerance: How much filled pixels are permitted to vary :type tolerance: float [0.0, 1.0] :param sample_merged: Use all visible layers when sampling :type sample_merged: bool :param make_new_layer: Write output to a new layer on top :type make_new_layer: bool Filling an infinite canvas requires limits. If the frame is enabled, this limits the maximum size of the fill, and filling outside the frame is not possible. Otherwise, if the entire document is empty, the limits are dynamic. Initially only a single tile will be filled. This can then form one corner for the next fill's limiting rectangle. This is a little quirky, but allows big areas to be filled rapidly as needed on blank layers. """ bbox = helpers.Rect(*tuple(self.get_effective_bbox())) rootstack = self.layer_stack if not self.layer_stack.current.get_fillable(): make_new_layer = True if bbox.empty(): bbox = helpers.Rect() bbox.x = N * int(x // N) bbox.y = N * int(y // N) bbox.w = N bbox.h = N elif not self.frame_enabled: bbox.expandToIncludePoint(x, y) cmd = command.FloodFill(self, x, y, color, bbox, tolerance, sample_merged, make_new_layer) self.do(cmd)
def load_ora(self, filename, feedback_cb=None): """Loads from an OpenRaster file""" logger.info('load_ora: %r', filename) t0 = time.time() tempdir = self._tempdir orazip = zipfile.ZipFile(filename) logger.debug('mimetype: %r', orazip.read('mimetype').strip()) xml = orazip.read('stack.xml') image_elem = ET.fromstring(xml) root_stack_elem = image_elem.find('stack') image_width = max(0, int(image_elem.attrib.get('w', 0))) image_height = max(0, int(image_elem.attrib.get('h', 0))) # Resolution: false value, 0 specifically, means unspecified image_xres = max(0, int(image_elem.attrib.get('xres', 0))) image_yres = max(0, int(image_elem.attrib.get('yres', 0))) # Delegate loading of image data to the layers tree itself self.layer_stack.clear() self.layer_stack.load_from_openraster(orazip, root_stack_elem, tempdir, feedback_cb, x=0, y=0) assert len(self.layer_stack) > 0 # Set up symmetry axes for path, descendent in self.layer_stack.deepenumerate(): descendent.set_symmetry_axis(self.get_symmetry_axis()) # Resolution information if specified # Before frame to benefit from its observer call if image_xres and image_yres: self._xres = image_xres self._yres = image_yres else: self._xres = None self._yres = None # Set the frame size to that saved in the image. self.update_frame(x=0, y=0, width=image_width, height=image_height, user_initiated=False) # Enable frame if the saved image size is something other than the # calculated bounding box. Goal: if the user saves an "infinite # canvas", it loads as an infinite canvas. bbox_c = helpers.Rect(x=0, y=0, w=image_width, h=image_height) bbox = self.get_bbox() frame_enab = not (bbox_c == bbox or bbox.empty() or bbox_c.empty()) self.set_frame_enabled(frame_enab, user_initiated=False) orazip.close() logger.info('%.3fs load_ora total', time.time() - t0)
def _notify_canvas_observers(self, layer_bboxes): """Notifies the document's redraw observers""" warn("Layers should issue their own canvas updates", PendingDeprecationWarning, stacklevel=2) redraw_bbox = helpers.Rect() for layer_bbox in layer_bboxes: if layer_bbox.w == 0 and layer_bbox.h == 0: redraw_bbox = layer_bbox break else: redraw_bbox.expandToIncludeRect(layer_bbox) self.doc.canvas_area_modified(*redraw_bbox)
def get_bbox(self): """Returns the dynamic bounding box of the document. This is currently the union of all the bounding boxes of all of the layers. It disregards the user-chosen frame. """ res = helpers.Rect() for layer in self.layers: # OPTIMIZE: only visible layers... # careful: currently saving assumes that all layers are included bbox = layer.get_bbox() res.expandToIncludeRect(bbox) return res
def get_full_redraw_bbox(self): """Returns the full-redraw bounding box of the document This is the same concept as `layer.BaseLayer.get_full_redraw_bbox()`, and is built up from the full-redraw bounding boxes of all layers. """ res = helpers.Rect() for layer in self.layer_stack.deepiter(): bbox = layer.get_full_redraw_bbox() if bbox.w == 0 and bbox.h == 0: # infinite res = bbox else: res.expandToIncludeRect(bbox) return res
if selected_layer is not None: for i, layer in zip(range(len(self.layers)), self.layers): if layer is selected_layer: self.select_layer(i) break # Set the frame size to that saved in the image. self.update_frame(x=0, y=0, width=image_w, height=image_h, user_initiated=False) # Enable frame if the saved image size is something other than the # calculated bounding box. Goal: if the user saves an "infinite # canvas", it loads as an infinite canvas. bbox_c = helpers.Rect(x=0, y=0, w=image_w, h=image_h) bbox = self.get_bbox() frame_enab = not (bbox_c == bbox or bbox.empty() or bbox_c.empty()) self.set_frame_enabled(frame_enab, user_initiated=False) z.close() # remove empty directories created by zipfile's extract() for root, dirs, files in os.walk(tempdir, topdown=False): for name in dirs: os.rmdir(os.path.join(root, name)) os.rmdir(tempdir) logger.info('%.3fs load_ora total', time.time() - t0)
def get_tiles_bbox(tiles): res = helpers.Rect() for tx, ty in tiles: res.expandToIncludeRect(helpers.Rect(N * tx, N * ty, N, N)) return res
def get_bbox(self): rect = helpers.Rect(*self.get_bbox_c()) return rect