Как получить точную копию изображения из Документа Гугл
Замечали, что при попытке копирования изображения из Документа Гугл в другой Документ пападает его упрощенная версия?
Решение “в лоб”
Первое, что приходит в голову, это copy()
. Синоним многих операций в Goole Apps Script, при котором происходит непонятно что, т.к. реальное копирование экземпляра не всегда доступно.
var image = DocumentApp.openById('ABC').getBody().getImages()[0].copy();
DocumentApp.openById('XYZ').getBody().insertImage(0, image);
Этот метод хорош, он подойдет для копирования внутри Документа. Но изображения в копии для другого Документа будут упрощенными, а анимация вообще исчезнет, оставив место первому кадру.
Поиск проблемы
Важно понимать, что не существует такого файла, как Документ Гугл. Это некая запись в базе данных, а не в файловлй системе, которая обладает некоторыми специфическими особенностями. Какими? Кто ж его знает! Но суть остается в том, что оптимизируя запросы к базе, первое, что страдает - количество запросов. Вот и в этом случае, система берет не исходное изображение, которое и так уже хорошенько сжали перед упаковкой, а непосредственную ссылку на ее реализацию в Документе. Для анимации, как уже понятно, для быстрой загрузки, это ссылка на миниатюру (thumbnail). Так это происходит, или я только придумал, знают только в Гугл.
Исходя из этого представления, метод “в лоб” уже не кажется таким очевидным. Даже больше, он сразу отпадает, как неуместный. проблема найдена: как получить источник, из которого формируется состав Документа?
Получение исходников
Понятно, что никаких исходников от проприетарного удаленного и защищенного законом другого государства сервера никто никогда не получит. Но можно получить сжатую совместимую версию. В таких задачах экспорт - это всё. Получаем zip
:
var template =
'https://docs.google.com/feeds/download/documents/export/Export?id=%s&exportFormat=zip';
var url = Utilities.formatString(template, from);
var file = UrlFetchApp.fetch(url).getBlob();
Если распаковать архив, то можно приятно удивиться, найдя там заветный исходный файл изображения. Сразу оговорюсь, что “схалтурить” так не получится, и хранить файлы большого размера не выйдет. Огромные файлы изображений нещадно оптимизируются корпорацией в незначащие для неё “пару мегабайт”.
Поиск индекса
Что самое сложное в этой задаче? Как ни странно, это поиск индекса заветного изображения, которое будет копироваться. Т.к. картинки были подвергнуты оптимизации, то для порядка их еще и переименовали в ./images/image1.jpg
, ./images/image2.gif
, ./images/image3.png
и т.д. Причем, если картинка создана на базе существующего изображения из Документа, то нового файла не появляется (следует учитывать при индексе).
Распаковка
var blobs = Utilities.unzip(file);
Порядок изображений
Имя изображения необходимо получить из порядка вхождения картинки в Документ. После редактирования порядок добавления элементов может не соответствовать порядку их следования. Поэтому необходимо построить карту вхождений файлов и отсчитать нужный по порядку. Надо, так надо, читаем html-файл:
var htmlContent = blobs
.find(function(b) {
return /^.+?\.html$/.test(b.getName());
})
.getDataAsString();
Из этого текста необходимо построить массив доступных изображений и получить имя изображения о индексу index
. Например,
var imageTag = htmlContent
.match(/<img.+?src="images\/image\d+\..{2,4}".+?>/g)[index];
Ну, а далее, дело техники - найти имя из тега и по этому имени еще раз перебрать данный blob
.
Результат
Самым эффективным для подобной функции будет возвращение изображения в blob
, т.к. другие методы позволяют создавать inlineImages
из blob
.