Datamatrix to TXT

  • Автор темы Автор темы izrukvruki
  • Дата начала Дата начала

Не по теме:

Программа с интерфейсом взамен командной строки — это эргономичность. Вопли программистов, что им удобнее учить строчки текста и их вводить останутся воплями и нытьём, как бы для них это не было быстро. Если бы все слушали этих программистов, то мы бы до сих пор в перфокартах дырочки делали отвёрткой. За программы с понятным и простым интерфейсом пользователь голосует рублём/долларом/тугриками.

 
Последнее редактирование:

Не по теме:

Программа с интерфейсом взамен командной строки — это эргономичность. Вопли программистов, что им удобнее учить строчки текста и их вводить останутся воплями и нытьём, как бы для них это не было быстро. Если бы все слушали этих программистов, то мы бы до сих пор в перфокартах дырочки делали отвёрткой. За программы с понятным и простым интерфейсом пользователь голосует рублём/долларом/тугриками.


Не по теме:

Это сильно похоже на утверждение, что лучше нажимать кнопки мышью, чем выучить некоторое количество шоткатов.

 
  • Спасибо
Реакции: zollinger и ~RA~
Программа с интерфейсом взамен командной строки — это эргономичность
и отсутствие возможности бесшовного встраивания в рабочий процесс. А так да, верное утверждение.
 
  • Спасибо
Реакции: zollinger
Дык по любому придется в растр конвертировать перед чтением. Или ваш нейросетевой скрипт прямо из PDF-ЕРS напрямую распознает, не конвертя?
 
Python:
import fitz
import cv2
import numpy as np
from PIL import Image
import csv
from pylibdmtx.pylibdmtx import decode
import io
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
from tqdm import tqdm
import time


print("🚀 DataMatrix: МНОГОПОТОЧНО + ПРОГРЕСС-БАР + ТАЙМЕР")

pdf_file = "Входной файл.pdf"
output_csv = "datamatrix_results.csv"

if not os.path.exists(pdf_file):
    print(f"❌ Файл '{pdf_file}' не найден!")
    exit()

try:
    pdf = fitz.open(pdf_file)
    total_pages = pdf.page_count
    print(f"📖 Открыт PDF: {total_pages} страниц")
    pdf.close()
except Exception as e:
    print(f"❌ Ошибка открытия PDF: {e}")
    exit()


def process_page(page_num):
    """Обработка одной страницы"""
    try:
        pdf = fitz.open(pdf_file)
        page = pdf[page_num]

        # Растеризация
        pix = page.get_pixmap(dpi=150, colorspace="gray")
        img_data = pix.tobytes("png")
        img_pil = Image.open(io.BytesIO(img_data))
        img_cv = np.array(img_pil)

        # Бинаризация
        _, binary = cv2.threshold(img_cv, 128, 255, cv2.THRESH_BINARY)

        # Распознавание
        decoded_objects = decode(binary)
        pdf.close()

        if decoded_objects:
            data = decoded_objects[0].data.decode('latin1', errors='replace')
            return page_num + 1, data, True
        else:
            return page_num + 1, None, False
    except Exception as e:
        return page_num + 1, f"Ошибка: {e}", False


# 🧵 Настройки
NUM_WORKERS = 4

print(f"⚡ Запуск многопоточной обработки ({NUM_WORKERS} потоков)...\n")

results = []
start_time = time.time()  # ⏱️ Запуск таймера

# Список номеров страниц
page_numbers = list(range(total_pages))

with ThreadPoolExecutor(max_workers=NUM_WORKERS) as executor:
    # Отправляем все задачи
    future_to_page = {executor.submit(process_page, i): i for i in page_numbers}

    # Прогресс-бар с оценкой времени
    for future in tqdm(
        as_completed(future_to_page),
        total=total_pages,
        desc="Обработка",
        unit="стр",
        ncols=100,
        colour="#1f77b4"
    ):
        page_num, data, success = future.result()
        if success and "Ошибка" not in str(data):
            results.append(data)
        # Игнорируем не найденные и ошибки (уже видно в статистике)

# ⏱️ Конец таймера
end_time = time.time()
elapsed = end_time - start_time
found_count = len(results)

# 📊 Финальный вывод
print(f"\n\n✅ Готово за {elapsed:.1f} секунд!")
print(f"📄 Обработано: {total_pages} страниц")
print(f"🎯 Найдено кодов: {found_count}")
print(f"💾 Результат: {output_csv}")

# 📥 Сохранение
try:
    with open(output_csv, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        for code in results:
            writer.writerow([code])
except Exception as e:
    print(f"❌ Ошибка записи CSV: {e}")

input("\nНажмите Enter, чтобы выйти...")
 
Последнее редактирование:
  • Спасибо
Реакции: izrukvruki
Ну да, обертка на библиотеку pylibdmtx, я смотрю, даже прогрессбар имеется
 
  • Спасибо
Реакции: romyk
Код:
Скрипт считывает коды маркировки системы ЧЕСТНЫЙ ЗНАК из кодов DataMatrix в формате PDF, EPS (в.ч. в ZIP-архивах) и записывает их в текстовый файл

1. Установить Python: https://www.python.org/downloads/

2. Установить Ghostscript: https://ghostscript.com/releases/gsdnld.html

3. В командной строке (Win+R - и введи CMD) выполни

pip install PyMuPDF pillow pylibdmtx

4. Создайте папку в удобном вам месте. Распакуйте туда содержимое архива zip_pdf_eps.rar.

5. Положите в эту папку файлы с кодами DataMatrix в формате pdf, eps или эти форматы в архиве zip.
ВНИМАНИЕ!!! Программа рассчитана на работу исключительно с кодами маркировки Честный знак, размеры/разрешение картинок подогнаны под их размеры. С другими кодами DataMatrix может работать некорректно, нужно править в скрипте размеры/разрешение.

6. Запустите скрипт zip_pdf_eps.py

7. В случае успешной работы в папке появится файл dm_codes.txt с текстовыми кодами закодированными в DataMatrix

Python:
import os
import sys
import zipfile
import tempfile
import subprocess
import shutil
from PIL import Image
from pylibdmtx.pylibdmtx import decode
import fitz  # PyMuPDF
import time

# ==============================
# Замер времени: начало
# ==============================
start_time = time.time()

# ==============================
# Настройки
# ==============================
# Папка, где находится скрипт
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) if getattr(sys, 'frozen', False) else os.path.dirname(os.path.abspath(sys.argv[0]))
os.chdir(SCRIPT_DIR)

# Параметры изображения
DPI_PDF = 300  # DPI для PDF
DPI_EPS = 600  # DPI для EPS (маленькие метки)

TARGET_WIDTH_MM = 1.63
TARGET_HEIGHT_MM = 1.63
WIDTH_PX = int(TARGET_WIDTH_MM * DPI_EPS / 25.4)
HEIGHT_PX = int(TARGET_HEIGHT_MM * DPI_EPS / 25.4)

TARGET_WIDTH_MM_PDF = 15
TARGET_HEIGHT_MM_PDF = 15
WIDTH_PX_PDF = int(TARGET_WIDTH_MM_PDF * DPI_PDF / 25.4)
HEIGHT_PX_PDF = int(TARGET_HEIGHT_MM_PDF * DPI_PDF / 25.4)

# Временные папки
TEMP_EXTRACT_ROOT = os.path.join(SCRIPT_DIR, "dm_zip")
TEMP_CONVERT_DIR = os.path.join(SCRIPT_DIR, "temp_converted")
OUTPUT_FILE = "dm_codes.txt"

# Добавлять GS (0x1D) в начало?
FORCE_START_WITH_GS = True

# Удалять временные папки?
CLEAN_UP_TEMP = True

# ==============================
# Проверка Ghostscript (для EPS)
# ==============================
print("Проверка Ghostscript...")
try:
    result = subprocess.run(["gswin64c", "--version"], capture_output=True, text=True)
    if result.returncode == 0:
        print(f"Ghostscript: {result.stdout.strip()}")
    else:
        raise Exception("Код возврата не 0")
except Exception as e:
    print(f"Ghostscript не установлен: {e}")
    print("Скачайте с: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases")
    input("Нажмите Enter для выхода...")
    exit()

# Создаём временную папку
os.makedirs(TEMP_CONVERT_DIR, exist_ok=True)

# ==============================
# Сбор файлов в текущей папке
# ==============================
zip_files = []
pdf_files = []
eps_files = []

for fname in os.listdir(SCRIPT_DIR):
    fpath = os.path.join(SCRIPT_DIR, fname)
    if os.path.isfile(fpath):
        lower = fname.lower()
        if lower.endswith(".zip"):
            zip_files.append(fpath)
        elif lower.endswith(".pdf"):
            pdf_files.append(fpath)
        elif lower.endswith(".eps"):
            eps_files.append(fpath)

print(f"ZIP: {len(zip_files)} | PDF: {len(pdf_files)} | EPS: {len(eps_files)}")

# ==============================
# Список для всех кодов
# ==============================
all_codes = []

# ==============================
# Функция: обработка изображения
# ==============================
def process_image(img):
    codes = []
    try:
        decoded_objects = decode(img)
        for obj in decoded_objects:
            raw_data = obj.data
            if raw_data.startswith(b'\x1d'):
                final_data = raw_data
            else:
                final_data = b'\x1d' + raw_data if FORCE_START_WITH_GS else raw_data
            codes.append(final_data)
    except Exception as e:
        print(f" Ошибка декодирования: {e}")
    return codes

# ==============================
# 1. Обработка ZIP-архивов
# ==============================
for zip_path in zip_files:
    zip_name = os.path.basename(zip_path)
    extract_dir = os.path.join(TEMP_EXTRACT_ROOT, os.path.splitext(zip_name)[0])
    os.makedirs(extract_dir, exist_ok=True)

    print(f"\nРаспаковка: {zip_name}")
    try:
        with zipfile.ZipFile(zip_path, 'r') as z:
            z.extractall(extract_dir)
        print(f" Архив распакован")
    except Exception as e:
        print(f" Ошибка распаковки: {e}")
        continue

    for root, _, files in os.walk(extract_dir):
        for fname in files:
            fpath = os.path.join(root, fname)
            lower = fname.lower()

            try:
                if lower.endswith(".pdf"):
                    print(f" PDF из ZIP: {fname}")
                    doc = fitz.open(fpath)
                    for page_num in range(len(doc)):
                        mat = fitz.Matrix(DPI_PDF / 72, DPI_PDF / 72)  # Масштаб по DPI
                        pix = doc[page_num].get_pixmap(matrix=mat)
                        img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                        img = img.convert('L')  # Grayscale
                        #img = img.resize((WIDTH_PX_PDF, HEIGHT_PX_PDF), Image.LANCZOS)
                        all_codes.extend(process_image(img))
                    doc.close()

                elif lower.endswith(".eps"):
                    print(f" EPS из ZIP: {fname}")
                    temp_png = os.path.join(TEMP_CONVERT_DIR, f"zip_{fname}.png")                  
                    gs_cmd = [
                        "gswin64c", "-dBATCH", "-dNOPAUSE", "-dSAFER",
                        f"-r{DPI_EPS}", "-sDEVICE=pnggray",
                        f"-dDEVICEWIDTHPOINTS={WIDTH_PX}", f"-dDEVICEHEIGHTPOINTS={HEIGHT_PX}",
                        "-dPDFFitPage", "-dTextAlphaBits=1", "-dGraphicsAlphaBits=1",
                        f"-sOutputFile={temp_png}", fpath
                    ]
 
                    res = subprocess.run(gs_cmd, capture_output=True, text=True, encoding='utf-8')
                    if res.returncode != 0:
                        print(f" GS ошибка: {res.stderr[:100]}...")
                    else:
                        img = Image.open(temp_png).convert('L')
                        all_codes.extend(process_image(img))

            except Exception as e:
                print(f" Ошибка: {e}")

# ==============================
# 2. Обработка PDF и EPS напрямую
# ==============================
for fpath in pdf_files + eps_files:
    fname = os.path.basename(fpath)
    print(f"Прямой файл: {fname}")

    try:
        if fname.lower().endswith(".pdf"):
            doc = fitz.open(fpath)
            for page_num in range(len(doc)):
                mat = fitz.Matrix(DPI_PDF / 72, DPI_PDF / 72)
                pix = doc[page_num].get_pixmap(matrix=mat)
                img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                img = img.convert('L')
                #img = img.resize((WIDTH_PX_PDF, HEIGHT_PX_PDF), Image.LANCZOS)
                all_codes.extend(process_image(img))
            doc.close()

        elif fname.lower().endswith(".eps"):
            temp_png = os.path.join(TEMP_CONVERT_DIR, f"direct_{fname}.png")
            gs_cmd = [
                        "gswin64c", "-dBATCH", "-dNOPAUSE", "-dSAFER",
                        f"-r{DPI_EPS}", "-sDEVICE=pnggray",
                        f"-dDEVICEWIDTHPOINTS={WIDTH_PX}", f"-dDEVICEHEIGHTPOINTS={HEIGHT_PX}",
                        "-dPDFFitPage", "-dTextAlphaBits=1", "-dGraphicsAlphaBits=1",
                        f"-sOutputFile={temp_png}", fpath
            ]
            res = subprocess.run(gs_cmd, capture_output=True, text=True, encoding='utf-8')
            if res.returncode != 0:
                print(f" GS ошибка: {res.stderr[:100]}...")
            else:
                img = Image.open(temp_png).convert('L')
                all_codes.extend(process_image(img))

    except Exception as e:
        print(f" Ошибка: {e}")

# ==============================
# Сохранение всех кодов
# ==============================
with open(OUTPUT_FILE, "wb") as f:
    for code in all_codes:
        f.write(code + b'\n')

print(f"\nГотово!")
print(f"ZIP: {len(zip_files)} | PDF/EPS: {len(pdf_files) + len(eps_files)}")
print(f"Всего найдено кодов: {len(all_codes)}")
print(f"Результат: {OUTPUT_FILE}")

# ==============================
# Удаление временных папок
# ==============================
if CLEAN_UP_TEMP:
    print("\nУдаление временных папок...")
    try:
        if os.path.exists(TEMP_CONVERT_DIR):
            shutil.rmtree(TEMP_CONVERT_DIR, ignore_errors=True)
            print(f" Удалено: {TEMP_CONVERT_DIR}")
    except Exception as e:
        print(f" Ошибка удаления {TEMP_CONVERT_DIR}: {e}")

    try:
        if os.path.exists(TEMP_EXTRACT_ROOT):
            shutil.rmtree(TEMP_EXTRACT_ROOT, ignore_errors=True)
            print(f" Удалено: {TEMP_EXTRACT_ROOT}")
    except Exception as e:
        print(f" Ошибка удаления {TEMP_EXTRACT_ROOT}: {e}")

# ==============================
# Время выполнения
# ==============================
end_time = time.time()
total_time = end_time - start_time
hours, rem = divmod(total_time, 3600)
minutes, seconds = divmod(rem, 60)
time_str = "{:02}:{:02}:{:02}".format(int(hours), int(minutes), int(seconds))
print(f"\n⏱ Время работы скрипта: {time_str}")

# Завершение
input("\nНажмите Enter для выхода...")
 
  • Спасибо
Реакции: Chiga и _MBK_
Жора правильно сделал, что тему не закрыл.
Хороший пример, когда профессиональные подсказки и негативная мотивация заставляют пользователя перейти от потребительской позиции к активным поискам самостоятельного решения, которое, в итоге, его устраивает!
 
  • Смешно
Реакции: George