hm_qc/checks/HM_image_dimension_check.py
2025-11-13 13:41:31 +02:00

116 lines
4.3 KiB
Python

import re
from PIL import Image
def run_check(config: dict, context: dict, check_id: str) -> dict:
"""
QC check that validates image dimensions match the dimensions specified in the filename.
Expects format: WIDTHxHEIGHT (e.g., 1200x400 means 1200 pixels wide by 400 pixels high)
"""
# Get required data from previous checks' context
error_responses = []
# 1. Validate HM_image_filename_parse data
hm_filename_data = context.get("HM_image_filename_parse")
if not hm_filename_data or not isinstance(hm_filename_data, dict):
error_responses.append("HM_image_filename_parse data missing or invalid")
else:
parsed_data = hm_filename_data.get("parsed", {})
dimensions_str = parsed_data.get("dimensions", "").strip()
if not dimensions_str:
error_responses.append("HM_image_filename_parse: dimensions field missing")
# 2. Validate HM_image_parse data
hm_image_data = context.get("HM_image_parse")
if not hm_image_data or not isinstance(hm_image_data, dict):
error_responses.append("HM_image_parse data missing or invalid")
else:
image_object = hm_image_data.get("parsed_image")
if not image_object:
error_responses.append("HM_image_parse: parsed_image object missing")
if error_responses:
return {
"status": "error",
"error_message": "Missing/invalid context data from previous checks: " + ", ".join(error_responses),
"details": {
"missing_data": error_responses,
"available_context_keys": list(context.keys())
}
}
# Extract validated values
dimensions_str = hm_filename_data["parsed"]["dimensions"].strip()
image_object = hm_image_data["parsed_image"]
filename = hm_image_data.get("filename", "unknown")
# Prepare base result structure
context_result = {
"filename": filename,
"expected_dimensions_str": dimensions_str,
"expected_width": None,
"expected_height": None,
"actual_width": None,
"actual_height": None,
"dimensions_match": False
}
try:
# Parse expected dimensions from filename
# Handle various formats: 1200x400, 1200x400px, 1200x400cm, etc.
dimension_pattern = r'(\d+)\s*x\s*(\d+)'
match = re.search(dimension_pattern, dimensions_str, re.IGNORECASE)
if not match:
context_result["error"] = f"Could not parse dimensions from: {dimensions_str}"
context[check_id] = context_result
return {
"status": "error",
"error_message": f"Invalid dimension format in filename: {dimensions_str}",
"details": context_result
}
expected_width = int(match.group(1))
expected_height = int(match.group(2))
# Get actual image dimensions
if isinstance(image_object, Image.Image):
actual_width, actual_height = image_object.size
else:
raise ValueError("Image object is not a PIL Image")
# Update context result
context_result.update({
"expected_width": expected_width,
"expected_height": expected_height,
"actual_width": actual_width,
"actual_height": actual_height,
"dimensions_match": (expected_width == actual_width and expected_height == actual_height)
})
# Store in context
context[check_id] = context_result
# Check if dimensions match
if context_result["dimensions_match"]:
return {
"status": "passed",
"details": {
"message": "Image dimensions match filename specification",
**context_result
}
}
else:
return {
"status": "error",
"error_message": f"Dimension mismatch: Expected {expected_width}x{expected_height}px, got {actual_width}x{actual_height}px",
"details": context_result
}
except Exception as e:
context_result["error"] = str(e)
context[check_id] = context_result
return {
"status": "error",
"error_message": f"Dimension check failed: {str(e)}",
"details": context_result
}