Как изменить размер фотографии на несколько размеров перед сохранением в Parse.Cloud.beforeSave

Прежде всего, позвольте мне начать с того, что я получил этот код, который отлично работает, чтобы получить эскиз ( https://parse.com/docs/cloud_modules_guide).

Мой текущий код:

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 ответа

Решение

Итак, после целого ряда исследований, проб и ошибок, я наконец понял, как Promises работает вместе с httpRequests.

Первоначально у меня были проблемы с получением двух одновременных httpRequests, идущих параллельно друг другу, так как по какой-то причине он перезаписывается или просто игнорируется.

Вот что вам нужно знать.

  1. Parse.Cloud.httpRequest возвращает объект Parse.Promise.

  2. Вы на самом деле должны вернуть объект в цикле for. Это означало, что я поместил свой объект Parse.Cloud.httpRequest в отдельную функцию вне цикла for, которую я могу вызывать в цикле for.

  3. Когда у вас наконец есть все объекты Promise, собранные в массиве обещаний, вы проходите через него с помощью Parse.Promise.when(promises).then()...

Ниже приведен мой код, который получает загруженную фотографию, обрабатывает ее 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, где я собрал этот код вместе.

Прежде всего вам не нужно каждый раз загружать исходное изображение. Загрузите его один раз, затем измените его размер несколько раз.

Вы не можете повторно использовать один и тот же объект 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);
});
Другие вопросы по тегам