Генерация изображения из строки в 1С 8.3: SVG, PowerShell, HTTP и вывод в макет
Содержание
Преобразовать текст в картинку в 1С проще всего так: собрать из строки SVG-разметку и передать её в конструктор Новый Картинка(ДвоичныеДанные). Если нужен растровый PNG с конкретным шрифтом, текст рендерят внешней программой (PowerShell или ImageMagick) из внешней обработки и загружают готовый файл обратно в объект Картинка.
Встроенной функции вида «ТекстВКартинку» в платформе 1С:Предприятие 8.3 нет. Зато есть всё, чтобы её собрать: тип Картинка, двоичные данные, запуск внешних программ, HTTP-клиент и рисунки табличного документа. Задача общая для платформы и не зависит от конфигурации: код одинаково работает в Бухгалтерии, УТ или самописной базе.
Что подготовить и какой способ выбрать
Сначала решите три вопроса. От ответов зависит способ.
- 🖥️ Где выполняется код. На клиенте или на сервере, Windows или Linux. COM и PowerShell есть только в Windows.
- 🖼️ Какой нужен формат. Для печатной формы и поля формы хватит SVG. Для отправки по почте, на сайт или в мессенджер обычно нужен PNG или JPEG.
- 🔒 Есть ли права. Внешней обработке нужна роль с правом интерактивного открытия внешних обработок. В режиме безопасного выполнения запуск программ и COM запрещены.
| Способ | Когда подходит | Ограничения |
|---|---|---|
| SVG средствами платформы | Простая надпись, печатная форма, поле картинки | Шрифт берётся из системы, перевод в PNG поддерживается не везде |
| PowerShell + System.Drawing | Windows, нужен PNG с выбранным шрифтом | Только Windows, нужен доступ к временному каталогу |
| ImageMagick | Linux-сервер или пакетная обработка | Программу надо установить и прописать путь |
| COM-объекты | Есть готовая COM-библиотека для графики | Только Windows, Office на сервере ставить не стоит |
| HTTP-сервис | Рендер вынесен на отдельный сервер | Нужна сеть и свой или сторонний сервис |
| Модуль штрихкодов БСП | Текст нужно превратить в QR-код | Это не надпись, а код для сканера |
Для отладки удобна внешняя обработка: её не нужно встраивать в конфигурацию, а правки видны после повторного открытия файла.
Встроенные средства платформы: картинка из SVG
Тип Картинка умеет создаваться из двоичных данных. Формат платформа определяет по содержимому. SVG — это обычный XML-текст, поэтому его легко собрать строкой прямо в коде 1С.
Порядок действий:
- Экранируйте в тексте символы
&,<и>, иначе разметка сломается. - Разбейте текст на строки по
Символы.ПС, чтобы перенос строки сохранился. - Посчитайте ширину и высоту холста от длины самой длинной строки и размера шрифта.
- Соберите строку SVG и превратите её в двоичные данные.
- Создайте объект
Картинка.
Функция ТекстВКартинкуSVG(Знач Текст, РазмерШрифта = 24, ИмяШрифта = "Arial") Экспорт
Текст = СтрЗаменить(Текст, "&", "&");
Текст = СтрЗаменить(Текст, "<", "<");
Текст = СтрЗаменить(Текст, ">", ">");
Строки = СтрРазделить(Текст, Символы.ПС, Истина);
МаксДлина = 1;
Для Каждого Стр Из Строки Цикл
МаксДлина = Макс(МаксДлина, СтрДлина(Стр));
КонецЦикла;
ВысотаСтроки = Цел(РазмерШрифта * 1.4);
Ширина = Цел(МаксДлина * РазмерШрифта * 0.6) + 20;
Высота = ВысотаСтроки * Строки.Количество() + 20;
Тело = "";
Для Индекс = 0 По Строки.ВГраница() Цикл
Y = 10 + РазмерШрифта + Индекс * ВысотаСтроки;
Тело = Тело + СтрШаблон("<text x=""10"" y=""%1"">%2</text>",
Формат(Y, "ЧГ=0"), Строки[Индекс]);
КонецЦикла;
SVG = СтрШаблон(
"<svg xmlns=""http://www.w3.org/2000/svg"" width=""%1"" height=""%2"">"
+ "<rect x=""0"" y=""0"" width=""%1"" height=""%2"" fill=""white""/>"
+ "<g font-family=""%3"" font-size=""%4"" fill=""black"">%5</g></svg>",
Формат(Ширина, "ЧГ=0"), Формат(Высота, "ЧГ=0"),
ИмяШрифта, Формат(РазмерШрифта, "ЧГ=0"), Тело);
ДД = ПолучитьДвоичныеДанныеИзСтроки(SVG, КодировкаТекста.UTF8, Ложь);
Возврат Новый Картинка(ДД);
КонецФункции
Пример расчёта: строка из 20 символов при шрифте 24 даёт ширину 20 × 24 × 0,6 + 20 = 308 пикселей. Коэффициент 0,6 — средняя ширина символа для пропорционального шрифта. Для моноширинного Courier New он точнее, для жирного шрифта увеличьте его до 0,7.
Атрибуты width и height в SVG обязательны. Без них платформа не знает размер холста, и картинка в макете выводится крошечной или пустой.
Если нужен PNG, а не SVG
У объекта Картинка есть метод Преобразовать(ФорматКартинки.PNG). Растровые форматы между собой он переводит надёжно. Растеризация векторного SVG зависит от версии платформы, поэтому проверьте результат на своём релизе. Не вышло — переходите к внешнему рендеру из следующего раздела.
Внешний рендер: PowerShell, ImageMagick и COM
Когда нужен точный шрифт, сглаживание и гарантированный PNG, текст рисует операционная система. 1С лишь готовит входные данные, запускает программу и забирает файл.
PowerShell и System.Drawing (Windows)
Сохраните скрипт в файл, например C:\Scripts\text2png.ps1:
param($InFile, $OutFile, $FontName = 'Arial', $FontSize = 28)
Add-Type -AssemblyName System.Drawing
$text = [IO.File]::ReadAllText($InFile, [Text.Encoding]::UTF8)
$font = New-Object System.Drawing.Font($FontName, [single]$FontSize)
$probe = New-Object System.Drawing.Bitmap(1, 1)
$g = [System.Drawing.Graphics]::FromImage($probe)
$size = $g.MeasureString($text, $font)
$g.Dispose(); $probe.Dispose()
$w = [int][Math]::Ceiling($size.Width) + 20
$h = [int][Math]::Ceiling($size.Height) + 20
$bmp = New-Object System.Drawing.Bitmap($w, $h)
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.Clear([System.Drawing.Color]::White)
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAliasGridFit
$g.DrawString($text, $font, [System.Drawing.Brushes]::Black, 10, 10)
$bmp.Save($OutFile, [System.Drawing.Imaging.ImageFormat]::Png)
$g.Dispose(); $bmp.Dispose()
Скрипт сам меряет текст через MeasureString, поэтому холст подстраивается под длину и переносы строк. Подбирать коэффициенты, как в SVG, не нужно.
Вызов из 1С:
Функция ТекстВКартинкуPNG(Текст, ПутьКСкрипту) Экспорт
ФайлТекста = ПолучитьИмяВременногоФайла("txt");
ФайлКартинки = ПолучитьИмяВременногоФайла("png");
Запись = Новый ЗаписьТекста(ФайлТекста, КодировкаТекста.UTF8);
Запись.Записать(Текст);
Запись.Закрыть();
Команда = СтрШаблон(
"powershell.exe -NoProfile -ExecutionPolicy Bypass -File ""%1"" ""%2"" ""%3""",
ПутьКСкрипту, ФайлТекста, ФайлКартинки);
ЗапуститьПриложение(Команда, , Истина);
Если Не Новый Файл(ФайлКартинки).Существует() Тогда
УдалитьФайлы(ФайлТекста);
ВызватьИсключение "Скрипт не создал файл картинки: " + ФайлКартинки;
КонецЕсли;
ДД = Новый ДвоичныеДанные(ФайлКартинки);
УдалитьФайлы(ФайлТекста);
УдалитьФайлы(ФайлКартинки);
Возврат Новый Картинка(ДД);
КонецФункции
Текст передаётся через файл в UTF-8, а не параметром командной строки. Так кириллица, кавычки и переносы строк доходят до скрипта без искажений.
Картинка читается в ДвоичныеДанные до удаления файла. Если создать Новый Картинка(ИмяФайла) и сразу удалить файл, можно получить пустой результат.
ImageMagick (Windows и Linux)
На Linux-сервере PowerShell с System.Drawing не вариант. Там удобнее ImageMagick: он есть в репозиториях всех популярных дистрибутивов. Команда для надписи из файла:
magick -background white -fill black -font DejaVu-Sans -pointsize 28 label:@/tmp/text.txt /tmp/out.png
В ImageMagick 6 вместо magick используется команда convert с теми же параметрами. Конструкция label:@файл читает текст из файла. Учтите: в политике безопасности ImageMagick чтение через @ бывает запрещено. Тогда разрешите его в policy.xml или передавайте текст аргументом.
Из 1С вызов тот же: ЗапуститьПриложение(Команда, , Истина), только команда другая.
COM-объекты
COM в 1С создаётся через Новый COMОбъект("ProgID"). Для графики годится любая зарегистрированная библиотека с COM-интерфейсом. Пример — автоматизация Word: вставить текст, экспортировать документ в PDF. Получится не картинка, а документ, поэтому для изображений этот путь неудобен.
Не ставьте Microsoft Office на сервер 1С ради рендера. Офис не рассчитан на работу под служебной учётной записью без рабочего стола: зависшие процессы WINWORD.EXE копятся и блокируют файлы. Для сервера надёжнее PowerShell или ImageMagick.
Внешняя обработка для генерации изображения
Отлаживать код удобнее во внешней обработке, а не в конфигурации. Порядок:
- В Конфигураторе выберите
Файл → Новый → Внешняя обработка. - Добавьте реквизит
Текст(строка неограниченной длины) и форму. - На форму добавьте реквизит
АдресКартинки(строка) и поле картинки с путём к даннымАдресКартинки. - Создайте команду «Сформировать» и серверную процедуру с вызовом одной из функций выше.
- Сохраните файл
.epfи откройте его в 1С:Предприятии через главное меню:Файл → Открыть.
Код формы:
&НаКлиенте
Процедура Сформировать(Команда)
СформироватьНаСервере();
КонецПроцедуры
&НаСервере
Процедура СформироватьНаСервере()
Обработка = РеквизитФормыВЗначение("Объект");
Картинка = Обработка.ТекстВКартинкуSVG(Объект.Текст, 28);
АдресКартинки = ПоместитьВоВременноеХранилище(
Картинка.ПолучитьДвоичныеДанные(), УникальныйИдентификатор);
КонецПроцедуры
Функцию ТекстВКартинкуSVG поместите в модуль объекта обработки с ключевым словом Экспорт. Поле картинки показывает данные по адресу временного хранилища: присвоили адрес — картинка появилась.
Для быстрой проверки фрагмента без своей обработки подойдёт консоль кода — универсальная обработка для выполнения произвольного кода на сервере. Вставьте функцию, вызовите её и сохраните результат в файл методом Картинка.Записать(ИмяФайла).
В конфигурациях на БСП внешнюю обработку можно подключить через справочник дополнительных отчётов и обработок. Тогда её видят пользователи без права открывать файлы с диска.
Буфер обмена и смена формата картинки
Текст часто копируют из другой программы, а готовую картинку надо вставить в письмо или мессенджер. Здесь два сценария.
Вставка картинки из буфера в 1С. В актуальных версиях платформы есть программный доступ к буферу обмена (объект СредстваБуфераОбмена, точный состав методов смотрите в синтакс-помощнике своей версии). На старых версиях выручает тот же PowerShell:
Add-Type -AssemblyName System.Windows.Forms
$img = [System.Windows.Forms.Clipboard]::GetImage()
if ($img) { $img.Save('C:\Temp\clip.png', [System.Drawing.Imaging.ImageFormat]::Png) }
Скрипт работает только на клиенте: у сервера 1С нет буфера обмена пользователя.
Смена формата. Готовую растровую картинку переводят между форматами методом Преобразовать:
КартинкаJPEG = Картинка.Преобразовать(ФорматКартинки.JPEG);
ДД = КартинкаJPEG.ПолучитьДвоичныеДанные();
Для хранения в базе используйте реквизит типа ХранилищеЗначения: Новый ХранилищеЗначения(ДД, Новый СжатиеДанных(9)). Текстовая картинка в PNG весит единицы килобайт, база от тысячи таких записей почти не растёт.
Рендер через HTTP: свой сервис или внешний API
Когда рендер нужен многим базам сразу или сервер 1С работает на Linux без графических библиотек, генерацию выносят в отдельный сервис. 1С отправляет текст и получает PNG в ответе.
Функция ТекстВКартинкуHTTP(Текст) Экспорт
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Новый Структура("text, size", Текст, 28));
ТелоJSON = Запись.Закрыть();
Соединение = Новый HTTPСоединение("render.example.local", 443, , , , 30,
Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос("/text2png");
Запрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Запрос.УстановитьТелоИзСтроки(ТелоJSON, КодировкаТекста.UTF8,
ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение "Сервис рендера вернул код " + Формат(Ответ.КодСостояния, "ЧГ=0");
КонецЕсли;
Возврат Новый Картинка(Ответ.ПолучитьТелоКакДвоичныеДанные());
КонецФункции
Адрес render.example.local и путь /text2png — условные, подставьте свои. Таймаут 30 секунд защищает сеанс от зависания при недоступном сервисе.
Обратная задача — отдать картинку из 1С наружу, например на сайт. Для этого в конфигурации создают HTTP-сервис и в обработчике формируют ответ:
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "image/png");
Ответ.УстановитьТелоИзДвоичныхДанных(ДД);
Не отправляйте во внешние публичные сервисы персональные данные, суммы договоров и реквизиты контрагентов. Для такого текста используйте свой сервис внутри сети.
Текст в QR-код
Частый частный случай — закодировать строку в QR для счёта или этикетки. В конфигурациях на БСП для этого есть модуль ГенерацияШтрихкода с функцией ИзображениеШтрихкода. Он работает через компоненту печати штрихкодов и возвращает готовую картинку. Писать свой генератор QR не нужно.
Вывод картинки в печатную форму и макет
Картинку из текста чаще всего печатают. Есть два способа поместить её в табличный документ.
Рисунок в области макета
В макете добавьте рисунок (тип «Картинка») в нужную область и задайте ему имя, например Надпись. В коде:
Макет = ПолучитьМакет("ПечатнаяФорма");
Область = Макет.ПолучитьОбласть("Шапка");
Область.Рисунки.Надпись.Картинка = ТекстВКартинкуSVG(Текст, 20);
ТабДок.Вывести(Область);
Во внешней обработке вызывайте ПолучитьМакет из модуля объекта. Размер рисунка задаётся в макете, а режим масштабирования — свойством рисунка РазмерКартинки.
Рисунок, добавленный программно
Если макета нет, рисунок создают на лету:
Рисунок = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = Картинка;
Рисунок.РазмерКартинки = РазмерКартинки.Пропорционально;
Рисунок.Расположить(ТабДок.Область("R2C2:R6C8"));
Метод Расположить растягивает рисунок на прямоугольник ячеек. Режим Пропорционально сохраняет пропорции надписи и не даёт ей сплющиться.
Сохранить табличный документ прямо в PNG платформа не умеет. Доступны PDF, XLSX, DOCX, HTML и другие форматы через ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.PDF). Картинка внутри PDF сохраняется.
Ошибки при генерации изображений и как их исправить
Ещё две ловушки, которые не дают явной ошибки:
- 🔤 Текст обрезан справа. В SVG-варианте коэффициент ширины 0,6 мал для жирного или широкого шрифта. Увеличьте его или перейдите на PowerShell, где ширину считает
MeasureString. - 🧹 Временный каталог забит файлами. Вызов упал между созданием и удалением файлов. Оберните код в
Попытка … Исключениеи удаляйте файлы в обеих ветках.
Можно ли сделать картинку из текста без внешних программ?
Новый Картинка(ДвоичныеДанные). Для надписей в печатной форме этого достаточно.Работает ли PowerShell-способ в веб-клиенте?
Как вывести текст на картинку поверх фотографии?
[System.Drawing.Image]::FromFile, получите для него Graphics и вызовите DrawString. В ImageMagick для этого есть параметр -annotate.