Generate a compressed folder containing a collection of PNG images

While attempting to generate a zip file using JSZip, I encounter issues where the images are falsely flagged as not being instances of Blob or the final result turns out to be corrupt and cannot be extracted.

The process involves an API on the back-end that returns .png images based on specific ids obtained from an authenticated endpoint. Within the server component, the image ids are fetched from a separate endpoint and converted into an array of .png images (as Blob objects) using await res.blob(). Subsequently, these images are combined into a zip file using JSZip, which is then returned as a Buffer object. On the client side, the Buffer object is received, converted into a Blob object, and an URL is created for downloading purposes.

The server-side script:

const download = async (file, format: string) => {
        "server-side function"

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

        const zip = new JSZip();

        await Promise.all(imageArray.map(async (rendered) => {
            console.log("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
    }

The client-side script:

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()
    }

Note that the current code downloads a corrupted zip archive. If replacing

rendered.data.arrayBuffer()).toString("base64"
with rendered.data, it results in the error message within the server component:
Internal error: Error: Can't read the data of 'Generic_image.png'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?

Edit:

The potentially problematic code for the makeImageArray function:

const makeImageArray = async (id: string, format: string) => {
        "server-side function"
        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))
    }

This function takes an array of ids (Strings) from the initial fetch request and transforms them into an array of .png images through another fetch operation. The issue seems to lie in the construction of the zip file itself rather than individual image corruption.

Answer №1

After thorough investigation, I managed to pinpoint the issue:

It turns out that the client component was receiving a buffer and wrongly treating it as an array, resulting in a corrupted file.

The solution involved creating a new Uint8Array object from the buffer before proceeding with the array processing:

Server-side code snippet:

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)
    }

Client-side code snippet:

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();
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Run JavaScript upon the webpage loading without the dependency of jQuery

Is there a way to ensure that JavaScript code is executed only after the entire page has loaded, without relying on jQuery? Take this example... <html> <head> <script type="text/javascript"> var box = document.ge ...

Determining the maximum number within an array using JavaScript

Similar Question: How can I identify the largest number in a JavaScript array? I'm facing issues with this piece of code. Despite spending some time on it, I can't seem to make it work properly. The console only shows 0 when I run it. Can som ...

Can a Unicode character be overwritten using a specific method?

Is there a way to display a number on top of the unicode character '♤' without using images? I have over 200 ♤ symbols each with a unique number, and using images would take up too much space. The characters will need to be different sizes, a ...

How to make a GET request to a Node server using Angular

I am currently running a node server on port 8000 app.get('/historical/:days' ,(req,res,next){..}) My question is how to send a request from an Angular app (running on port 4200) in the browser to this node server. Below is my attempt: makeReq ...

Utilizing asynchronous operations in MongoDB with the help of Express

Creating a mobile application utilizing MongoDB and express.js with the Node.js MongoDB driver (opting for this driver over Mongoose for enhanced performance). I am aiming to incorporate asynchronous functions as a more sophisticated solution for handling ...

Enhancing Bootstrap utility classes in a Next.js project with TypeScript

After successfully installing sass in Next.js and Bootstrap, I am able to access bootstrap variables and reassign their values. However, when attempting to extend a utility class from bootstrap, I encounter the following error: SassError: The target sel ...

Utilizing modal functionality in CakePHP 3 (or: Incorporating JavaScript within Controllers)

I have a typical form that was created using cake/bake. After the form is submitted, my controller checks a simple condition: If condition A is met, it will just save the data using patchEntity($foo, $this->request->getData()) If condition B is me ...

Why is it that Next Auth states that the client_id is a required field when using their authentication system, even though in the Discord providers section there is

Each time I attempt to utilize next auth for creating a discord oauth client and subsequently click sign in, an error occurs: https://next-auth.js.org/errors#get_authorization_url_error client_id is required { message: 'client_id is required', ...

What is preventing obj from being iterable?

When I try to compile this code, an error appears stating that the object is not iterable. Why is this happening? My goal is to determine the number of users currently online. let users = { Alan: { age: 27, online: false }, Jeff: { age ...

Don't forget to save the selected date in the datepicker

I have a datepicker with two text fields: fromdate and todate. When I input the month of May and submit, then input another date, the default date should remain as May, instead of changing to the current month. Check out my code below. $(function() { ...

Revamping JSON structure by identifying id references

I recently attempted to update the city name within the JSON object provided below. "City":[ { "Name":"Delhi", "id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd", "Towns":[ ...

Next Js is having trouble locating the Service messaging component (firebase-cloud-messaging)

Hey there! I'm currently working on a project with Next JS that involves using Firebase Cloud Messaging. However, I've encountered an error when trying to run or build the project: info - Checking validity of types info - Creating an optimiz ...

Converting CSS into jQuery

I am exploring ways to create a collapsible section with arrow icons (right and down arrows) in jQuery or JavaScript. Can anyone provide guidance on how to convert my CSS styling into jQuery code? Below is the jQuery approach I have attempted: $(document ...

No response text returned from the local Ajax request

Currently, I am facing a challenge while attempting to send an ajax call from the client to my server containing data related to an input parameter. The issue is that although I can view the data in my server's console, it does not display in the brow ...

React form submissions result in FormData returning blank data

I am having trouble retrieving the key-value pair object of form data when the form is submitted, using the new FormData() constructor. Unfortunately, it always returns empty data. Despite trying event.persist() to prevent react event pooling, I have not ...

Vue: The function "priceFilter" is not defined in this context

function sanitizeInput(event) { event.target.value = event.target.value.replace(/[^\d.]/g, ""); event.target.value = event.target.value.replace(/^\./g, ""); event.target.value = event.target.value.replace(/\.{2,}/g, "."); event.targe ...

What is the best way to convert JavaScript to JSON in Python programming?

I encountered a situation where I have an HTML page that contains a lengthy product list, making it too large for me to upload. The products are stored within the script section of the page, specifically in one variable. Initially, I mistook this data for ...

Guide on incorporating d3 axis labels within <a> elements?

Issue at Hand: I am working with a specific scale var y = d3.scalePoint().domain(['a','b','c']).range([0,100]); I have successfully created an axis for this scale var y_axis = svg.append("g").attr("class", "axis").call(d3. ...

Emulate an AngularJS ng-click action

My website has HTML code with three buttons: <button ng-click='showStats(player.data,0)'>Death Match</button> <button ng-click='showStats(player.data,1)'>Champions Rumble</button> <button ng-click='sho ...

Organizing multiple <image> tags into an array with Javascript - a beginner's guide!

My HTML file contains multiple images. When a user clicks on them, their IDs should be captured without any issues. I am looking for help with the following tasks: 1) Storing all clicked image IDs in an array For example: array = img01 ; array = img ...