Choosing Export DPI from Minimum Mark Size

Find the narrowest mark the style actually draws, require at least two device dots across it, and take the resulting resolution — because 300 dpi is the correct answer for a mid-range product and both wasteful and insufficient at the two ends of the range.

Core Algorithm and Workflow

The requirement is not “how sharp should this be” but “what is the smallest thing this map draws, and how many dots does it need”. Two dots across the narrowest mark is the practical floor: one dot renders a mark that appears and disappears depending on where it falls on the grid, and three offers no visible improvement over two on a solid edge.

So the derivation is:

  1. Scan the style for the narrowest mark. Thinnest stroke, smallest halo radius, narrowest dash gap, and the stem width of the smallest type. The last two are the ones usually missed, and they are typically narrower than any line deliberately specified.
  2. Require two dots across it. Required DPI = 2 / (mark in mm) × 25.4.
  3. Cap at the device. No output benefit exists above the imagesetter or printer resolution.
  4. Sanity-check against viewing distance. A design read from two metres should not contain sub-half-millimetre marks in the first place.
Four products, four different correct answers A table of four map products. A wall map read at two metres has a narrowest mark of 0.6 millimetres and needs 85 dpi, rounded to 150. A tourist map has 0.25 millimetres and needs 203, rounded to 300. A topographic sheet has 0.15 and needs 339, rounded to 400. A hydrographic chart has 0.08 and needs 635, rounded to 600 at the device ceiling. product narrowest mark required shipped wall map, 2 m 0.60 mm 85 150 tourist map 0.25 mm 203 300 topographic sheet 0.15 mm 339 400 hydrographic chart 0.08 mm 635 600 Only the highlighted row wanted 300. The top row renders four times faster at no visible cost; the bottom row loses hairlines at 300 and is capped by the imagesetter, not by the design.
Three of these four products are mis-served by a 300 dpi default, in one direction or the other, and none of the errors is visible until the sheet is printed.

Production-Ready Python Implementation

MM_PER_INCH = 25.4
DEVICE_CEILING_DPI = {"offset_imagesetter": 2400, "large_format_inkjet": 720,
                      "office_laser": 600, "screen": 96}


def required_dpi(narrowest_mark_mm: float, dots_across: int = 2) -> float:
    """Resolution needed to render the narrowest mark with `dots_across` dots."""
    if narrowest_mark_mm <= 0:
        raise ValueError("narrowest mark must be positive")
    return dots_across * MM_PER_INCH / narrowest_mark_mm


def choose_export_dpi(style_marks_mm: dict, device: str,
                      ladder=(96, 150, 200, 300, 400, 600, 1200)) -> dict:
    """Pick an export resolution from the design and the output device.

    `style_marks_mm` maps a description to a physical size — thinnest stroke,
    smallest halo, narrowest dash gap, smallest type stem.
    """
    if not style_marks_mm:
        raise ValueError("no marks supplied; the design has to state its own limits")
    if device not in DEVICE_CEILING_DPI:
        raise KeyError(f"unknown device {device!r}")

    name, mark = min(style_marks_mm.items(), key=lambda kv: kv[1])
    needed = required_dpi(mark)
    ceiling = DEVICE_CEILING_DPI[device]

    usable = [d for d in ladder if d >= needed and d <= ceiling]
    chosen = usable[0] if usable else min(max(ladder[0], min(ceiling, needed)), ceiling)

    return {"driver": name, "narrowest_mark_mm": mark,
            "required_dpi": round(needed), "device_ceiling": ceiling,
            "chosen_dpi": int(chosen),
            "capped": needed > ceiling}

Returning driver — the name of the mark that set the requirement — is what makes the result actionable. “600 dpi because the dash gap on the footpath style is 0.08 mm” invites a conversation about whether that dash pattern is worth quadrupling the render cost; a bare number does not.

The capped flag matters too: when the design asks for more than the device can deliver, the correct response is to widen the mark, not to export at an impossible resolution and hope.

Performance Tuning and Cartographic Best Practices

  • Include dash gaps and type stems in the scan. Both are routinely narrower than any deliberately specified line, and both are what actually breaks up on press.
  • Remember the memory cost. Doubling DPI quadruples the pixel count and therefore peak rasterisation memory, which is what sets worker concurrency — see Parallelizing Map Sheet Rendering with Celery Workers.
  • Widen the mark rather than raising the resolution. A 0.08 mm hairline that forces 600 dpi across a 400-sheet atlas is an expensive detail; 0.12 mm is visually equivalent at reading distance and halves the job.
  • Cap at the device. Exporting above the imagesetter resolution produces larger files and identical print.
  • Re-derive when the style changes. A new layer with a finer hairline silently raises the requirement, which is why the narrowest mark belongs in the style manifest rather than in an operator’s memory.
What each doubling of resolution costs Three quantities plotted against export resolution from 150 to 600 dpi for one map sheet. Render time rises from 9 to 141 seconds, peak memory from 0.3 to 4.8 gigabytes, and file size from 6 to 94 megabytes. All three scale with the square of the resolution, so each doubling is a fourfold cost. dpi render peak memory file size 150 9 s 0.3 GB 6 MB 300 35 s 1.2 GB 24 MB 600 141 s 4.8 GB 94 MB All three scale with the square of the resolution, so each doubling is a fourfold cost — and the memory column is what decides how many workers a host can run. Over 400 sheets, the difference between 300 and 600 is roughly twelve hours of render time.
The memory column is the one with a hard edge: a job that no longer fits does not run slower, it fails.

Integration and Next Steps

The narrowest mark is the same figure that drives feature thresholds in Choosing Minimum Feature Size Thresholds by Output Medium, so a style that records it gets both its resolution and its generalisation tolerance for free. Feed the chosen DPI into the export settings validated in DPI and Resolution Management, and assert the delivered pixel dimensions afterwards rather than trusting the setting.

The same figure decides two unrelated-looking settings A narrowest-mark figure feeding two outputs. Multiplied by the scale denominator it gives the ground threshold for dropping and simplifying features. Divided into two device dots it gives the required export resolution. A note records that a style recording only one of the two ends up with them inconsistent. narrowest mark in millimetres × scale denominator → ground threshold drop and simplification tolerance 2 × 25.4 ÷ mark → required dpi capped at the output device A style that records only one of these ends up exporting at a resolution its own thresholds contradict.
The two settings look unrelated in a style file and are the same measurement seen from two directions. Recording the measurement rather than its consequences is what keeps them agreeing.

Frequently Asked Questions

Why not simply always use 300 dpi?

Because it is right for one common case and wrong in both directions elsewhere. A large-format wall map read from two metres is visually identical at 150 and renders four times faster with a quarter of the memory; a hydrographic chart with 0.08 millimetre hairlines loses them at 300 and needs 600. Three hundred is a sensible default because most products sit in the middle of the range, not because it satisfies a requirement — and the products at the ends are exactly the ones where the cost or the defect is largest.

What counts as the narrowest mark?

The smallest dimension anything in the style is drawn at: the thinnest stroke width, the smallest halo radius, the narrowest gap in a dash pattern, and the stem width of the smallest type. The last two are the ones usually forgotten and they are typically narrower than any line that was consciously specified — a 0.2 millimetre dashed line often has a 0.1 millimetre gap, and 6 point type has stems finer than that.

Does higher DPI ever make a map worse?

Not in appearance, but the second-order costs are real. Doubling resolution quadruples pixel count, and therefore peak rasterisation memory, which is the quantity that sets how many render workers a host can run. A job that fitted at 300 and does not fit at 600 does not render more slowly — it fails, or forces the pool down to one worker. Storage and transfer for raster deliverables scale the same way.

How does viewing distance enter the calculation?

Through the mark size rather than directly. A mark that must be legible from two metres has to be physically larger, and once the design reflects that the resolution requirement follows from the same two-dots rule. In practice a wall map contains nothing below about half a millimetre, which puts the requirement near 100 dpi and means anything above about 150 buys nothing a reader at that distance could perceive.


Back to DPI and Resolution Management