The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

使用 Code 128 字型建立 Code 128 (ISO/IEC 15417:2007) 條碼的注意事項

最近有專案需要在報表上顯示 Code 128 條碼,但負責這個功能的開發人員會遇到特定文字產生的條碼無法被掃描/辨識的問題。由於我之前沒有親手處理過 Code 128 條碼,所以藉此研究了一下 Code 128 條碼的產生過程,特別用這篇文章筆記一下整個過程。

理解 Code 128 格式

如果透過 Code 128 Font 字型來呈現條碼的話,如果文件上的文字沒有照 Code 128 的規則排列文字的話,產生的字型是無法辨識的,所以開發人員必須理解 Code 128 條碼的排列規則!

Code 128 其實是一種編碼規則,他可以支援完整的 128 個 ASCII 字元,其中包括大寫英文、小寫英文、數字、符號、控制字元等等。

Code 128 也可以包含定義在 ISO/IEC 8859-1 編碼中的 Latin-1 拉丁字集中的所有文字,不過要編碼 ISO 8859-1 的文字需要搭配 FNC4 ("Function 4") 特殊字元才能用,而且並非所有掃描器有支援這種格式!所以 Latin-1 字集中的文字,不在本文的探討範圍。

Code 128 雖然支援 128 個字元,但區分成 3 種字元集,你在建立條碼之前,要先思考你要將什麼文字資料編碼成 Code 128 格式,然後決定一個字元集來進行編碼運算。

以下就是這 3 種字元集的字碼範圍:

  • 128A (Code Set A) – ASCII characters 00 to 95 (0–9, A–Z and control codes), special characters, and FNC 1–4

    大寫英文、數字、符號、控制字元

  • 128B (Code Set B) – ASCII characters 32 to 127 (0–9, A–Z, a–z), special characters, and FNC 1–4

    大寫英文、數字、符號、小寫英文

  • 128C (Code Set C) – 00–99 (encodes two digits with a single code point) and FNC1

    連續數字

    相較於 Code 39 來說,Code 128 可以產生較為精簡的條碼格式。那是因為 Code 128 特別針對只有「數字」的組合,設計了一組 128C (Code Set C) 字元集,讓你可以用「兩個數字」只需要輸出一種符號(條碼),因此可以產生較小的條碼!

如果你想輸出的條碼只有「數字」的話,這三種字集都可以使用,但是選擇 128C (Code Set C) 可以產生最短的條碼,如果是螢幕顯示就沒差多少,但若要印出來的話,可以節省印表機的油墨,降低條碼列印的成本。

如果你想輸出的條碼只有「大寫英文」與「數字」的話,可以使用 128A128B 字集。

如果你想輸出的條碼包含「小寫英文」字母的話,就只能用 128B 字集了!

產生可與 Code 128 字型搭配的文字資料

瞭解 Code 128 的基本概念後,接下來就要瞭解 Code 128 是如何與字型檔搭配的了!

基本上,一個 Code 128 條碼包含 7 大區塊:

  1. (留白區) Quiet zone
  2. (開始碼) Start symbol
  3. (編碼資料) Encoded data
  4. (檢查碼) Check symbol (mandatory)
  5. (結束碼) Stop symbol
  6. (結束棒) Final bar (often considered part of the stop symbol)
  7. (留白區) Quiet zone

要搭配 Code 128 字型輸出條碼的話,只需要知道 開始碼 + 編碼資料 + 檢查碼 + 結束碼 就可以產生出合規的 Code 128 條碼!

  1. 開始碼 (Start symbol)

    由於 Code 128 區分成 3 種字元集,這裡的「開始碼」將會決定你選用哪種字元集。

    • 128A (Code Set A) – 使用 Ë 字元 ( Value = 103 )
    • 128B (Code Set B) – 使用 Ì 字元 ( Value = 104 )
    • 128C (Code Set C) – 使用 Í 字元 ( Value = 105 )

    依據你選用的 Code 128 字型,上述字元所對應到字型中的條碼不盡相同,以 128A (Code Set A) 為例,大多字型都是使用 Ë 字元,少部分字型使用 Ð 字元,若是 Barcodesoft 出品的字型則會用 ø 字元。本文建議使用 Fonts2u 的 Code 128 字型,就是屬於比較常見的字型。

    image

  2. 編碼資料 (Encoded data)

    搭配 Code 128 字型輸出條碼的話,這裡的資料不用額外轉換,直接輸出即可。

  3. 檢查碼 (Check symbol)

    這裡是 Code 128 最複雜的部分,因為你要透過一套公式,計算出一個驗證碼(數字),然後再透過驗證碼計算出一個檢查碼字元(文字)。

    雖然在 Code 128 的 Wikipedia 都有寫到完整的計算過程,還有一張大表可以參考,但是第一次面對 Code 128 的人其實沒有很好理解。稍後你會看到完整的 C# 實作程式碼,大家直接看 Code 說故事,可能會比生硬的文字來的容易理解,我都有補上完整註解。

  4. 結束碼 (Stop symbol)

    結束碼無論用哪種字元集都固定為 Î 字元。

以下就是我的 C# 程式碼實作:

// 開始碼
var startSymbol = "Ë";
// 這是我們要進行編碼的資料
var encodedData = "177345239061003";
// 檢查碼
var checkSymbol = "";
// 結束碼
var stopSymbol  = "Î";

// 預設使用 Code Set A ( 128A ) 字元集
Code128Type type = Code128Type.CodeSetA;

// 如果有小寫字元就改用 Code Set B ( 128B ) 字元集
if (Regex.IsMatch(encodedData, "[a-z]"))
{
  type = Code128Type.CodeSetB;
}

// 不同的 Code 128 字元集會使用不同的開始碼,其 checksum (驗證碼) 的起算點也會不一樣
var checksum = 0;
switch (type)
{
  case Code128Type.CodeSetA:
    startSymbol = "Ë";
    checksum = 103;
    break;
  case Code128Type.CodeSetB:
    startSymbol = "Ì";
    checksum = 104;
    break;
  case Code128Type.CodeSetC:
    startSymbol = "Í";
    checksum = 105;
    break;
  default:
    throw new ArgumentException("錯誤的 Code128Type 類型", "type");
}

// 你必須一個字元、一個字元拆開計算驗證碼(checksum)
var chars = encodedData.ToCharArray();

for (int i = 0; i < chars.Length; i++)
{
  // 取得字元的位置,從 1 開始
  var position = i + 1;
  // 這裡必須計算該字元在 Code 128 中的 Value 是多少
  var value = 0;
  // 其實 Value 可以不用查表,你可以透過 ASCII 的字碼轉換成 Value 值
  var asciiasc = (int)chars[i];
  if (asciiasc >= 32)
  {
    value = asciiasc - 32;
    checksum += value * position;
  }
  else
  {
    value = asciiasc + 64;
    checksum += value * position;
  }
}

// 驗證碼最終要取 103 的餘數
checksum = checksum % 103;

// 驗證碼轉檢查也不用查表,透過以下公式即可轉換出字元
if (checksum < 95)
{
  checkSymbol = char.ConvertFromUtf32(checksum + 32);
}
else
{
  checkSymbol = char.ConvertFromUtf32(checksum + 100);
}

// 取得最終結果
var result = startSymbol + encodedData + checkSymbol + stopSymbol;

result.Dump();

public enum Code128Type
{
  CodeSetA,
  CodeSetB,
  CodeSetC
}

試算可輸出 Code 128 條碼的文字

假設我們想進行 Code 128 編碼的文字為 177345239061003,那麼我們可以選用任何字集進行計算,以下我就以 Code Set A (128A) 來進行運算:

  1. 開始碼 (Start symbol)

    128A (Code Set A) 使用 Ë 字元。

  2. 編碼資料 (Encoded data)

    直接輸出 177345239061003 文字。

  3. 檢查碼 (Check symbol)

    image

    最後計算出來為 Å 字元。

  4. 結束碼 (Stop symbol)

    固定為 Î 字元。

四個部分全部組合起來就是:Ë177345239061003ÅÎ

測試 Code 128 條碼

  1. 下載並安裝 GNU GPL 授權的 Code 128 Font 字型

  2. 開啟 Microsoft Word 並新增空白文件

  3. 貼上文字:Ë177345239061003ÅÎ

  4. 將這段文字的調整使用 Code 128 字型顯示,此時這段文字就會變成 Code 128 條碼的樣子!

    Code 128 in Microsoft Word

  5. 使用手機測試掃描這份 Code 128 條碼,看是否可以正確辨識!👍

相關連結

留言評論