fix: properly handle transparency in trim_whitespace

Simplify transparency handling by flattening image with white
background for bounds detection while preserving original
transparency in the final crop. This fixes the issue where
transparent areas were being treated as black during trimming.
This commit is contained in:
Esa Kataja
2024-12-03 22:06:51 +02:00
parent 84e1a6a82e
commit 75dc1c3e2c
+42 -17
View File
@@ -96,12 +96,18 @@ def trim_whitespace(image_path: str) -> bool:
# Open image with PIL
image = Image.open(image_path)
# Convert to grayscale if not already
if image.mode != 'L':
image = image.convert('L')
# Create flattened version with white background for finding bounds
flattened = Image.new('RGB', image.size, 'white')
if image.mode == 'RGBA':
flattened.paste(image, mask=image.split()[3])
else:
flattened.paste(image)
# Convert to grayscale for finding bounds
flattened = flattened.convert('L')
# Get the bounding box of non-white pixels
bbox = image.getbbox()
bbox = flattened.getbbox()
if not bbox:
print(f"Warning: No content found in {image_path}")
return False
@@ -115,11 +121,11 @@ def trim_whitespace(image_path: str) -> bool:
x2 = min(width, x2 + padding)
y2 = min(height, y2 + padding)
# Crop the image
image = image.crop((x1, y1, x2, y2))
# Crop the original image (preserving transparency)
cropped = image.crop((x1, y1, x2, y2))
# Save the image
image.save(image_path, "PNG", optimize=False)
# Save the cropped image
cropped.save(image_path, "PNG", optimize=False)
return True
except Exception as e:
@@ -203,25 +209,44 @@ def deskew():
def convert_to_monochrome(image_path: str) -> bool:
"""Convert image to 1-bit monochrome.
Handles RGBA images by converting transparent pixels to white before thresholding.
Returns:
bool: True if successful, False otherwise
"""
try:
# Read the image
img = cv2.imread(image_path)
if img is None:
print(f"Warning: Could not read image {image_path}")
return False
# Open image with PIL
image = Image.open(image_path)
# Convert to RGBA if not already
if image.mode != 'RGBA':
image = image.convert('RGBA')
# Get the image data as a list of pixels
data = image.getdata()
# Create new image data, replacing transparent pixels with white
new_data = []
for item in data:
# If pixel is transparent (alpha < 128), make it white
if item[3] < 128:
new_data.append((255, 255, 255, 255))
else:
new_data.append(item)
# Create new image with modified data
image.putdata(new_data)
# Convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
image = image.convert('L')
# Apply threshold
_, mono = cv2.threshold(gray, settings.MONOCHROME_THRESHOLD, 255, cv2.THRESH_BINARY)
# Convert to 1-bit using threshold
image = image.point(lambda x: 255 if x > settings.MONOCHROME_THRESHOLD else 0, '1')
# Save the monochrome image
cv2.imwrite(image_path, mono)
image.save(image_path, "PNG", optimize=False)
return True
except Exception as e:
print(f"Error converting to monochrome {image_path}: {str(e)}")
return False