Update nodes with new version
This commit is contained in:
@@ -10,6 +10,7 @@ from .blackextract import *
|
||||
from .autocrop import *
|
||||
from .numfunction import *
|
||||
from .linecounter import *
|
||||
from .numstrcleanup import *
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RasterToUniformSVG": RasterToSVGConverter,
|
||||
@@ -27,6 +28,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"RoundUpNode": RoundUpNode,
|
||||
"RoundDownNode": RoundDownNode,
|
||||
"CSVValueExtractor": CSVValueExtractor,
|
||||
"NumberStringCleanup": NumberStringCleanup,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -45,4 +47,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RoundUpNode": "Round Up",
|
||||
"RoundDownNode": "Round Down",
|
||||
"CSVValueExtractor": "CSV Value Extractor",
|
||||
"NumberStringCleanup": "Number String Cleanup",
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
"""
|
||||
SVG Path Length Calculator Node for ComfyUI
|
||||
|
||||
Calculates the total length of all paths in an SVG file,
|
||||
ignoring line thickness (stroke-width).
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class NumberStringCleanup:
|
||||
"""
|
||||
Cleans up a raw string containing a number and converts it
|
||||
into a two-decimal-place float-compatible string.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"raw_string": ("STRING", {"default": "", "multiline": False}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("cleaned_number",)
|
||||
FUNCTION = "clean_number"
|
||||
CATEGORY = "utils/string"
|
||||
|
||||
def clean_number(self, raw_string: str):
|
||||
s = raw_string.strip()
|
||||
|
||||
# Remove everything except digits, commas, dots, and minus sign
|
||||
s = re.sub(r"[^\d.,-]", "", s)
|
||||
|
||||
# Replace comma with dot (e.g. "52,25" -> "52.25")
|
||||
s = s.replace(",", ".")
|
||||
|
||||
# If multiple dots exist, keep only the last one as decimal separator
|
||||
if s.count(".") > 1:
|
||||
parts = s.split(".")
|
||||
s = "".join(parts[:-1]) + "." + parts[-1]
|
||||
|
||||
# Handle edge cases
|
||||
if s in ("", ".", "-", "-."):
|
||||
return ("0.00",)
|
||||
|
||||
# Handle leading minus
|
||||
negative = s.startswith("-")
|
||||
if negative:
|
||||
s = s[1:]
|
||||
|
||||
# Convert to float and format to 2 decimal places
|
||||
try:
|
||||
value = float(s)
|
||||
except ValueError:
|
||||
value = 0.0
|
||||
|
||||
if negative:
|
||||
value = -value
|
||||
|
||||
result = f"{value:.2f}"
|
||||
return (result,)
|
||||
@@ -0,0 +1,121 @@
|
||||
import re
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class MaxValuePaddleOCR:
|
||||
"""
|
||||
A ComfyUI node that uses PaddleOCR to extract numbers from an image
|
||||
and returns the largest numeric value found.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.ocr = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
},
|
||||
"optional": {
|
||||
"use_gpu": ("BOOLEAN", {"default": False}),
|
||||
"lang": (["en", "ch", "japan", "korean", "french", "german"], {"default": "en"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
RETURN_NAMES = ("max_value",)
|
||||
FUNCTION = "extract_max_number"
|
||||
CATEGORY = "image/text"
|
||||
|
||||
def _init_ocr(self, use_gpu=False, lang="en"):
|
||||
"""Initialize PaddleOCR if not already done."""
|
||||
if self.ocr is None:
|
||||
from paddleocr import PaddleOCR
|
||||
self.ocr = PaddleOCR(
|
||||
use_angle_cls=True,
|
||||
lang=lang,
|
||||
use_gpu=use_gpu,
|
||||
show_log=False
|
||||
)
|
||||
return self.ocr
|
||||
|
||||
def _extract_numbers(self, text):
|
||||
"""
|
||||
Extract all numeric values (integers and floats) from text.
|
||||
Handles various number formats including negative numbers and decimals.
|
||||
"""
|
||||
# Pattern matches integers and floats, including negative numbers
|
||||
# Examples: 123, -456, 3.14, -2.5, .5, -.5
|
||||
pattern = r'-?\d+\.?\d*|-?\.\d+'
|
||||
|
||||
numbers = []
|
||||
matches = re.findall(pattern, text)
|
||||
|
||||
for match in matches:
|
||||
try:
|
||||
# Try to convert to float (works for both int and float strings)
|
||||
num = float(match)
|
||||
numbers.append(num)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
return numbers
|
||||
|
||||
def extract_max_number(self, image, use_gpu=False, lang="en"):
|
||||
"""
|
||||
Main function to extract the maximum number from an image.
|
||||
|
||||
Args:
|
||||
image: ComfyUI IMAGE tensor (B, H, W, C) in range [0, 1]
|
||||
use_gpu: Whether to use GPU for OCR
|
||||
lang: Language for OCR recognition
|
||||
|
||||
Returns:
|
||||
Tuple containing the maximum numeric value found, or 0.0 if none found
|
||||
"""
|
||||
# Initialize OCR
|
||||
ocr = self._init_ocr(use_gpu=use_gpu, lang=lang)
|
||||
|
||||
# Convert ComfyUI image tensor to numpy array
|
||||
# ComfyUI images are (B, H, W, C) with values in [0, 1]
|
||||
if isinstance(image, np.ndarray):
|
||||
img_array = image
|
||||
else:
|
||||
# Convert from torch tensor if needed
|
||||
img_array = image.cpu().numpy()
|
||||
|
||||
# Handle batch dimension - process first image
|
||||
if len(img_array.shape) == 4:
|
||||
img_array = img_array[0]
|
||||
|
||||
# Convert from [0, 1] to [0, 255] and ensure uint8
|
||||
img_array = (img_array * 255).astype(np.uint8)
|
||||
|
||||
# Convert to PIL Image then back to numpy for PaddleOCR
|
||||
# PaddleOCR expects BGR or RGB numpy array
|
||||
pil_image = Image.fromarray(img_array)
|
||||
img_for_ocr = np.array(pil_image)
|
||||
|
||||
# Run OCR
|
||||
result = ocr.ocr(img_for_ocr, cls=True)
|
||||
|
||||
# Extract all numbers from OCR results
|
||||
all_numbers = []
|
||||
|
||||
if result and result[0]:
|
||||
for line in result[0]:
|
||||
if line and len(line) >= 2:
|
||||
# line[1] contains (text, confidence)
|
||||
text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
|
||||
numbers = self._extract_numbers(text)
|
||||
all_numbers.extend(numbers)
|
||||
|
||||
# Return the maximum value, or 0.0 if no numbers found
|
||||
if all_numbers:
|
||||
max_value = max(all_numbers)
|
||||
else:
|
||||
max_value = 0.0
|
||||
|
||||
return (float(max_value),)
|
||||
Reference in New Issue
Block a user