shinestacker 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of shinestacker might be problematic. Click here for more details.

shinestacker/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.3.0'
1
+ __version__ = '0.3.1'
@@ -47,10 +47,14 @@ def img_bw(img):
47
47
 
48
48
 
49
49
  def get_img_metadata(img):
50
+ if img is None:
51
+ return None, None
50
52
  return img.shape[:2], img.dtype
51
53
 
52
54
 
53
55
  def validate_image(img, expected_shape=None, expected_dtype=None):
56
+ if img is None:
57
+ raise RuntimeError("Image is None")
54
58
  shape, dtype = get_img_metadata(img)
55
59
  if expected_shape and shape[:2] != expected_shape[:2]:
56
60
  raise ShapeError(expected_shape, shape)
@@ -0,0 +1,13 @@
1
+ import numpy as np
2
+
3
+
4
+ def white_balance_from_rgb(img, target_rgb):
5
+ img_float = img.astype(np.float64)
6
+ target_bgr = (target_rgb[2], target_rgb[1], target_rgb[0])
7
+ target_gray = sum(target_bgr) / 3.0
8
+ scales = [target_gray / val if val != 0 else 1.0 for val in target_bgr]
9
+ for c in range(3):
10
+ img_float[..., c] *= scales[c]
11
+ max_val = np.iinfo(img.dtype).max
12
+ img_float = np.clip(img_float, 0, max_val)
13
+ return img_float.astype(img.dtype)
@@ -85,6 +85,7 @@ class NewProjectDialog(QDialog):
85
85
  bunch_overlap_range = gui_constants.NEW_PROJECT_BUNCH_OVERLAP
86
86
  self.bunch_overlap.setRange(bunch_overlap_range['min'], bunch_overlap_range['max'])
87
87
  self.bunch_overlap.setValue(constants.DEFAULT_OVERLAP)
88
+ self.update_bunch_options(gui_constants.NEW_PROJECT_BUNCH_STACK)
88
89
  self.focus_stack_pyramid = QCheckBox()
89
90
  self.focus_stack_pyramid.setChecked(gui_constants.NEW_PROJECT_FOCUS_STACK_PYRAMID)
90
91
  self.focus_stack_depth_map = QCheckBox()
@@ -0,0 +1,20 @@
1
+ from PySide6.QtGui import QRadialGradient
2
+ from PySide6.QtGui import QColor
3
+ from .. config.gui_constants import gui_constants
4
+
5
+
6
+ def create_brush_gradient(center_x, center_y, radius, hardness, inner_color=None, outer_color=None, opacity=100):
7
+ gradient = QRadialGradient(center_x, center_y, float(radius))
8
+ inner = inner_color if inner_color is not None else QColor(*gui_constants.BRUSH_COLORS['inner'])
9
+ outer = outer_color if outer_color is not None else QColor(*gui_constants.BRUSH_COLORS['gradient_end'])
10
+ inner_with_opacity = QColor(inner)
11
+ inner_with_opacity.setAlpha(int(float(inner.alpha()) * float(opacity) / 100.0))
12
+ if hardness < 100:
13
+ hardness_normalized = float(hardness) / 100.0
14
+ gradient.setColorAt(0.0, inner_with_opacity)
15
+ gradient.setColorAt(hardness_normalized, inner_with_opacity)
16
+ gradient.setColorAt(1.0, outer)
17
+ else:
18
+ gradient.setColorAt(0.0, inner_with_opacity)
19
+ gradient.setColorAt(1.0, inner_with_opacity)
20
+ return gradient
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
  from PySide6.QtWidgets import QGraphicsPixmapItem
3
- from PySide6.QtCore import Qt, QPointF
3
+ from PySide6.QtCore import Qt
4
4
  from PySide6.QtGui import QPixmap, QPainter, QImage
5
5
 
6
6
 
@@ -42,6 +42,8 @@ def create_brush_mask(size, hardness_percent, opacity_percent):
42
42
  class BrushPreviewItem(QGraphicsPixmapItem):
43
43
  def __init__(self):
44
44
  super().__init__()
45
+ self.layer_collection = None
46
+ self.brush = None
45
47
  self.setVisible(False)
46
48
  self.setZValue(500)
47
49
  self.setTransformationMode(Qt.SmoothTransformation)
@@ -68,31 +70,26 @@ class BrushPreviewItem(QGraphicsPixmapItem):
68
70
  else:
69
71
  raise Exception("Bitmas is neither 8 bit nor 16, but of type " + area.dtype)
70
72
 
71
- def update(self, editor, pos, size):
73
+ def update(self, scene_pos, size):
72
74
  try:
73
- if editor.current_stack is None or not hasattr(editor, 'image_viewer') or size <= 0:
75
+ if self.layer_collection.layer_stack is None or size <= 0:
74
76
  self.hide()
75
77
  return
76
78
  radius = size // 2
77
- if isinstance(pos, QPointF):
78
- scene_pos = pos
79
- else:
80
- cursor_pos = editor.image_viewer.mapFromGlobal(pos)
81
- scene_pos = editor.image_viewer.mapToScene(cursor_pos)
82
79
  x = int(scene_pos.x() - radius + 0.5)
83
80
  y = int(scene_pos.y() - radius)
84
81
  w = h = size
85
- if editor.current_layer < 0 or editor.current_layer >= len(editor.current_stack):
82
+ if not self.layer_collection.valid_current_layer_idx():
86
83
  self.hide()
87
84
  return
88
- layer_area = self.get_layer_area(editor.current_stack[editor.current_layer], x, y, w, h)
89
- master_area = self.get_layer_area(editor.master_layer, x, y, w, h)
85
+ layer_area = self.get_layer_area(self.layer_collection.current_layer(), x, y, w, h)
86
+ master_area = self.get_layer_area(self.layer_collection.master_layer, x, y, w, h)
90
87
  if layer_area is None or master_area is None:
91
88
  self.hide()
92
89
  return
93
- height, width = editor.current_stack[editor.current_layer].shape[:2]
94
- full_mask = create_brush_mask(size=size, hardness_percent=editor.brush.hardness,
95
- opacity_percent=editor.brush.opacity)[:, :, np.newaxis]
90
+ height, width = self.layer_collection.current_layer().shape[:2]
91
+ full_mask = create_brush_mask(size=size, hardness_percent=self.brush.hardness,
92
+ opacity_percent=self.brush.opacity)[:, :, np.newaxis]
96
93
  mask_x_start = max(0, -x) if x < 0 else 0
97
94
  mask_y_start = max(0, -y) if y < 0 else 0
98
95
  mask_x_end = size - (max(0, (x + w) - width)) if (x + w) > width else size