0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

バーコード(コード 128:JIS X 0504 (ISO/IEC 15417) )の生成

Last updated at Posted at 2021-12-08

JIS X 0504 (ISO/IEC 15417) 規格のバーコード(HTMLとGIF画像)を JavaScript で生成します。

実行画面とソース

スクリーンショット

ソース(HTML+JavaScript)

動作確認した環境
 macOS 12.0.1
 Safari: 15.1
 Microsoft Edge: 96.0.1054.43
 Google Chrome: 96.0.4664.93
 FireFox: 95.0
 Opera: 82.0.4227.23

sample.html
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
    <title>バーコード(コード 128):JIS X 0504 (ISO/IEC 15417)</title>
  </head>
  <body>
    <h3>JIS X 0504 (ISO/IEC 15417) 規格</h3>
    <hr>
    <p>バーコード(コード 128)をローカル(JavaScript)で生成します。</p>
    <p>
      <input
        type="text"
        id="gbcinp" size="50"
        placeholder="ここに半角文字を入力"
        style="font-size: large;"
        oninput="genBarCode128()"
        />
    </p>
    <div>HTMLによるバーコード</div><blockquote id="gbcout"></blockquote>
    <div>GIF画像によるバーコード</div>
    <blockquote>
      <table style="border-collaspe: collaspe; border-spacing: 0;">
        <tr>
          <td id="gbcimg" style="border: solid 1px; margin: 0; padding: 0px 8px; font-size: xx-small;"></td>
          <td style="font-size: 12px; padding: 36px 1px;">&nbsp;</td>
        </tr>
      </table>
    </blockquote>
    <hr>
    <table id="chartab" style="border: solid 1px; border-collaspe: collaspe; border-spacing: 0;"></table>

    <script type="text/javascript">
    <!--
      function code128CharSet() {
          let tab = document.getElementById("chartab");
          if (true) {
              let tr = document.createElement('tr');
              let th = document.createElement('th');
              th.setAttribute("colspan", "16");
              th.style.setProperty('border', 'solid 1px');
              th.style.setProperty('padding', '5px 10px');
              th.innerText = "使用可能な文字";
              tr.appendChild(th);
              tab.appendChild(tr);
          }
          for (let y = 2; y < 16; y++) {
              let tr = document.createElement('tr');
              for (let x = 0; x < 16; x++) {
                  let td = document.createElement('td');
                  td.style.setProperty('border', 'solid 1px');
                  td.style.setProperty('padding', '5px 10px');
                  td.innerText = String.fromCharCode(y * 16 + x);
                  tr.appendChild(td);
              }
              tab.appendChild(tr);
          }
      }
      code128CharSet();
      // -->
    </script>

    <script type="text/javascript">
    <!--
      /* **************************************** */

      class GenBarCode128 {
          static CodeSet = { Shift: 98 };
          static CodeSetA = { Flag: 1, Start: 103, Next: 101, FNC4: 101 }
          static CodeSetB = { Flag: 2, Start: 104, Next: 100, FNC4: 100 }
          static CodeSetC = { Flag: 4, Start: 105, Next:  99 }
          static CodeSetX = { Flag: 8 }
          static CodeSetAB = { Flag: 3 }
          static CodeSetABC = { Flag: 7 }
          static CodeSetFlagTable = [
              +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
              +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
              +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3,
              +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
              +3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
              +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
              +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
              +9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
              +9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
              11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
              11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
              11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
              11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
              10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
              10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
          ]

          static CodePatternTable = [
              411, 435, 819, 201, 393, 401, 153, 281, 305, 147, 275, 291, 461, 473, 921, 413,
              441, 825, 627, 467, 915, 315, 371, 951, 407, 423, 807, 311, 359, 615, 219, 795,
              867, 197, 209, 785, 141, 177, 561, 139, 163, 547, 237, 909, 945, 221, 797, 881,
              887, 907, 931, 187, 571, 955, 215, 791, 839, 183, 567, 711, 759, 531, 655, 101,
              389, 105, 777, 417, 801,  77, 269,  89, 537, 353, 609, 579,  83, 751, 323, 753,
              485, 489, 969, 317, 377, 633, 303, 335, 591, 987, 891, 879, 245, 965, 977, 189,
              573, 175, 559, 989, 957, 983, 943, 267,  75, 459,
          ]
          static StopPattern = [1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1]
          static QuietPattern = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

          static byteToCodeSetA(b) { return (b < 32) ? (b + 64) : (b - 32); }
          static byteToCodeSetB(b) { return (b - 32); }
          static byteToCodeSetC(b) { return (b - 48); }

          static FlagToCodeSet = [
              undefined,
              { CodeSet: GenBarCode128.CodeSetA, byteToCodeSet: GenBarCode128.byteToCodeSetA },
              { CodeSet: GenBarCode128.CodeSetB, byteToCodeSet: GenBarCode128.byteToCodeSetB },
              { CodeSet: GenBarCode128.CodeSetB, byteToCodeSet: GenBarCode128.byteToCodeSetB },
              { CodeSet: GenBarCode128.CodeSetC, byteToCodeSet: GenBarCode128.byteToCodeSetC },
          ]

          constructor() {
              this.S = GenBarCode128;
              this.useQuietZone = true;
              this.useCodeSetC = true;
              this.data = [];
              this.charData = [];
              this.codeData = [];
          }

          buildCodeData(data) {
              this.data = data;
              this.makeCharData();
              this.checkCodeSetC();
              this.makeCodeSetSpan();
              this.updateCodeSet();
              this.makeFnc4Span();
              this.updateFnc4Code();
              this.makeCodeData();
          }

          makeCharData() {
              const S = this.S;
              const flagA = S.CodeSetA.Flag;
              const flagB = S.CodeSetB.Flag;
              const flagC = S.CodeSetC.Flag;
              const flagX = S.CodeSetX.Flag;
              const table = S.CodeSetFlagTable;

              let cdata = [];
              for (let b of this.data) {
                  let flag = table[b];
                  cdata.push({
                      flag: flag,
                      aflag: ((flag & flagA) != 0),
                      bflag: ((flag & flagB) != 0),
                      cflag: ((flag & flagC) != 0),
                      xflag: ((flag & flagX) != 0),
                      data: (b & 0x7f),
                      code: -1,
                      shift: false,
                      next: false,
                      xshift: false,
                      xenter: false,
                      xleave: false,
                  });
              }
              this.charData = cdata;
          }

          checkCodeSetC() {
              const S = this.S;
              const flagC = S.CodeSetC.Flag;
              let cdata = this.charData;
              let dilen = cdata.length;

              if (!this.useCodeSetC) {
                  this.clearCodeSetC(0, dilen);
                  return;
              }

              let cspan = [];
              let cindex = 0;
              let pf = false;
              for (let index = 0; index < dilen; index++) {
                  let di = cdata[index];
                  let nf = di.cflag;
                  if (pf != nf) {
                      if (pf)
                          cspan.push({ start: cindex, end: index });
                      cindex = index;
                      pf = nf;
                  }
              }
              if (pf)
                  cspan.push({ start: cindex, end: dilen });

              for (let span of cspan) {
                  let sc = span.start;
                  let ec = span.end;
                  let nc = ec - sc;

                  let bt = (sc == 0);
                  let be = (ec == dilen);
                  let odd = ((nc & 1) != 0);

                  let amove = false;
                  let pmove = false;
                  let nmove = false;
                  if (bt && be) {
                      amove = ((nc == 1) || (nc == 3));
                      nmove = odd;
                  } else {
                      amove = (nc < ((bt || be) ? 4 : 6));
                      if (be)
                          pmove = odd;
                      else
                          nmove = odd;
                  }

                  let mp = {
                      clear: { start: -1, end: -1 },
                      set: { start: -1, end: -1 }
                  };
                  if (amove)
                      mp.clear = { start: sc, end: ec };
                  else if (pmove)
                      mp = {
                          clear: { start: sc, end: sc+1 },
                          set: { start: sc+1, end: ec }
                      };
                  else if (nmove)
                      mp = {
                          set: { start: sc, end: ec-1 },
                          clear: { start: ec-1, end: ec }
                      };
                  else
                      mp.set = { start: sc, end: ec };
                  this.clearCodeSetC(mp.clear.start, mp.clear.end);
                  this.setCodeSetC(mp.set.start, mp.set.end);
              }
          }

          clearCodeSetC(start, end) {
              for (let index = start; index < end; index++)
                  this.disableCodeSetC(this.charData[index]);
          }

          setCodeSetC(start, end) {
              for (let index = start; index < end; index++)
                  this.enableCodeSetC(this.charData[index]);
          }

          disableCodeSetC(di) {
              if (!di.cflag) return;
              di.flag -= this.S.CodeSetC.Flag;
              di.cflag = false;
          }

          enableCodeSetC(di) {
              if (!di.cflag) return;
              di.flag = this.S.CodeSetC.Flag;
              di.aflag = false;
              di.bflag = false;
          }

          makeCodeSetSpan() {
              const S = this.S;
              const flagA = S.CodeSetA.Flag;
              const flagB = S.CodeSetB.Flag;
              const flagC = S.CodeSetC.Flag;
              const flagAB = S.CodeSetAB.Flag;
              const flagABC = S.CodeSetABC.Flag;

              let cdata = this.charData;
              let dilen = cdata.length;
              if (dilen == 0) return;

              let addspan = function(l, f, s, e) {
                  if (f == flagAB)
                      f = flagB;
                  let index = l.length;
                  l.push({
                      index: index,
                      flag: f,
                      shift: false,
                      next: false,
                      start: s,
                      end: e,
                  });
              }

              let cspan = [];
              let pindex = 0;
              let pflag = flagABC;
              for (let index = 0; index < dilen; index++) {
                  let di = cdata[index];
                  let nflag = di.flag & flagABC;
                  let mflag = pflag & nflag;
                  if (mflag != 0) {
                      pflag = mflag;
                      continue;
                  }
                  addspan(cspan, pflag, pindex, index);
                  pindex = index;
                  pflag = nflag;
              }
              if (pindex != dilen)
                  addspan(cspan, pflag, pindex, dilen);

              let csplen = cspan.length;
              for (let index = 1; index < csplen; index++) {
                  let psp = cspan[index - 1];
                  let nsp = cspan[index];
                  if ((psp.flag == flagC) ||
                      (nsp.flag == flagC)) {
                      nsp.next = true;
                      continue;
                  }
                  if (index == (csplen - 1)) {
                      nsp.next = !psp.shift;
                      continue;
                  }
                  let shift = ((nsp.end - nsp.start) < 3);
                  nsp.shift = shift;
                  nsp.next = !shift;
              }
              this.cspan = cspan;
          }

          updateCodeSet() {
              let cdata = this.charData;
              let ftable = this.S.FlagToCodeSet;
              for (let span of this.cspan) {
                  let top = span.start;
                  let end = span.end;
                  let flag = span.flag;
                  let shift = span.shift;
                  let b2cs = ftable[flag].byteToCodeSet;
                  cdata[top].next = span.next;
                  for (let i = top; i < end; i++) {
                      let di = cdata[i];
                      di.flag = flag;
                      di.shift = shift;
                      di.code = b2cs(di.data);
                  }
              }
          }

          makeFnc4Span() {
              let cdata = this.charData;
              let dilen = cdata.length;
              if (dilen == 0) return;

              let addspan = function(l, f, s, e) {
                  l.push({
                      flag: f,
                      start: s,
                      end: e,
                  });
              }

              let xspan = [];
              let pindex = 0;
              let pflag = false;
              for (let index = 0; index < dilen; index++) {
                  let di = cdata[index];
                  let nflag = di.xflag;
                  if (pflag == nflag)
                      continue;
                  addspan(xspan, pflag, pindex, index);
                  pindex = index;
                  pflag = nflag;
              }
              if (pindex != dilen)
                  addspan(xspan, pflag, pindex, dilen);
              this.xspan = xspan;
          }

          updateFnc4Code() {
              let cdata = this.charData;
              let dilen = cdata.length;
              for (let span of this.xspan) {
                  if (!span.flag)
                      continue;
                  let ss = span.start;
                  let es = span.end;
                  let ep = (es == dilen);
                  let ns = es - ss;
                  let nc = (ep ? 2 : 4);
                  if (ns < nc) {
                      for (let dp = ss; dp < es; dp++)
                          cdata[dp].xshift = true;
                      continue;
                  }
                  cdata[ss].xenter = true;
                  if (!ep)
                      cdata[es].xleave = true;
              }
          }

          makeCodeData() {
              let S = this.S;
              let Shift = S.CodeSet.Shift;
              let ftable = this.S.FlagToCodeSet;
              let cdata = this.charData;

              if (cdata.length == 0) {
                  this.codeData = [S.CodeSetA.Start];
                  return;
              }

              let pdi = cdata[0];
              let pcs = ftable[pdi.flag].CodeSet;
              let code = [pcs.Start];
              let cskip = false;
              let clast = 0;
              for (let di of cdata) {
                  let cs = ftable[di.flag].CodeSet;
                  let xleave = true;
                  if (di.xleave && di.cflag) {
                      code.push(pcs.FNC4);
                      code.push(pcs.FNC4);
                      xleave = false;
                  }
                  if (di.next)
                      code.push(cs.Next);
                  if (di.xenter || (xleave && di.xleave)) {
                      code.push(cs.FNC4);
                      code.push(cs.FNC4);
                  }
                  if (di.xshift)
                      code.push(cs.FNC4);
                  if (di.shift)
                      code.push(Shift);
                  if (!di.cflag)
                      code.push(di.code);
                  else {
                      if (cskip)
                          code.push(clast + di.code);
                      else
                          clast = di.code * 10;
                      cskip = !cskip;
                  }

                  pdi = di;
                  pcs = cs;
              }
              this.codeData = code;
          }

          addSymbolCheck() {
              let code = this.codeData;
              let clen = code.length;
              let sum = code[0];
              for (let index = 1; index < clen; index++)
                  sum += code[index] * index;
              code.push(sum % 103);
          }

          buildModule() {
              let S = this.S;
              let table = S.CodePatternTable;
              let r = [];
              for (let code of this.codeData) {
                  let bin = table[code];
                  for (let b = 0; b < 11; b++, bin >>= 1)
                      r.push(bin & 1);
              }
              r = r.concat(S.StopPattern);
              if (this.useQuietZone) {
                  let q = S.QuietPattern;
                  r = q.concat(r, q);
              }
              return r;
          }
      }

      class BarCode128FromString extends GenBarCode128 {
          static toByteList(s) {
              let bs = [];
              for (let index = 0; index < s.length; index++) {
                  let c = s.charCodeAt(index);
                  if ((c < 0) || (c >= 0x100))
                      throw ('unknown char: ' + c)
                  bs.push(c);
              }
              return bs;
          }

          constructor(s, useQuietZone=true, useCodeSetC=true) {
              super();

              let bs = BarCode128FromString.toByteList(s);
              this.useQuietZone = useQuietZone;
              this.useCodeSetC = useCodeSetC;
              this.buildCodeData(bs);
              this.addSymbolCheck();
          }
      }

      /* **************************************** */

      class GenBarCode128GIF {
          constructor(barcode, scale=2, height=20, padding={ top: 10, bottom: 10, left: 10, right:10 }) {
              let sbarcode = [];
              for (let b of barcode)
                  for (let n = 0; n < scale; n++)
                      sbarcode.push(b);
              let sheight = height * scale;
              let spadding = {
                  top: padding.top * scale,
                  bottom: padding.bottom * scale,
                  left: padding.left * scale,
                  right: padding.right * scale,
              }

              let width = padding.left + barcode.length + padding.right;
              let swidth = width * scale;

              let space = new Array(swidth);
              for (let x = 0; x < swidth; x++)
                  space[x] = 0;
              let raster = space.slice(0, spadding.left).concat(sbarcode, space.slice(0, spadding.right))

              let data = [];
              for (let y = 0; y < spadding.top; y++)
                  data = data.concat(space);
              for (let y = 0; y < sheight; y++)
                  data = data.concat(raster);
              for (let y = 0; y < spadding.bottom; y++)
                  data = data.concat(space);

              sheight += spadding.top + spadding.bottom;

              this.S = GenBarCode128GIF;
              this.width = swidth;
              this.height = sheight;
              this.source = data;

              this.binary = [
                  0x47, 0x49, 0x46, // Signature
                  0x38, 0x39, 0x61, // Version89a

                  // Logical Screen Descriptor
                  (swidth & 0xff), ((swidth >> 8) & 0xff),
                  (sheight & 0xff),((sheight >> 8) & 0xff),
                  0x91, 3, 49,

                  // Global Color Table
                  0xff, 0xff, 0xff,
                  0x00, 0x00, 0x00,
                  0xff, 0xff, 0xff,
                  0xff, 0xff, 0xff,

                  // Image Descriptor
                  0x2c,
                  0x00, 0x00,
                  0x00, 0x00,
                  (swidth & 0xff), ((swidth >> 8) & 0xff),
                  (sheight & 0xff),((sheight >> 8) & 0xff),
                  0,
              ];

              this.tableBasedImage();

              // Trailer
              this.binary.push(0x3b);
          }

          tableBasedImage() {
              this.buffer = [];
              this.bs_pos = 0;
              this.table = [];
              this.code_max = (1 << 12) - 1;

              let tree = [];
              let tree_size = this.code_max + 1;
              for (let i = 0; i < tree_size; i++)
                  tree.push({
                      code: i,
                      next: -1,
                      down: -1,
                      data: 0,
                  });
              this.tree = tree;

              this.bits_init = 3;
              this.encodeImage();

              this.binary.push(this.bits_init);
              this.pushSubBlock(this.buffer)
          }

          pushSubBlock(data) {
              let binary = this.binary;
              let buffer = this.buffer;
              let offset = 0;
              let size = buffer.length;
              while (size > 0) {
                  let count = size;
                  if (count > 255) count = 255;
                  binary = binary.concat([count], buffer.slice(offset, offset + count));
                  offset += count;
                  size -= count;
              }
              binary.push(0);
              this.binary = binary;
          }

          encodeImage() {
              let tree = this.tree;
              let bits_init = this.bits_init;
              let bits_curr = bits_init + 1;
              let code_max = this.code_max;
              let code_clear = (1 << bits_init);
              let code_end = code_clear + 1;
              let code_curr = code_end;
              let code_step = (1 << bits_curr);

              let source = this.source;
              this.bs_pos = 0;
              this.buffer = [];
              this.bsWrite(code_clear, bits_curr);
              if (source.length == 0) {
                  this.bsWrite(code_end, bits_curr);
                  return;
              }

              let s_curr = source.values();
              let s_data = s_curr.next();
              for (;;) {
                  let c_curr = s_data.value;
                  let data = c_curr;
                  lzw4: for (;;) {
                      s_data = s_curr.next();
                      if (s_data.done) {
                          this.bsWrite(c_curr, bits_curr);
                          this.bsWrite(code_end, bits_curr);
                          return;
                      }
                      data = s_data.value;
                      let next = tree[c_curr].down;
                      for (;;) {
                          if (next < 0)
                              break lzw4;
                          let ntree = tree[next];
                          if (data == ntree.data)
                              break;
                          next = ntree.next;
                      }
                      c_curr = next;
                  }
                  this.bsWrite(c_curr, bits_curr);
                  {
                      let node = tree[c_curr];
                      let next = tree[++code_curr];
                      next.code = code_curr;
                      next.next = node.down;
                      next.down = -1;
                      next.data = data;
                      node.down = code_curr;
                  }
                  if (code_curr < code_step)
                      continue;
                  if (code_curr < code_max) {
                      bits_curr++
                      code_step <<= 1;
                      if (code_step < code_max)
                          continue;
                      code_step = code_max;
                      continue;
                  }
                  this.bsWrite(code_clear, bits_curr);
                  this.clearTree();
                  bits_curr = bits_init + 1;
                  code_curr = code_end;
                  code_step = (1 << bits_curr);
              }
          }

          clearTree() {
              let tree = this.tree;
              let tsz = (1 << this.bits_init);
              for (let i = 0; i < tsz; i++) {
                  let node = tree[i];
                  node.code = i;
                  node.next = -1;
                  node.down = -1;
                  node.data = 0;
              }
          }

          bsWrite(data, bits) {
              let buffer = this.buffer;
              let bpos = this.bs_pos;
              let idxs = (bpos >> 3);
              let idxe = ((bpos + bits - 1) >> 3);
              data <<= (bpos & 7);
              if (idxs < buffer.length) {
                  buffer[idxs] |= (data & 0xff);
                  data >>= 8;
                  idxs++;
              }
              while (idxs <= idxe) {
                  buffer.push(data & 0xff);
                  data >>= 8;
                  idxs++;
              }
              this.bs_pos = bpos + bits;
          }

          buildBase64() {
              let table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
              let padding = ['', '==', '='];
              let data = this.binary;
              let dlen = data.length;
              let drem = dlen % 3;
              let dsiz = dlen - drem;
              let b0 = 0;
              let b1 = 0;
              let b2 = 0;
              let d = 0;
              let s = '';
              let i = 0;
              for (i = 0; i < dsiz;) {
                  b0 = data[i++];
                  b1 = data[i++];
                  b2 = data[i++];
                  d = (b0 << 16) | (b1 << 8) | b2;
                  s += table[(d >> 18) & 0x3f];
                  s += table[(d >> 12) & 0x3f];
                  s += table[(d >> 6) & 0x3f];
                  s += table[d & 0x3f];
              }
              if (drem == 0)
                  return s;
              b0 = data[i++];
              if (drem == 1)
                  b1 = data[i++];
              d = (b0 << 16) | (b1 << 8);
              s += table[(d >> 18) & 0x3f];
              s += table[(d >> 12) & 0x3f];
              if (drem == 2)
                  s += table[(d >> 6) & 0x3f];
              return (s + padding[drem]);
          }
      }

      /* **************************************** */

      function createHTMLBarCode128(p) {
          const tdcolor = ['white', 'black'];
          const priority = 'important';

          let table = document.createElement('table');
          table.style.setProperty('background-color', 'white', priority);
          table.style.setProperty('border-collaspe', 'collaspe', priority);
          table.style.setProperty('border-spacing', '0', priority);
          table.style.setProperty('margin', '0', priority);
          table.style.setProperty('border', 'solid 1px', priority);
          table.style.setProperty('padding', '32px', priority);

          let tr = document.createElement('tr');
          for (let b of p) {
              let td = document.createElement('td');
              td.style.setProperty('background-color', tdcolor[b], priority);
              td.style.setProperty('color', tdcolor[b], priority);
              td.style.setProperty('font-size', 'xx-small', priority);
              td.style.setProperty('margin', '0', priority);
              td.style.setProperty('border', '0', priority);
              td.style.setProperty('padding', '20px 1px', priority);
              tr.appendChild(td);
          }
          table.appendChild(tr);
          return table;
      }

      /* **************************************** */

      function genBarCode128() {
          let clearChild = function(e) {
              while (e.firstChild)
                  e.removeChild(e.firstChild);
          }
          let setError = function(e, msg) {
              const priority = 'important';
              let table = createHTMLBarCode128([]);
              let tr = table.firstChild;
              let td = document.createElement('td');
              td.style.setProperty('font-size', '12px', priority);
              td.style.setProperty('margin', '0', priority);
              td.style.setProperty('border', '0', priority);
              td.style.setProperty('padding', '11px 1px', priority);
              td.innerText = msg;
              tr.appendChild(td);

              clearChild(e);
              e.appendChild(table);
          }
          let setPattern = function(e, p) {
              let t = createHTMLBarCode128(p);
              clearChild(e);
              e.appendChild(t);
          }

          let clrImage = function(e, msg) {
              const priority = 'important';
              let span = document.createElement('span');
              span.style.setProperty('font-size', '12px', priority);
              span.style.setProperty('padding', '0px 26px', priority);
              span.innerText = msg;
              clearChild(e);
              e.appendChild(span);
          }
          let setImage = function(e, p) {
              const priority = 'important';
              let bcimage = new GenBarCode128GIF(pattern);
              let b64s = bcimage.buildBase64();
              let img = document.createElement('img');
              img.setAttribute('src', 'data:image/gif;charset=utf-8;base64,' + b64s);
              img.style.setProperty('margin', '0', priority);
              img.style.setProperty('padding', '0px 4px', priority);
              img.style.setProperty('image-rendering', 'pixelated');

              clearChild(e);
              e.appendChild(img);
          }

          let setMessage = function(dom, img, msg) {
              setError(dom, msg);
              clrImage(img, msg);
          }

          let inp = document.getElementById("gbcinp");
          let out = document.getElementById("gbcout");
          let img = document.getElementById("gbcimg");

          let str = inp.value;
          if (str.length == 0) {
              setMessage(out, img, '(待機中)');
              return;
          }

          let pattern = [];
          try {
              let barcode = new BarCode128FromString(str);
              pattern = barcode.buildModule();
              setPattern(out, pattern);
              setImage(img, pattern);
          } catch (e) {
              setMessage(out, img, '(エラー:非対応の文字が使用されています)');
          }
      }
      genBarCode128();

      /* **************************************** */
      // -->
    </script>
  </body>
</html>
旧バージョンのソース(HTML+JavaScript)

動作確認した環境
 macOS 12.0.1
 Safari: バージョン15.1 (17612.2.9.1.20)
 Microsoft Edge: バージョン 96.0.1054.43
 Google Chrome: 96.0.4664.55
 FireFox: 95.0

sample.html
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
    <title>バーコード(コード 128):JIS X 0504 (ISO/IEC 15417)</title>
  </head>
  <body>
    <h3>JIS X 0504 (ISO/IEC 15417) 規格(コード 128)のバーコード生成</h3>
    <p>バーコードをローカル(JavaScript)で生成します。</p>
    <p>
      <input type="button" value="生成" onclick="genBarCode();" />
      <input type="text" id="gbcinp" size="50" placeholder="ここに半角文字を入力" style="font-size: large;" />
    </p>
    <p style="font-size: small;">ここで対応している文字は半角(7ビット文字)のみです。</p>
    <p style="font-size: small;">注意:コードセットC(数値二桁)による短縮は非対応です。</p>
    <p id="gbcout">(待機中)</p>

    <script type="text/javascript">
    <!--
      /* **************************************** */

      const BARCODE_CSET_A2C = 99;
      const BARCODE_CSET_B2C = 99;
      const BARCODE_CSET_A2B = 100;
      const BARCODE_CSET_B2A = 101;
      const BARCODE_CSET_C2B = 100;
      const BARCODE_CSET_C2A = 101;

      const BARCODE_START_A = 103;
      const BARCODE_START_B = 104;
      const BARCODE_START_C = 105;

      const BARCODE_PATTERN = [
          411, 435, 819, 201, 393, 401, 153, 281, 305, 147, 275, 291, 461, 473, 921, 413,
          441, 825, 627, 467, 915, 315, 371, 951, 407, 423, 807, 311, 359, 615, 219, 795,
          867, 197, 209, 785, 141, 177, 561, 139, 163, 547, 237, 909, 945, 221, 797, 881,
          887, 907, 931, 187, 571, 955, 215, 791, 839, 183, 567, 711, 759, 531, 655, 101,
          389, 105, 777, 417, 801,  77, 269,  89, 537, 353, 609, 579,  83, 751, 323, 753,
          485, 489, 969, 317, 377, 633, 303, 335, 591, 987, 891, 879, 245, 965, 977, 189,
          573, 175, 559, 989, 957, 983, 943, 267,  75, 459,
      ];
      const BARCODE_STOP = [1,1,0,0,0,1,1,1,0,1,0,1,1];
      const BARCODE_QUIET = [0,0,0,0,0,0,0,0,0,0];

      /* **************************************** */

      const BARCODE_CSET_A = 1;
      const BARCODE_CSET_B = 2;
      const BARCODE_CSET_C = 4;
      const BARCODE_CSET_X = 8;

      const BARCODE_CSET_AB = 1 + 2;
      const BARCODE_CSET_ABC = 1 + 2 + 4;

      const BARCODE_CSET = [
          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
          3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3,
          3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
          3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
          2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
          2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
      ];

      /* **************************************** */

      function gbcGetStrType(s)
      {
          let r = []

          for (let i in s)
          {
              let c = s.charCodeAt(i);

              if (c < 128)
                  r.push(BARCODE_CSET[c]);
              else
                  r.push(BARCODE_CSET_X);
          }
          return r;
      }

      function gbcCompStrType(stl)
      {
          if (stl.length == 0)
              return [0, 0];

          let r = []
          let t = stl[0];
          let n = 0;
          for (let i in stl)
          {
              let u = t & stl[i];

              if (u != 0)
              {
                  t = u;
                  n += 1;
                  continue;
              }

              r.push([n, t]);
              t = stl[i];
              n = 1;
          }
          r.push([n, t]);
          return r;
      }

      function gbcGetCodeSet(pt, nt)
      {
          if (pt == 0)
          {
              if ((nt & BARCODE_CSET_A) != 0)
                  return BARCODE_START_A;
              if ((nt & BARCODE_CSET_B) != 0)
                  return BARCODE_START_B;
              if ((nt & BARCODE_CSET_C) != 0)
                  return BARCODE_START_C;
              throw 'unknown code set';
          }
          if ((pt & BARCODE_CSET_A) != 0)
          {
              if ((nt & BARCODE_CSET_B) != 0)
                  return BARCODE_CSET_A2B;
              if ((nt & BARCODE_CSET_C) != 0)
                  return BARCODE_CSET_A2C;
              throw 'unknown code set';
          }
          if ((pt & BARCODE_CSET_B) != 0)
          {
              if ((nt & BARCODE_CSET_A) != 0)
                  return BARCODE_CSET_B2A;
              if ((nt & BARCODE_CSET_C) != 0)
                  return BARCODE_CSET_B2C;
              throw 'unknown code set';
          }
          if ((pt & BARCODE_CSET_C) != 0)
          {
              if ((nt & BARCODE_CSET_B) != 0)
                  return BARCODE_CSET_C2B;
              if ((nt & BARCODE_CSET_C) != 0)
                  return BARCODE_CSET_C2A;
              throw 'unknown code set';
          }
          throw 'unknown code set';
      }

      function gbcGetCodeSetA(c)
      {
          if (c < 32)
              return (c + 96);
          if (c < 96)
              return (c - 32);
          throw ('invalid code (A):' + c);
      }

      function gbcGetCodeSetB(c)
      {
          if (32 <= c && c < 128)
              return (c - 32);
          throw ('invalid code (B):' + c);
      }

      function gbcGetCodeSetFunc(t)
      {
          if ((t & BARCODE_CSET_A) != 0)
              return gbcGetCodeSetA;
          if ((t & BARCODE_CSET_B) != 0)
              return gbcGetCodeSetB;
          throw 'unknown code set';
      }

      function gbcStrToCode(str, cst)
      {
          let r = []
          let si = 0;
          let pt = 0;

          for (let ct of cst)
          {
              let c = ct[0];
              let nt = ct[1];
              nt &= BARCODE_CSET_AB; /* コードセット C は非対応 */

              r.push(gbcGetCodeSet(pt, nt));
              pt = nt;

              let s2c = gbcGetCodeSetFunc(nt);
              for (let ci = 0; ci < c; ci++, si++)
              {
                  r.push(s2c(str.charCodeAt(si)));
              }
          }
          return r;
      }

      function gbcGetCheckCode(l)
      {
          let t = l[0];

          for (let i = 1; i < l.length; i++)
          {
              t += l[i] * i;
          }
          return (t % 103);
      }

      /* **************************************** */

      function gbcCodeToPattern(c)
      {
          let p = BARCODE_PATTERN[c];
          let r = [];

          for (let b = 0; b < 11; b++)
          {
              r.push(p & 1);
              p >>= 1;
          }
          return r;
      }

      function gbcMakePattern(l)
      {
          let pl = [];
          for (let c of l)
          {
              pl = pl.concat(gbcCodeToPattern(c));
          }

          let pc = gbcCodeToPattern(gbcGetCheckCode(l));

          return BARCODE_QUIET.concat(pl, pc, BARCODE_STOP, BARCODE_QUIET);
      }

      function gbcStrToPattern(str)
      {
          let stl = gbcGetStrType(str);
          let cst = gbcCompStrType(stl);
          let bcs = gbcStrToCode(str, cst);
          return gbcMakePattern(bcs);
      }

      /* **************************************** */

      function gbcClearChild(e)
      {
          while (e.firstChild)
              e.removeChild(e.firstChild);
      }

      function gbcSetError(e, msg)
      {
          let m = document.createElement('div');

          m.innerText = msg;
          gbcClearChild(e);
          e.appendChild(m);
      }

      function gbcSetPattern(e, p)
      {
          const tdcolor = ['white', 'black'];
          let priority = 'important';

          let tab = document.createElement('table');

          tab.style.setProperty('background-color', 'white', priority);
          tab.style.setProperty('border-collaspe', 'collaspe', priority);
          tab.style.setProperty('border-spacing', '0', priority);
          tab.style.setProperty('margin', '0', priority);
          tab.style.setProperty('border', 'solid 1px', priority);
          tab.style.setProperty('padding', '32px', priority);

          let tr = document.createElement('tr');
          for (let b in p)
          {
              td = document.createElement('td');
              td.style.setProperty('background-color', tdcolor[p[b]], priority);
              td.style.setProperty('color', tdcolor[p[b]], priority);
              td.style.setProperty('font-size', 'xx-small', priority);
              td.style.setProperty('margin', '0', priority);
              td.style.setProperty('border', '0', priority);
              td.style.setProperty('padding', '20px 1px', priority);
              tr.appendChild(td);
          }
          tab.appendChild(tr);

          gbcClearChild(e);
          e.appendChild(tab);
      }

      /* **************************************** */

      function genBarCode()
      {
          let inp = document.getElementById("gbcinp");
          let out = document.getElementById("gbcout");

          let str = inp.value;
          if (str.length == 0)
          {
              gbcSetError(out, '(待機中)');
              return;
          }

          try
          {     
              let bcp = gbcStrToPattern(str);
              gbcSetPattern(out, bcp);
          }
          catch (e)
          {
              gbcSetError(out, '(エラー:非対応の文字が使用されています)');
          }
      }

      // -->
    </script>
  </body>
</html>

コード 128 の構成

コード 128は、以下の要素で構成されています。

a b c d e f
■□■□■□ ■□■□■□ … ■□■□■□ ■□■□■□ ■□■□■□■
項目 内容
a 先頭クワイエットゾーン(余白)
b スタートキャラクタ
c データキャラクタ
d シンボルチェックキャラクタ
e ストップキャラクタ
f 末尾クワイエットゾーン(余白)

キャラクタの構成

ストップキャラクタを除いて、キャラクタは「黒と白」の対が三つ並んでいます。

ストップキャラクタは最後に「黒」があります。

これで、キャラクタ(バーコード)の最初は黒で、バーコードの最後も黒になります。

黒または白の幅

黒または白の幅は 4 種類あります。

1
2 ■■ □□
3 ■■■ □□□
4 ■■■■ □□□□

幅(1) の倍数です。幅(1)をモジュールと呼ぶようです。

キャラクタの幅およびパターン

キャラクタの幅は固定で、三対の黒白の幅の合計が 11 モジュールになります。

  例(35): ■□□□■□□□■■□

幅の異なるパターンで 0 から 105 の値を表します。

ストップキャラクタの幅は、2 モジュールの黒が追加されて、13 モジュールになります。

  ストップキャラクタ: ■■□□□■■■□■□ + ■■

キャラクタのパターン表
パターン
0 ■■□■■□□■■□□
1 ■■□□■■□■■□□
2 ■■□□■■□□■■□
3 ■□□■□□■■□□□
4 ■□□■□□□■■□□
5 ■□□□■□□■■□□
6 ■□□■■□□■□□□
7 ■□□■■□□□■□□
8 ■□□□■■□□■□□
9 ■■□□■□□■□□□
10 ■■□□■□□□■□□
11 ■■□□□■□□■□□
12 ■□■■□□■■■□□
13 ■□□■■□■■■□□
14 ■□□■■□□■■■□
15 ■□■■■□□■■□□
16 ■□□■■■□■■□□
17 ■□□■■■□□■■□
18 ■■□□■■■□□■□
19 ■■□□■□■■■□□
20 ■■□□■□□■■■□
21 ■■□■■■□□■□□
22 ■■□□■■■□■□□
23 ■■■□■■□■■■□
24 ■■■□■□□■■□□
25 ■■■□□■□■■□□
26 ■■■□□■□□■■□
27 ■■■□■■□□■□□
28 ■■■□□■■□■□□
29 ■■■□□■■□□■□
30 ■■□■■□■■□□□
31 ■■□■■□□□■■□
32 ■■□□□■■□■■□
33 ■□■□□□■■□□□
34 ■□□□■□■■□□□
35 ■□□□■□□□■■□
36 ■□■■□□□■□□□
37 ■□□□■■□■□□□
38 ■□□□■■□□□■□
39 ■■□■□□□■□□□
40 ■■□□□■□■□□□
41 ■■□□□■□□□■□
42 ■□■■□■■■□□□
43 ■□■■□□□■■■□
44 ■□□□■■□■■■□
45 ■□■■■□■■□□□
46 ■□■■■□□□■■□
47 ■□□□■■■□■■□
48 ■■■□■■■□■■□
49 ■■□■□□□■■■□
50 ■■□□□■□■■■□
51 ■■□■■■□■□□□
52 ■■□■■■□□□■□
53 ■■□■■■□■■■□
54 ■■■□■□■■□□□
55 ■■■□■□□□■■□
56 ■■■□□□■□■■□
57 ■■■□■■□■□□□
58 ■■■□■■□□□■□
59 ■■■□□□■■□■□
60 ■■■□■■■■□■□
61 ■■□□■□□□□■□
62 ■■■■□□□■□■□
63 ■□■□□■■□□□□
64 ■□■□□□□■■□□
65 ■□□■□■■□□□□
66 ■□□■□□□□■■□
67 ■□□□□■□■■□□
68 ■□□□□■□□■■□
69 ■□■■□□■□□□□
70 ■□■■□□□□■□□
71 ■□□■■□■□□□□
72 ■□□■■□□□□■□
73 ■□□□□■■□■□□
74 ■□□□□■■□□■□
75 ■■□□□□■□□■□
76 ■■□□■□■□□□□
77 ■■■■□■■■□■□
78 ■■□□□□■□■□□
79 ■□□□■■■■□■□
80 ■□■□□■■■■□□
81 ■□□■□■■■■□□
82 ■□□■□□■■■■□
83 ■□■■■■□□■□□
84 ■□□■■■■□■□□
85 ■□□■■■■□□■□
86 ■■■■□■□□■□□
87 ■■■■□□■□■□□
88 ■■■■□□■□□■□
89 ■■□■■□■■■■□
90 ■■□■■■■□■■□
91 ■■■■□■■□■■□
92 ■□■□■■■■□□□
93 ■□■□□□■■■■□
94 ■□□□■□■■■■□
95 ■□■■■■□■□□□
96 ■□■■■■□□□■□
97 ■■■■□■□■□□□
98 ■■■■□■□□□■□
99 ■□■■■□■■■■□
100 ■□■■■■□■■■□
101 ■■■□■□■■■■□
102 ■■■■□■□■■■□
103 ■■□■□□□□■□□
104 ■■□■□□■□□□□
105 ■■□■□□■■■□□
黒白の幅表
[2,1,2,2,2,2], [2,2,2,1,2,2], [2,2,2,2,2,1], [1,2,1,2,2,3],
[1,2,1,3,2,2], [1,3,1,2,2,2], [1,2,2,2,1,3], [1,2,2,3,1,2],
[1,3,2,2,1,2], [2,2,1,2,1,3], [2,2,1,3,1,2], [2,3,1,2,1,2],
[1,1,2,2,3,2], [1,2,2,1,3,2], [1,2,2,2,3,1], [1,1,3,2,2,2],

[1,2,3,1,2,2], [1,2,3,2,2,1], [2,2,3,2,1,1], [2,2,1,1,3,2],
[2,2,1,2,3,1], [2,1,3,2,1,2], [2,2,3,1,1,2], [3,1,2,1,3,1],
[3,1,1,2,2,2], [3,2,1,1,2,2], [3,2,1,2,2,1], [3,1,2,2,1,2],
[3,2,2,1,1,2], [3,2,2,2,1,1], [2,1,2,1,2,3], [2,1,2,3,2,1],

[2,3,2,1,2,1], [1,1,1,3,2,3], [1,3,1,1,2,3], [1,3,1,3,2,1],
[1,1,2,3,1,3], [1,3,2,1,1,3], [1,3,2,3,1,1], [2,1,1,3,1,3],
[2,3,1,1,1,3], [2,3,1,3,1,1], [1,1,2,1,3,3], [1,1,2,3,3,1],
[1,3,2,1,3,1], [1,1,3,1,2,3], [1,1,3,3,2,1], [1,3,3,1,2,1],

[3,1,3,1,2,1], [2,1,1,3,3,1], [2,3,1,1,3,1], [2,1,3,1,1,3],
[2,1,3,3,1,1], [2,1,3,1,3,1], [3,1,1,1,2,3], [3,1,1,3,2,1],
[3,3,1,1,2,1], [3,1,2,1,1,3], [3,1,2,3,1,1], [3,3,2,1,1,1],
[3,1,4,1,1,1], [2,2,1,4,1,1], [4,3,1,1,1,1], [1,1,1,2,2,4],

[1,1,1,4,2,2], [1,2,1,1,2,4], [1,2,1,4,2,1], [1,4,1,1,2,2],
[1,4,1,2,2,1], [1,1,2,2,1,4], [1,1,2,4,1,2], [1,2,2,1,1,4],
[1,2,2,4,1,1], [1,4,2,1,1,2], [1,4,2,2,1,1], [2,4,1,2,1,1],
[2,2,1,1,1,4], [4,1,3,1,1,1], [2,4,1,1,1,2], [1,3,4,1,1,1],

[1,1,1,2,4,2], [1,2,1,1,4,2], [1,2,1,2,4,1], [1,1,4,2,1,2],
[1,2,4,1,1,2], [1,2,4,2,1,1], [4,1,1,2,1,2], [4,2,1,1,1,2],
[4,2,1,2,1,1], [2,1,2,1,4,1], [2,1,4,1,2,1], [4,1,2,1,2,1],
[1,1,1,1,4,3], [1,1,1,3,4,1], [1,3,1,1,4,1], [1,1,4,1,1,3],

[1,1,4,3,1,1], [4,1,1,1,1,3], [4,1,1,3,1,1], [1,1,3,1,4,1],
[1,1,4,1,3,1], [3,1,1,1,4,1], [4,1,1,1,3,1], [2,1,1,4,1,2],
[2,1,1,2,1,4], [2,1,1,2,3,2],

キャラクタとコードセット

キャラクタ(値)の 0 〜 105 に対して、コードセットは 3 種類(A,B,C)あります。

A B C
0 32 32 0
1 33 33 1
63 95 95 63
64 0 96 64
95 31 127 95
96 FNC3 FNC3 96
97 FNC2 FNC2 97
98 シフト シフト 98
99 コードC コードC 99
100 コードB FNC4 コードB
101 FNC4 コードA コードA
102 FNC1 FNC1 FNC1
103 スタートA スタートA スタートA
104 スタートB スタートB スタートB
105 スタートC スタートC スタートC

103,104,105 はスタートキャラクタで、コードセット(A,B,C)の初期指定になります。

101,100,99 は後続のコードセット(A,B,C)の指定になります。

98 のシフトは、後続の「1キャラクタ」をコードセット「A→B」または「B→A」にする指定となります。

FNC1,FNC2,FNC3,FNC4 はファンクションキャラクタです。この記事では FNC4(bit7情報の追加) のみ使用しています。

コードセット

コードセット A は ISO/IEC 646 IRV の文字(0 〜 95)が含まれます。

コードセット B は ISO/IEC 646 IRV の文字(32 〜 127)が含まれます。

0 〜 63 64 〜 95
A 32 〜 95 0 〜 31
B 32 〜 95 96 〜 127

コードセット C は 2 桁の数字(0 〜 99)を一つのキャラクタにします。

シンボルチェックキャラクタ

次の計算で、シンボルチェックキャラクタ(値)を算出します。

  スタートキャラクタ: D[0]
  データキャラクタ : D[1〜n]

  シンボルチェックキャラクタ: (D[0] + D[1]*1 + D[2]*2 + … + D[n]*n) % 103

クワイエットゾーン

バーコード前後の余白は、最小で 10 モジュールとされています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?