Как сохранить диаграмму в графический файл на сервере 1С, если метод ПолучитьКартинку возвращает пустой файл?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Мы рассмотрим сложную проблему, с которой сталкиваются разработчики 1С:Предприятия при попытке сохранить диаграмму в графический файл непосредственно на сервере. Метод ПолучитьКартинку объекта Диаграмма, который прекрасно работает на клиенте, при вызове на сервере зачастую возвращает пустой графический файл. Разберем, почему это происходит, и какие подходы можно использовать для решения этой задачи.

Суть проблемы: Метод ПолучитьКартинку на сервере возвращает пустую картинку

Ситуация, описанная в первом сообщении форума, является достаточно распространенной для разработчиков 1С:Предприятия. При попытке получить изображение диаграммы и сохранить его в файл на сервере с помощью следующего кода:


ГрафикКартинка = График.ПолучитьКартинку(,,ФорматКартинки.PNG);
ГрафикКартинка.Записать("C:\temp\график.PNG");

где График — это объект типа Диаграмма, в результате получается пустой графический файл указанного формата. При этом, если точно такой же код выполнить на клиенте, файл сохраняется корректно, содержа изображение диаграммы. Данная проблема проявляется как в регламентных заданиях, так и в обычных серверных процедурах, что подтверждается сообщениями 5 и 7 из обсуждения.

Проведенный анализ показал, что проблема заключается именно в методе ПолучитьКартинку. При его выполнении на сервере, получаемые двоичные данные картинки отличаются от тех, что получаются на клиенте, и соответствуют пустому изображению. Попытки указать конкретные размеры картинки (например, 200x200) также не привели к изменению ситуации: на сервере по-прежнему генерируется пустая картинка заданных размеров, как отмечено в сообщении 9.

Почему метод ПолучитьКартинку может работать некорректно на сервере?

Для понимания причин такого поведения необходимо глубже рассмотреть архитектуру платформы 1С:Предприятие и особенности работы серверного компонента.

  1. Отсутствие графического интерфейса (GUI) на сервере. Сервер 1С:Предприятия, как правило, запускается в качестве службы операционной системы и не имеет собственного графического интерфейса. Методы, которые требуют отрисовки графики или доступа к системным графическим библиотекам для рендеринга изображения (например, GDI+ в Windows), могут работать некорректно или вообще не работать в такой среде. Сервер может просто не иметь необходимых ресурсов или контекста для "рисования" диаграммы.
  2. Различия в контекстах выполнения. Клиентское приложение 1С имеет полный доступ к графическим возможностям операционной системы пользователя. Серверное же приложение выполняется в изолированном контексте, который может быть ограничен как с точки зрения доступа к ресурсам, так и с точки зрения используемых системных библиотек.
  3. Права доступа учетной записи сервера. Служба агента сервера 1С:Предприятия запускается от имени определенной учетной записи Windows (например, Local System, Network Service или специализированная пользовательская учетная запись). Эта учетная запись может не иметь достаточных прав для создания графических объектов в памяти или доступа к необходимым графическим компонентам операционной системы.
  4. Особенности реализации платформы 1С. Вполне возможно, что реализация метода ПолучитьКартинку для серверного вызова содержит логику, которая по каким-то причинам не может быть успешно завершена в "безголовом" режиме, или опирается на компоненты, отсутствующие в серверном окружении по умолчанию.

Подтвержденные диагностики и обходные пути

В ходе обсуждения были сделаны важные наблюдения, которые помогают сузить круг поиска решения и предложить обходные пути:

  1. Данные диаграммы присутствуют. Как было подтверждено в сообщении 3, данные для диаграммы точно есть и они корректны. Проблема не в отсутствии данных для построения, а именно в процессе их визуализации в графический файл на сервере.
  2. Сохранение через табличный документ работает. В сообщении 3 указано, что если поместить эту же диаграмму в табличный документ, а затем сохранить табличный документ как файл PDF на сервере, то график сохраняется в PDF-файле корректно. Это очень важный факт! Он указывает на то, что объект ТабличныйДокумент, вероятно, использует другие, более надежные механизмы для работы с графикой на сервере, которые не зависят от наличия GUI или других специфических графических библиотек. Это может быть связано с тем, что табличный документ не "рисует" картинку сам, а скорее, инкапсулирует данные и использует специализированный компонент для экспорта в PDF, который способен самостоятельно рендерить графические объекты.

Предлагаемые подходы и решения

Учитывая выявленные особенности, мы можем рассмотреть несколько стратегий для решения задачи сохранения диаграммы в файл на сервере.

1. Генерация картинки на клиенте и передача на сервер

Поскольку на клиенте метод ПолучитьКартинку работает корректно, одним из наиболее надежных обходных путей является генерация изображения на стороне клиента, а затем его передача на сервер для сохранения в файл.

Шаги реализации:

  1. На клиенте: Получаем картинку из диаграммы и её двоичные данные.
    
    // В клиентской процедуре
    ГрафикКартинка = Элементы.ПолеДиаграммы.Значение.ПолучитьКартинку(,,ФорматКартинки.PNG); // Элементы.ПолеДиаграммы.Значение - это сама Диаграмма
    ДвоичныеДанныеКартинки = ГрафикКартинка.ПолучитьДвоичныеДанные();
    
  2. На клиенте: Передаем двоичные данные на сервер. Для этого можно использовать временное хранилище или передать их напрямую в серверную процедуру, если объем данных не слишком велик.
    
    // Продолжение клиентской процедуры
    АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеКартинки, УникальныйИдентификатор);
    

    Затем вызываем серверную процедуру:

    
    // Вызов серверной процедуры
    СохранитьКартинкуНаСервере(АдресВременногоХранилища, "C:\temp\график.PNG");
    
  3. На сервере: Получаем двоичные данные из временного хранилища и сохраняем их в файл.
    
    // Серверная процедура
    Процедура СохранитьКартинкуНаСервере(АдресВременногоХранилища, ПутьКФайлу) Экспорт
        ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
        Если ДвоичныеДанные <> Неопределено Тогда
            ДвоичныеДанные.Записать(ПутьКФайлу);
        Иначе
            ЗаписьЖурналаРегистрации(НСтр("ru='Не удалось получить данные картинки из временного хранилища.'"), УровеньЖурналаРегистрации.Ошибка);
        КонецЕсли;
    КонецПроцедуры
    

Важно: Этот метод подходит, если инициация сохранения может происходить с клиента (например, по кнопке пользователя). Для регламентных заданий или полностью серверного кода этот вариант не подходит, поскольку клиент отсутствует.

2. Использование Табличного Документа как посредника (для серверных задач)

Как было выяснено, сохранение диаграммы в PDF через табличный документ на сервере работает корректно. Этот подход является весьма ценным, если конечной целью может быть PDF-файл. К сожалению, напрямую получить растровый графический файл (PNG, JPG) из табличного документа на сервере без GUI может быть также затруднительно из-за тех же ограничений. Однако, сам факт успешной работы с PDF указывает на потенциал.

Принцип: Объект ТабличныйДокумент, по всей видимости, имеет свои собственные механизмы рендеринга графических объектов или использует системные компоненты, которые доступны на сервере и не требуют активного GUI. Он способен корректно обрабатывать и встраивать диаграмму для последующего экспорта в PDF.

Пример кода для сохранения в PDF (подтвержденный обходной путь):


// Серверная процедура (например, в регламентном задании)
Процедура СохранитьДиаграммуВPDFНаСервере() Экспорт
    // Предположим, у нас есть Диаграмма с данными
    Диаграмма = Новый Диаграмма;
    // ... Заполняем Диаграмму данными (пример) ...
    Диаграмма.Заголовок = "Пример Диаграммы";
    Диаграмма.ТипДиаграммы = ТипДиаграммы.ГистограммаОбъемная;

    Серия1 = Диаграмма.Серии.Добавить();
    Серия1.Имя = "Серия 1";
    Серия1.Значение = 100;

    Серия2 = Диаграмма.Серии.Добавить();
    Серия2.Имя = "Серия 2";
    Серия2.Значение = 150;

    Точка1 = Диаграмма.Точки.Добавить();
    Точка1.Имя = "Точка 1";
    Точка1.Значение = 1;

    Значение11 = Диаграмма.Значения.Добавить();
    Значение11.Серия = Серия1;
    Значение11.Точка = Точка1;
    Значение11.Значение = 20;

    Значение12 = Диаграмма.Значения.Добавить();
    Значение12.Серия = Серия2;
    Значение12.Точка = Точка1;
    Значение12.Значение = 30;

    // Создаем новый ТабличныйДокумент
    ТабДок = Новый ТабличныйДокумент;
    
    // Определяем область, в которую будет вставлена диаграмма
    // Можем задать размер области, чтобы диаграмма отображалась корректно
    ОбластьДляДиаграммы = ТабДок.Область(1, 1, 20, 10); // Например, 20 строк, 10 колонок
    ТабДок.Вывести(ОбластьДляДиаграммы); // Важно вывести область, даже если она пустая

    // Добавляем рисунок типа Диаграмма в ТабличныйДокумент
    РисунокДиаграмма = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Диаграмма);
    РисунокДиаграмма.Область = ОбластьДляДиаграммы; // Привязываем к нашей области
    РисунокДиаграмма.Объект = Диаграмма;
    РисунокДиаграмма.РазмерКартинки = РазмерКартинки.Авто;
    РисунокДиаграмма.ВыводитьЗаголовок = Истина;
    РисунокДиаграмма.Текст = Диаграмма.Заголовок; // Можно указать текст, если заголовок не выводится по другим причинам

    // Сохраняем табличный документ в формате PDF
    ПутьКФайлуPDF = "C:\temp\диаграмма.pdf";
    Попытка
        ТабДок.Записать(ПутьКФайлуPDF, ТипФайлаТабличногоДокумента.PDF);
        ЗаписьЖурналаРегистрации(НСтр("ru='Диаграмма успешно сохранена в файл: '") + ПутьКФайлуPDF, УровеньЖурналаРегистрации.Информация);
    Исключение
        ЗаписьЖурналаРегистрации(НСтр("ru='Ошибка при сохранении диаграммы в PDF: '") + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
    КонецПопытки;
КонецПроцедуры

Этот метод подтвержден как рабочий и является хорошим решением, если конечной целью может быть PDF-файл. Если нужен именно растровый формат (PNG/JPG), придется либо использовать внешние инструменты для конвертации PDF в PNG на сервере (что усложняет решение), либо принять факт, что прямой способ получить растровую картинку из Диаграммы на сервере без GUI крайне затруднителен.

3. Проверка окружения сервера

Хотя этот вариант менее вероятен для "чистого" 1С-кода, особенно если проблема носит системный характер, стоит убедиться, что окружение сервера соответствует минимальным требованиям для работы с графикой.

  1. Установка графических компонентов. Убедитесь, что на сервере установлены все необходимые системные графические библиотеки. В некоторых случаях (особенно для Windows Server в режиме Core или на Linux), может потребоваться установка дополнительных компонентов рабочего стола или библиотек (например, X Window System для Linux), даже если вы не используете GUI напрямую. Это может быть связано с тем, что некоторые функции рендеринга вызываются через системные API, которые зависят от этих компонентов. Мы рекомендуем проконсультироваться с системными администраторами и документацией по используемой операционной системе сервера.
  2. Права доступа. Проверьте, от имени какой учетной записи запущена служба агента сервера 1С:Предприятия. Убедитесь, что эта учетная запись имеет достаточные права для доступа к системным ресурсам и создания временных файлов. Недостаточные права могут препятствовать инициализации некоторых графических компонентов или созданию необходимых объектов в памяти.
  3. Журналы событий. Проанализируйте журналы событий Windows (или системные логи для Linux) и журнал регистрации 1С на предмет ошибок, связанных с графикой, отрисовкой или доступом к системным компонентам, которые могли бы прояснить причину некорректной работы ПолучитьКартинку. Подробные логи могут указать на отсутствие DLL-файлов или сбои в вызовах системных функций.

Заключение

Проблема с методом График.ПолучитьКартинку() на сервере 1С:Предприятия, вероятно, связана с особенностями работы в среде без графического интерфейса и отсутствием необходимых системных компонентов для рендеринга. Прямого и простого решения, которое позволило бы использовать ПолучитьКартинку на сервере так же эффективно, как на клиенте, не обнаружено. Однако, существуют эффективные обходные пути.

Если вам нужен PDF-файл, мы настоятельно рекомендуем использовать ТабличныйДокумент в качестве посредника — этот метод подтвержден как рабочий и надежный. Если же требуется именно растровое изображение (PNG, JPG) для серверного задания, рассмотрите возможность генерации на клиенте с последующей передачей двоичных данных на сервер. В крайнем случае, для получения растрового изображения из PDF на сервере, возможно, потребуется интеграция со сторонними инструментами для конвертации форматов, что, однако, значительно усложняет архитектуру решения.

Мы продолжим следить за развитием платформы 1С и надеемся, что в будущих версиях появятся более удобные и прямые способы работы с графикой на сервере без привязки к GUI.

← На главную