{"spec_id":"barcode-code128","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nbarcode-code128: Code 128 Barcode\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport altair as alt\nimport pandas as pd\nfrom PIL import Image\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Code 128 encoding tables (subset B - ASCII printable characters)\n# Each pattern is a sequence of bar widths: [bar, space, bar, space, bar, space] in units\nCODE128_PATTERNS = {\n    \" \": [2, 1, 2, 2, 2, 2],\n    \"!\": [2, 2, 2, 1, 2, 2],\n    '\"': [2, 2, 2, 2, 2, 1],\n    \"#\": [1, 2, 1, 2, 2, 3],\n    \"$\": [1, 2, 1, 3, 2, 2],\n    \"%\": [1, 3, 1, 2, 2, 2],\n    \"&\": [1, 2, 2, 2, 1, 3],\n    \"'\": [1, 2, 2, 3, 1, 2],\n    \"(\": [1, 3, 2, 2, 1, 2],\n    \")\": [2, 2, 1, 2, 1, 3],\n    \"*\": [2, 2, 1, 3, 1, 2],\n    \"+\": [2, 3, 1, 2, 1, 2],\n    \",\": [1, 1, 2, 2, 3, 2],\n    \"-\": [1, 2, 2, 1, 3, 2],\n    \".\": [1, 2, 2, 2, 3, 1],\n    \"/\": [1, 1, 3, 2, 2, 2],\n    \"0\": [1, 2, 3, 1, 2, 2],\n    \"1\": [1, 2, 3, 2, 2, 1],\n    \"2\": [2, 2, 3, 2, 1, 1],\n    \"3\": [2, 2, 1, 1, 3, 2],\n    \"4\": [2, 2, 1, 2, 3, 1],\n    \"5\": [2, 1, 3, 2, 1, 2],\n    \"6\": [2, 2, 3, 1, 1, 2],\n    \"7\": [3, 1, 2, 1, 3, 1],\n    \"8\": [3, 1, 1, 2, 2, 2],\n    \"9\": [3, 2, 1, 1, 2, 2],\n    \":\": [3, 2, 1, 2, 2, 1],\n    \";\": [3, 1, 2, 2, 1, 2],\n    \"<\": [3, 2, 2, 1, 1, 2],\n    \"=\": [3, 2, 2, 2, 1, 1],\n    \">\": [2, 1, 2, 1, 2, 3],\n    \"?\": [2, 1, 2, 3, 2, 1],\n    \"@\": [2, 3, 2, 1, 2, 1],\n    \"A\": [1, 1, 1, 3, 2, 3],\n    \"B\": [1, 3, 1, 1, 2, 3],\n    \"C\": [1, 3, 1, 3, 2, 1],\n    \"D\": [1, 1, 2, 3, 1, 3],\n    \"E\": [1, 3, 2, 1, 1, 3],\n    \"F\": [1, 3, 2, 3, 1, 1],\n    \"G\": [2, 1, 1, 3, 1, 3],\n    \"H\": [2, 3, 1, 1, 1, 3],\n    \"I\": [2, 3, 1, 3, 1, 1],\n    \"J\": [1, 1, 2, 1, 3, 3],\n    \"K\": [1, 1, 2, 3, 3, 1],\n    \"L\": [1, 3, 2, 1, 3, 1],\n    \"M\": [1, 1, 3, 1, 2, 3],\n    \"N\": [1, 1, 3, 3, 2, 1],\n    \"O\": [1, 3, 3, 1, 2, 1],\n    \"P\": [3, 1, 3, 1, 2, 1],\n    \"Q\": [2, 1, 1, 3, 3, 1],\n    \"R\": [2, 3, 1, 1, 3, 1],\n    \"S\": [2, 1, 3, 1, 1, 3],\n    \"T\": [2, 1, 3, 3, 1, 1],\n    \"U\": [2, 1, 3, 1, 3, 1],\n    \"V\": [3, 1, 1, 1, 2, 3],\n    \"W\": [3, 1, 1, 3, 2, 1],\n    \"X\": [3, 3, 1, 1, 2, 1],\n    \"Y\": [3, 1, 2, 1, 1, 3],\n    \"Z\": [3, 1, 2, 3, 1, 1],\n    \"[\": [3, 3, 2, 1, 1, 1],\n    \"\\\\\": [3, 1, 4, 1, 1, 1],\n    \"]\": [2, 2, 1, 4, 1, 1],\n    \"^\": [4, 3, 1, 1, 1, 1],\n    \"_\": [1, 1, 1, 2, 2, 4],\n    \"`\": [1, 1, 1, 4, 2, 2],\n    \"a\": [1, 2, 1, 1, 2, 4],\n    \"b\": [1, 2, 1, 4, 2, 1],\n    \"c\": [1, 4, 1, 1, 2, 2],\n    \"d\": [1, 4, 1, 2, 2, 1],\n    \"e\": [1, 1, 2, 2, 1, 4],\n    \"f\": [1, 1, 2, 4, 1, 2],\n    \"g\": [1, 2, 2, 1, 1, 4],\n    \"h\": [1, 2, 2, 4, 1, 1],\n    \"i\": [1, 4, 2, 1, 1, 2],\n    \"j\": [1, 4, 2, 2, 1, 1],\n    \"k\": [2, 4, 1, 2, 1, 1],\n    \"l\": [2, 2, 1, 1, 1, 4],\n    \"m\": [4, 1, 3, 1, 1, 1],\n    \"n\": [2, 4, 1, 1, 1, 2],\n    \"o\": [1, 3, 4, 1, 1, 1],\n    \"p\": [1, 1, 1, 2, 4, 2],\n    \"q\": [1, 2, 1, 1, 4, 2],\n    \"r\": [1, 2, 1, 2, 4, 1],\n    \"s\": [1, 1, 4, 2, 1, 2],\n    \"t\": [1, 2, 4, 1, 1, 2],\n    \"u\": [1, 2, 4, 2, 1, 1],\n    \"v\": [4, 1, 1, 2, 1, 2],\n    \"w\": [4, 2, 1, 1, 1, 2],\n    \"x\": [4, 2, 1, 2, 1, 1],\n    \"y\": [2, 1, 2, 1, 4, 1],\n    \"z\": [2, 1, 4, 1, 2, 1],\n    \"{\": [4, 1, 2, 1, 2, 1],\n    \"|\": [1, 1, 1, 1, 4, 3],\n    \"}\": [1, 1, 1, 3, 4, 1],\n    \"~\": [1, 3, 1, 1, 4, 1],\n}\n\n# Code 128 value mapping for subset B (characters to values for checksum)\nCODE128_VALUES = {chr(i + 32): i for i in range(95)}\n\n# Special patterns\nSTART_B = [2, 1, 1, 2, 1, 4]  # Start Code B (value 104)\nSTOP = [2, 3, 3, 1, 1, 1, 2]  # Stop pattern\n\n# Check digit patterns (values 0-102)\nCHECK_PATTERNS = [\n    [2, 1, 2, 2, 2, 2],\n    [2, 2, 2, 1, 2, 2],\n    [2, 2, 2, 2, 2, 1],\n    [1, 2, 1, 2, 2, 3],\n    [1, 2, 1, 3, 2, 2],\n    [1, 3, 1, 2, 2, 2],\n    [1, 2, 2, 2, 1, 3],\n    [1, 2, 2, 3, 1, 2],\n    [1, 3, 2, 2, 1, 2],\n    [2, 2, 1, 2, 1, 3],\n    [2, 2, 1, 3, 1, 2],\n    [2, 3, 1, 2, 1, 2],\n    [1, 1, 2, 2, 3, 2],\n    [1, 2, 2, 1, 3, 2],\n    [1, 2, 2, 2, 3, 1],\n    [1, 1, 3, 2, 2, 2],\n    [1, 2, 3, 1, 2, 2],\n    [1, 2, 3, 2, 2, 1],\n    [2, 2, 3, 2, 1, 1],\n    [2, 2, 1, 1, 3, 2],\n    [2, 2, 1, 2, 3, 1],\n    [2, 1, 3, 2, 1, 2],\n    [2, 2, 3, 1, 1, 2],\n    [3, 1, 2, 1, 3, 1],\n    [3, 1, 1, 2, 2, 2],\n    [3, 2, 1, 1, 2, 2],\n    [3, 2, 1, 2, 2, 1],\n    [3, 1, 2, 2, 1, 2],\n    [3, 2, 2, 1, 1, 2],\n    [3, 2, 2, 2, 1, 1],\n    [2, 1, 2, 1, 2, 3],\n    [2, 1, 2, 3, 2, 1],\n    [2, 3, 2, 1, 2, 1],\n    [1, 1, 1, 3, 2, 3],\n    [1, 3, 1, 1, 2, 3],\n    [1, 3, 1, 3, 2, 1],\n    [1, 1, 2, 3, 1, 3],\n    [1, 3, 2, 1, 1, 3],\n    [1, 3, 2, 3, 1, 1],\n    [2, 1, 1, 3, 1, 3],\n    [2, 3, 1, 1, 1, 3],\n    [2, 3, 1, 3, 1, 1],\n    [1, 1, 2, 1, 3, 3],\n    [1, 1, 2, 3, 3, 1],\n    [1, 3, 2, 1, 3, 1],\n    [1, 1, 3, 1, 2, 3],\n    [1, 1, 3, 3, 2, 1],\n    [1, 3, 3, 1, 2, 1],\n    [3, 1, 3, 1, 2, 1],\n    [2, 1, 1, 3, 3, 1],\n    [2, 3, 1, 1, 3, 1],\n    [2, 1, 3, 1, 1, 3],\n    [2, 1, 3, 3, 1, 1],\n    [2, 1, 3, 1, 3, 1],\n    [3, 1, 1, 1, 2, 3],\n    [3, 1, 1, 3, 2, 1],\n    [3, 3, 1, 1, 2, 1],\n    [3, 1, 2, 1, 1, 3],\n    [3, 1, 2, 3, 1, 1],\n    [3, 3, 2, 1, 1, 1],\n    [3, 1, 4, 1, 1, 1],\n    [2, 2, 1, 4, 1, 1],\n    [4, 3, 1, 1, 1, 1],\n    [1, 1, 1, 2, 2, 4],\n    [1, 1, 1, 4, 2, 2],\n    [1, 2, 1, 1, 2, 4],\n    [1, 2, 1, 4, 2, 1],\n    [1, 4, 1, 1, 2, 2],\n    [1, 4, 1, 2, 2, 1],\n    [1, 1, 2, 2, 1, 4],\n    [1, 1, 2, 4, 1, 2],\n    [1, 2, 2, 1, 1, 4],\n    [1, 2, 2, 4, 1, 1],\n    [1, 4, 2, 1, 1, 2],\n    [1, 4, 2, 2, 1, 1],\n    [2, 4, 1, 2, 1, 1],\n    [2, 2, 1, 1, 1, 4],\n    [4, 1, 3, 1, 1, 1],\n    [2, 4, 1, 1, 1, 2],\n    [1, 3, 4, 1, 1, 1],\n    [1, 1, 1, 2, 4, 2],\n    [1, 2, 1, 1, 4, 2],\n    [1, 2, 1, 2, 4, 1],\n    [1, 1, 4, 2, 1, 2],\n    [1, 2, 4, 1, 1, 2],\n    [1, 2, 4, 2, 1, 1],\n    [4, 1, 1, 2, 1, 2],\n    [4, 2, 1, 1, 1, 2],\n    [4, 2, 1, 2, 1, 1],\n    [2, 1, 2, 1, 4, 1],\n    [2, 1, 4, 1, 2, 1],\n    [4, 1, 2, 1, 2, 1],\n    [1, 1, 1, 1, 4, 3],\n    [1, 1, 1, 3, 4, 1],\n    [1, 3, 1, 1, 4, 1],\n    [1, 1, 4, 1, 1, 3],\n    [1, 1, 4, 3, 1, 1],\n    [4, 1, 1, 1, 1, 3],\n    [4, 1, 1, 3, 1, 1],\n    [1, 1, 3, 1, 4, 1],\n    [1, 1, 4, 1, 3, 1],\n    [3, 1, 1, 1, 4, 1],\n    [4, 1, 1, 1, 3, 1],\n]\n\n# Data — encode a shipping label\ncontent = \"SHIP-2024-ABC123\"\n\n# Build the barcode pattern\npattern = []\npattern.extend(START_B)\n\nchecksum = 104  # Start B value\nfor i, char in enumerate(content):\n    if char in CODE128_PATTERNS:\n        pattern.extend(CODE128_PATTERNS[char])\n        checksum += CODE128_VALUES.get(char, 0) * (i + 1)\n\ncheck_value = checksum % 103\nif check_value < len(CHECK_PATTERNS):\n    pattern.extend(CHECK_PATTERNS[check_value])\n\npattern.extend(STOP)\n\n# Convert pattern to bar rectangles\nbars_data = []\nx = 0\nis_bar = True  # Start with bar (dark)\nfor width in pattern:\n    if is_bar:\n        bars_data.append({\"x\": x, \"x2\": x + width, \"y\": 0, \"y2\": 1, \"encoded\": f\"Code 128B: {content}\"})\n    x += width\n    is_bar = not is_bar\n\ntotal_width = x\n\n# Add quiet zones (10% on each side)\nquiet_zone = total_width * 0.1\nfor bar in bars_data:\n    bar[\"x\"] += quiet_zone\n    bar[\"x2\"] += quiet_zone\ntotal_width_with_zones = total_width + 2 * quiet_zone\n\ndf_bars = pd.DataFrame(bars_data)\ndf_text = pd.DataFrame([{\"x\": total_width_with_zones / 2, \"y\": -0.15, \"text\": content}])\n\n# Barcode bars — theme-adaptive INK color, tooltip shows encoded content\nbars_chart = (\n    alt.Chart(df_bars)\n    .mark_rect(color=\"#1A1A17\")\n    .encode(\n        x=alt.X(\"x:Q\", scale=alt.Scale(domain=[0, total_width_with_zones]), axis=None),\n        x2=\"x2:Q\",\n        y=alt.Y(\"y:Q\", scale=alt.Scale(domain=[-0.3, 1.1]), axis=None),\n        y2=\"y2:Q\",\n        tooltip=[alt.Tooltip(\"encoded:N\", title=\"Encoded\")],\n    )\n)\n\n# Human-readable text below barcode\ntext_chart = (\n    alt.Chart(df_text)\n    .mark_text(fontSize=20, font=\"monospace\", fontWeight=\"bold\", color=\"#1A1A17\")\n    .encode(x=\"x:Q\", y=\"y:Q\", text=\"text:N\")\n)\n\nchart = (\n    (bars_chart + text_chart)\n    .properties(\n        width=620,\n        height=320,\n        background=PAGE_BG,\n        padding={\"left\": 0, \"right\": 0, \"top\": 0, \"bottom\": 0},\n        title=alt.Title(\"barcode-code128 · python · altair · anyplot.ai\", fontSize=16, anchor=\"middle\", color=INK),\n    )\n    .interactive()\n    .configure_view(strokeWidth=0, fill=\"#FAF8F1\", continuousWidth=620, continuousHeight=320)\n    .configure_title(color=INK)\n)\n\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\n# PAD to canonical 3200×1800 — vl-convert leaves chart undersized; never crop\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\nchart.save(f\"plot-{THEME}.html\")\n"}