-1

Assume I have a Table

---------Image-------------

imageFile (File)   |    thumbnail (File)  | Post (a pointer to Post)

Any idea how to write a cloud code to take a smaller version of that image in another column?

For example, If a user uploaded a (2000x3500 px) image, Parse will save it in imageFile column, and save its thumbnail in the other column

thanks

nathan
  • 9,329
  • 4
  • 37
  • 51
Hatim
  • 1,516
  • 1
  • 18
  • 30

1 Answers1

5

Here's the current solution I'm using (Original script was published by Parse.com some time ago and deleted after the ownership transfer to the community):

Usage example in main.js:

var resizeImageKey = require('cloud/resize-image-key.js'),
    THUMBNAIL_SIZE = 100,
    Image = require("parse-image");


Parse.Cloud.afterSave("TableName", function(request) {
    return resizeImageKey({
        object: request.object, // ParseObject in which the thumbnail will be saved
        url: objectImage.url(), // Full size image URL
        toKey: "thumbnail", // thumbnail's attribute key
        width: THUMBNAIL_SIZE, // width
        crop: false // resize or crop ?
    });
});

resize-image-key.js (async-await)

const Image = require("parse-image");

/*
  Original: https://github.com/ParsePlatform/Anyimg/blob/master/parse/cloud/resize-image-key.js
  Resizes an image from one Parse Object key containing
  a Parse File to a file object at a new key with a target width.
  If the image is smaller than the target width, then it is simply
  copied unaltered.

  object: Parse Object
  url: URL of the Parse File
  toKey: Key to contain the target Parse File
  width: Target width
  crop: Center crop the square
*/
module.exports = function(options) {
    let format, originalHeight, originalWidth, newHeight, newWidth;

    // First get the image data
    const response = await Parse.Cloud.httpRequest({
        //url: options.object.get(options.fromKey).url()
        url: options.url
    })

    let image = new Image();
    await image.setData(response.buffer);

    // set some metadata that will be on the object
    format = image.format();
    originalHeight = image.height();
    originalWidth = image.width();
    if (image.width() <= options.width) {
        // No need to resize
        // Remove from code
    } else {
        var newWidth = options.width;
        var newHeight = options.width * image.height() / image.width();

        // If we're cropping to a square, then we need to adjust height and
        // width so that the greater length of the two fits the square
        if (options.crop && (newWidth > newHeight)) {
            var newHeight = options.width;
            var newWidth = newHeight * image.width() / image.height();
        }

        // resize down to normal width size
        image = await image.scale({
            width: newWidth,
            height: newHeight
        });
    }

    // crop ?
    if (options.crop) {
        let left = 0;
        let top = 0;

        // Center crop
        if (image.width() > image.height()) {
            left = (image.width() - image.height()) / 2;
        } else {
            top = (image.height() - image.width()) / 2;
        }

        image = await image.crop({
            left: left,
            top: top,
            width: options.width,
            height: options.width
        });
    }

    newHeight = image.height();
    newWidth = image.width();
    // Get the image data in a Buffer.
    const buffer = await image.data();

    // Save the image into a new file.
    const base64 = buffer.toString("base64");
    //var scaled = new Parse.File("thumbnail_" + options.object.get("name") + "." + format, {
    const scaled = new Parse.File("thumbnail." + format, {
        base64: base64
    });
    const savedImage = await scaled.save();

    // Set metadata on the image object
    options.object.set(options.toKey, savedImage);
    //return options.object.save();
    options.object.set("thumbnail_width", newWidth);
    options.object.set("thumbnail_height", newHeight);
};

resize-image-key.js (vanilla JS)

var Image = require("parse-image");

/*
  Original: https://github.com/ParsePlatform/Anyimg/blob/master/parse/cloud/resize-image-key.js
  Resizes an image from one Parse Object key containing
  a Parse File to a file object at a new key with a target width.
  If the image is smaller than the target width, then it is simply
  copied unaltered.

  object: Parse Object
  url: URL of the Parse File
  toKey: Key to contain the target Parse File
  width: Target width
  crop: Center crop the square
*/
module.exports = function(options) {
    var format, originalHeight, originalWidth, newHeight, newWidth;

    // First get the image data
    return Parse.Cloud.httpRequest({
        //url: options.object.get(options.fromKey).url()
        url: options.url
    }).then(function(response) {
        var image = new Image();
        return image.setData(response.buffer);
    }).then(function(image) {
        // set some metadata that will be on the object
        format = image.format();
        originalHeight = image.height();
        originalWidth = image.width();

        if (image.width() <= options.width) {
            // No need to resize
            return new Parse.Promise.as(image);
        } else {
            var newWidth = options.width;
            var newHeight = options.width * image.height() / image.width();

            // If we're cropping to a square, then we need to adjust height and
            // width so that the greater length of the two fits the square
            if (options.crop && (newWidth > newHeight)) {
                var newHeight = options.width;
                var newWidth = newHeight * image.width() / image.height();
            }

            // resize down to normal width size
            return image.scale({
                width: newWidth,
                height: newHeight
            });
        }
    }).then(function(image) {
        if (options.crop) {
            var left = 0;
            var top = 0;

            // Center crop
            if (image.width() > image.height()) {
                var left = (image.width() - image.height()) / 2;
            } else {
                var top = (image.height() - image.width()) / 2;
            }

            return image.crop({
                left: left,
                top: top,
                width: options.width,
                height: options.width
            });
        } else {
            return Parse.Promise.as(image);
        }
    }).then(function(image) {
        newHeight = image.height();
        newWidth = image.width();
        // Get the image data in a Buffer.
        return image.data();
    }).then(function(buffer) {
        // Save the image into a new file.
        var base64 = buffer.toString("base64");
        //var scaled = new Parse.File("thumbnail_" + options.object.get("name") + "." + format, {
        var scaled = new Parse.File("thumbnail." + format, {
            base64: base64
        });
        return scaled.save();
    }).then(function(image) {
        // Set metadata on the image object
        options.object.set(options.toKey, image);
        //return options.object.save();
        options.object.set("thumbnail_width", newWidth);
        options.object.set("thumbnail_height", newHeight);
    });
};

Update: Found a clone of the original script and archived it just in case: https://web.archive.org/web/20190107225015/https://github.com/eknight7/Anyimg/blob/master/parse/cloud/resize-image-key.js

nathan
  • 9,329
  • 4
  • 37
  • 51
  • You're welcome but as I said it's not my code :) (Not sure why Parse deleted that specific repo) – nathan Aug 29 '17 at 01:13