InDesignで様々なバーコード、特にJAN/EAN-13のような商品バーコードを扱うことがよくあります。
現代Javascriptでは色々バーコードを生成する無料ライブラリー沢山ありますが、ExtendScriptでは、その恩恵を受けていない。
JANコード裏にある複雑なエンコード仕様を理解して作れるが、大量な時間が必要ではないかと。 一方、考え方を変えると、描画されるまで、バーコードは一本一本の黒と白のバーの並びだけで、その並び順番分かれば、InDesignの作業は単純な描画作業になります。
バーコードデータの生成
まず、python-barcode(pip install python-barcode)ライブラリを使って、データとなる黒白のバーのシーケンスを取得します。
from barcode import JAN # 13桁のJANコードを指定 jan_code_str = "4901550151296" # JANコードオブジェクトを作成 code_obj = JAN(jan_code_str) # build()`メソッドは、バイナリ文字列を含むリストを返します。 # この長さ95の文字列が、EAN-13バーコードを構成する(左右のクワイエットゾーンを除いた)すべてのモジュールです。 # '1'と'0'で構成されるバーコードのシーケンスを取得 bar_sequence = code_obj.build()[0] print(bar_sequence) # '10100010110100111001100101******'
バーコードを描画
黒と白バーの順番分かれば、残りの作業は非常に簡単。appscriptを使ってInDesignで、生成したシーケンスに基づいて描画します。→効率を上げるため、黒いバーを一本ずつ描くのではなく、連続する黒いバーを一つの幅広の矩形にまとめて一度に描画します。
from barcode import JAN # pip3 install python-barcode
from appscript import app, k
id_app = app("Adobe InDesign 2024")
class InDesignJancodeMaker():
def __init__(self):
self.black_color = "Black"
self.white_color = "Paper"
def __find_true_segments(self, a: list):
"""
Finds the true segments in a given list.
Args:
a (list): The input list.
Returns:
list: A list of tuples representing the true segments.
Each tuple contains the start index and length of a true segment.
"""
true_segments = []
start = None
length = 0
for i, value in enumerate(a):
if value:
if start is None:
start = i
length += 1
else:
if start is not None:
true_segments.append((start, length))
start = None
length = 0
# handle the case where the list ends with a True segment
if start is not None:
true_segments.append((start, length))
return true_segments
def create_jancode(self, data: str, module_width=0.33,
module_height=22.85,
guard_bar_height=25.93,
left_quiet_zone=11, right_quiet_zone=7):
# https://internationalbarcodes.com/ean-13-specifications/
# unit: mm
# 13桁のJANコードを生成する。
# JAN-13/EAN-13の寸法
# 1モジュールの幅:0.33mm
# 左右のクワイエットゾーンを除く幅:31.35mm(0.33mm x 95モジュール)
# クワイエットゾーンを含めた幅:37.29mm(0.33mm x 113モジュール)
# 高さ(キャラクタのパターンのバー):22.85mm
# 左2本、右2本、中央2本のバーコードの高さ:25.93mm <--ヒゲ
if len(data) != 13: # TODO:JAN8の場合
raise ValueError("JAN code must be 13 digits.", data)
code_obj = JAN(data) # , guardbar=True
assert code_obj.get_fullcode() == data, "Invalid JAN code."
bar_sequence = code_obj.build()[0] # '10100010*******'
# 黒バーの開始位置と長さを取得(効率よく描画する為)
true_segments = self.__find_true_segments(int(x) for x in bar_sequence)
assert len(true_segments) == 30, "Invalid JAN code length."
# draw white background
bg_rect_width = (left_quiet_zone + len(bar_sequence) + right_quiet_zone
) * module_width
doc = id_app.make(new=k.document)
group_items = []
rect = doc.make(new=k.rectangle,
with_properties={
k.name: "background",
k.stroke_weight: 0,
k.fill_color: self.white_color, # 背景の矩形
k.geometric_bounds: [0, 0, guard_bar_height, bg_rect_width],
})
group_items.append(rect)
# draw module rectangles
guard_bar_pos = (0, 1, 14, 15, 28, 29)
for i, (start_pos, length) in enumerate(true_segments):
height = guard_bar_height if i in guard_bar_pos else module_height
rect = doc.make(new=k.rectangle,
with_properties={
k.stroke_weight: 0,
k.fill_color: self.black_color, # 黒バーの背景
k.geometric_bounds: [0, (start_pos + left_quiet_zone) * module_width,
height, (start_pos + left_quiet_zone + length) * module_width],
})
group_items.append(rect)
# 背景とバーをグループ化
group_obj = doc.make(new=k.group,
with_properties={k.group_items: group_items})
group_obj.name.set("JANCode")
return doc
my_code = InDesignJancodeMaker()
my_code.create_jancode("4901550151296")
全て種類のバーコード内部実は全て同じ構造:黒と白の並び、create_jancode関数を少し抽象化したら、code128、ITF等の描画も可能だ。