Hi @desiremuson and @khilda
To reiterate, it is not possible to compress uploaded files - more details here
Furthermore, in terms of doing it in the backend after the fact I could not find a standard NPM package that allows image compression AND works via CloudCode (this is because of the the image compression libs require access to OS binaries that you cannot access from CloudCode - at least not at time of writing)
However, there are several API services that you can use that accomplishes the same thing.
I tried one, called TinyPNG, as they have a free tier, and the implementation was fairly simple.
From a workflow point of view, if you need to have compressed images for a PDF report or something similar, I would recommend saving a compressed version of the original together with the original. I would create the compressed version “immediately” whenever the original is uploaded using a webhook triggered CC task. I would not do the compression “inline” at the time when you want to generate the PDF.
Your results may vary, but the test case I had reduced a 2.5MB png down to 0.5 MB without having to resize the image. When I added resizing, that number goes down to 0.05MB. See below results and example code.
PS. You will have to review TinyPNG’s terms and usage to determine if you want to make use of their service or not.
Compression Results - from CC
11:29:07.110 [TASK:INFO] Original File Size: 2.473 MB (decimal) | 2.358 MB (binary)
11:29:09.029 [TASK:INFO] Compressed File Size: 0.612 MB (decimal) | 0.597 MB (binary)
11:29:11.074 [TASK:INFO] Resized File Size: 0.059 MB (decimal) | 0.056 MB (binary)
11:29:11.254 [TASK:INFO] Request complete. Response code: 204. Memory used: 76MB.
11:29:11.272 [QUEUE:INFO] Moved from state 'QUEUED' to 'COMPLETED'
CloudCode Code
const tinify = require("tinify");
tinify.key = process.env.TINIFY_KEY
export async function run() {
// Your code here
let photoObj = await DB.photo.first("photo != ?", null);
let photo = photoObj.photo;
let photoBuffer = await photo.toBuffer();
let originalSize = photoBuffer.byteLength
console.log(`Original Size: ${(originalSize/1000/1000).toFixed(3)} MB (decimal) | ${(originalSize/1024/1024).toFixed(3)} MB (binary)`)
// OPTION 1: Just compression - no resizing (your results may vary)
const compressedFileBuffer = await tinify.fromBuffer(photoBuffer).toBuffer();
let compressedSize = compressedFileBuffer.byteLength;
console.log(`Compressed Size: ${(compressedSize/1000/1000).toFixed(3)} MB (decimal) | ${(compressedSize/1024/1000).toFixed(3)} MB (binary)`)
let newCompressedFile = await Attachment.create({data: compressedFileBuffer, filename: 'Compressed File.jpg'})
let newPhoto = DB.photo.create();
newPhoto.photo = newCompressedFile;
newPhoto.name = "Compressed Photo";
await newPhoto.save();
// OPTION 2: Compression + Resizing (your results may vary)
let resizeOptions = {
method: 'fit',
width: 1200,
height: 1200
}
const resizedFileBuffer = await tinify.fromBuffer(photoBuffer).resize(resizeOptions).toBuffer();
let resizedSize = resizedFileBuffer.byteLength;
console.log(`Resized Size: ${(resizedSize/1000/1000).toFixed(3)} MB (decimal) | ${(resizedSize/1024/1024).toFixed(3)} MB (binary)`)
let newResizedFile = await Attachment.create({data: resizedFileBuffer, filename: 'Resized File.jpg'})
newPhoto = DB.photo.create();
newPhoto.photo = newResizedFile;
newPhoto.name = "Resized Photo";
await newPhoto.save();
}
I hope this helps