Наложение PNG изображений

Вопрос или проблема

Мне нужно создать продукт с перекрытием изображения из AppSheet. Я сразу подумал о том, чтобы вызвать скрипт AppScript, который перечисляет изображения в формате .png и сохраняет изображение с перекрытием. Однако скрипт изображения не поддерживается напрямую, поэтому мне нужно вызвать HTML. Идея такая:

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

карман для ножа

талия_40

фон

Таким образом, у меня есть:
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.

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

Анализ вашего кода

  1. Загрузка изображений: Вы правильно используете DriveApp для получения файлов по их ID, и затем преобразовываете их в формат Data URI. Убедитесь, что переданные вами идентификаторы файлов действительно относятся к изображениями в формате PNG.

  2. HTML и JavaScript: Ваш HTML-код создает элемент <canvas> и правильно рисует изображения, используя контекст рисования 2D. Однако сам процесс наложения изображений можно оптимизировать.

  3. Сохранение изображения: Вы правильно используете функцию saveImage для сохранения наложенного изображения. Убедитесь, что ваша функция google.script.run.withSuccessHandler корректно обрабатывает результат.

Возможные ошибки и исправления

  1. Время загрузки изображений: В вашем коде используется setTimeout для ожидания загрузки изображений. Это может не всегда сработать корректно, особенно если изображения загружаются медленно. Вместо этого, вы можете использовать Promise для более надежного контроля загрузки изображений.

  2. Состояние канваса: Убедитесь, что канвас имеет правильные размеры после загрузки первого изображения. Это критично для корректного наложения последующих изображений.

  3. Отладка: Проверяйте консоль на наличие ошибок. Если что-то идет не так, то консольные сообщения могут помочь в диагностике проблемы. Например, вы можете использовать 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>

Заключение

Проверьте, чтобы все идентификаторы файлов и папок были действительными, а также убедитесь, что у вас есть достаточные права доступа к данным ресурсам. После внесения изменений в код, попробуйте снова выполнить скрипт. Если у вас возникнут дополнительные вопросы или проблемы, не стесняйтесь задавать их.

Оцените материал
Добавить комментарий

Капча загружается...