Blob Blame Raw

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <helianthus.h>

#include "svg-save.inc.h"



char codes[10][2][10] = {
  { "0001101", "0100111" }, // 0
  { "0011001", "0110011" }, // 1
  { "0010011", "0011011" }, // 2
  { "0111101", "0100001" }, // 3
  { "0100011", "0011101" }, // 4
  { "0110001", "0111001" }, // 5
  { "0101111", "0000101" }, // 6
  { "0111011", "0010001" }, // 7
  { "0110111", "0001001" }, // 8
  { "0001011", "0010111" }, // 9
};


int seed;
double pb = 10;
double pw = 298;
double ph = 210;
double bh = 15;
double th = 5;
double step = 0.5;


unsigned long long genNum()
  { return rand()%1000000ull*1000000 + rand()%1000000; }


void drawCode(FILE *f, unsigned long long num, double x, double y, double w, double h, double hh) {
  char numA[10] = {};
  char numB[10] = {};
  char code[] =
    "101"       // prefix
    "[digit][digit][digit][digit][digit][digit]"
    "01010"     // separator
    "[digit][digit][digit][digit][digit][digit]"
    "101";      // suffix
  int count = sizeof(code) - 1;
  char path[2048] = {};

  sprintf(numA, "%06d", (int)(num/1000000ull%1000000));
  sprintf(numB, "%06d", (int)(num%1000000));

  for(int i = 0; i < 6; ++i) {
    memcpy(code + 3 + i*7          , codes[numA[i]-'0'][0], 6);
    memcpy(code + 3 + 6*7 + 5 + i*7, codes[numB[i]-'0'][1], 6);
  }

  saveState();
  noFill();
  strokeWidth(w);
  char *p = path;
  for(int i = 0; i < count; ++i) {
    if (code[i] != '1') continue;
    int xl = i < 3
          || (i >= 3 + 6*7 && i < 3 + 6*7 + 5)
          || i >= 3 + 6*7 + 5 + 6*7;
    double hhh = xl ? h + hh : h;
    if (f) {
      p += sprintf(p, "M %g %g l 0 %g ", x+i*w, y, hhh);
    } else {
      line(x+i*w, y, x+i*w, y + hhh);
    }
  }

  if (f) {
    svgAddPath(f, path, w, FALSE);
    svgAddText(f, x + (3+2)*w, y + h + hh, hh, numA);
    svgAddText(f, x + (3+6*7+5+2)*w, y + h + hh, hh, numB);
  } else {
    textSize(hh);
    textAlign(HALIGN_CENTER, VALIGN_TOP);
    text(x + (3+3*7)*w, y + h, numA);
    text(x + (3+6*7+5+3*7)*w, y + h, numB);
  }
  restoreState();
}


void drawAllCodes(FILE *f) {
  srand(seed);

  double cw = step*(3 + 6*7 + 5 + 6*7 + 3);
  double minSpace = 9*step;
  double w = pw - 2*pb;
  double h = ph - 2*pb;
  int cols = (int)(w/(cw + minSpace) + 0.001);
  int rows = (int)(h/(bh + th + th) + 0.001);
  if (cols <= 0 || rows <= 0) return;

  double exw = w - cols*cw;
  double exh = h - rows*(bh+th);
  if (cols > 1) exw /= cols - 1;
  if (rows > 1) exh /= rows - 1;

  double cww = cw + exw;
  double chh = bh + th + exh;

  for(int r = 0; r < rows; ++r)
    for(int c = 0; c < cols; ++c)
      drawCode(f, genNum(), pb + c*cww, pb + r*chh, step, bh, th);
}


void generate() {
  seed = rand();
  FILE *f = svgBegin("data/output/generated-barcode.svg", pw, ph, 1);
  drawAllCodes(f);
  svgEnd(f);
}



void init() {
  generate();
}


void draw() {
  double w = windowGetWidth();
  double h = windowGetHeight();

  double kw = w/pw;
  double kh = h/ph;
  double k = kw < kh ? kw : kh;

  if (keyWentDown("space"))
    generate();

  saveState();
  translate(w/2, h/2);
  zoom(k);
  translate(-pw/2, -ph/2);
  noFill();
  strokeWidth(1);
  rect(0, 0, pw, ph);
  drawAllCodes(NULL);
  restoreState();
}


int main() {
  windowSetVariableFrameRate();
  windowSetResizable(TRUE);
  windowSetInit(&init);
  windowSetDraw(&draw);
  windowRun();
}