При работе с изображениями в 1С:Предприятие 8.3, особенно в старых типовых конфигурациях вроде Управление торговлей 10.3, разработчики часто сталкиваются со специфической проблемой. При попытке программно определить формат изображения с помощью метода Картинка.Формат() или просто при просмотре карточки номенклатуры система выдает критическую ошибку «Недостаточно памяти», после чего работа программы аварийно завершается. Самое неприятное в этой ситуации то, что стандартная конструкция Попытка...Исключение не спасает — 1С «вылетает» до того, как код перейдет в блок обработки ошибки.
В этой статье мы подробно разберем, почему это происходит, как локализовать «битые» картинки среди тысяч позиций номенклатуры и какими способами можно решить эту проблему, чтобы выгрузка на сайт или работа пользователей не прерывалась.
Проанализируем ситуацию: файл изображения может иметь вполне стандартный размер (например, 200 Кб) и успешно открываться обычными средствами Windows (Paint, Просмотр фотографий). Однако встроенный в 1С механизм работы с графикой, использующий системные библиотеки GDI+, при анализе заголовка файла натыкается на структуру, которую не может корректно интерпретировать.
Основными техническими причинами являются:
Формат().Картинка.Если в вашей базе десятки тысяч товаров, искать «виновника» вручную невозможно. Нам необходимо написать обработку, которая переберет все картинки и зафиксирует те, на которых платформа падает. Поскольку 1С закрывается, обычное сообщение пользователю нам не поможет — мы должны использовать текстовый лог, который сохраняется на диск немедленно.
Рассмотрим пример кода для поиска проблемных объектов:
Процедура ПоискБитныхКартинок()
Выборка = Справочники.ХранилищеДополнительнойИнформации.Выбрать();
Пока Выборка.Следующий() Цикл
// Записываем ID в лог перед началом обработки
ЗаписатьВЛог("Проверка объекта: " + Выборка.Ссылка + " (" + Выборка.Наименование + ")");
Попытка
КартинкаОбъект = Выборка.Хранилище.Получить();
Если ТипЗнч(КартинкаОбъект) = Тип("Картинка") Тогда
// Именно здесь происходит падение
ТипФайла = КартинкаОбъект.Формат();
КонецЕсли;
Исключение
// Сюда код может не дойти при жестком падении
ЗаписатьВЛог("Обнаружена ошибка (обработано): " + Выборка.Ссылка);
КонецПопытки;
ЗаписатьВЛог("Успешно завершено");
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьВЛог(ТекстСообщения)
Текст = Новый ЗаписьТекста("C:\temp\check_images.log", КодировкаТекста.UTF8, , Истина);
Текст.ЗаписатьСтроку("" + ТекущаяДата() + ": " + ТекстСообщения);
Текст.Закрыть();
КонецПроцедуры
При запуске этой процедуры 1С рано или поздно закроется. Вам нужно будет открыть файл check_images.log. Последний объект, для которого не появилась запись «Успешно завершено», и является причиной сбоя. Запишите его идентификатор, перезапустите 1С и запустите проверку заново, начиная со следующего по порядку объекта.
Как показывает практика и обсуждения на форумах, самым простым и эффективным способом «лечения» такой картинки является её пересохранение. Если открыть проблемный файл в стандартном редакторе Paint и нажать «Сохранить», редактор перепишет заголовки файла в стандартный формат (Baseline JPEG), вычистит некорректные метаданные и установит верную цветовую модель.
Порядок действий:
Картинка.Записать() обычно работает без ошибок, так как он просто копирует двоичные данные).После этой процедуры метод Картинка.Формат() начнет работать корректно.
Если вы хотите полностью обезопасить свой код от падений платформы, мы рекомендуем отказаться от использования метода Картинка.Формат() в пользу анализа сигнатур файлов. Каждый формат файла (JPEG, PNG, GIF) имеет уникальную последовательность байтов в самом начале. Чтение двоичных данных не задействует графический движок 1С и не вызывает ошибок памяти.
Разберем, как реализовать безопасную функцию определения формата:
Функция ОпределитьФорматБезопасно(Картинка)
ДвоичныеДанные = Картинка.ПолучитьДвоичныеДанные();
Чтение = Новый ЧтениеДанных(ДвоичныеДанные);
ПервыеБайты = Чтение.Прочитать(4).РазложитьПоБайтам();
// JPEG начинается с FF D8 FF
Если ПервыеБайты[0] = 255 И ПервыеБайты[1] = 216 И ПервыеБайты[2] = 255 Тогда
Возврат ФорматКартинки.JPEG;
// PNG начинается с 89 50 4E 47 (в десятичном виде: 137 80 78 71)
ИначеЕсли ПервыеБайты[0] = 137 И ПервыеБайты[1] = 80 И ПервыеБайты[2] = 78 Тогда
Возврат ФорматКартинки.PNG;
// GIF начинается с 47 49 46 38 (в десятичном виде: 71 73 70 56)
ИначеЕсли ПервыеБайты[0] = 71 И ПервыеБайты[1] = 73 И ПервыеБайты[2] = 70 Тогда
Возврат ФорматКартинки.GIF;
КонецЕсли;
Возврат ФорматКартинки.НеизвестныйФормат;
КонецФункции
Использование такого подхода гарантирует, что ваша обработка выгрузки на сайт (например, в Битрикс) не прервется из-за одной некорректной картинки.
Проанализируем еще несколько вариантов решения проблемы, если обновление платформы до последних версий (где многие ошибки работы с GDI+ исправлены) невозможно:
Config или Files). Запустите ТИИ с проверкой логической и ссылочной целостности.WIA.ImageFile (через COM-соединение) или консольную утилиту ImageMagick. Они значительно стабильнее работают с «битыми» файлами, чем штатные средства 1С.Подводя итог, можно сказать, что наиболее надежный путь — это сочетание логирования для поиска проблемных мест и перехода на чтение двоичных данных для анализа форматов. Это позволит вашей системе работать стабильно даже при наличии некорректного контента в базе данных.