Как программно создать скриншот в 1С:Предприятие и сохранить его?

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

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

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

Решение 1: Создание скриншота средствами платформы 1С (начиная с версии 8.3.17)

Начиная с версии 8.3.17, платформа 1С предоставляет нам довольно изящный способ получения скриншота текущего сеанса пользователя. Этот метод использует внутренний механизм формирования отчета об ошибке, который, помимо прочего, включает в себя снимок экрана.

Для того чтобы этот метод работал, нам необходимо убедиться, что в настройках вашей базы данных включены соответствующие опции. Перейдите в раздел "Управление настройками обработки ошибок" и проверьте, что опции "Снимок окон приложения" и "Отправлять" установлены. Без этих настроек платформа не будет формировать скриншот в составе отчета об ошибке.

Давайте рассмотрим подробнее, как мы можем использовать этот подход в нашем коде. Платформа при формировании отчета об ошибке создает временный ZIP-архив, внутри которого содержится файл screenshot.png. Наша задача — получить этот архив, распаковать его и извлечь нужный нам графический файл. В этом контексте полезным вспомогательным инструментом может стать распаковщик и запаковщик файлов, реализованный исключительно средствами языка 1С для работы с архивами без сторонних библиотек. Для этой задачи есть система учета обращений и техподдержки в 1С.

Важно отметить, что этот метод предназначен для работы в толстом или тонком клиенте 1С и, к сожалению, не поддерживается в веб-клиенте. Также, как и любая работа с файловой системой и внешними процессами, этот код может столкнуться с ошибками (например, из-за прав доступа или отсутствия файла), поэтому крайне рекомендуется оборачивать его в блок Попытка...Исключение.

Посмотрим на пример кода, который реализует описанный механизм:


// Процедура сохраняет скриншот текущего сеанса пользователя по переданному адресу.
// Работает начиная с версии 8.3.17.
//
// Параметры:
//   ПолныйПуть     - Строка    - Полный путь к файлу, куда будет сохранен скриншот (например, "C:\Temp\МойСкриншот.png").
//
&НаКлиенте
Процедура СохранитьСкриншотСеанса(ПолныйПуть = "")

    #Если НЕ ВебКлиент Тогда
        Если ПустаяСтрока(ПолныйПуть) Тогда
            Сообщить("Не указан путь для сохранения скриншота.", СтатусСообщения.Важное);
            Возврат;
        КонецЕсли;

        Попытка
            ВременныйФайл = ПолучитьИмяВременногоФайла(".zip");
            ОтчетОбОшибке = Новый ОтчетОбОшибке(ИнформацияОбОшибке()); // Создаем фиктивный отчет об ошибке
            ОтчетОбОшибке.Записать(ВременныйФайл, Ложь); // Записываем его во временный ZIP-архив

            КаталогДляРаспаковки = КаталогВременныхФайлов() + СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
            СоздатьКаталог(КаталогДляРаспаковки);

            ЧтениеАрхива  = Новый ЧтениеZipФайла(ВременныйФайл);
            // Извлекаем все содержимое архива во временный каталог, не восстанавливая пути
            ЧтениеАрхива.ИзвлечьВсе(КаталогДляРаспаковки, РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
            ЧтениеАрхива.Закрыть();

            ПутьСкриншотаИзАрхива = КаталогДляРаспаковки + "\screenshot.png";

            Если ФайлСуществует(ПутьСкриншотаИзАрхива) Тогда
                КопироватьФайл(ПутьСкриншотаИзАрхива, ПолныйПуть);
                Сообщить("Скриншот успешно сохранен: " + ПолныйПуть, СтатусСообщения.Информация);
            Иначе
                Сообщить("Файл скриншота не найден в архиве.", СтатусСообщения.Важное);
            КонецЕсли;

        Исключение
            Сообщить("Ошибка при сохранении скриншота: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
        КонецПопытки;

        // Очищаем временные файлы и каталоги
        Попытка
            УдалитьФайлы(ВременныйФайл);
            УдалитьФайлы(КаталогДляРаспаковки);
        Исключение
            // Обработка ошибок удаления, если необходимо
        КонецПопытки;

    #КонецЕсли

КонецПроцедуры

В этом коде мы сначала получаем имя временного ZIP-файла. Затем, используя объект ОтчетОбОшибке, мы "генерируем" фиктивный отчет, который платформа сохраняет вместе со снимком экрана. После этого мы создаем временный каталог, распаковываем в него архив с помощью ЧтениеZipФайла и копируем найденный screenshot.png в указанное пользователем место. В конце обязательно удаляем все временные файлы и каталоги, чтобы не засорять систему.

Решение 2: Использование внешних компонент (например, VanessaExt)

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

Мы с вами рассмотрим пример библиотеки внешних компонент VanessaExt, которая включает в себя компоненту WindowsControl — для этого подойдёт инструментарий для автоматизированного регресс-тестирования 1С. Эта компонента предоставляет нам ряд функций для захвата изображений экрана.

Давайте посмотрим, какие возможности она нам предлагает:

1. ПолучитьСнимокЭкрана (TakeScreenshot): Эта функция позволяет нам сделать снимок всего экрана целиком. 2. ПолучитьСнимокОбласти (CaptureRegion): Если нам нужен скриншот определенной области экрана, мы можем указать координаты и размеры этой области. 3. ПолучитьСнимокОкна (CaptureWindow): С помощью этой функции мы можем получить снимок конкретного окна приложения. 4. ПолучитьСнимокПроцесса (CaptureProcess): Эта функция захватывает изображение, связанное с определенным процессом.

Внешние компоненты могут быть разработаны на различных языках программирования (например, C++, Delphi) и интегрируются с 1С через специальный API. Они могут работать как на клиенте (толстом, тонком), так и на сервере, а некоторые компоненты даже поддерживают работу в веб-клиенте.

Для использования такой компоненты нам обычно требуется:

Примерный код использования (предполагается, что компонента уже подключена и инициализирован объект `ВК`):


// Предполагаем, что ВК уже подключена и является экземпляром WindowsControl
// Например:
// ПодключитьВнешнююКомпоненту("AddIn.WindowsControl");
// ВК = Новый("AddIn.WindowsControl");

Если НЕ ВК.Инициализирован() Тогда
    Сообщить("Внешняя компонента WindowsControl не инициализирована!", СтатусСообщения.Ошибка);
    Возврат;
КонецЕсли;

// Пример 1: Снимок всего экрана
ПутьДляСнимкаЭкрана = "C:\Temp\СнимокЭкрана.png";
Если ВК.ПолучитьСнимокЭкрана(ПутьДляСнимкаЭкрана) Тогда
    Сообщить("Снимок всего экрана сохранен: " + ПутьДляСнимкаЭкрана);
Иначе
    Сообщить("Не удалось сделать снимок всего экрана. " + ВК.ПолучитьПоследнююОшибку());
КонецЕсли;

// Пример 2: Снимок активного окна 1С
// Здесь потребуется знание дескриптора окна или его заголовка
// Для простоты, предположим, что мы хотим сделать снимок текущего активного окна
ПутьДляСнимкаОкна = "C:\Temp\СнимокОкна1С.png";
// Метод может принимать дескриптор окна. Если 0, то обычно текущее активное окно.
// Дескриптор можно получить, например, через GetForegroundWindow() в Windows API
// Для VanessaExt, обычно, если не указан дескриптор, она может пытаться определить текущее окно
Если ВК.ПолучитьСнимокОкна(0, ПутьДляСнимкаОкна) Тогда // 0 может означать текущее активное окно или другое поведение
    Сообщить("Снимок активного окна сохранен: " + ПутьДляСнимкаОкна);
Иначе
    Сообщить("Не удалось сделать снимок окна. " + ВК.ПолучитьПоследнююОшибку());
КонецЕсли;

Использование внешних компонент дает нам максимальную гибкость и контроль над процессом создания скриншотов, позволяя адаптироваться к самым специфическим требованиям.

Решение 3: Работа с буфером обмена (начиная с версии 8.3.24)

С выходом платформы 1С версии 8.3.24 у нас появилась новая, очень полезная возможность — программная работа с буфером обмена непосредственно из встроенного языка. Это открывает нам двери для обмена не только текстом, но и картинками, а также HTML-документами.

Мы можем использовать асинхронные методы объекта СредстваБуфераОбмена для получения и помещения данных. Для изображений нас интересуют методы СредстваБуфераОбмена.ПолучитьДанныеАсинх(СтандартныйФорматДанныхБуфераОбмена.Картинка) для получения картинки из буфера и СредстваБуфераОбмена.ПоместитьДанныеАсинх() для помещения.

Давайте разберем по шагам, как это может работать.

  1. Получение картинки из буфера обмена: Когда пользователь скопировал изображение (например, с помощью Print Screen или из графического редактора), мы можем программно получить его. Поскольку работа с буфером обмена, особенно в веб-клиенте, часто требует асинхронного подхода из-за специфики работы API браузеров и операционных систем, мы будем использовать асинхронные методы. Для обработки вставки изображений или файлов из буфера обмена в объект ФормаКлиентскогоПриложения и в клиентское приложение добавлены события ПриВставкеИзБуфераОбмена(). Это событие возникает, когда пользователь вставляет данные из буфера обмена, и позволяет нам перехватить и обработать их. Примерный сценарий: * Пользователь делает скриншот (например, Print Screen) или копирует изображение. * Мы вызываем асинхронный метод для получения данных из буфера. * Результат получения данных обрабатывается в процедуре-обработчике.
    
    &НаКлиенте
    Процедура ПолучитьКартинкуИзБуфераОбменаАсинхронно()
        Если СредстваБуфераОбмена.ПоддерживаетсяРаботаСИзображениями() Тогда
            ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьПолученнуюКартинкуИзБуфера", ЭтотОбъект);
            СредстваБуфераОбмена.ПолучитьДанныеАсинх(СтандартныйФорматДанныхБуфераОбмена.Картинка, ОписаниеОповещения);
            Сообщить("Запрос на получение картинки из буфера обмена отправлен.");
        Иначе
            Сообщить("Работа с изображениями в буфере обмена не поддерживается в текущем клиенте.", СтатусСообщения.Важное);
        КонецЕсли;
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ОбработатьПолученнуюКартинкуИзБуфера(Результат, ДополнительныеПараметры) Экспорт
        Если Результат.Успех Тогда
            КартинкаИзБуфера = Результат.Данные; // Получаем объект типа "Картинка"
            Если ТипЗнч(КартинкаИзБуфера) = Тип("Картинка") Тогда
                // Теперь у нас есть объект "Картинка". Мы можем:
                // 1. Записать ее во временный файл
                ВременныйФайл = ПолучитьИмяВременногоФайла(".png");
                КартинкаИзБуфера.Записать(ВременныйФайл);
                Сообщить("Картинка из буфера обмена сохранена во временный файл: " + ВременныйФайл);
    
                // 2. Поместить ее во временное хранилище или выполнить склейку нескольких картинок в одну для вывода в СКД
                АдресВременногоХранилища = ПоместитьВоВременноеХранилище(КартинкаИзБуфера, Новый УникальныйИдентификатор());
                Сообщить("Картинка помещена во временное хранилище: " + АдресВременногоХранилища);
    
            Иначе
                Сообщить("В буфере обмена нет картинки или формат не распознан.", СтатусСообщения.Важное);
            КонецЕсли;
        Иначе
            Сообщить("Ошибка при получении картинки из буфера обмена: " + Результат.ОписаниеОшибки, СтатусСообщения.Ошибка);
        КонецЕсли;
    КонецПроцедуры
    
  2. Помещение картинки в буфер обмена: Аналогично, мы можем программно поместить объект Картинка в буфер обмена, чтобы пользователь мог затем вставить его в другое приложение.
    
    &НаКлиенте
    Процедура ПоместитьКартинкуВБуферОбмена(КартинкаДляБуфера)
        Если ТипЗнч(КартинкаДляБуфера) = Тип("Картинка") И СредстваБуфераОбмена.ПоддерживаетсяРаботаСИзображениями() Тогда
            ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьРезультатПомещенияВБуфер", ЭтотОбъект);
            СредстваБуфераОбмена.ПоместитьДанныеАсинх(СтандартныйФорматДанныхБуфераОбмена.Картинка, КартинкаДляБуфера, ОписаниеОповещения);
            Сообщить("Запрос на помещение картинки в буфер обмена отправлен.");
        Иначе
            Сообщить("Невозможно поместить картинку в буфер обмена.", СтатусСообщения.Важное);
        КонецЕсли;
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ОбработатьРезультатПомещенияВБуфер(Результат, ДополнительныеПараметры) Экспорт
        Если Результат.Успех Тогда
            Сообщить("Картинка успешно помещена в буфер обмена.");
        Иначе
            Сообщить("Ошибка при помещении картинки в буфер обмена: " + Результат.ОписаниеОшибки, СтатусСообщения.Ошибка);
        КонецЕсли;
    КонецПроцедуры
    

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

Решение 4: Для веб-клиента (использование JavaScript-библиотек, например, html2canvas)

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

Один из популярных подходов — использование JavaScript-библиотек, таких как `html2canvas`. Эта библиотека позволяет захватывать содержимое веб-страницы (или ее части) и конвертировать его в изображение (обычно в формате PNG или JPEG). Она работает полностью на стороне клиента, то есть в браузере пользователя, что очень удобно для веб-клиента 1С.

Давайте проанализируем ситуацию с `html2canvas`:

Для интеграции `html2canvas` в веб-клиент 1С нам потребуется разместить файлы библиотеки на веб-сервере и встроить JavaScript-код, который после создания изображения сможет передать его на сервер 1С.

Решение 5: Использование PowerShell (для версий до 8.3.17 или как альтернатива)

Для версий 1С, предшествующих 8.3.17, или в ситуациях, когда использование внешних компонент нежелательно, мы можем прибегнуть к помощи сторонних системных инструментов, таких как PowerShell. Этот подход позволяет выполнять команды операционной системы непосредственно из 1С. Однако если ваша задача состоит не в снимке экрана, а в том, чтобы осуществить программную конвертацию отчетов 1С в графический формат или преобразование PDF-файлов в PNG, существуют специализированные методики, работающие без установки дополнительных компонентов.

Принцип работы PowerShell заключается в следующем:

  1. Из кода 1С мы запускаем PowerShell-скрипт через COM-объект "WScript.Shell".
  2. PowerShell-скрипт использует .NET Framework для создания снимка основного экрана и сохранения его на диск.
  3. После сохранения мы загружаем файл обратно в 1С.

Давайте посмотрим на общий алгоритм действий и пример PowerShell-скрипта:

Шаг 1: PowerShell-скрипт для создания скриншота


# CaptureScreen.ps1
param (
    [string]$OutputPath = "C:\Temp\screenshot.png"
)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Получаем размеры основного экрана
$Screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$Bitmap = New-Object System.Drawing.Bitmap($Screen.Width, $Screen.Height)
$Graphics = [System.Drawing.Graphics]::FromImage($Bitmap)
$Graphics.CopyFromScreen($Screen.X, $Screen.Y, 0, 0, $Screen.Size)

# Сохраняем изображение
$Bitmap.Save($OutputPath, [System.Drawing.Imaging.ImageFormat]::Png)

$Graphics.Dispose()
$Bitmap.Dispose()

Шаг 2: Вызов PowerShell из 1С


&НаКлиенте
Процедура СоздатьСкриншотЧерезPowerShell(ПолныйПуть = "")
    Если ПустаяСтрока(ПолныйПуть) Тогда
        Сообщить("Не указан путь для сохранения скриншота.", СтатусСообщения.Важное);
        Возврат;
    КонецЕсли;

    Попытка
        ИмяФайлаСкрипта = КаталогТекущейБазы() + "CaptureScreen.ps1";
        Команда = "powershell.exe -ExecutionPolicy Bypass -File """ + ИмяФайлаСкрипта + """ -OutputPath """ + ПолныйПуть + """";

        WshShell = Новый COMОбъект("WScript.Shell");
        WshShell.Run(Команда, 0, Истина); // 0 - скрыть окно, Истина - дождаться завершения

        Если ФайлСуществует(ПолныйПуть) Тогда
            Сообщить("Скриншот успешно сохранен с помощью PowerShell: " + ПолныйПуть, СтатусСообщения.Информация);
        Иначе
            Сообщить("Скриншот не был создан или файл не найден.", СтатусСообщения.Важное);
        КонецЕсли;

    Исключение
        Сообщить("Ошибка при создании скриншота через PowerShell: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
    КонецПопытки;
КонецПроцедуры

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

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

← На главную