При выгрузке табличного документа, содержащего графические элементы, в формат HTML для последующего вывода в поле формы часто возникает ситуация, когда вместо графики отображается пустая рамка или пиктограмма ошибки. Разберем по шагам, почему возникает эта проблема и как ее правильно решить несколькими способами.
Проанализируем механизм сохранения табличного документа платформой 1С. Когда выполняется метод ТабличныйДокумент.Записать() с типом ТипФайлаТабличногоДокумента.HTML или HTML4, платформа формирует не один файл, а сохраняет HTML-разметку и создает рядом отдельный каталог с ресурсами вида ИмяФайла_files. В этот каталог помещаются все графические объекты документа под именами image001.png, image002.png и так далее.
В самой разметке HTML платформа прописывает относительные пути к этим файлам. Если после сохранения вычитать текст файла с помощью объекта ТекстовыйДокумент и передать полученную строку в реквизит формы, связанный с полем HTML, встроенный браузерный движок не сможет определить базовый путь на диске и не найдет каталог с графикой. В результате ссылки на изображения оказываются недействительными.
Рассмотрим наиболее надежный и универсальный метод, который отлично работает как в тонком клиенте, так и в веб-клиенте. Идея заключается в том, чтобы после сохранения файла на диск прочитать созданные графические файлы, преобразовать их в строку формата Base64 и внедрить непосредственно в тело HTML-кода.
Посмотрим на пример программного кода, реализующего этот алгоритм:
ИмяФайла = ПолучитьИмяВременногоФайла("html");
ТабДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.HTML);
ФайлHTML = Новый Файл(ИмяФайла);
КаталогРесурсов = ФайлHTML.ИмяБезРасширения + "_files";
ПутьКФайлу = ФайлHTML.Путь;
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла);
ТекстHTML = ТекстДок.ПолучитьТекст();
Индекс = Найти(ТекстHTML, КаталогРесурсов);
Пока Индекс <> 0 Цикл
ПозицияКавычки = Найти(Сред(ТекстHTML, Индекс), """");
Если ПозицияКавычки <> 0 Тогда
ОтносительныйПуть = Сред(ТекстHTML, Индекс, ПозицияКавычки - 1);
ПолныйПутьКФайлу = ПутьКФайлу + ОтносительныйПуть;
Если Новый Файл(ПолныйПутьКФайлу).Существует() Тогда
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПолныйПутьКФайлу);
СтрокаBase64 = "data:image/png;base64," + Base64Строка(ДвоичныеДанныеФайла);
ТекстHTML = СтрЗаменить(ТекстHTML, ОтносительныйПуть, СтрокаBase64);
КонецЕсли;
КонецЕсли;
Индекс = Найти(ТекстHTML, КаталогРесурсов);
КонецЦикла;
// Передаем итоговый текст в реквизит формы, привязанный к полю HTML
ЭлементФормыТекстHTML = ТекстHTML;
// Очищаем временные файлы
УдалитьФайлы(ИмяФайла);
УдалитьФайлы(ПутьКФайлу + КаталогРесурсов);
Рассмотрим подробнее второй вариант. Если не требуется передавать разметку в автономном виде, можно указать браузерному движку исходный каталог, откуда следует загружать ресурсы с относительными путями. Для этого в тег <head> внедряется директива <base href="...">.
Разберем реализацию этого способа:
ИмяФайла = ПолучитьИмяВременногоФайла("html");
ТабДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.HTML);
ФайлHTML = Новый Файл(ИмяФайла);
ПутьККаталогу = "file:///" + СтрЗаменить(ФайлHTML.Путь, "\", "/");
ТекстДок = Новый ТекстовыйДокумент;
ТекстДок.Прочитать(ИмяФайла);
ТекстHTML = ТекстДок.ПолучитьТекст();
// Вставляем базовый URL сразу после открывающего тега head
ТегБазовогоПути = "<head><base href=""" + ПутьККаталогу + """>";
ТекстHTML = СтрЗаменить(ТекстHTML, "<head>", ТегБазовогоПути);
ЭлементФормыТекстHTML = ТекстHTML;
Проанализируем ситуацию, когда не обязательно читать текст HTML в строковый реквизит формы. Если файл сформирован на стороне клиента, можно выполнить его прямую навигацию в элемент управления формы.
Посмотрим на пример вызова метода:
ИмяФайла = ПолучитьИмяВременногоФайла("html");
ТабДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.HTML);
// Загружаем сохраненный файл напрямую в элемент управления
Элементы.ПолеHTML.Перейти(ИмяФайла);
В этом случае браузерный компонент открывает файл с диска и автоматически находит связанную папку с графикой по относительному пути.
Разберем ключевые технические моменты, на которые следует обратить внимание при реализации:
&НаСервере, временные файлы создаются в файловой системе сервера. Клиентское приложение не имеет к ним прямого доступа по локальным путям. Поэтому при серверном формировании рекомендуется использовать метод с конвертацией в Base64, возвращая на клиент уже полностью готовый текст страницы.file://. Для браузеров единственным гарантированным решением остается кодирование в Base64.УдалитьФайлы() после того, как двоичные данные или текст были прочитаны в память.