Skill: charmingzuo/circle-png-image (version 1.0.1)

--- name: circle-png-image description: Convert PNG images into circular PNG avatars with transparent corners. Use when the user asks to crop, mask, cut out, or convert a PNG image into a circle. version: 1.0.0 metadata: openclaw: requires: anyBins: - python - python3 install: - kind: uv package: pillow emoji: "⭕" --- # Circle PNG Image ## What This Skill Does Use this skill to turn any PNG image into a circular PNG with transparency outside the circle. It is intended for avatars, profile photos, icons, and other round image assets. The default behavior is: 1. Open the input PNG. 2. Convert it to RGBA so transparency is preserved. 3. Center-crop the image to a square using the shorter side. 4. Apply a circular alpha mask. 5. Save the result as a PNG. ## Quick Start Run the helper script: ```bash python scripts/circle_png.py input.png output.png ``` If the system uses `python3`: ```bash python3 scripts/circle_png.py input.png output.png ``` ## Options Set an exact output size: ```bash python scripts/circle_png.py input.png output.png --size 512 ``` Preserve the entire image by padding it to a square before applying the circular mask: ```bash python scripts/circle_png.py input.png output.png --fit contain ``` Overwrite an existing output file: ```bash python scripts/circle_png.py input.png output.png --force ``` ## Dependency The script requires Pillow. If it is missing, install it in the active Python environment: ```bash python -m pip install pillow ``` Prefer a virtual environment when modifying a project: ```bash python -m venv .venv .venv/Scripts/python -m pip install pillow .venv/Scripts/python scripts/circle_png.py input.png output.png ``` On macOS or Linux, use `.venv/bin/python` instead of `.venv/Scripts/python`. ## Agent Instructions When the user asks to make a PNG circular: 1. Confirm the input image path and desired output path. If no output is specified, use the input name with `-circle.png` appended before the extension. 2. Use `scripts/circle_png.py` to generate the output. 3. Use `--fit cover` by default for avatar-style results. 4. Use `--fit contain` when the user says to preserve the full image. 5. Use `--size` only when the user asks for a specific output dimension. 6. Never overwrite an existing output unless the user explicitly asks or `--force` is appropriate. ## Notes - Output is always PNG with an alpha channel. - Non-square inputs are centered automatically. - The circle touches the output square's edges.

path: scripts/circle_png.py
content: #!/usr/bin/env python3
"""Create circular PNG images with transparent corners."""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

try:
    from PIL import Image, ImageChops, ImageDraw
except ImportError as exc:  # pragma: no cover - exercised only without Pillow
    raise SystemExit(
        "Pillow is required. Install it with: python -m pip install pillow"
    ) from exc


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Convert a PNG image into a circular PNG with transparency."
    )
    parser.add_argument("input", type=Path, help="Path to the source PNG image.")
    parser.add_argument("output", type=Path, help="Path for the generated PNG image.")
    parser.add_argument(
        "--fit",
        choices=("cover", "contain"),
        default="cover",
        help=(
            "cover center-crops to fill the circle; contain pads the full image "
            "inside a transparent square. Default: cover."
        ),
    )
    parser.add_argument(
        "--size",
        type=int,
        help="Optional output diameter in pixels. Must be a positive integer.",
    )
    parser.add_argument(
        "--force",
        action="store_true",
        help="Overwrite the output file if it already exists.",
    )
    return parser.parse_args()


def make_square(image: Image.Image, fit: str) -> Image.Image:
    width, height = image.size

    if fit == "cover":
        side = min(width, height)
        left = (width - side) // 2
        top = (height - side) // 2
        return image.crop((left, top, left + side, top + side))

    side = max(width, height)
    square = Image.new("RGBA", (side, side), (0, 0, 0, 0))
    left = (side - width) // 2
    top = (side - height) // 2
    square.alpha_composite(image, (left, top))
    return square


def apply_circle_mask(image: Image.Image) -> Image.Image:
    side = image.size[0]
    mask = Image.new("L", (side, side), 0)
    draw = ImageDraw.Draw(mask)
    draw.ellipse((0, 0, side - 1, side - 1), fill=255)

    result = Image.new("RGBA", (side, side), (0, 0, 0, 0))
    result.alpha_composite(image)
    original_alpha = result.getchannel("A")
    result.putalpha(ImageChops.multiply(original_alpha, mask))
    return result


def convert_to_circle(input_path: Path, output_path: Path, fit: str, size: int | None) -> None:
    if size is not None and size <= 0:
        raise ValueError("--size must be a positive integer.")

    with Image.open(input_path) as source:
        image = source.convert("RGBA")

    square = make_square(image, fit)
    if size is not None and square.size != (size, size):
        square = square.resize((size, size), Image.Resampling.LANCZOS)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    apply_circle_mask(square).save(output_path, format="PNG")


def main() -> int:
    args = parse_args()

    if not args.input.exists():
        print(f"Input file does not exist: {args.input}", file=sys.stderr)
        return 2

    if args.input.suffix.lower() != ".png":
        print(f"Input must be a PNG file: {args.input}", file=sys.stderr)
        return 2

    if args.output.exists() and not args.force:
        print(
            f"Output file already exists: {args.output}. Use --force to overwrite.",
            file=sys.stderr,
        )
        return 2

    try:
        convert_to_circle(args.input, args.output, args.fit, args.size)
    except Exception as exc:  # noqa: BLE001 - CLI should report concise failures.
        print(f"Failed to create circular PNG: {exc}", file=sys.stderr)
        return 1

    print(f"Created circular PNG: {args.output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)