Печать макетов CorelDraw 2019 из 1С через COM: FindShape, ReplaceText, Export/Import JPG/PNG
1. Постановка задачи
Типовые средства вывода 1С - СКД и табличный документ (MXL) - закрывают подавляющее большинство печатных форм. Но есть класс задач, где их недостаточно: этикетки, ярлыки, упаковка, наклейки, бирки, пропуска. Здесь нужен векторный макет, подготовленный дизайнером в CorelDraw: точные кривые, цветопроба, фирменный стиль, готовность к допечатной подготовке.
Задача: не пересоздавать макет в 1С, а взять готовый .cdr, подставить в него данные из базы (наименование, цена, штрихкод) и напечатать - по нажатию кнопки на форме обработки.
Решение - автоматизация CorelDraw через COM. 1С на клиенте подключается к локально установленному CorelDraw 2019, открывает шаблон, находит именованные объекты, заполняет их и выводит на печать или в PDF.

CorelDRAW 2019 - именно эта версия используется для автоматизации через COM
2. Архитектура решения
Логика - во внешней обработке 1С (.epf) с формой и командой «Печать».
COM-объект создаётся НА КЛИЕНТЕ (&НаКлиенте, Новый COMОбъект). Серверный контекст не подходит - CorelDraw установлен на рабочем месте пользователя.
Требования к рабочему месту: Windows, CorelDraw 2019, толстый или тонкий клиент. Веб-клиент COM не поддерживает.
Разрядность: COM-сервер CorelDraw и платформа 1С должны совпадать по битности процесса либо работать через out-of-process COM (CorelDraw запускается отдельным процессом, это штатно).
3. Подключение к COM-объекту CorelDraw
ProgID для CorelDraw 2019 - CorelDRAW.Application.21 (21 - версия движка). Подключение оборачиваем в Попытку: если Corel не установлен или COM не зарегистрирован, выдаём понятное сообщение и выходим.

Код подключения к CorelDRAW 2019 через COM-объект в 1С
4. Объектная модель CorelDraw для 1С-разработчика
Чтобы заполнять макет из кода, нужно понимать иерархию объектов CorelDraw. Она напоминает DOM:

Ключевая идея: дизайнер задаёт объектам на макете осмысленные имена, а код 1С находит их по этим именам и подставляет данные. Это контракт между макетом и кодом.
Важно по версии 2019: имя объекта (свойство Shape.Name, по которому работает FindShape) задаётся в докере Objects (бывший Object Manager), а не в докере Properties (бывший Object Properties - там только заливка, обводка, размеры). Открыть докер: Window → Dockers → Objects.
Справочник методов SDK: community.coreldraw.com - Shapes.FindShape (Draw 21)

Портал API-документации CorelDRAW 2019 на community.coreldraw.com (работает через VPN) - здесь описаны все методы, используемые в статье.
Соглашение об именовании плейсхолдеров:
Договоритесь с дизайнером о префиксе для заполняемых объектов, например ph_ (placeholder):
| Имя объекта в Corel | Источник данных в 1С |
| ph_name | Номенклатура.Наименование |
| ph_price | ЦенаНоменклатуры |
| ph_barcode | Штрихкод (текст или картинка) |
| ph_article | Номенклатура.Артикул |
4.1. Где именно задаётся имя объекта
Связь макета и кода держится на одном свойстве - имени объекта. Схема ниже показывает всю цепочку: от выделенного объекта на макете до строки кода 1С, которая его находит.
Пошагово, как дизайнер проставляет имя в CorelDraw 2019:
Открыть докер: Window → Dockers → Objects (Ctrl+F9). Появится дерево слоёв и объектов страницы.
Выделить нужный объект на макете (например текстовую надпись с ценой) - в дереве подсветится соответствующая строка.
Дважды кликнуть по названию строки (или правый клик → Rename) и ввести имя плейсхолдера, например ph_price.
Имя сохраняется в свойстве Shape.Name внутри файла .cdr. Именно его принимает Shapes.FindShape("ph_price").
По умолчанию объекты имеют системные названия (Curve, Artistic Text, Rectangle) - FindShape по ним работать не должен. Имена-плейсхолдеры проставляются вручную один раз при подготовке шаблона.
Это и есть контракт: поменяли имя в макете - правим строку в коде, и наоборот.

Докер Objects в CorelDRAW 2019: структура Page → Layer → объекты. Правый клик → Rename для присвоения имени плейсхолдера

Рабочая область CorelDRAW 2019 с открытым докером Objects (справа) - дерево объектов текущей страницы
5. Поиск объектов на макете: FindShape
Есть два способа добраться до объекта: метод FindShape (поиск по имени напрямую) и обход коллекции Shapes с проверкой свойства Name. FindShape короче и быстрее, но возвращает Неопределено/ничего, если объект не найден - это нужно проверять.
Вариант А - FindShape:
// 1C (BSL)
Страница = Документ.ActivePage;
Объект = Страница.Shapes.FindShape("ph_name");
Если Объект = Неопределено Тогда
Сообщить("На макете нет объекта ph_name");
Иначе
Объект.Text.Story.Text = "Вода питьевая 19 л";
КонецЕсли;
SDK CorelDRAW 2019: Shapes.FindShape - параметры Name, Type, StaticID, Recursive, Query (Corel Query Language)
Вариант Б - обход коллекции Shapes:
Полезен, когда нужно перебрать все плейсхолдеры или FindShape ведёт себя нестабильно на конкретной сборке Corel:
// 1C (BSL)
Страница = Документ.ActivePage;
Для НомерОбъекта = 1 По Страница.Shapes.Count Цикл
Объект = Страница.Shapes.Item(НомерОбъекта);
Если Лев(Объект.Name, 3) = "ph_" Тогда
Сообщить("Найден плейсхолдер: " + Объект.Name);
КонецЕсли;
КонецЦикла;
6. Подстановка данных: работа с текстом
Текст объекта живёт в Shape.Text.Story. Свойство .Text перезаписывает содержимое целиком, сохраняя форматирование рамки (шрифт, размер, цвет заданы в макете).
// 1C (BSL)
Процедура ЗаполнитьТекст(Страница, ИмяОбъекта, Значение)
Объект = Страница.Shapes.FindShape(ИмяОбъекта);
Если Объект <> Неопределено Тогда
Объект.Text.Story.Text = Значение;
КонецЕсли;
КонецПроцедуры
Точечная замена подстроки (ReplaceText)
Когда нужно заменить не весь текст, а маркер внутри (например {PRICE} в готовой надписи), используется метод ReplaceText текстовой истории:
// 1C (BSL)
// Заменить маркер {PRICE} на значение, без учёта регистра, целые слова
Объект = Страница.Shapes.FindShape("ph_label");
Если Объект <> Неопределено Тогда
Объект.Text.Story.ReplaceText("{PRICE}", "250 руб", Ложь, Ложь, Ложь);
КонецЕсли;
// Параметры (по документации SDK): ИскомыйТекст, НовыйТекст,
// CaseSensitive, WholeWord, WildCards
Точную сигнатуру ReplaceText и допустимые параметры берите из SDK по версии Draw 21 - поведение флагов отличается между релизами Corel.
6.1. Управление порядком наложения: OrderToBack() и др.
При подстановке данных часто нужно управлять тем, что находится спереди, а что сзади: логотип - на задний план под текст, штрихкод - поверх фона, плашку с ценой - над картинкой. За это отвечает stacking order (порядок наложения) - методы группы Order у объекта Shape и диапазона ShapeRange.
Скриншот из SDK (CorelDRAW 2019 → ShapeRange → метод OrderToBack):
Основные методы порядка наложения (вызываются у Shape или у ShapeRange):
| Метод | Действие |
| OrderToBack() | На самый задний план слоя (под все объекты) |
| OrderToFront() | На самый передний план слоя (поверх всех) |
| OrderBackOne() | На один уровень назад |
| OrderForwardOne() | На один уровень вперёд |
| OrderBackOf(Shape) | Поместить за указанный объект |
| OrderFrontOf(Shape) | Поместить перед указанным объектом |

Пример: логотипы на задний план
Метод FindShapes (множественное число) возвращает диапазон всех объектов, подходящих под критерий. Второй параметр - тип объекта (число из перечисления типов SDK). Дальше цикл по найденным объектам с OrderToBack():
// 1C (BSL)
// Логотип помещаем на задний слой
// https://community.coreldraw.com/sdk/api/draw/21/m/shaperange.ordertoback
СписокЛоготиповПриемник = ActiveLayer.Shapes.FindShapes("", 5);
Для Каждого Лого Из СписокЛоготиповПриемник Цикл
Лого.OrderToBack();
КонецЦикла;
Второй параметр FindShapes - код типа объекта (например 5 в примере). Точные значения типов берите из перечисления SDK для Draw 21; при поиске по имени используйте FindShape (единственное число), по типу/массово - FindShapes.
SDK CorelDRAW 2019: перечисление cdrShapeType - коды типов объектов для параметра Type в FindShape/FindShapes. cdrBitmapShape = 5 (логотипы/картинки), cdrTextShape = 6 (текст), cdrRectangleShape = 1

Типовые сценарии порядка в шаблоне этикетки:
1. Фоновая подложка (плашка, рамка) - OrderToBack(), чтобы текст и штрихкод всегда были поверх.
2. Логотип - на задний план или сразу за текстом через OrderBackOf(ТекстовыйОбъект).
3. Штрихкод/QR, импортированный в макет - OrderToFront(), чтобы его не перекрыла подложка.
4. Цена в цветной плашке - плашка OrderBackOf(ph_price), сам текст ph_price остаётся сверху.
Управление порядком обычно делают один раз после импорта новых элементов (картинок, штрихкодов) в макет - до вывода на печать.
6.2. Импорт JPG-фото в макет
Кроме текста в макет часто нужно вставить картинку из базы: фото сотрудника на бейдж, фото слушателя в удостоверение, изображение товара на этикетку. Картинка хранится в 1С (реквизит, хранилище значения), её нужно выгрузить во временный файл и импортировать в CorelDraw методом Import.
Логика разбивается на пять шагов:
1. Получить картинку из базы и выгрузить во временный JPG-файл на клиенте (ПолучитьИзВременногоХранилища → ЗаписатьДвоичныеДанные).
2. Найти на макете объект-контейнер по имени (FindShape с типом 5 — bitmap-область, заданная дизайнером как место под фото).
3. Импортировать файл в активный слой: ActiveLayer.Import(ИмяФайла, ...) — фото попадает в документ как новый объект.
4. Подогнать импортированное фото под габариты и центр контейнера (SizeWidth/SizeHeight + CenterX/CenterY).
5. Удалить временный файл (УдалитьФайлы) — не оставлять мусор на диске пользователя.
Боевой пример процедуры (фото слушателя из карточки физлица (Справочник.ФизическиеЛица) в макет удостоверения):
// 1C (BSL)
&НаКлиенте
Процедура НайтиЗаменитьФото(ActiveLayer, СтрДанных)
Попытка
АдресФото = ПолучитьФайлФотографииНаСервере(СтрДанных.Слушатель);
Исключение
ОбщегоНазначенияКлиент.СообщитьПользователю(ОписаниеОшибки());
Возврат;
КонецПопытки;
дд = ПолучитьИзВременногоХранилища(АдресФото);
ИмяФайлаФото = ПолучитьИмяВременногоФайла("jpg");
Попытка
дд.Записать(ИмяФайлаФото);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("Не удалось записать файл фотографии %1", ИмяФайлаФото);
Сообщение.Сообщить();
КонецПопытки;
// https://community.coreldraw.com/sdk/api/draw/21/m/shapes.findshape?lang=cli
containerShape = ActiveLayer.Shapes.FindShape(СтрДанных.ShapeName, 5);
Если НЕ containerShape = Неопределено Тогда
Попытка
ActiveShape = ActiveLayer.Import(ИмяФайлаФото, 0, СтрДанных.StructImportOptions);
ActiveShape = СтрДанных.Документ.Selection();
ActiveShape.SizeWidth = containerShape.SizeWidth;
ActiveShape.SizeHeight = containerShape.SizeHeight;
ActiveShape.CenterX = containerShape.CenterX;
ActiveShape.CenterY = containerShape.CenterY;
Исключение
ОбщегоНазначенияКлиент.СообщитьПользователю(СтрШаблон("В карточке слушателя %1 нет фото!", СтрДанных.Слушатель));
КонецПопытки;
ActiveShape = Неопределено;
КонецЕсли;
УдалитьФайлы(ИмяФайлаФото);
КонецПроцедуры
Процедура импорта JPG-фото из базы 1С в макет CorelDRAW: выгрузка во временный файл, поиск контейнера, Import, подгонка по габаритам и центру
Ключевые моменты:
- Контейнер на макете (containerShape) задаёт область фото: дизайнер рисует прямоугольник/рамку нужного размера и именует его. Габариты этого объекта и наследует фото.
- Тип 5 в FindShape (cdrBitmapShape) - ищем именно растровый плейсхолдер. Если контейнер задан прямоугольником, используйте тип 1 (cdrRectangleShape) или поиск по имени без типа.
- Import возвращает результат в Selection() - сразу после импорта выделен вставленный объект, его и берём в ActiveShape.
- CenterX/CenterY центрируют фото по центру контейнера; SizeWidth/SizeHeight растягивают точно по габаритам (пропорции могут исказиться - если важно их сохранить, считайте коэффициент вручную или используйте PowerClip).
- Третий параметр Import - StructImportOptions (опции импорта). Их состав зависит от версии SDK; для простого импорта можно передавать пустую структуру опций.
- Обратите внимание на обработку исключений: если у слушателя нет фото в базе, процедура не падает, а выдаёт понятное сообщение и продолжает печать остальных полей. Для тиражной печати это критично - одна пустая карточка не должна срывать весь пакет.
7. Передача данных из 1С в макет
Удобно описать соответствие «имя объекта Corel ↔ значение» структурой и пройти по ней одним циклом. Это разделяет данные и механику заполнения.
// 1C (BSL)
&НаКлиенте
Процедура ЗаполнитьМакет(Документ, ДанныеЭтикетки)
Страница = Документ.ActivePage;
Соответствие = Новый Структура;
Соответствие.Вставить("ph_name", ДанныеЭтикетки.Наименование);
Соответствие.Вставить("ph_price", ДанныеЭтикетки.Цена);
Соответствие.Вставить("ph_article", ДанныеЭтикетки.Артикул);
Для Каждого КЗ Из Соответствие Цикл
Объект = Страница.Shapes.FindShape(КЗ.Ключ);
Если Объект <> Неопределено Тогда
Объект.Text.Story.Text = Строка(КЗ.Значение);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Тираж: цикл по строкам табличной части
Для печати пачки этикеток перебираем строки ТЧ. Шаблон можно переоткрывать на каждую строку или подставлять данные и печатать по очереди в одной сессии (быстрее):
// 1C (BSL)
Для Каждого Строка Из Объект.Товары Цикл
ДанныеЭтикетки = Новый Структура("Наименование, Цена, Артикул",
Строка.Наименование, Строка.Цена, Строка.Артикул);
ЗаполнитьМакет(Документ, ДанныеЭтикетки);
Документ.PrintOut(); // печать текущего состояния макета
КонецЦикла;
8. Вывод на печать:
После открытия и заполнения макета CorelDraw (наполнение и замещение макета данными будет идти не быстро!), пользователь смотрит корректность заполнения и печатает стандартными методами CorelDraw и ОС Windows.
9. Обработка ошибок и крайние случаи
| Ситуация | Что делать |
| CorelDraw не установлен | Попытка при создании COM, понятное сообщение, выход |
| Другая версия Corel | Перебор ProgID: .21, затем без суффикса; либо настройка версии |
| Объект-плейсхолдер не найден | Проверка FindShape <> Неопределено, лог имени |
| Завис процесс CorelDRW.exe | Гарантированный Close()/Quit() в блоке после Попытки |
| Диалог сохранения при Close | Закрывать без сохранения изменений шаблона |
| Утечки COM | Обнулять переменные (= Неопределено) после Quit |
Автоопределение версии (если на рабочих местах разные сборки):
// 1C (BSL)
Функция ПодключитьCorelDrawАвто()
ВерсииProgID = "CorelDRAW.Application.21,CorelDRAW.Application";
Для Каждого ProgID Из СтрРазделить(ВерсииProgID, ",") Цикл
Попытка
Возврат Новый COMОбъект(СокрЛП(ProgID));
Исключение
КонецПопытки;
КонецЦикла;
Сообщить("CorelDRAW не найден ни в одной поддерживаемой версии.");
Возврат Неопределено;
КонецФункции
10. Производительность и UX
1. Для тиражной фоновой печати ставьте CorelApp.Visible = Ложь - окно не мелькает, печать быстрее.
2. Переиспользуйте одну сессию Application на весь тираж - создание COM-объекта дорогое.
3. Закрывайте документ без сохранения изменений в шаблоне, иначе CorelDraw 2019 покажет модальный диалог и заблокирует поток.
4. Показывайте прогресс по строкам тиража - печать пачки этикеток занимает время.
11. Чек-лист внедрения
| Пункт | Как проверить |
| CorelDraw 2019 установлен | ProgID CorelDRAW.Application.21 создаётся |
| Клиент Windows (не веб) | Толстый/тонкий клиент |
| Имена плейсхолдеров заданы | Object Properties → Name = ph_* |
| Шаблон .cdr доступен по пути | OpenDocument не падает |
| Права на запуск COM | DCOM-конфигурация / UAC |
| Принтер настроен | PrintOut выводит лист |
12. Заключение
COM-автоматизация CorelDraw из 1С закрывает разрыв между учётной системой и допечатной подготовкой: дизайнер отвечает за макет, 1С - за данные и тираж. Подход применим к печати упаковки, бирок, ярлыков, пропусков, наклеек - везде, где нужен векторный фирменный шаблон, заполняемый данными из базы.
Вступайте в нашу телеграмм-группу Инфостарт