Может ли 1С работать с изображениями? Отчасти да. Например есть возможность изменять размеры, конвертировать в другие форматы. Тем не менее 1С - это далеко не про работу с графикой.
Поделюсь своей болью. При выводе изображения в табличной части (таблице значений или в динамическом списке) нельзя вывести его пропорционально или хотя бы центрировать. Ладно, первую проблему можно решить:
ВысотаКартинки = Картинка.Высота();
ШиринаКартинки = Картинка.Ширина();
КоэффициентСжатия = Мин(
МаксимальнаяВысота / ВысотаКартинки,
МаксимальнаяШирина / ШиринаКартинки
);
ОбрабатываемаяКартинка = Новый ОбрабатываемаяКартинка(Картинка);
ОбрабатываемаяКартинка.УстановитьРазмер(КоэффициентСжатия * ШиринаКартинки, КоэффициентСжатия * ВысотаКартинки);
Возврат ОбрабатываемаяКартинка.ПолучитьКартинку().ПолучитьДвоичныеДанные();
Мы просто сжимаем картинку до размеров миниатюры.
Но когда речь идёт о том, чтобы получившееся изображение показывать по центру ячейки, то здесь так легко не отделаешься. Пожалуй, единственный способ реализации - сделать картинку квадратной, то есть добавить отступы в нужные края картинки. Объектом ОбрабатываемаяКартинка это не реализовать, как и прочими средствами 1С.
Тем не менее есть два пути, чтобы решить эту задачу. Первый и более простой – написать скрипт на Java Script, вывести на форму поле HTML документа и вызывать процедуру из скрипта. Плюс этого способа заключается в том, что JS схож с 1С. Достаточно опытный разработчик сможет прочитать и понять код. Минус – работает только на клиенте.
Второй путь – внешняя компонента. Из плюсов – работает и на клиенте и на сервере. Минус – сложный в освоении. Одно дело на JS написать:
let Image = new Image();
Image.src = base64Image;
На C++ же нужно будет: скачать библиотеку по работе с изображениями, правильно её собрать, слинковать в проект.
Поэтому я остановился на первом варианте. В этой статье распишу работу с JS и связку в 1С. Вот, как это будет выглядеть:
- Сначала напишем и разберем сам скрипт
- Организуем двустороннее взаимодействие JS <-> 1С
1. Скрипт
Скорее всего большинство помнят из школьной программы информатики, как мы рисовали на HTML, используя объект canvas или холст. Его мы и будем использовать.
Получаем объект класса Image
let currentImage = new Image();
currentImage.src = base64Image;
В JS загрузка картинки происходит ассинхронно, поэтому нужно дождаться, когда картинка подгрузится и только потом её обрабатывать. Вот, как это выглядит:
currentImage.onload = function() {
// СЮДА пишем обработчик после загрузки
}
Внутри конструкции создаем canvas, выводим на него изображение:
const tempCanvas = document.createElement("canvas"); // создание холста
tempCanvas.width = currentImage.width; // назначение ему ширину и высоту как у картинки
tempCanvas.height = currentImage.height;
const ctx = tempCanvas.getContext("2d"); // получаем контекст. Это объект, с помощью которого изменяем холст.
ctx.drawImage(currentImage, 0, 0); // выводим изображение на холст в точке 0,0 то есть левый верхний угол
Теперь нам нужно определиться с тем, какого цвета мы будем делать паддинги. Разумеется, мы хотим, чтобы их не было видно, то есть чтобы они были в цвет фона. Сделаем максимально просто: получим левый верхний пиксель и будем считать, что это и есть наш цвет фона.
pixelData = ctx.getImageData(0, 0, 1, 1).data; // получение одного пикселя по ширине и высоте в левом верхнем углу
const bg = {
'r': pixelData[0],
'g': pixelData[1],
'b': pixelData[2],
'a': pixelData[3]
}; // a – это прозрачность. Доступна на png картинках, это нужно учитывать.
Определяем новую ширину и высоту. Это должен быть квадрам – максимум между высотой и шириной.
const new_width_height = Math.max(currentImage.width, currentImage.height);
tempCanvas.width = new_width_height;
tempCanvas.height = new_width_height; // При изменении этих свойств холст очищается и контекст сбрасывается
ctx.imageSmoothingEnabled = false; // После сброса контекста отключим сглаживание картинки. Из-за него картинка получается мыльной
Далее нужно заполнить холст новым фоном и вывести картинку ровно посередине холста.
ctx.fillStyle = `rgba(${bg.r},${bg.g},${bg.b},${bg.a / 255})` // установка цвета фона
ctx.fillRect(0, 0, tempCanvas.width, tempCanvas.height); // вывод закрашенного прямоугольника на весь холст
ctx.drawImage(
currentImage,
(new_width_height - currentImage.width) / 2,
(new_width_height - currentImage.height) / 2
);
В конце получаем результирующую картинку в виде base64 строки.
resultImage = tempCanvas.toDataURL("image/png");
На этом всё. Достаточно просто. Но вот в чём вопрос. Если мы из 1С просто вызовем нашу готовую функцию, то мы ничего не получим в ответ. Причина – та самая ассинхронная обработка загрузки изображения. Как сделать так, чтобы после обработки триггернуть 1С, чтобы она получила результат? Ниже опишу систему взаимодействия 1С и JS.
2. 1С -> JS
Нам нужен объект приложения, к которому будем обращаться. Получить его так:
ОбработчикИзображений = Элементы.HTMLДокумент.Документ.defaultView;
Примечание: после открытия формы может пройти какое-то время, прежде чем прогрузится страница HTML. Правильно было бы дождаться этого события. Для этого у поля HTML документа есть событие ДокументСформирован.
Выведем в начало формы отдельную переменную, куда поместим наш обработчик изображений, а после загрузки страницы назначим ей наше приложение.
#Область ОписаниеПеременных
&НаКлиенте
Перем ОбработчикИзображений;
#КонецОбласти
// ...
#Область ОбработчикиСобытийЭлементовШапкиФормы
&НаКлиенте
Процедура HTMLДокументДокументСформирован(Элемент)
ОбработчикИзображений = Элементы.HTMLДокумент.Документ.defaultView;
КонецПроцедуры
#КонецОбласти
После этого мы можем в любой клиентской процедуры вызывать функции из нашего приложения. Примерно так:
Если ОбработчикИзображений <> Неопределено Тогда
ОбработчикИзображений.MakeImageSquared();
КонецЕсли;
3. JS -> 1С
Здесь всё интереснее. Решение чуть костыльное на мой взгляд, но другого способа я найти не смог.
Мы можем увидеть, что у поля HTML документа есть событие ПриНажатии. Почему бы не попробовать в HTML создать некую служебную кнопку и имитировать её нажатие? Так и сделаем.
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Обработка изображений </title>
</head>
<body>
<button id='interactionButton' style='display: none'>Кнопка взаимодействия</button>
<script>
// ОПИСАНИЕ ПЕРЕМЕННЫХ
let interactionButton = null;
// НАЗНАЧЕНИЕ ПЕРЕМЕННЫХ
document.addEventListener('DOMContentLoaded', function() {
interactionButton = document.getElementById('interactionButton');
});
////////////////////////////////////////////////////////////////////////////
// ЗДЕСЬ НАПИСАНА НАША ФУНКЦИЯ ПО ОБРАБОТКЕ КАРТИНКИ
////////////////////////////////////////////////////////////////////////////
</script>
</body>
</html>
Здесь мы в документе создали невидимую кнопку с id='interactionButton', в скрипте создали глобальную переменную interactionButton и после загрузки страницы назначили этой переменной нашу кнопку.
Теперь после того, как мы обработали картинку, мы можем просто сделать так:
interactionButton.Click();
И вот оно – чудо! 1С триггернулась на то, что в JS мы сымитировали клик невидимой кнопки.

Дальше мы можем с этим работать, как хотим. Я сделал так: в JS поместил результирующую картинку в отдельную переменную, написал простейшую функцию GetResult(), в которой просто возвращаю результат, а в 1С в поле HTML документа в событии ПриНажатии вызываю эту функцию, которая выдаёт мне желанный результат.
4. Последний вопрос
Как сделать поле HTML документа невидимым? Если просто сделать Элемент.Видимость = Ложь, то HTML страница не загрузится. И правильно: зачем ей это, если на неё не смотрят? Но мы обойдём и это.

Создадим группу – страницы и поставим ей Отображение страниц = Нет. На первой странице будет наш привычный интерфейс, а на второй – наше видимое, но скрытое поле HTML документа.
Вот наш результат:

Внутренний перфекционист доволен!
Мы можем прописать другую логику расширения изображения. Например, просто сделать паддинги прозрачными, а не брать первый пиксель. Всё зависит от задачи.
Заключение
Это небольшой демонстрационный пример, показывающий возможности, которые скрыты в описанной технологии. На самом деле возможности гораздо шире. Можно сделать простой графический редактор, красивый рабочий стол и много того, на что хватит фантазии.
Прикладываю обработку с тестовым цельным примером, который описал в статье. Обработка разрабатывалась и тестировалась на платформе 8.3.26.1540, но будет работать и на более старых версиях. БСП не требуется.
Вступайте в нашу телеграмм-группу Инфостарт