DEV Community

Cover image for Binarising AI Line Art For Vector Traceability: Threshold Choices That Survive Adobe QC

Binarising AI Line Art For Vector Traceability: Threshold Choices That Survive Adobe QC

A batch of 40 line art assets came back from Adobe Stock review with the same rejection note: "issues with technical quality, visible noise or artifacts." I had traced them at whatever threshold the default gave me. The vectors looked fine on my screen. Zoomed to 400%, the strokes were made of tiny islands and speckles, and the reviewer saw it in seconds. That rejection cost me a week of rework, so I got systematic about the binarisation step. Here is what I learned, with the numbers I now use.

Why the threshold matters more than the trace

If you sell vectors from AI generated line art, the pipeline is: generate raster, binarise to pure black and white, trace to paths, export. The trace step is honest. It draws exactly what you give it. If your binarised image has stray pixels along an edge, the trace turns them into microscopic path fragments. Adobe's QC reviewers zoom in, and Adobe's own checks flag files with excessive path fragmentation. Vecteezy's review is a bit more forgiving, but a messy trace gets rejected there too, and Dreamstime asks for clean editable vectors in its 15 column metadata sheet the same way.

The fix is upstream. Get the bitmap clean and the trace takes care of itself.

Pick a threshold, do not trust the default

Most tracing tools apply an automatic threshold when you feed them grayscale or color input. That default is tuned for photos, not for AI line art. AI generators produce anti-aliased edges and faint gray halos around strokes. A mid range threshold can turn those halos into a fog of tiny specks.

What works for me, tested across a few hundred assets:

  • Convert to grayscale first, then look at the histogram. AI line art is almost always bimodal, one peak near white and one near black.
  • Set the threshold in the valley between the peaks. For my generator's output that lands around 140 to 160 on a 0 to 255 scale. Yours will differ, so look, do not guess.
  • If a stroke comes out broken, lower the threshold. If halos appear as fuzz, raise it. One pass of visual checking per batch beats 50 rejected uploads.

For anything destined for stickers or print, I binarise harder than feels comfortable. Pure 0 and pure 255, nothing in between. Cutters and printers do not care about your grays.

Clean the bitmap before you trace

Two operations, in this order, remove most rejections:

  1. Despeckle. Remove connected components below a minimum pixel count. I use roughly 8 pixels at 1000 px canvas size as the cutoff. Smaller than that and it is almost always noise, not detail.
  2. Close small gaps. AI art sometimes leaves hairline breaks in a stroke. A morphological close of 1 or 2 pixels repairs them without visibly thickening the line.

Both run in Pillow plus a little numpy-free logic in my scripts, and on my 1 vCPU, 2 GB RAM server each image takes under a second. I process one file at a time, call gc.collect() after each asset, and measure peak RSS with resource.getrusage(RUSAGE_SELF).ru_maxrss rather than trusting my feel for memory use. That habit came from watching a parallel batch swap itself to death on the small box.

Verify the trace the cheap way

You do not need to open every SVG in Illustrator. Render the vector back to a raster at the same size and diff it against the binarised source. If the pixel difference is small and there are no tiny isolated regions in the render, the trace is clean. I inspect at 60 dpi previews during the batch and only render at full resolution for final output, which keeps the small server happy.

Count your paths too. If one asset traces to ten times the path count of its siblings in the same batch, something went wrong at the threshold step. That single number caught more problems for me than any visual review.

Metadata is the other silent killer

A clean vector with a wrong CSV header is still an instant rejection. Adobe's upload CSV has a fixed 5 column header, Vecteezy uses 4 columns, Dreamstime wants 15. All three reject the file immediately if the header does not match exactly. After hand-editing a spreadsheet wrong twice, I wrote make_metadata.py to emit the exact header per platform from a folder of finished files, and upload_tracker.py so a re-run of the batch never double-posts an asset. Double-posting is the fastest way to get an account flagged, and at 3 am with a batch running, you will not remember what you already uploaded.

The honest summary

Binarisation is not glamorous. It is a histogram, a threshold in the valley, a despeckle, and a path count check. But it is the difference between a vector that survives Adobe QC and one that comes back with the same rejection note four times. Everything above runs on a 1 vCPU, 2 GB box with no GPU, one process at a time.

This whole workflow, the metadata builders, the upload ledger, the packager that zips files and renders a 1280x720 cover and 600x600 thumbnail, is part of a kit I built after packaging 39 products this way, about 856 MB of finished output on that tiny server. If you want the scripts instead of rebuilding them from this post, they are here:

See the kit


Building digital products? Free guides & kits for digital product sellers.

Top comments (0)