Skip to content

Downscale Pixel Art to 1× — Undo an Upscale or Resize

A sprite saved at ×4, a screenshot, a store image resized by a fractional factor: each pixel is now a block of many, sometimes smeared by smoothing. The Cleanup panel measures the pixel size from the picture itself, shows the grid it found with how sure it is, and rebuilds the 1× sprite as a new sprite without touching the original.

To take upscaled pixel art back to 1×, first find its pixel size, then keep one colour per block: a 128 × 128 image that is a 4× nearest upscale is made of 4 × 4 blocks and becomes 32 × 32. A plain “resize to 25 %” only works when the factor is a whole number you already know and the grid starts at pixel 0; fractional (×3.3) and smooth (bilinear) resizes need the grid measured. Nerulio’s Cleanup panel measures it, shows it with a confidence and creates the 1× sprite as a new sprite, in the browser.

Drop a sprite, frames, a GIF or an .aseprite file to paint on — or an upscaled picture to clean up
Runs in your browser. Files are not uploaded.
Studio Pixel workspace, Cleanup panel: a CC0 sprite resized ×4.25 with bilinear filtering, measured as a smooth resize with its grid drawn, and the 64×48 result previewed before Apply
The real Studio with a CC0 asset (OpenGameArt).
Exports to
  • .asepriteVerified· Aseprite 1.3.18
  • Palette filesMeasured· read back
  • Engine bundlesVerified· Godot 4.7.2 · Unity 6000.5
  • Frame PNG · .nerulioPlain files

Why “resize to 25 %” is not enough

A clean nearest-neighbour upscale by a whole number k turns every art pixel into a k × k block of one colour, so every colour change sits on a multiple of k. Going back is exact when you know k and where the grid starts: any pixel of a block has the block’s colour. Nerulio proves k from the positions of the colour changes; if the picture was cropped a few pixels off the grid, the shared remainder of those positions gives the offset.

A fractional nearest upscale has blocks of two widths in turn: at ×2.5 the runs are 3, 2, 3, 2 pixels. A fixed 40 % resize samples some blocks on their border, so one-pixel lines vanish or double. Nerulio puts a cut at every measured edge and reads each cell from its inner half (the outer quarter on each side is dropped), taking the most common colour, never an average.

A smooth resize (bilinear, bicubic, Lanczos) has no flat blocks: every edge is a ramp. Nerulio treats the picture as a linear interpolation between the original pixel centres and solves for those centres by least squares, then merges near-identical colours, so the edges are hard again. For a true bilinear resize that is an inversion; after JPEG or blur it is the closest bilinear explanation, not the exact original.

Pixel size (scale)
How many image pixels one art pixel covers: 4 for a ×4 upscale, about 3.78 for a 96 px wide sprite stored 363 px wide.
Offset (phase)
Where the first full block starts when the image was cropped off the grid.
Cell sample
One colour per cell: the most common colour of its inner half, or the Oklab medoid when no colour dominates.

Example: one 96 × 144 sprite, upscaled two ways

The same CC0 sheet (Sumo Hulk by Eris, 9 colours) was enlarged by ×4 nearest and by ×3.78 bilinear, then brought back to 1×:

truth              96 × 144, 9 colours

×4 nearest         384 × 576      384/4 = 96    576/4 = 144
  Nerulio          96 × 144 found by itself, 100 % of pixels exact
  Aseprite 1.3.18  Sprite Size 25 %, nearest: 96 × 144, 100 % exact

×3.78 bilinear     363 × 544      363/96 = 3.78   544/144 = 3.78
  Nerulio          96 × 144 found by itself, 99.7 % exact, 13 colours
  Aseprite         true size typed (96 × 144), nearest: 81.5 % exact
  Aseprite         25 % guessed: 91 × 136, 54.4 % exact

The ×4 case is easy for any tool once you know the factor. The bilinear one is where measuring matters: 25 % of 363 × 544 is 90.75 × 136, which is neither the right size nor on the grid.

What it does

  • Measure changes nothing: it reports the verdict (for example "Upscaled ×7" or "Smoothly resized ≈ ×4.25"), the pixel size with a confidence of sure, likely or unsure, the input and result sizes, the colour noise and a detected background, and draws the grid on the canvas.
  • Exact integer blocks are found with off-grid crops. Fractional nearest-neighbour scales, where cells are 2 or 3 px wide in turn, are found from the spacing of edges, and smooth resizes are undone with a least-squares inverse of the bilinear filter.
  • Each cell becomes one pixel by its most common colour or its Oklab medoid, never by averaging the edge, and near-identical colours are merged in Oklab, so outlines stay crisp.
  • Preview shows before and after at whole-number zoom, with a side-by-side compare. Apply adds the 1× sprite as a new sprite in one undo step, keeping frames, durations, pivots, boxes and tags.
  • All work runs in a worker off the main thread, and the same input and options always give the same bytes. A 384×576 ×4 upscale took 1.4 s end to end, a 363×544 bilinear resize 4.7 s.

How to do it

  1. Drop the upscaled PNG on this page; it opens in the Pixel workspace as one picture.
  2. Open the Cleanup panel, choose the scope (this frame, the tag or all frames) and press Measure; check the verdict and the grid drawn on the canvas.
  3. If the art has a solid background that belongs to the picture, set Background to keep; otherwise the border colour is made transparent.
  4. Press Preview to compare before and after, then Apply as new sprite and export the 1× result.

Check the result

  • Read the verdict before applying: “Upscaled ×4 (exact block grid)” is proof; “Smoothly resized ≈ ×3.78” is a measurement with a confidence; “… too weak to trust” is not applied.
  • Check the result size: input ÷ pixel size (384 ÷ 4 = 96, 576 ÷ 4 = 144).
  • Compare before and after in Preview at a whole-number zoom: outlines should stay one pixel wide and unbroken.
  • Compare the colour count with what the art should have (9 for the sprite above); many more means noise survived — set a colour limit.

How close the 1× result is, by kind of upscale

Exact pixels against the known original: defaults / background kept. 69 CC0 cases, docs/STUDIO-PIXEL.md §5.

UpscaleSize found exactlyExact pixels
Nearest, whole number (×2–×8)100 %92.2 % / 97.4 %
Nearest, fractional (×2.5, ×3.3, ×4.7)100 %88.6 % / 97.0 %
Smooth (bilinear, bicubic, Lanczos)93 %70.5 % / 75.9 %
Blurred after upscaling67 %53.8 % / 66.4 %
JPEG after upscaling80 %4.5 % / 12.1 % (84.0 % within ΔE 0.02)

Troubleshooting

SymptomLikely causeHow to checkFix
Result is half or double the expected sizeThe grid locked onto a multiple or a half of the real block (flat art with long runs)Show the grid on the canvas: does each cell hold exactly one art pixel?Type the pixel size (for example 4) in the Cleanup panel and measure again
A one-pixel line is missing or doubledA fixed-percentage resize sampled block borders (fractional factor or off-grid crop)Lay the grid over the lineUse the measured grid instead of a percentage; the offset of a crop is found automatically
Colours are slightly off everywhereJPEG input or a smooth resize: no pixel is bit-exactThe report lists far more colours than the art should haveKeep the background, set a colour limit, or quantize to the sprite’s palette (palette editor)
The background became transparent but belongs to the pictureBackground “Make transparent” (the default) removes the detected border colourThe report names the colour and its share of the borderSet Background to Keep before Apply
“A grid of ≈ … px was found, but it is too weak to trust”No consistent grid, typical for generated images (fixing AI pixel art)The dashed amber grid on the canvasType the size you see, or redraw the part that matters

Other ways to do it

OptionWhen it is the better choice
Aseprite: Sprite › Sprite Size, 25 %, nearest-neighbourA clean whole-number upscale whose factor you know: three steps and 100 % exact in our test. There is no grid detection, so fractional or smooth resizes need the true size typed in (81.5 % in our test).
Pixel-perfect checker (Pixel Lab)You only need to know whether an image is an exact integer upscale and recover it pixel for pixel; it offers recovery only when a block grid is proven.
Ordinary image resizeThe picture is not pixel art (a photo or a painting), where smooth resampling is what you want.

Engine exports and how each was checked

"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.

TargetFilesCheck
.asepritelayers · blend · opacity · locked · indexed palette · frames · tagsVerified Aseprite 1.3.18The real Aseprite command line reopened the file as INDEXED with 2 layers, Multiply at opacity 160 and the locked layer not editable; the frames are pixel-identical.
Palette files.gpl · .pal · .hex · .ase · .act · .jsonMeasured read backEach format was written and read back identical; Aseprite's own .gpl, .pal, .hex and .act and a real Adobe .ase (16 colours) were read.
Engine bundlesGodot 4 · Unity 6 · Phaser 3/4 · PixiJS 8 … through Pack & ExportVerified Godot 4.7.2 · Unity 6000.5The sprite you drew is packed in Pack & Export; those engine files were loaded in each engine on real CC0 assets (47 of 49 runs pass; the 2 failures are a Phaser 3.90 bug the Phaser 3 preset avoids).
Frame PNG · .nerulioPNG-8 with the palette when an indexed frame fits it · project filePlain filesPlain files for any tool; no engine run is claimed for them.

Evidence

Cleanup benchmark, 69 CC0 cases with a known 1× original: the exact size found for 81 % (±1 px: 90 %) and 74.0 % of pixels exact with the background kept; the best competitor found 30 % of sizes (perfectPixel) and the best exact-pixel score was 44.6 % (unfake.js). An Aseprite-made ×4 nearest upscale came back 100 % exact and a ×3.78 bilinear resize 99.7 %, both with the size found automatically. A 1 px outline and a drop shadow matched Aseprite pixel for pixel (1846 and 705 px). .aseprite files written here reopen in Aseprite 1.3.18 as indexed, with their layers, blend mode and lock.

Limits

  • One pixel size per cleanup: frames that were upscaled by different factors have to be cleaned separately.
  • The grid is measured along rows and columns; rotated or perspective-distorted screenshots have no axis-aligned grid to find.
  • Blurred upscales are the weakest kind in the benchmark: the size was right in 67 % of those cases.
  • Not in the Pixel workspace (Aseprite has them): layer groups, linked cels, tilemap layers, reference layers, RotSprite and free rotation or scaling of a selection (only flips and 90°), gradient, spray, contour and text tools, custom brushes (square or round, 1–16 px), tiled drawing, Lua scripting and a command line.
  • The symmetry axis is typed, not dragged on the canvas. On touch there is no right button, so the background colour needs the swap button or X.
  • Cleanup: JPEG input comes back close (84 % of pixels within ΔE 0.02 with the background kept) but rarely exact (12 %); simulated generated art gets the exact size 20 % of the time (±1 px: 80 %); none of 7 real generated images was snapped automatically — you type the pixel size the panel suggests.
  • Indexed conversion picks the nearest colour in Oklab, not Aseprite's RGB distance: 68 % of the test sprite's pixels got a different (perceptually closer) pick. The Lospec search is the only network request and asks first.

Versions and sources

Numbers from Nerulio’s cleanup benchmark (69 CC0 cases with a known 1× original; exact size 81 %, within 1 px 90 %) and the head-to-head on the Sumo Hulk sheet, where Aseprite 1.3.18 was run through its command line (docs/STUDIO-PIXEL.md §5–§6). Aseprite’s menu path follows its documentation.

Official documentation used

Questions

What if the measured pixel size is wrong?

The verdict names its confidence, and a weak grid is drawn dashed in amber rather than applied as sure. Type the pixel size yourself in the Cleanup panel; nothing is changed until you press Apply, and Apply makes a new sprite.

Why is my result one pixel smaller or larger than expected?

When the picture was cropped a few pixels off the grid, the border cells are partial. In the benchmark the exact size was found for 81 % of the cases and the size was within 1 px for 90 %.

Does it work on JPEG screenshots?

Partly. JPEG noise means colours rarely come back bit-exact (12 % of pixels with the background kept), but 84 % land within ΔE 0.02 of the true colour, which is not visible at 1×. Use PNG when you have it.

Is it free, and do I need an account?

Everything on these pages is free and works without an account. There is no watermark and no export that is held back.

Are my sprites uploaded?

No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.

Does it need Aseprite or an engine plugin installed?

No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).