Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compress more than one image #46

Closed
pavliukpetro opened this issue Jun 27, 2018 · 13 comments
Closed

Compress more than one image #46

pavliukpetro opened this issue Jun 27, 2018 · 13 comments

Comments

@pavliukpetro
Copy link

Hello,
is there a way to compress in one set more than one image?

@fengyuanchen
Copy link
Owner

const imageCompressor = new ImageCompressor();

Promise.all([
  imageCompressor.compress(file1),
  imageCompressor.compress(file2),
  imageCompressor.compress(file3),
]).then(([result1, result2, result3) => {
  // Handle the compressed image files.
}).catch((err) => {
  // Handle the error
});

@grreeenn
Copy link

can you please provide an example with a new(?) way (passing file into the constructor) and a for loop? I have a "multiple" file input and need to compress all of the output files before sending them to the server.
Thanks

@grreeenn
Copy link

grreeenn commented May 12, 2020

I still don't understand the author's comment, so I'll answer myself and anyone else who stumbles upon this.

First, you need to create a function that compresses an image and returns a promise:

  compressImage(file: File): Promise<File> {
        return new Promise<File>((resolve, reject) => {
            new Compressor(file, {
                ...someOptions,
                success: (result) => {
                    resolve(new File([result], file.name, {type: result.type}))
                },
                error: (error: Error) => reject(error)
            })
        });
    }

so you can use it like this:

    public async onFileInputChange(files: File[]) {
        // collect promises from the compression function
        const compressPromises: Promise<File>[] = [];
        for (const file of files) {
            compressPromises.push(this.compressImage(file));
        }

        // wait until these properties are resolved and loop through the result
        Promise.all(compressPromises).then((compressedFiles) => {
            for (const file of compressedFiles) {
              // do whatever you need to do with these files - upload to server or whatever
            }
        })
            .catch((error) => console.log('ooops :(', error))
    }

This was referenced May 12, 2020
@samuelstroschein
Copy link

Coming from Python, I wrote this function which at least makes it understandable (for me) what is happening:

// returns a promise so the function can be used with await compressImages()
    function compressImages(){
        return new Promise(async function(resolve){
            let processedImages = 0
            let numImagesToProcess = $images.files.length
            for (let i = 0; i < numImagesToProcess; i++){
                const file = $images.files[i]
                await new Promise(resolve =>{
                    new Compressor(file, {
                        quality: 0.5,
                        success(result){
                            $images.files[i] = result
                            resolve()
                        }
                    })
                })
                processedImages += 1
            }
            if (processedImages === numImagesToProcess){
                resolve()
            }
        })
    }

@JordoHeffernan
Copy link

@grreeenn Just wanted to say thank you for this suggestion. I've been looking for away to free my compressed files that compressorjs has been holding hostage so that I can use async await as well as write tests by mocking out the helper function and get around compressorjs in tests. This solution was immensely helpful. Thank you!

@warrenkc
Copy link

warrenkc commented Jun 8, 2021

Coming from Python, I wrote this function which at least makes it understandable (for me) what is happening:

// returns a promise so the function can be used with await compressImages()
    function compressImages(){
        return new Promise(async function(resolve){
            let processedImages = 0
            let numImagesToProcess = $images.files.length
            for (let i = 0; i < numImagesToProcess; i++){
                const file = $images.files[i]
                await new Promise(resolve =>{
                    new Compressor(file, {
                        quality: 0.5,
                        success(result){
                            $images.files[i] = result
                            resolve()
                        }
                    })
                })
                processedImages += 1
            }
            if (processedImages === numImagesToProcess){
                resolve()
            }
        })
    }

I made an example. Would you mind terribly helping me to learn how to use your method? I have it setup for compressor.js here: https://codepen.io/warrenkc/pen/XWMYGxE?editors=0011

@samuelstroschein
Copy link

I made an example. Would you mind terribly helping me to learn how to use your method? I have it setup for compressor.js here: https://codepen.io/warrenkc/pen/XWMYGxE?editors=0011

Sure! The function is pretty ugly and I used some global variables. I guess the latter is the predominant reason why it's not working for you. This should work (sorry I don't have a Codepen account):

btnResize.addEventListener("click", async function () {
  let compressedImages = [];
  // the function uses the file input dom element directly. 
  // compressedImages is an empty array which will contain 
  // the compressed images after processing. 
  await compressImages(fileInput, compressedImages);
  console.log(compressedImages.length);
  
});
async function compressImages(fileInput, output){
        return new Promise(async function(resolve){
            let numProcessedImages = 0
            let numImagesToProcess = fileInput.files.length
            for (let i = 0; i < numImagesToProcess; i++){
                const file = fileInput.files[i]
                await new Promise(resolve =>{
                    new Compressor(file, {
                        quality: 0.5,
                        success(result){
                            output.push(result)
                            resolve()
                        }
                    })
                })
                numProcessedImages += 1
            }
            if (numProcessedImages === numImagesToProcess){
                resolve()
            }
        })
    }

@warrenkc
Copy link

warrenkc commented Jun 8, 2021

Thank you. I am trying to figure out a way to process the files before uploading them to the server.

@fengyuanchen
Copy link
Owner

Example for compressing multiple image files one by one:

async function compress(files) {
  for (const file of files) {
    await new Promise((resolve, reject) => {
      new Compressor(file, {
        success: resolve,
        error: reject,
      });
    });
  }
}

compress(files).then((result) => {
  console.log('Compress success');
}).catch((err) => {
  console.log('Compress error');
}).finally(() => {
  console.log('Compress complete');
});

@warrenkc
Copy link

Thank you. Here is the updated example: https://codepen.io/warrenkc/pen/ZEeqxOz?editors=0011
Does that look correct?

@fengyuanchen
Copy link
Owner

@warrenkc Yes, it works fine.

@warrenkc
Copy link

Thank you so much. I want to show you a video of what happens in Safari on the 4th gen iPad.
https://drive.google.com/file/d/1SnJ3LJLnICjzlr97VVbIxijqxdN-tH0I/view?usp=sharing
Do you know what would cause this?

@fengyuanchen
Copy link
Owner

I have not idea on this, maybe you can defer calling the resovle function for a try:

// resolve();
setTimeout(() => {
  resolve();
}, 1000);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants