6 Commits
Author SHA1 Message Date
bmad 225d3e23ed updated pyproject.toml
- set opencv version to 4.13>=; this uses a newer numpy version so should solve issues with newer libraries used in generative workflows. The issue has been raised once in the past (now deleted by the op) so hopefully it is addressed for now. MIGHT update to the new opencv 5.x later (would need to test it first).
- updated some pyproject.toml fields so that pip install can run without problems.
- misc.: updated a speech bubbles workflow to use the native list node instead of requiring an additional custom nodes.
2026-06-23 23:58:16 +01:00
bmad4ever 8a3f158a01 update repository URL
fix issue #1
2025-11-04 12:52:32 +00:00
Bruno Madeira 65ba532074 removed unused nodes from the following workflow: QwenEdit2509 Oneshot Multiple Speech Bubbles. 2025-10-27 16:03:28 +00:00
Bruno Madeira 23142347ab fix prior fix (missing workflow results in panel extraction workflows) 2025-10-23 12:08:39 +01:00
Bruno Madeira 076a041562 fix previous commit workflow images 2025-10-23 12:05:35 +01:00
Bruno Madeira ea4711a996 panel sorting & updated workflows
- added SortPanels node to custom nodes
- updated Manga Panel Extration Example workflows
- added new workflow: WAN2.2 I2V Oneshot Animate All Panels Sequentially with FadeIn
- updated project version to 1.1.0
2025-10-23 12:00:25 +01:00
9 changed files with 1416 additions and 4 deletions
+85
View File
@@ -1598,6 +1598,89 @@ class DetectPanelsInImage:
return (panels,) return (panels,)
class SortPanels:
CENTER_FUNCS = {
"TOP-LEFT": lambda bxmin, bymin, bxmax, bymax: (bxmin, bymin),
"CENTER": lambda bxmin, bymin, bxmax, bymax: ( (bxmin + bxmax)/2, (bymin + bymax)/2 ),
"BOTTOM-RIGHT": lambda bxmin, bymin, bxmax, bymax: (bxmax, bymax),
}
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"panels": (IO_Types.PANEL,),
"left2right": ("BOOLEAN", {"default": True}),
"center": (list(cls.CENTER_FUNCS.keys()), {"default": "TOP-LEFT",
"tooltip": "point used for sorting."})
}
}
INPUT_IS_LIST = True
CATEGORY = CATEGORY_PATH
RETURN_TYPES = (IO_Types.PANEL,)
OUTPUT_IS_LIST = (True,)
OUTPUT_TOOLTIPS = ("Panels (Shapely Polygons)",)
FUNCTION = "exec"
DESCRIPTION = """
Simple algo that attempts to sort panels by reading order according to
their bounds center coordinates in quantized space.
"""
def exec(self, panels, left2right, center):
if not panels:
return ([],)
if isinstance(left2right, list):
left2right = left2right[0]
if isinstance(center, list):
center = center[0]
# find global bounding box
minx = min(p.bounds[0] for p in panels)
miny = min(p.bounds[1] for p in panels)
maxx = max(p.bounds[2] for p in panels)
maxy = max(p.bounds[3] for p in panels)
n = len(panels)
grid_size = n # number of grid cells in one dimension
# if there is a bias towards columns or rows only, then non-quantized coordinates should suffice
# thus is better to have a somewhat small n, under the supposition the "grid like" layout is balanced
# quantize space
# compute grid cell dimensions
cell_w = (maxx - minx) / grid_size if maxx != minx else 1.0
cell_h = (maxy - miny) / grid_size if maxy != miny else 1.0
# assign each polygon to a grid cell
poly_cells = []
center_func = self.CENTER_FUNCS[center]
for i, p in enumerate(panels):
x, y = center_func(*p.bounds)
# compute grid indices (col, row)
col = int((x - minx) // cell_w)
row = int((maxy - y) // cell_h) # top-to-bottom order
# clamp indices
col = max(0, min(grid_size - 1, col))
row = max(0, min(grid_size - 1, row))
poly_cells.append((row, col, y, x, i, p))
# sort by row, then by column (reading order)
if left2right:
poly_cells.sort(key=lambda t: (-t[0], t[1], t[2], t[3])) # row, col, x, y(desc)
else:
poly_cells.sort(key=lambda t: (-t[0], -t[1], t[2], -t[3])) # reverse col order
# extract sorted polygons
sorted_polygons = [t[-1] for t in poly_cells]
return (sorted_polygons,)
class InvertCardinals: class InvertCardinals:
@classmethod @classmethod
def INPUT_TYPES(cls): def INPUT_TYPES(cls):
@@ -1789,6 +1872,7 @@ NODE_CLASS_MAPPINGS = {
"bmad_GridPanelLayoutGenerator": GridPanelLayoutGenerator, "bmad_GridPanelLayoutGenerator": GridPanelLayoutGenerator,
"bmad_MutatePanelLayout": MutatePanelLayout, "bmad_MutatePanelLayout": MutatePanelLayout,
"bmad_DetectPanelsInImage": DetectPanelsInImage, "bmad_DetectPanelsInImage": DetectPanelsInImage,
"bmad_SortPanels": SortPanels,
"bmad_PolygonBounds": PolygonBounds, "bmad_PolygonBounds": PolygonBounds,
"bmad_PolygonUnwrappedBounds": PolygonUnwrappedBounds, "bmad_PolygonUnwrappedBounds": PolygonUnwrappedBounds,
@@ -1847,6 +1931,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"bmad_GridPanelLayoutGenerator": "Grid Panel Layout Generator", "bmad_GridPanelLayoutGenerator": "Grid Panel Layout Generator",
"bmad_MutatePanelLayout": "Mutate Panel Layout", "bmad_MutatePanelLayout": "Mutate Panel Layout",
"bmad_DetectPanelsInImage": "Detect Panels In Image", "bmad_DetectPanelsInImage": "Detect Panels In Image",
"bmad_SortPanels": "Sort Panels",
"bmad_PolygonBounds": "Polygon.bounds", "bmad_PolygonBounds": "Polygon.bounds",
"bmad_PolygonUnwrappedBounds": "Polygon.bounds (unwrapped)", "bmad_PolygonUnwrappedBounds": "Polygon.bounds (unwrapped)",
+7 -4
View File
@@ -1,12 +1,15 @@
[project] [project]
name = "comfyui_panels" name = "comfyui_panels"
description = "Comics/Manga like panel layouts." description = "Comics/Manga like panel layouts."
version = "1.0.0" version = "1.1.5"
license = { file = "LICENSE" } license = "MIT"
dependencies = ["shapely==2.1.1", "matplotlib==3.10.6", "opencv-python~=4.8.1.78"] dependencies = ["shapely==2.1.1", "matplotlib==3.10.6", "opencv-python>=4.13"]
[tool.setuptools]
packages = []
[project.urls] [project.urls]
Repository = "https://github.com/bmad4ever/comfyui-panels" Repository = "https://github.com/bmad4ever/comfyui_panels"
[tool.comfy] [tool.comfy]
PublisherId = "bmad4ever" PublisherId = "bmad4ever"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 KiB

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 KiB

After

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 KiB

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 KiB