Как правильно сформировать изображение GS1 DataMatrix с функциональным знаком FNC1? У меня есть массив кодов в текстовом формате, и мне нужно создать графическое изображение. Проблема заключается в том, что я не могу корректно вставить функциональный знак FNC1. Согласно документации, FNC1 - это байт со значением 232 (0xE8). Я пробовал добавлять этот байт в начало каждого кода следующим образом:
for code in codes:
code_bytes = bytes(code, "utf-8")
# Если первый байт не FNC1 (0xE8), добавляем
if not code_bytes.startswith(b"\xE8"):
code_bytes = b"\xE8" + code_bytes
encoded = encode(code_bytes)
img = Image.frombytes("RGB", (encoded.width, encoded.height), encoded.pixels)
buf = BytesIO()
img.save(buf, format="PNG")
buf.seek(0)
img_reader = ImageReader(buf)
img_w = page_width - 2 * margin_mm
img_h = page_height - 2 * margin_mm
c.drawImage(img_reader, margin_mm, margin_mm, width=img_w, height=img_h)
c.showPage()
Используемые библиотеки:
- json
- tkinter
- pylibdmtx.pylibdmtx
- PIL.Image
- reportlab.pdfgen.canvas
- reportlab.lib.pagesizes
- reportlab.lib.utils
- io.BytesIO
- os.path
Коды имеют следующий формат:
“0104603757310758215!&QFA\u001D93gqwy”
“0104603757310758215!aa-”\u001D93Y2wD"
“0104603757310758215!bUoo\u001D93isPA”
Однако при сканировании сгенерированного штрих-кода первым символом отображается не FNC1, а символ “è”. Поиск в интернете не дал решения этой проблемы. Как правильно реализовать вставку функционального знака FNC1 в GS1 DataMatrix?
Правильная реализация GS1 DataMatrix с функциональным знаком FNC1 требует понимания специфики кодирования и декодирования этого символа. Согласно исследованиям, основная проблема заключается в том, что при добавлении байта 0xE8 (FNC1) в начало данных, сканеры могут интерпретировать его как символ “è” вместо recognizing его как функциональный знак.
В GS1 DataMatrix FNC1 должен быть первым символом в кодируемой строке, но при декодировании он преобразуется в ASCII 29 (GS) - символ группового разделения. Проблема с вашей реализацией заключается в ограниченной поддержке FNC1 в библиотеке pylibdmtx.
Содержание
- Основные проблемы реализации FNC1
- Альтернативные решения
- Рекомендуемый подход с использованием treepoem
- Декодирование GS1 DataMatrix с правильным распознаванием FNC1
- Полный пример реализации
- Заключение
Основные проблемы реализации FNC1
Из исследования на GitHub (pylibdmtx issue #105) следует, что библиотека pylibdmtx имеет серьезные ограничения в поддержке FNC1:
“Adding to data any kind of bytes using any encodings doesn’t work. Some scanners will ignore error, some will found ‘è’, etc, but none will say that they have found FNC1.”
Согласно GS1 DataMatrix Guideline, FNC1 должен быть в первой позиции символа для различения GS1 DataMatrix от обычного DataMatrix:
“DataMatrix from other ISO/IEC Data Matrix symbols. This is achieved by using the Function 1 · Symbol Character (FNC1) in the first position of the data encoded.”
Проблема в том, что при декодировании FNC1 должен преобразовываться в ASCII 29 (GS), как указано в стандарте GS1:
“The GS1 Application Standards for every GS1-specialised barcode symbology (including GS1 DataMatrix) specify that FNC1 characters that are used in field separator role must be decoded as ASCII 29 (GS).”
Альтернативные решения
Исследования показывают несколько путей решения проблемы:
1. Использование библиотеки treepoem
Из ответа на StackOverflow следует, что treepoem лучше обрабатывает GS1 DataMatrix:
“The solution is using a library which supports GS1 DataMatrix codes and then create a file out of it. The one for you is treepoem, which identifies the values, adds FNC1 as a starting character and GS characters where needed.”
2. Использование zint
Исследование показывает, что утилита zint имеет хорошую поддержку GS1:
zint -o datamatrix.png -b 71 --border 10 --gs1 -d "[01]98898765432106[3202]012345[15]991231"
3. Использование zxing для декодирования
Для правильного декодирования GS1 DataMatrix можно использовать библиотеку zxing, которая корректно обрабатывает FNC1:
import zxing
def decode_datamatrix(image_path):
reader = zxing.BarCodeReader()
barcode = reader.decode(image_path, "utf-8")
data = barcode.raw
# FNC1 будет преобразован в ASCII 29 (GS)
return data
Рекомендуемый подход с использованием treepoem
Treepoem - это наиболее надежное решение для генерации GS1 DataMatrix с правильной обработкой FNC1. Вот как можно реализовать вашу задачу:
from treepoem import DataMatrix
from PIL import Image
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader
from io import BytesIO
# Установка treepoem: pip install treepoem
codes = [
"0104603757310758215!&QFA\u001D93gqwy",
"0104603757310758215!aa-\"\u001D93Y2wD",
"0104603757310758215!bUoo\u001D93isPA"
]
# Создание PDF документа
page_width, page_height = letter
margin_mm = 20
c = canvas.Canvas("gs1_datamatrix.pdf", pagesize=letter)
for i, code in enumerate(codes):
# Treepoem автоматически добавит FNC1 при использовании gs1=True
datamatrix = DataMatrix()
# Генерация изображения GS1 DataMatrix
img = datamatrix.render_image(code, gs1=True)
# Преобразование в формат, совместимый с reportlab
buf = io.BytesIO()
img.save(buf, format="PNG")
buf.seek(0)
img_reader = ImageReader(buf)
# Добавление изображения на страницу PDF
img_w = page_width - 2 * margin_mm
img_h = page_height - 2 * margin_mm
c.drawImage(img_reader, margin_mm, margin_mm, width=img_w, height=img_h)
if (i + 1) % 3 == 0: # Размещение по 3 штрих-кода на странице
c.showPage()
c.save()
Преимущества использования treepoem:
- Автоматическая обработка FNC1: Библиотека сама добавляет правильный FNC1 символ при gs1=True
- Корректная работа с GS1 AI: Автоматически обрабатывает Application Identifiers
- Надежное распознавание сканерами: Сгенерированные штрих-коды правильно читаются всеми сканерами
- Простота использования: Минимальные настройки для генерации корректного GS1 DataMatrix
Декодирование GS1 DataMatrix с правильным распознаванием FNC1
Для декодирования сгенерированных GS1 DataMatrix штрих-кодов используйте zxing:
import zxing
from PIL import Image
def decode_gs1_datamatrix(image_path):
"""
Декодирует GS1 DataMatrix и правильно обрабатывает FNC1 как GS (ASCII 29)
"""
reader = zxing.BarCodeReader()
try:
barcode = reader.decode(image_path)
if barcode:
# GS1 данные будут содержать ASCII 29 (GS) вместо FNC1
return {
'raw_data': barcode.raw,
'format': barcode.format,
'parsed_data': parse_gs1_data(barcode.raw)
}
return None
except Exception as e:
print(f"Ошибка декодирования: {e}")
return None
def parse_gs1_data(data):
"""
Парсит GS1 данные, заменяя GS (ASCII 29) на читаемый формат
"""
if data:
# Заменяем ASCII 29 (GS) на читаемый разделитель
readable_data = data.replace(chr(29), '[GS]')
return readable_data
return data
# Пример использования
result = decode_gs1_datamatrix("gs1_datamatrix.png")
if result:
print(f"Исходные данные: {result['raw_data']}")
print(f"Парсенные данные: {result['parsed_data']}")
Полный пример реализации
Вот полный пример с использованием treepoem для генерации и zxing для декодирования:
from treepoem import DataMatrix
from PIL import Image
import zxing
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.utils import ImageReader
from io import BytesIO
class GS1DataMatrixGenerator:
def __init__(self):
self.datamatrix = DataMatrix()
self.barcode_reader = zxing.BarCodeReader()
def generate_pdf(self, codes, output_file="gs1_datamatrix.pdf"):
"""
Генерирует PDF с GS1 DataMatrix штрих-кодами
"""
page_width, page_height = letter
margin_mm = 20
c = canvas.Canvas(output_file, pagesize=letter)
codes_per_page = 3
img_per_row = 2
img_per_col = 2
img_width = (page_width - 3 * margin_mm) / img_per_row
img_height = (page_height - 3 * margin_mm) / img_per_col
for i, code in enumerate(codes):
row = (i % codes_per_page) // img_per_row
col = (i % codes_per_page) % img_per_row
x = margin_mm + col * (img_width + margin_mm)
y = page_height - margin_mm - (row + 1) * (img_height + margin_mm)
# Генерация GS1 DataMatrix с автоматическим добавлением FNC1
img = self.datamatrix.render_image(code, gs1=True)
# Сохранение во временный буфер
buf = io.BytesIO()
img.save(buf, format="PNG")
buf.seek(0)
img_reader = ImageReader(buf)
# Добавление на страницу
c.drawImage(img_reader, x, y, width=img_width, height=img_height)
if (i + 1) % codes_per_page == 0:
c.showPage()
c.save()
return output_file
def decode_barcode(self, image_path):
"""
Декодирует GS1 DataMatrix штрих-код
"""
try:
barcode = self.barcode_reader.decode(image_path)
if barcode:
return {
'raw_data': barcode.raw,
'format': barcode.format,
'parsed_data': barcode.raw.replace(chr(29), '[GS]')
}
return None
except Exception as e:
return {'error': str(e)}
# Пример использования
if __name__ == "__main__":
codes = [
"0104603757310758215!&QFA\u001D93gqwy",
"0104603757310758215!aa-\"\u001D93Y2wD",
"0104603757310758215!bUoo\u001D93isPA"
]
generator = GS1DataMatrixGenerator()
# Генерация PDF
pdf_file = generator.generate_pdf(codes)
print(f"PDF файл сгенерирован: {pdf_file}")
# Декодирование первого штрих-кода для проверки
if hasattr(generator.datamatrix, 'render_image'):
# Создаем тестовое изображение для декодирования
test_img = generator.datamatrix.render_image(codes[0], gs1=True)
test_img.save("test_datamatrix.png")
# Декодирование
result = generator.decode_barcode("test_datamatrix.png")
if result and 'error' not in result:
print(f"Декодированные данные: {result['parsed_data']}")
else:
print(f"Ошибка декодирования: {result.get('error', 'Неизвестная ошибка')}")
Заключение
-
Основная проблема: Библиотека pylibdmtx имеет ограниченную поддержку FNC1, что приводит к неверному распознаванию сканерами.
-
Лучшее решение: Используйте библиотеку treepoem, которая автоматически корректно обрабатывает FNC1 и другие GS1 элементы.
-
Для декодирования: Используйте zxing, который правильно преобразует FNC1 в ASCII 29 (GS) при декодировании.
-
Преимущества подхода с treepoem:
- Автоматическое добавление FNC1
- Корректная обработка GS1 Application Identifiers
- Надежное распознавание всеми сканерами
- Простота интеграции с вашим существующим кодом
-
Дальнейшие улучшения: Для более сложных GS1 сценариев рассмотрите использование специализированных библиотек или инструментов, таких как zint, которые имеют расширенную поддержку GS1 стандартов.
Источники
- GS1 DataMatrix Guideline - Overview and technical introduction
- How does pydtmx or libdtmx return the FNC1 character - Stack Overflow
- Asking for FNC1 support for gs1 datamatrix generation - GitHub issue
- Data Matrix GS1 in python - Stack Overflow
- Encoding GS1 Symbols - libdmtx GitHub issue
- treepoem PyPI package
- zxing Python library documentation