如何在保存Parse.Cloud.beforeSave之前将照片调整为多个照片尺寸

时间:2015-03-13 12:57:40

标签: parse-platform

首先让我先谈谈我让这段代码完美地运行以获得缩略图(https://parse.com/docs/cloud_modules_guide#images

我目前的代码是:

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

var photoSizesArray = {};
photoSizesArray["Thumb"] = [40,40];
photoSizesArray["Normal"] = [180,180];

    Parse.Cloud.beforeSave("_User", function(request, response) {
      var user = request.object;
      if (!user.get("profilePicture")) {
        // response.error("Users must have a profile photo.");
        // return;
        response.success();
        return;
      } else {


        if (!user.dirty("profilePicture")) {
          // The profile photo isn't being modified.
          response.success();
          return;
        }

        for (var key in photoSizesArray) {

          Parse.Cloud.httpRequest({
            url: user.get("profilePicture").url()

          }).then(function(response) {
            var image = new Image();
            return image.setData(response.buffer);

          }).then(function(image) {
            // Crop the image to the smaller of width or height.
            var size = Math.min(image.width(), image.height());
            return image.crop({
              left: (image.width() - size) / 2,
              top: (image.height() - size) / 2,
              width: size,
              height: size
            });

          }).then(function(image) {

              // Resize the image to 40 x 40.
              return image.scale({
                width: photoSizesArray[key][0],
                height: photoSizesArray[key][1]
              });


          }).then(function(image) {
            // Make sure it's a JPEG to save disk space and bandwidth.
            return image.setFormat("JPEG");

          }).then(function(image) {
            // 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 cropped = new Parse.File("profilePicture"+key+"_" + Parse.User.current().id + ".jpg", { base64: base64 });
            return cropped.save();

          }).then(function(cropped) {
            // Attach the image file to the original object.
            user.set("profilePicture" + key, cropped);

          }).then(function(result) {
            response.success();
          }, function(error) {
            response.error(error);
          });

      }
    }
  });

我的问题是如何在相同的_User表中保存相同的照片但不同的尺寸?

目前我收到的错误是

"无法多次调用多次成功/错误"

或有时如果确实有效,它只会保存2张照片尺寸中的一张。

如果我应该如何移动成功/错误响应,我们将不胜感激。

或者,如果我应该研究如何保存额外照片尺寸的不同方法。

感谢,

2 个答案:

答案 0 :(得分:4)

经过一番研究和反复试验后,我终于明白了Promise如何与httpRequests一起工作。

我最初遇到的问题是,由于某种原因,它会同时并发2个httpRequests,它会被覆盖或被忽略。

这是您需要了解的内容。

  1. Parse.Cloud.httpRequest返回一个Parse.Promise对象。

  2. 你实际上必须在for循环中返回对象。这意味着我将Parse.Cloud.httpRequest对象放在for循环之外的一个单独函数中,我可以在for循环中调用它。

  3. 当你最终在promises数组中收集了所有的Promise对象时,你可以使用Parse.Promise.when(promises)来完成它.then()...

  4. 以下是我的代码,它获取上传的照片,处理它的2个大小并将它们保存在单独的_User列中 - profilePictureThumb和profilePictureNormal。

    var Image = require("parse-image");
    Parse.Cloud.beforeSave("_User", function(request, response) {
    var user = request.object;
    if (!user.get("profilePicture")) {
      // response.error("Users must have a profile photo.");
      // return;
      response.success();
      return;
    } else {
    
        if (!user.dirty("profilePicture")) {
          // The profile photo isn't being modified.
          response.success();
          return;
        }    
    
        var promises = [];
        var sizes = { 
            Normal: { width: 180, height: 180 }, 
            Thumb: { width: 80, height: 80 }
        };
    
        for(var key in sizes) {            
            promises.push(
                ProcessUrls(user.get("profilePicture").url(), key, sizes[key])
            );
        }
    
        return Parse.Promise
            .when(promises)
            .then(function () {
                // results are passed as function arguments
                // map processed photos to result
                var photos = Array.prototype.slice.call(arguments);
                var result = {};
                console.log("promises:" + promises)
    
                photos.forEach(function (photo) {
                    console.log("photo.key: " + photo.key)
                    result[photo.key] = photo;
    
                    user.set('profilePicture' + photo.key, photo.file);
    
                });
                response.success();
            }, function(error) {
                response.error("error: " + error);
        });
    
    } // Else
    
    
    
    });
    
    function ProcessUrls(fullUrl, key, size) {
    /* debugging
    console.log("fullUrl: " + fullUrl);
    console.log("key: " + key);
    console.log("width: " + size["width"]);
    console.log("height: " + size["height"]);
    */    
    return Parse.Cloud.httpRequest({ url: fullUrl })
    .then(function(response) {
        var image = new Image();
        return image.setData(response.buffer);
    
    })
    .then(function(image) {
        // Crop the image to the smaller of width or height.
        var size = Math.min(image.width(), image.height());
        return image.crop({
          left: (image.width() - size) / 2,
          top: (image.height() - size) / 2,
          width: size["width"],
          height: size["height"]
        })
    })
    .then(function(image) {
        // Resize the image to 40 x 40.
        return image.scale({
            width: size["width"],
            height: size["height"]
        });
    })
    .then(function(image) {
        // Make sure it's a JPEG to save disk space and bandwidth.
        return image.setFormat("JPEG");
    })
    .then(function(image) {
        // 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 cropped = new Parse.File("profilePicture"+key+"_" + Parse.User.current().id + ".jpg", { base64: base64 });
        return cropped.save()
        .then(function (file) {
             // this object is passed to promise below
             return { 
                 key: key, 
                 file: file
             };
        })
    })
    };
    

    感谢@Andy和其他一些StachOverflow用户,我将这些代码拼凑在一起。

答案 1 :(得分:0)

首先,您不必每次都加载源图像。加载一次,然后多次调整大小。

您无法重复使用相同的Image对象,因此您必须为每个单独的调整大小操作创建所需数量的对象。

粗略地说,流程如下:

var grandPromise = Parse.Cloud.httpRequest({ url: url })
        .then(function (response) {
            var buffer = response.buffer;
            var promises = [];
            var sizes = { 
                normal: { width: 300, height: 300 }, 
                thumb: { width: 100, height: 100 }
            };

            for(var key in sizes) {
                var size = sizes[key];
                var image = new Image();

                // create promise for resize operation
                var promise = image.setData(buffer)
                    .then(function(image) {
                        // do whatever scaling you want
                        return image.scale({
                            width: size.width, 
                            height: size.height
                        });
                    })
                    .then(function (scaledImage) {
                        return scaledImage.data();
                    })
                    .then(function (buffer) {
                        var base64 = buffer.toString('base64');
                        var name = key + '.jpg';
                        var file = new Parse.File(name, { base64: base64 });

                        return file.save()
                             .then(function (file) {
                                 // this object is passed to promise below
                                 return { 
                                     key: key, 
                                     size: size, 
                                     file: file
                                 };
                             });
                    });

                // save promise to array
                promises.push(promise);
            }

            // create promise that waits for all promises
            return Parse.Promise
                    .when(promises)
                    .then(function ( /* result1, result2, ... */ ) {
                        // results are passed as function arguments
                        // map processed photos to result
                        var photos = Array.prototype.slice.call(arguments);
                        var result = {};

                        photos.forEach(function (photo) {
                            result[photo.key] = photo;
                        });

                        return result;
                    });
        });

grandPromise.then(function (result) {
   var normalURL = result.normal.file.url();
   var thumbURL = result.thumb.file.url();

   // save URLs on user model
   user.set('profilePictureNormal', normalURL);
   user.set('profilePictureThumb', thumbURL);

   console.log('Saved normal size photo at ' + normalURL);
   console.log('Saved thumb size photo at ' + thumbURL);

   response.success();
}, function (err) {
    console.log('Got error ' + err.code + ' : ' + err.message);
    response.error(err);
});