Вопрос или проблема
Мне нужно создать продукт с перекрытием изображения из AppSheet. Я сразу подумал о том, чтобы вызвать скрипт AppScript, который перечисляет изображения в формате .png и сохраняет изображение с перекрытием. Однако скрипт изображения не поддерживается напрямую, поэтому мне нужно вызвать HTML. Идея такая:
Ниже я вставил предполагаемую композицию изображений. Они представляют собой пары штанов, где есть модели талии, тип кармана и фон, передняя часть штанов:
Таким образом, у меня есть:
Codigo.gs
function testOverlayImages() {
try {
// Введите идентификаторы ваших тестовых файлов и идентификатор выходной папки вручную
var fileIds = ['12dNuA7z0HpwjjEWQqk_Ka11gRlZXg9gm',
'12aGTgwgQFS1FvBK-o1-H_lx7K_lIUVxF',
'1JYBKj80vA_sJ-yIHcww308G9FqIWmFqK',
'1HaDk5r1xIRqR3RwE-vCxrNDiUvuO3MNs',
'1IeEce1cygeexeS1CspISszPyKpvPtnce'
];
var outputFolderId = "11mipFucwgcW0Vlei9dseMwVwglHtYJOe"; // Замените на идентификатор вашей папки в Google Drive, где будет сохранен результат
// Получаем изображения по их идентификаторам
var images = getImagesByIds(fileIds);
// Создаем HTML-страницу для наложения изображений
var template = HtmlService.createTemplateFromFile('Overlay');
template.images = images; // Передаем изображения в HTML-шаблон
template.outputFolderId = outputFolderId; // Передаем идентификатор выходной папки в HTML-шаблон
var html = template.evaluate().getContent();
// Возвращаем HTML-страницу клиенту для обработки наложения
return ContentService.createTextOutput(html).setMimeType(ContentService.MimeType.HTML);
} catch (error) {
// Возвращаем ответ с ошибкой, если что-то пошло не так
return ContentService.createTextOutput(JSON.stringify({
status: 'error',
message: error.message
})).setMimeType(ContentService.MimeType.JSON);
}
}
// Функция для получения изображений по их идентификаторам файлов
function getImagesByIds(fileIds) {
var images = [];
for (var i = 0; i < fileIds.length; i++) {
var file = DriveApp.getFileById(fileIds[i]);
if (file.getMimeType() == "image/png") {
var imageBlob = file.getBlob();
var base64Image = Utilities.base64Encode(imageBlob.getBytes());
var dataUri = "data:image/png;base64," + base64Image;
images.push(dataUri);
}
}
return images;
}
// Сохранить наложенное изображение в Google Drive
function saveImage(base64Image, folderId) {
Logger.log('Сохранение изображения в папку: ' + folderId); // Логирование идентификатора папки
Logger.log('Base64 изображение: ' + base64Image.substring(0, 100)); // Логирование части строки Base64 (первые 100 символов)
// Декодируем изображение base64
var blob = Utilities.newBlob(Utilities.base64Decode(base64Image.replace(/^data:image\/png;base64,/, "")), 'image/png', 'overlay_image.png');
// Получаем папку по идентификатору папки
var folder = DriveApp.getFolderById(folderId);
// Если папка не существует, логируем ошибку
if (!folder) {
Logger.log('Папка не найдена!');
return 'Папка не найдена!';
}
// Создаем файл в папке
var file = folder.createFile(blob);
// Логируем URL созданного файла
Logger.log('Файл создан: ' + file.getUrl());
// Возвращаем URL сохраненного файла
return file.getUrl();
}
Overlay.html
canvas {
border: 1px solid black;
}
Наложение изображений
Ниже приведен пример наложенного изображения. Это изображение должно быть сохранено в определенной папке. overlay_image
Может кто-нибудь помочь мне, где я ошибаюсь?
Я надеялся, что, вызвав функцию через скрипт, смогу сохранить наложенное изображение. Я вставил изображения, чтобы лучше понять наложение, но не могу их сохранить.
Ответ или решение
Конечно, давайте разберем ваш вопрос по поводу наложения изображений и сохранения результирующего изображения с помощью Google Apps Script и HTML.
На первый взгляд, ваш код выглядит в целом корректно, но есть несколько моментов, на которые стоит обратить внимание, чтобы убедиться, что все работает как ожидается. Давайте рассмотрим весь процесс более детально и внесем необходимые коррективы.
Анализ вашего кода
-
Загрузка изображений: Вы правильно используете
DriveApp
для получения файлов по их ID, и затем преобразовываете их в формат Data URI. Убедитесь, что переданные вами идентификаторы файлов действительно относятся к изображениями в формате PNG. -
HTML и JavaScript: Ваш HTML-код создает элемент
<canvas>
и правильно рисует изображения, используя контекст рисования 2D. Однако сам процесс наложения изображений можно оптимизировать. -
Сохранение изображения: Вы правильно используете функцию
saveImage
для сохранения наложенного изображения. Убедитесь, что ваша функцияgoogle.script.run.withSuccessHandler
корректно обрабатывает результат.
Возможные ошибки и исправления
-
Время загрузки изображений: В вашем коде используется
setTimeout
для ожидания загрузки изображений. Это может не всегда сработать корректно, особенно если изображения загружаются медленно. Вместо этого, вы можете использоватьPromise
для более надежного контроля загрузки изображений. -
Состояние канваса: Убедитесь, что канвас имеет правильные размеры после загрузки первого изображения. Это критично для корректного наложения последующих изображений.
-
Отладка: Проверяйте консоль на наличие ошибок. Если что-то идет не так, то консольные сообщения могут помочь в диагностике проблемы. Например, вы можете использовать
console.error
для поиска ошибок.
Обновленный код
Вот обновленный код с исправлениями:
Код Codigo.gs
function testOverlayImages() {
try {
var fileIds = [
'12dNuA7z0HpwjjEWQqk_Ka11gRlZXg9gm',
'12aGTgwgQFS1FvBK-o1-H_lx7K_lIUVxF',
'1JYBKj80vA_sJ-yIHcww308G9FqIWmFqK',
'1HaDk5r1xIRqR3RwE-vCxrNDiUvuO3MNs',
'1IeEce1cygeexeS1CspISszPyKpvPtnce'
];
var outputFolderId = "11mipFucwgcW0Vlei9dseMwVwglHtYJOe";
var images = getImagesByIds(fileIds);
var template = HtmlService.createTemplateFromFile('Overlay');
template.images = images;
template.outputFolderId = outputFolderId;
var html = template.evaluate().getContent();
return ContentService.createTextOutput(html).setMimeType(ContentService.MimeType.HTML);
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({
status: 'error',
message: error.message
})).setMimeType(ContentService.MimeType.JSON);
}
}
function getImagesByIds(fileIds) {
var images = [];
for (var id of fileIds) {
var file = DriveApp.getFileById(id);
if (file.getMimeType() == "image/png") {
var imageBlob = file.getBlob();
var base64Image = Utilities.base64Encode(imageBlob.getBytes());
var dataUri = "data:image/png;base64," + base64Image;
images.push(dataUri);
}
}
return images;
}
function saveImage(base64Image, folderId) {
var blob = Utilities.newBlob(Utilities.base64Decode(base64Image.replace(/^data:image\/png;base64,/, "")), 'image/png', 'overlay_image.png');
var folder = DriveApp.getFolderById(folderId);
if (!folder) {
return 'Folder not found!';
}
var file = folder.createFile(blob);
return file.getUrl();
}
Код Overlay.html
<style>
canvas {
border: 1px solid black;
}
</style>
<h1>Overlaying Images</h1>
<canvas id="canvas"></canvas>
<script>
var images = <?= JSON.stringify(images) ?>;
var outputFolderId = "<?= outputFolderId ?>";
async function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous'; // Это важно, если изображения загружаются из внешних источников
img.src = src;
img.onload = () => resolve(img);
img.onerror = reject;
});
}
async function overlayImages() {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img1 = await loadImage(images[0]);
canvas.width = img1.width;
canvas.height = img1.height;
ctx.drawImage(img1, 0, 0);
for (let i = 1; i < images.length; i++) {
const img = await loadImage(images[i]);
ctx.drawImage(img, 0, 0);
}
const base64Image = canvas.toDataURL("image/png");
google.script.run.withSuccessHandler(function(url) {
alert('Image saved! You can access it here: ' + url);
}).saveImage(base64Image, outputFolderId);
}
overlayImages();
</script>
Заключение
Проверьте, чтобы все идентификаторы файлов и папок были действительными, а также убедитесь, что у вас есть достаточные права доступа к данным ресурсам. После внесения изменений в код, попробуйте снова выполнить скрипт. Если у вас возникнут дополнительные вопросы или проблемы, не стесняйтесь задавать их.