Создайте zip-файл из массива png-файлов

Всякий раз, когда я пытаюсь создать zip-файл с помощью JSZip, я либо получаю сообщение об ошибке, указывающее, что изображения не могут быть экземпляром Blob (так оно и есть), либо результат поврежден/не может быть извлечен.

У меня есть внутренний API, который возвращает изображение .png с идентификатором, соответствующим изображению из аутентифицированной конечной точки. В серверном компоненте я получаю набор идентификаторов изображений из отдельной конечной точки, а затем сопоставляю его с массивом изображений .png (как объекты Blob, используя await res.blob()). Затем я создаю zip-файл из этих изображений с помощью JSZip, который возвращаю как объект Buffer. В клиентском компоненте я получаю этот объект Buffer, создаю из него объект Blob, а затем URL-адрес, по которому щелкаю.

Серверная составляющая:

const download = async (file, format: string) => {
        "use server"

        const imageArray = await makeImageArray(file.id, format);

        const zip = new JSZip();

        await Promise.all(imageArray.map(async (rendered) => {
            console.info("blob", rendered.data)
            zip.file(`${rendered.name.replaceAll(" ", "_")}.${rendered.type}`, Buffer.from(await rendered.data.arrayBuffer()).toString("base64"), {base64: true});
            return rendered.data;
        }));
        const zipped = await zip.generateAsync({type: "blob"})
        const arrayBuffer = await zipped.arrayBuffer();
        const buffer = Buffer.from(arrayBuffer)
        return buffer
    }

Клиентский компонент:

const clickAZip = async (file, format) => {
        const a = document.createElement("a");
        const zip = await onDownload(file, format)
        a.href = URL.createObjectURL(new Blob(zip,{type: 'application/zip'}))
        a.download=`${file.name}.zip`
        a.click()
    }

Обратите внимание: код здесь загружает поврежденный zip-архив. Если я заменю rendered.data.arrayBuffer()).toString("base64") на rendered.data, я получу следующую ошибку в серверном компоненте: Internal error: Error: Can't read the data of 'Generic_image.png'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?

Редактировать:

Код функции makeImageArray, которая может быть источником поврежденного файла:

const makeImageArray = async (id: string, format: string) => {
        "use server"
        return await authenticatedFetch(process.env.NEXT_PUBLIC_API_URL + `/project/sheets/all/${id}`, "GET", null)
            .then(async (response) => {
                return await Promise.all(response
                    .map(async (sheet) => {
                        return {
                            data: await blobFetch(process.env.NEXT_PUBLIC_API_URL + '/private/render', "POST", JSON.stringify({
                                text: sheet.text,
                                format: format
                            })), name: sheet.name, type: format
                        }
                    }))
            }).then(res => res.filter(r => !r.data?.error))
    }

Функция получает массив идентификаторов (строков) из первой выборки, а затем сопоставляет его с массивом изображений .png посредством другой выборки. Маловероятно, что сами изображения повреждены, поскольку поврежден zip-архив в целом, а не отдельные содержащиеся в нем файлы.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, я нашел проблему:

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

Решением было создание экземпляра объекта Uint8Array из буфера перед обработкой этого массива:

Серверный компонент:

const download = async (file, format) => {
        "use server";

        const imageArray = await makeImageArray(file.id, format);

        const zip = new JSZip();

        await Promise.all(imageArray.map(async (rendered) => {
            const arrayBuffer = await rendered.data.arrayBuffer();
            zip.file(`${rendered.name.replaceAll(" ", "_")}.${rendered.type}`, arrayBuffer);
        }));

        const zipped = await zip.generateAsync({type: "arraybuffer"});
        return Buffer.from(zipped)
    }

Клиентский компонент:

const clickAZip = async (file, format) => {
        const a = document.createElement("a");
        const zipBuffer = await onDownload(file, format);
        const zipArr = new Uint8Array(zipBuffer);
        const blob = new Blob([zipArr.buffer], {type: 'application/zip'});
        a.href = URL.createObjectURL(blob);
        a.download = `${file.name}.zip`;
        a.click();
    }

Другие вопросы по теме