Генерация изображения из строки в 1С 8.3: SVG, PowerShell, HTTP и вывод в макет

· 10 мин

Содержание

Преобразовать текст в картинку в 1С проще всего так: собрать из строки SVG-разметку и передать её в конструктор Новый Картинка(ДвоичныеДанные). Если нужен растровый PNG с конкретным шрифтом, текст рендерят внешней программой (PowerShell или ImageMagick) из внешней обработки и загружают готовый файл обратно в объект Картинка.

Встроенной функции вида «ТекстВКартинку» в платформе 1С:Предприятие 8.3 нет. Зато есть всё, чтобы её собрать: тип Картинка, двоичные данные, запуск внешних программ, HTTP-клиент и рисунки табличного документа. Задача общая для платформы и не зависит от конфигурации: код одинаково работает в Бухгалтерии, УТ или самописной базе.

Что подготовить и какой способ выбрать

Сначала решите три вопроса. От ответов зависит способ.

  • 🖥️ Где выполняется код. На клиенте или на сервере, Windows или Linux. COM и PowerShell есть только в Windows.
  • 🖼️ Какой нужен формат. Для печатной формы и поля формы хватит SVG. Для отправки по почте, на сайт или в мессенджер обычно нужен PNG или JPEG.
  • 🔒 Есть ли права. Внешней обработке нужна роль с правом интерактивного открытия внешних обработок. В режиме безопасного выполнения запуск программ и COM запрещены.
СпособКогда подходитОграничения
SVG средствами платформыПростая надпись, печатная форма, поле картинкиШрифт берётся из системы, перевод в PNG поддерживается не везде
PowerShell + System.DrawingWindows, нужен PNG с выбранным шрифтомТолько Windows, нужен доступ к временному каталогу
ImageMagickLinux-сервер или пакетная обработкаПрограмму надо установить и прописать путь
COM-объектыЕсть готовая COM-библиотека для графикиТолько Windows, Office на сервере ставить не стоит
HTTP-сервисРендер вынесен на отдельный серверНужна сеть и свой или сторонний сервис
Модуль штрихкодов БСПТекст нужно превратить в QR-кодЭто не надпись, а код для сканера

Для отладки удобна внешняя обработка: её не нужно встраивать в конфигурацию, а правки видны после повторного открытия файла.

Встроенные средства платформы: картинка из SVG

Тип Картинка умеет создаваться из двоичных данных. Формат платформа определяет по содержимому. SVG — это обычный XML-текст, поэтому его легко собрать строкой прямо в коде 1С.

Порядок действий:

  1. Экранируйте в тексте символы &, < и >, иначе разметка сломается.
  2. Разбейте текст на строки по Символы.ПС, чтобы перенос строки сохранился.
  3. Посчитайте ширину и высоту холста от длины самой длинной строки и размера шрифта.
  4. Соберите строку SVG и превратите её в двоичные данные.
  5. Создайте объект Картинка.
Функция ТекстВКартинкуSVG(Знач Текст, РазмерШрифта = 24, ИмяШрифта = "Arial") Экспорт

	Текст = СтрЗаменить(Текст, "&", "&amp;");
	Текст = СтрЗаменить(Текст, "<", "&lt;");
	Текст = СтрЗаменить(Текст, ">", "&gt;");

	Строки = СтрРазделить(Текст, Символы.ПС, Истина);
	МаксДлина = 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.

Внешняя обработка для генерации изображения

Отлаживать код удобнее во внешней обработке, а не в конфигурации. Порядок:

  1. В Конфигураторе выберите Файл → Новый → Внешняя обработка.
  2. Добавьте реквизит Текст (строка неограниченной длины) и форму.
  3. На форму добавьте реквизит АдресКартинки (строка) и поле картинки с путём к данным АдресКартинки.
  4. Создайте команду «Сформировать» и серверную процедуру с вызовом одной из функций выше.
  5. Сохраните файл .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.
  • 🧹 Временный каталог забит файлами. Вызов упал между созданием и удалением файлов. Оберните код в Попытка … Исключение и удаляйте файлы в обеих ветках.
Можно ли сделать картинку из текста без внешних программ?
Да. Соберите SVG-строку и создайте Новый Картинка(ДвоичныеДанные). Для надписей в печатной форме этого достаточно.
Работает ли PowerShell-способ в веб-клиенте?
Нет. Браузер не даёт запускать программы на компьютере пользователя. Выполняйте генерацию на сервере 1С под Windows или используйте SVG либо HTTP-сервис.
Как вывести текст на картинку поверх фотографии?
В PowerShell загрузите исходное изображение через [System.Drawing.Image]::FromFile, получите для него Graphics и вызовите DrawString. В ImageMagick для этого есть параметр -annotate.
Какой формат выбрать для хранения в базе?
PNG. Он без потерь и для текста весит меньше JPEG, а буквы остаются чёткими.