From image-production
Use when the user wants to automatically straighten a tilted image — scanned documents, phone-captured pages, photographed receipts, or slightly off-axis photos. Detects the dominant skew angle and rotates the image to vertical/horizontal, optionally cropping the resulting transparent triangles. Uses ImageMagick `-deskew` for documents and a Hough-line fallback (via Python + OpenCV) for photographs.
npx claudepluginhub danielrosehill/claude-code-plugins --plugin image-productionThis skill uses the workspace's default tool permissions.
Straighten a tilted image. Two backends, picked by content type:
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
Straighten a tilted image. Two backends, picked by content type:
magick -deskew 40%. Detects skew via the Radon-style projection profile that ImageMagick's deskew operator implements. Fast, robust on text/scans up to ±15°.--mode photo).Do not use this skill when:
exiftool -Orientation, or rotate by 90/180 multiples) before deskewing.document (default) | photo | auto (heuristic: if magick identify -format "%[colorspace]" is Gray or the image has very low saturation → document; else photo).--recursive for directory descent._deskew. --output-dir <path> for sibling folder. --overwrite to replace.-deskew percentage. Default 40% (ImageMagick's recommended value). Higher = more aggressive detection, more false positives.15°. If detected skew exceeds this, refuse to rotate and flag the file (probably wrong orientation, not skew).on. After rotation, crop to the largest inscribed rectangle so there are no transparent / black triangle borders. --no-crop to keep the full rotated canvas.--no-crop. Default white. Use none for transparent (PNG/WebP only).Verify ImageMagick 7+. For photo mode, also verify the plugin's uv venv has opencv-python-headless and numpy (managed by install-deps; if missing, point at it).
Enumerate inputs (JPEG/JPG/PNG/TIFF/TIF/WebP). Skip and note RAW.
document mode:
magick "$IN" -background "$BG" -deskew ${THRESHOLD}% \
$( [ "$CROP" = on ] && echo "+repage -fuzz 1% -trim +repage" ) \
"$OUT"
-deskew applies the rotation. -trim with a small fuzz removes the resulting fill border when CROP=on. Read back the applied angle from the verbose output (-verbose) for the summary.
photo mode (Python via the plugin's uv venv):
import cv2, numpy as np, sys
img = cv2.imread(sys.argv[1])
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/720, 200)
if lines is None:
print("0.0"); sys.exit(0)
# Collect angles near horizontal (±30°) and near vertical (±30° of 90°)
angles = []
for rho, theta in lines[:200, 0]:
deg = np.degrees(theta) - 90 # 0 = horizontal line
if abs(deg) < 30:
angles.append(deg)
elif abs(deg - 90) < 30:
angles.append(deg - 90)
elif abs(deg + 90) < 30:
angles.append(deg + 90)
if not angles:
print("0.0"); sys.exit(0)
print(f"{np.median(angles):.3f}")
Then rotate via ImageMagick using the detected angle:
ANGLE=$(uv run --project "$PLUGIN_VENV" python deskew_photo.py "$IN")
magick "$IN" -background "$BG" -rotate "$(awk "BEGIN{print -1*$ANGLE}")" \
$( [ "$CROP" = on ] && echo "+repage -fuzz 1% -trim +repage" ) \
"$OUT"
Max-angle guard: if |angle| > MAX_ANGLE, skip the file and flag it: "$IN: detected ${angle}° — exceeds max-angle ${MAX_ANGLE}°, skipping (likely wrong orientation, not skew)".
Crop to inscribed rectangle (when --no-crop is off and the simple -trim leaves uneven borders): use the analytic formula for the largest inscribed axis-aligned rectangle inside a rotated rectangle. For input W×H rotated by θ:
new_w = (W·|cos θ| - H·|sin θ|) / (cos²θ - sin²θ) if W ≥ H
new_h = (H·|cos θ| - W·|sin θ|) / (cos²θ - sin²θ)
Crop centred. For small angles (<5°) the difference vs. -trim is negligible — -trim is fine.
For batch, parallelise with xargs -P $(nproc). Skip files ending _deskew.
-deskew is tuned for bilevel/grayscale text. On colour photos it often returns 0° or noise — that's why photo mode exists.magick "$IN" -threshold 50% or hand off to tesseract directly.--mode auto. The heuristic isn't perfect — review the angle distribution in the summary and re-run misclassified files explicitly.dewarp or OpenCV's getPerspectiveTransform — auto-deskew won't fix keystoning.