EAN-13 Barcode — Makie.jl

A standard EAN-13 barcode visualization commonly used for retail products worldwide. The plot renders a scannable linear barcode encoding a 13-digit number with proper bar widths, guard patterns, and human-readable digits. This visualization is essential for product identification, inventory management, and point-of-sale systems.

EAN-13 Barcode rendered with Makie.jl

Renders

Julia source (Makie.jl)

# anyplot.ai
# barcode-ean13: EAN-13 Barcode
# Library: makie 0.21.9 | Julia 1.11.9
# Quality: 90/100 | Created: 2026-09-01

using CairoMakie
using Colors

# --- Theme tokens -----------------------------------------------------------
const THEME    = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG  = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const INK      = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"
const IMPRINT_PALETTE = [
    colorant"#009E73", colorant"#C475FD", colorant"#4467A3", colorant"#BD8233",
    colorant"#AE3030", colorant"#2ABCCD", colorant"#954477", colorant"#99B314",
]

# A real EAN-13 needs a light quiet zone to stay scannable, so the label
# stock and bar ink are fixed rather than theme-adaptive — like a printed
# barcode photographed on a page, this "data" doesn't flip with the theme.
const LABEL_BG   = colorant"#FBF9F2"
const BAR_INK    = colorant"#15130F"
const PAPER_TEXT = colorant"#4A4A44"  # fixed muted ink for text on the paper card

# --- Data: encode a 13-digit EAN-13 -----------------------------------------
# GS1 prefix "400" identifies Germany; the remaining digits are a
# manufacturer reference, product reference, and check digit.
code   = "4006381333931"
digits = [parse(Int, c) for c in code]

# Recompute the check digit from the first 12 digits (odd positions x1,
# even positions x3, mod 10) to confirm the example is a valid EAN-13.
odd_sum    = sum(digits[i] for i in 1:2:11)
even_sum   = sum(digits[i] for i in 2:2:12)
digits[13] = (10 - (odd_sum + 3 * even_sum) % 10) % 10

# 7-module digit patterns: L (left, odd parity), G (left, even parity), R (right)
L_CODE = ["0001101", "0011001", "0010011", "0111101", "0100011",
          "0110001", "0101111", "0111011", "0110111", "0001011"]
G_CODE = ["0100111", "0110011", "0011011", "0100001", "0011101",
          "0111001", "0000101", "0010001", "0001001", "0010111"]
R_CODE = ["1110010", "1100110", "1101100", "1000010", "1011100",
          "1001110", "1010000", "1000100", "1001000", "1110100"]

# Which of the 6 left digits use L vs. G code, keyed by the leading digit
PARITY = Dict(
    0 => "LLLLLL", 1 => "LLGLGG", 2 => "LLGGLG", 3 => "LLGGGL", 4 => "LGLLGG",
    5 => "LGGLLG", 6 => "LGGGLL", 7 => "LGLGLG", 8 => "LGLGGL", 9 => "LGGLGL",
)

first_digit    = digits[1]
left_digits    = digits[2:7]
right_digits   = digits[8:13]
parity         = PARITY[first_digit]
left_patterns  = [parity[i] == 'L' ? L_CODE[left_digits[i] + 1] : G_CODE[left_digits[i] + 1]
                  for i in 1:6]
right_patterns = [R_CODE[right_digits[i] + 1] for i in 1:6]

START_GUARD, CENTER_GUARD, END_GUARD = "101", "01010", "101"

# --- Geometry: lay out modules left to right --------------------------------
quiet   = 9      # quiet-zone module widths (spec minimum on each side)
bar_h   = 70.0   # data-bar height, in module-width units
guard_h = 75.0   # guard bars run 5 modules deeper than data bars (GS1 spec)

bars = Tuple{Float64,Float64}[]  # (x, height) of every printed (black) module
x = Float64(quiet)
for bit in START_GUARD
    bit == '1' && push!(bars, (x, guard_h))
    global x += 1
end
for pattern in left_patterns
    for bit in pattern
        bit == '1' && push!(bars, (x, bar_h))
        global x += 1
    end
end
for bit in CENTER_GUARD
    bit == '1' && push!(bars, (x, guard_h))
    global x += 1
end
for pattern in right_patterns
    for bit in pattern
        bit == '1' && push!(bars, (x, bar_h))
        global x += 1
    end
end
for bit in END_GUARD
    bit == '1' && push!(bars, (x, guard_h))
    global x += 1
end
total_width = x + quiet

left_start  = quiet + 3
right_start = quiet + 3 + 42 + 5

# --- Plot ---------------------------------------------------------------
title_str  = "barcode-ean13 · julia · makie · anyplot.ai"
title_size = length(title_str) > 67 ? round(Int, 20 * 67 / length(title_str)) : 20

fig = Figure(size = (1600, 900), fontsize = 14, backgroundcolor = PAGE_BG)

ax = Axis(
    fig[1, 1];
    title               = title_str,
    titlesize           = title_size,
    titlecolor          = INK,
    subtitle            = "EAN-13 · $(join(digits)) · Germany · retail product identification",
    subtitlesize        = 13,
    subtitlecolor       = INK_SOFT,
    backgroundcolor     = PAGE_BG,
    xticksvisible       = false,
    yticksvisible       = false,
    xticklabelsvisible  = false,
    yticklabelsvisible  = false,
    topspinevisible     = false,
    rightspinevisible   = false,
    leftspinevisible    = false,
    bottomspinevisible  = false,
    xgridvisible        = false,
    ygridvisible        = false,
    xminorgridvisible   = false,
    yminorgridvisible   = false,
)

# Vertical layout, top to bottom: bars -> human-readable digits ->
# colored structure underlines -> segment names -> paper backdrop.
text_top      = -(guard_h + 8.0)
underline_y   = text_top - 34.0
underline_h   = 6.0
seg_label_top = underline_y - underline_h - 10.0
paper_top     = 18.0
paper_bottom  = seg_label_top - 26.0

poly!(ax, Rect2f(0.0, paper_bottom, total_width, paper_top - paper_bottom);
      color = LABEL_BG, strokewidth = 0)

# Bars: guard patterns (start, center, end) run deeper than data bars
for (bx, bh) in bars
    poly!(ax, Rect2f(bx, -bh, 1.0, bh); color = BAR_INK, strokewidth = 0)
end

# Human-readable digits — the leading digit sits left of the start guard
text!(ax, quiet - 1.0, text_top; text = string(first_digit),
      color = BAR_INK, fontsize = 24, align = (:right, :top))
for (i, d) in enumerate(left_digits)
    text!(ax, left_start + (i - 1) * 7 + 3.5, text_top; text = string(d),
          color = BAR_INK, fontsize = 24, align = (:center, :top))
end
for (i, d) in enumerate(right_digits)
    text!(ax, right_start + (i - 1) * 7 + 3.5, text_top; text = string(d),
          color = BAR_INK, fontsize = 24, align = (:center, :top))
end

# Structure legend: country / manufacturer / product / check digit.
# Imprint positions 1-3 in canonical order for the abstract groups; the
# check digit gets the semantic-red anchor (position 5) instead of the
# next ordinal slot, since its role is error detection, not an abstract
# category (see "Semantic exception" in the default style guide).
segments = [
    (2.0,                left_start + 7.0,   IMPRINT_PALETTE[1], "Country"),
    (left_start + 7.0,   left_start + 42.0,  IMPRINT_PALETTE[2], "Manufacturer"),
    (right_start,        right_start + 35.0, IMPRINT_PALETTE[3], "Product"),
    (right_start + 35.0, right_start + 42.0, IMPRINT_PALETTE[5], "Check"),
]

for (x1, x2, color, label) in segments
    poly!(ax, Rect2f(x1, underline_y, x2 - x1, underline_h); color = color, strokewidth = 0)
    text!(ax, (x1 + x2) / 2, seg_label_top; text = label,
          color = PAPER_TEXT, fontsize = 15, align = (:center, :top))
end

xlims!(ax, -4.0, total_width + 4.0)
ylims!(ax, paper_bottom - 8.0, paper_top + 8.0)

# --- Save -------------------------------------------------------------------
save("plot-$(THEME).png", fig; px_per_unit = 2)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/barcode-ean13/makie/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "barcode-ean13",
  "language": "julia",
  "library": "makie",
  "page": "https://anyplot.ai/barcode-ean13/julia/makie",
  "hub": "https://anyplot.ai/barcode-ean13",
  "code_json": "https://api.anyplot.ai/specs/barcode-ean13/makie/code",
  "spec_json": "https://api.anyplot.ai/specs/barcode-ean13",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/barcode-ean13/julia/makie/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/barcode-ean13/julia/makie/plot-dark.png",
  "quality_score": 90.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of EAN-13 Barcode on anyplot.ai.

Other implementations