В современной разработке на платформе 1С часто возникает задача автоматизации обработки входящих данных. Одним из популярных сценариев является получение фотографий через Telegram-ботов. Когда пользователь отправляет фото чека или документа с QR-кодом, сервер 1С должен самостоятельно «прочитать» это изображение и извлечь текстовые данные. Поскольку встроенных средств для декодирования произвольных изображений (непосредственно из файла в текст) в платформе 1С на текущий момент не предусмотрено, нам необходимо рассмотреть использование внешних инструментов и библиотек. Для решения этой задачи можно использовать инструмент для чтения штрихкодов и QR-кодов из изображений и PDF.
В рамках данной статьи мы подробно разберем несколько эффективных способов решения этой задачи: от использования самописных микросервисов на языке Go до интеграции с профессиональными библиотеками компьютерного зрения.
Проанализируем подход, который заключается в создании небольшой вспомогательной программы на языке Go. Этот язык отлично подходит для таких задач, так как позволяет скомпилировать код в единый исполняемый файл (.exe для Windows или бинарный файл для Linux), который не требует установки дополнительных сред выполнения на сервере.
Рассмотрим код на языке Go, который использует специализированную библиотеку gozxing для декодирования QR-кодов. Проанализируем представленный ниже алгоритм:
package main
import (
"fmt"
"image"
"image/png"
"io"
"os"
"path/filepath"
"github.com/h2non/filetype"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
"github.com/sunshineplan/imgconv"
"github.com/sunshineplan/pdf"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func decodeQR(file io.Reader) string {
img, imgType, err := image.Decode(file)
check(err)
bmp, err := gozxing.NewBinaryBitmapFromImage(img)
check(err)
qrReader := qrcode.NewQRCodeReader()
result, err := qrReader.Decode(bmp, nil)
check(err)
return result.String()
}
func main() {
if len(os.Args) < 3 {
fmt.Println("Использование: qrsсan.exe входной_файл выходной_файл")
return
}
inFile := os.Args[1]
outFile := os.Args[2]
file, err := os.Open(inFile)
check(err)
defer file.Close()
// В реальном приложении здесь может быть логика конвертации из разных форматов
result := decodeQR(file)
f, err := os.Create(outFile)
check(err)
f.WriteString(result)
f.Close()
}
После компиляции этого кода мы получим файл gozxing.exe. Теперь выясним, как вызвать это приложение из кода 1С. Разберем процедуру на сервере, которая сохраняет картинку во временный файл, вызывает нашу утилиту и считывает результат:
&НаСервере
Функция РаспознатьQRИзКартинкиНаСервере(ИмяФайлаКартинки)
ИмяВременногоКаталога = ПолучитьИмяВременногоФайла();
СоздатьКаталог(ИмяВременногоКаталога);
// Предположим, бинарник хранится в макете обработки как Двоичные Данные
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
ДвоичныеДанныеПриложения = ОбработкаОбъект.ПолучитьМакет("gozxing_exe");
ИмяФайлаПриложения = ИмяВременногоКаталога + "\gozxing.exe";
ДвоичныеДанныеПриложения.Записать(ИмяФайлаПриложения);
ИмяФайлаРезультата = ПолучитьИмяВременногоФайла("txt");
// Формируем командную строку: приложение.exe путь_к_картинке путь_к_результату
СтрокаКоманды = СтрШаблон("%1 %2 %3", ИмяФайлаПриложения, ИмяФайлаКартинки, ИмяФайлаРезультата);
// Запускаем приложение и ждем завершения
ЗапуститьПриложение(СтрокаКоманды, ИмяВременногоКаталога, Истина);
// Считываем то, что распознала утилита
ТекстРезультат = "";
ФайлРезультата = Новый Файл(ИмяФайлаРезультата);
Если ФайлРезультата.Существует() Тогда
ЧтениеТекста = Новый ЧтениеТекста(ИмяФайлаРезультата, КодировкаТекста.UTF8);
ТекстРезультат = СокрЛП(ЧтениеТекста.Прочитать());
ЧтениеТекста.Закрыть();
КонецЕсли;
// Очистка временных файлов
Попытка
УдалитьФайлы(ИмяВременногоКаталога);
УдалитьФайлы(ИмяФайлаРезультата);
Исключение
// Логируем ошибку удаления, если необходимо
КонецПопытки;
Возврат ТекстРезультат;
КонецФункции
Если ваша серверная ОС — Linux, или вы предпочитаете проверенные open-source инструменты, проанализируем использование ZBar. Это мощный набор инструментов для сканирования штрихкодов.
Рассмотрим последовательность действий для реализации этого метода:
sudo apt-get install zbar-tools. Для Windows скачайте zbarimg.exe.ЗапуститьПриложение. Утилита zbarimg умеет выводить результат прямо в консоль (stdout).zbarimg --raw путь_к_файлу. Флаг --raw позволяет получить только содержимое кода без лишней служебной информации.Преимущество ZBar заключается в его исключительной скорости и поддержке множества форматов помимо QR (например, EAN-13, Code 128). Также в 1С возможна простая генерация QR и штрихкодов без библиотек.
В случаях, когда пользователи присылают фотографии низкого качества (размытые, под углом, со вспышкой), стандартные библиотеки могут давать сбой. Здесь на помощь приходит Python с библиотекой OpenCV.
Разберем, почему этот метод считается наиболее надежным:
wechat_qrcode (модуль внутри OpenCV) использует нейронные сети для поиска и выравнивания QR-кодов. Она была разработана специально для работы с «шумными» изображениями в мессенджерах.pyzbar можно реализовать быструю предварительную обработку изображения: перевод в градации серого, увеличение контрастности и бинаризацию (превращение в строго черно-белое изображение).Для интеграции с 1С на сервере должен быть установлен интерпретатор Python. 1С сохраняет файл, вызывает python decode_script.py image.jpg и получает ответ через текстовый файл или консольный вывод.
Посмотрим на решение, которое не требует вызова внешних исполняемых файлов. Это использование Внешних компонент 1С. Существуют готовые компоненты, написанные на C++, которые используют движок ZXing (Zebra Crossing).
Проанализируем преимущества этого подхода:
.exe.ПодключитьВнешнююКомпоненту.Выясним, почему иногда код не распознается, хотя визуально он виден. Часто проблема кроется в качестве исходного фото. Разберем шаги, которые помогут улучшить результат сканирования:
Важное замечание: При работе на сервере всегда следите за правами доступа. Пользователь, от имени которого запущен процесс rphost (обычно это usr1cv8), должен иметь права на исполнение внешних файлов и запись в используемые временные папки. Также не забывайте генерировать уникальные имена для временных файлов, используя ПолучитьИмяВременногоФайла(), чтобы избежать конфликтов при одновременной работе нескольких пользователей.