При разработке печатных форм в системе 1С:Предприятие 7.7 разработчики часто сталкиваются с аппаратными ограничениями штатного табличного документа (так называемого "Мокселя"). Одной из наиболее острых проблем является невозможность напрямую управлять геометрическими размерами и координатами рамки рисунка из встроенного языка 1С. Попытка динамически загрузить картинку (например, логотип компании, изображение товара или факсимиле подписи) в заранее подготовленный макет часто приводит к тому, что изображение либо искажается, либо не влезает в отведенные рамки.
В этой статье мы подробно разберем, как обойти это ограничение платформы. Мы изучим несколько альтернативных подходов: от штатного позиционирования с привязкой к ячейкам до использования мощной внешней компоненты Йоксель (Yoksel) и встроенных системных библиотек Windows для работы с метаданными изображений.
Самый простой и надежный способ управлять физическим размером картинки программно без привлечения сторонних библиотек — это использование механизма привязки графического объекта к сетке ячеек таблицы 1С. Выясним, как работает этот алгоритм.
По умолчанию любой рисунок, добавленный в макет 1С 7.7, позиционируется независимо от ячеек. Однако мы можем изменить это поведение:
После активации этого режима границы рамки жестко привязываются к индексам строк и колонок таблицы. Теперь, чтобы программно изменить физический размер графического "окна" на экране или при печати, нам достаточно программно изменить высоту строк и ширину колонок, на пересечении которых находится данный рисунок.
Проанализируем пример кода, который выполняет масштабирование ячеек под нужные физические параметры:
// Создаем табличный документ
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("МакетСКартинкой");
// Выводим секцию, содержащую привязанную картинку
Таб.ВывестиСекцию("Шапка");
// Определяем область ячеек, к которым привязан наш рисунок.
// Допустим, рисунок расположен в диапазоне строк с 3 по 5 и колонок с 2 по 4.
СтрокаСтарт = 3;
СтрокаКонец = 5;
КолонкаСтарт = 2;
КолонкаКонец = 4;
// Задаем новые физические размеры для ячеек (в пунктах для высоты и символах для ширины)
НоваяВысотаСтроки = 45; // Примерное значение высоты
НоваяШиринаКолонки = 18; // Примерное значение ширины
// Применяем изменения к области таблицы
Для НомерСтроки = СтрокаСтарт По СтрокаКонец Цикл
Таб.Область(НомерСтроки, , НомерСтроки, ).ВысотаСтроки(НоваяВысотаСтроки);
КонецЦикла;
Для НомерКолонки = КолонкаСтарт По КолонкаКонец Цикл
Таб.Область(, НомерКолонки, , НомерКолонки).ШиринаСтолбца(НоваяШиринаКолонки);
КонецЦикла;
// Показываем готовый документ пользователю
Таб.Показать("Печать документа");
Благодаря этому методу картинка автоматически сожмется или растянется вслед за ячейками таблицы. Это исключает необходимость создавать десятки дублирующих секций под разные размеры в конфигураторе.
Если штатных возможностей масштабирования ячеек недостаточно, на помощь приходит специализированная внешняя компонента Йоксель. Она полностью заменяет стандартный движок отображения таблиц 1С 7.7 и предоставляет разработчику колоссальный набор инструментов для работы с графикой.
С помощью Йокселя мы можем напрямую обращаться к объекту графики, динамически создавать рисунки в памяти, точно задавать их координаты в пикселях и изменять размеры изображений "на лету" перед выводом на печать.
Рассмотрим пример загрузки и изменения размеров картинки с использованием объекта Йоксель.Картинка:
// Загружаем внешнюю компоненту Йоксель
Если ЗагрузитьВнешнююКомпоненту("yoksel.dll") = 0 Тогда
Предупреждение("Компонента Йоксель не найдена!");
Возврат;
КонецЕсли;
// Создаем объект графического изображения Йоксель
ЙоксКартинка = СоздатьОбъект("Йоксель.Картинка");
// Загружаем файл изображения с диска
ПутьКФайлу = "C:\images\logo.jpg";
ЙоксКартинка.Загрузить(ПутьКФайлу);
// Программно изменяем размеры картинки до точных значений в пикселях (Ширина, Высота)
НоваяШиринаПикс = 300;
НоваяВысотаПикс = 150;
ЙоксКартинка.ИзменитьРазмер(НоваяШиринаПикс, НоваяВысотаПикс);
// Теперь мы можем сохранить отмасштабированное изображение или внедрить его
// непосредственно в отчет Йокселя по точным координатам без привязки к ячейкам макета.
Использование Йокселя полностью решает проблему "сломанных" макетов, поскольку вся геометрия и параметры позиционирования прописываются непосредственно в коде модуля и не зависят от случайных действий пользователей в конфигураторе.
Часто перед тем как выводить изображение в табличный документ, программисту требуется узнать оригинальное разрешение файла (ширину и высоту в пикселях), чтобы рассчитать пропорции рамки. Вместо тяжелых внешних библиотек можно задействовать стандартные интерфейсы операционной системы Windows через OLE/COM-соединение.
Компонента WIA предустановлена во всех современных версиях операционных систем семейства Windows и позволяет мгновенно считывать свойства медиафайлов.
Разберем по шагам, как прочитать разрешение файла:
Функция ПолучитьРазмерыКартинкиWIA(ПутьКФайлу, Ширина, Высота)
Попытка
WiaImage = СоздатьОбъект("WIA.ImageFile");
WiaImage.LoadFile(ПутьКФайлу);
Ширина = WiaImage.Width;
Высота = WiaImage.Height;
Возврат 1;
Исключение
Сообщить("Ошибка при чтении файла через WIA: " + ОписаниеОшибки(), "!");
Возврат 0;
КонецПопытки;
КонецФункции
Если по какой-то причине библиотека WIA недоступна, мы можем прочитать метаданные файла напрямую из проводника Windows с помощью объекта Shell.Application:
Функция ПолучитьРазмерыЧерезShell(КаталогФайла, ИмяФайла, Ширина, Высота)
Попытка
Shell = СоздатьОбъект("Shell.Application");
Folder = Shell.Namespace(КаталогФайла);
FolderItem = Folder.ParseName(ИмяФайла);
// Индекс 31 в свойствах проводника Windows отвечает за размеры (ширина х высота)
РазмерыТекст = Folder.GetDetailsOf(FolderItem, 31);
// Текст возвращается в формате "?300 x 150", очистим его от лишних символов
ОчищенныйТекст = "";
Для НомерСимвола = 1 По СтрДлина(РазмерыТекст) Цикл
Симв = Сред(РазмерыТекст, НомерСимвола, 1);
Если Найти("0123456789x ", Симв) > 0 Тогда
ОчищенныйТекст = ОчищенныйТекст + Симв;
КонецЕсли;
КонецЦикла;
// Разбираем строку на ширину и высоту
ПозицияРазделителя = Найти(ОчищенныйТекст, "x");
Если ПозицияРазделителя > 0 Тогда
Ширина = СокрЛП(Лев(ОчищенныйТекст, ПозицияРазделителя - 1));
Высота = СокрЛП(Сред(ОчищенныйТекст, ПозицияРазделителя + 1));
Возврат 1;
КонецЕсли;
Исключение
Сообщить("Ошибка Shell: " + ОписаниеОшибки());
КонецПопытки;
Возврат 0;
КонецФункции
При динамической загрузке изображений в подготовленный макет критически важно правильно настроить поведение картинки внутри рамки. Платформа 1С 7.7 предоставляет встроенный метод РежимРисования(), который применяется к объекту типа "Рисунок" в таблице.
Выясним, какие режимы нам доступны и как они влияют на визуализацию изображения:
Проанализируем пример применения режима сохранения пропорций в сочетании с динамической загрузкой файла:
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("Макет");
Таб.ВывестиСекцию("КартинкаТовара");
// Получаем доступ к объекту рисунка по его имени в макете
// Предположим, что рисунок в макете назван "Логотип"
Попытка
Рис = Таб.Рисунок("Логотип");
// Устанавливаем режим рисования "Сохранять пропорции"
Рис.РежимРисования(3);
// Загружаем изображение
Рис.Загрузить("C:\images\product.png");
Исключение
Сообщить("Не удалось загрузить картинку в макет: " + ОписаниеОшибки());
КонецПопытки;
Мы подробно разобрали, как решать проблему фиксированных размеров макетов в 1С 7.7. Наш анализ показывает, что:
РежимРисования(3).