Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

img-scripts

Shared Avior Studio image scripts. Keep image automation here instead of copying Python scripts into individual game repositories.

Setup

These scripts require Python 3.12 and Pillow.

python -m pip install -e .

Usage

Run project-specific scripts from the target game repository root, or pass --project-root explicitly.

python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out
python ../img-scripts/scripts/image_resize.py image.png

# Prizm
python ../img-scripts/scripts/cut_sheet.py --project-root .

# Fixed-grid sheets
python ../img-scripts/scripts/cut_sheet.py sheet.png --grid 4x3 --out-dir out

# Inferred-layout sheets. This finds transparent horizontal/vertical corridors,
# recursively slices on those logical lines, then tightly crops each region.
python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out

# If faint alpha debris blocks otherwise-clear corridors, tune the line mask.
python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out --line-min-gap 12 --line-max-pixels 8

# Revik
python ../img-scripts/scripts/generate_terrain_tiles.py --project-root . grass forest

Crop Contamination Counts

cut_sheet.py records two per-asset counts in the manifest. They cover different regions and each one is blind in a different mode, so they are only useful read together with component_source and the flags the manifest records alongside them.

Field Region Count
padding_ring_foreground inside padded_box, outside box mask_area(padded_box) - mask_area(box)
content_box_unclaimed_foreground inside box mask_area(box) - alpha_area

The run prints a warning naming every crop with a non-zero count on either.

Both are foreground counts over a region and are never negative. Neither computes ownership, and zero is necessary but NOT sufficient. The ring count is "foreground in the ring, whoever owns it". The in-box count is "foreground in the content box that is not this component's own blob" -- another sprite overlapping the box, or this asset's own detached sparks. Read them with these limits in mind:

  • --padding 0 makes padding_ring_foreground identically 0, by construction: there is no ring. --padding defaults to 0, so unless you pass a padding, the ring count measures nothing and --fail-on-ring-foreground can never fire. This is the common case, not the exception.
  • content_box_unclaimed_foreground is identically 0 unless component_source is connected_components and --group-radius is 0. On grid and corridors, at any --group-radius above 0, and for any asset --merge-distance merged (see below), alpha_area is measured over the whole content box, so the subtraction is 0 by construction. --group-radius defaults to 0, but --layout-mode auto (the default) prefers corridors and only falls back to connected components when corridor slicing under-splits -- so which count is live depends on the sheet. The manifest's component_source records which branch ran. Do not raise --group-radius to clear a non-zero count: that silences the measurement without changing the crop.
  • Neither sees a neighbour swallowed whole. If a corridor cuts through the next sprite and the box takes that part outright, tight_mask_box counts those pixels as the asset's own alpha_area, so both counts read clean.
  • A merged crop reports 0 on both. Two whole sprites in one box have nothing in the ring and nothing unclaimed. Raising --line-min-gap until sprites merge drives both counts to 0 while making the cut strictly worse.
  • They flag the asset's own art too. A box that clips a sprite leaves that sprite's own pixels in its ring; an asset with detached sparks reports them as unclaimed at --group-radius 0. Non-zero means "something is there", not "a neighbour is there".
  • --merge-distance above 0 zeroes the in-box count for the assets it merges. A merged asset's box is the union of its pieces, and its alpha_area is measured over that union rather than summed from the pieces, so the subtraction is 0 by construction for it -- the same degeneracy --group-radius has, for the same reason. Assets that merged with nothing still report the count. Summing instead would be wrong in both directions: it double-counts where two pieces' boxes overlap (reachable at --group-radius above 0) and misses foreground in the union box that belonged to no piece. Note that a merged asset's alpha_area therefore counts every foreground pixel in its union box, including debris below --min-area that belongs to no piece -- and alpha_area is not only reported. It also feeds --sort area ordering (so --names can map to different sprites) and --alpha-threshold auto selection (which can change the saved PNG bytes). Both need --merge-distance above 0 together with that flag; neither is reachable otherwise.

Non-zero means a sprite ships with a fragment of something baked into it. It happens when crop boxes sit closer together than --padding, or when a slice corridor runs through art rather than between it. Fix it by lowering --line-min-gap, lowering --padding, or spacing the assets further apart on the source sheet -- not by editing the cut PNGs.

Do not raise --line-min-gap. That value is the minimum width of a clear corridor for a split to be accepted, so raising it rejects narrow corridors and merges neighbouring sprites into a single crop. Measured on a 16-asset sheet: --line-min-gap 8 yields 16 assets, 24 yields 15 (two sprites in one crop), 40 yields 8 (one crop holding four sprites) -- and every one of those merged runs reports 0 on both counts, re-measured under the current formulas.

Because zero is not sufficient, both checks stay warnings by default. Pass --fail-on-ring-foreground or --fail-on-unclaimed-foreground to exit non-zero instead, so a consumer repo's CI can gate on them; a clean gate still needs a look at the cut PNGs. Gate on the count that is actually live for your flags -- gating on a count that is 0 by construction is a green light that measured nothing. --fail-on-padding-ring is accepted as the old spelling of --fail-on-ring-foreground.

# The warnings name the offenders and how many pixels each one carries.
python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out --padding 6

# Same, but non-zero exit if any ring is dirty. Needs --padding above 0 to mean anything.
python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out --padding 6 --fail-on-ring-foreground

# Gate the in-box count instead. Needs --group-radius 0 and a connected_components cut.
python ../img-scripts/scripts/cut_sheet.py sheet.png --out-dir out \
  --layout-mode components --group-radius 0 --fail-on-unclaimed-foreground

The manifest carries a padding_ring_foreground_note and a content_box_unclaimed_foreground_note restating these limits, because the manifest is the artifact that crosses a repo boundary and this README does not travel with it.

Script Inventory

Script Origin Notes
scripts/cut_sheet.py Shared Sprite sheet cutter with alpha/background detection, inferred transparent-corridor slicing, connected-component fallback, optional grid mode, auto threshold, padding, crop contamination counts, and manifest output.
scripts/generate_terrain_tiles.py Revik Revik-specific terrain hex tile generator.
scripts/image_resize.py Revik Pillow force-resize to exactly 512x512 while preserving the source extension.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages