【问题标题】:Download image through Parse Cloud Code function通过 Parse Cloud Code 功能下载图像
【发布时间】:2015-08-12 12:27:01
【问题描述】:

我正在开发一个处理图片并使用parse.com 服务作为后端的应用程序。在某些时候,我不得不在以下两者之间做出选择:

  • 存储同一张图片的不同版本,例如100x100 用于缩略图,400x400 用于更大视图,1000x1000 用于全屏视图;
  • 仅存储1000x1000 版本,并在需要时将其缩小,可能在服务器端。

我目前正在研究的解决方案是两者的混合:我持有100x100 用于缩略图,1000x1000 用于全屏视图,并希望将其缩小以满足任何其他需要。我开始研究 Cloud Code 功能来实现这一目标。我的愿望是将当前视图的宽度传递给函数,以便使图像适应客户的需要。

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

Parse.Cloud.define("getPicture", function(request, response) {

  var url = request.params.pictureUrl;
  var objWidth = request.params.width / 2;

  Parse.Cloud.httpRequest({
    url: url

  }).then(function(resp) {
    var i = new Image();
    return i.setData(resp.buffer);

  }).then(function(i) {
    var scale = objWidth / i.width();
    if (scale >= 1) {
        response.success(i.data());
    }
    return i.scale({
      ratio: scale
    });

  }).then(function(i) {
    return i.data();

  }).then(function(data) {
    response.success(data);
  });

});

我有两个问题:

  • 这种方法是否正确,或者我应该更好地存储一个中等大小的图像版本(如400x400)?这会决定对云代码函数的调用过多吗? (我不知道parse.com 对云函数调用的数量有任何限制,但可能有)

  • i.data() 返回的是什么类型的对象,我如何从中获取Bitmap?通过我正在调用的 Android 应用程序:

    HashMap<String, Object> params = new HashMap<>();
    params.put("pictureUrl",getUrl());
    params.put("width", getWidth());
    ParseCloud.callFunctionInBackground("getPicture", params, new FunctionCallback<Object>() {
        @Override
        public void done(Object object, ParseException e) {
    
            //here I should use BitmapFactory.decodeByteArray(...)
            //but object is definitely not a byte[] !
            //From debugging it looks like a List<Integer>,
            //but I don't know how to get a Bitmap from it.
    
        }
    });
    

【问题讨论】:

    标签: javascript java android parse-platform


    【解决方案1】:

    方法看起来不错。

    由于 Parse API 的返回值是 JSON,因此您可以返回二进制数据(图像)的唯一方法是 JSON 整数数组或使用二进制数据的 Hex 或 Base64 编码值。

    您可以使用Buffer#toString() method of Parse Cloud 返回base64 字符串,如下所示。与hex 编码相比,base64 字符串的大小更小,因此是首选。

    response.success(data.toString('base64'));
    

    在 Android 端,可以使用下面给出的代码将 base 64 字符串解码为byte[],以便可以在Bitmapfactory#decodeByteArray 中使用。

    ParseCloud.callFunctionInBackground("getPicture", params,
        new FunctionCallback<String>() {
            @Override
            public void done(String object,
                    ParseException e) {
    
                byte[] imgBytes = Base64.decode(object, Base64.DEFAULT);
                if (imgBytes.length > 0) {
                    Bitmap bitmap = BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length);
                    ((ImageView) findViewById(R.id.image_view)).setImageBitmap(bitmap); 
                }
            }
    
        }
    );
    

    我已经测试了上面提出的更改,它们工作得很好。

    注意:请注意,R.id.image_view 仅供参考,您必须使用适用于您的项目的id 或ImageView

    【讨论】:

    • 我曾经尝试过这个,但得到ClassCastException(或类似的东西)说你不能将imgBytes转换为byte[]。据我所知,它应该是List&lt;Integer&gt;。这使得使用 BitmapFactory 变得困难。所以我们应该在云端改变一些东西,以确保函数返回一个 byte[] 对象或类似的东西!
    • 谢谢。现在无法测试,但您的答案看起来不错。我只是想等着看看是否有 js 家伙想出了一个在后端进行这种转换的解决方案,我宁愿避免在设备上工作。
    • 更新了从服务器发送图片的base64编码值的答案
    • 如何上传?
    【解决方案2】:

    上面的答案是正确的并解决了我的问题,但在给出依赖“运行时宽度”图像的建议时我会更加小心。对于某些(大多数?)用途,使用托管在服务器上的预缩放图像肯定会更好。

    这里有两个问题:

    1. API 请求:

    Parse 根据您在一秒钟内执行的 API 网络请求向您收费。这不是问题:无论是从 ParseImageView 调用 callFunctionInBackground() 还是 loadInBackground(),都是一样的 - 每次调用一个 API 请求。但是。

    1. 缓存:

    如果你有一个服务器保存的 ParseFile,你可以在一秒钟内缓存它。如果你有一个刚刚为你创建的下载位图,你不能缓存它——无论如何,不​​能使用 Parse SDK。您可以尝试将此 ParseFile 放入 ParseObject 并固定它,但它不起作用 - 固定需要 ParseFiles 存在于服务器中。您可以尝试将图像 byte[] 放在 ParseObject 字段中,但这对于大图像会失败,并且我没有设法使其工作。

    如果您不缓存,事情很快就会结束 - 设置 RecyclerView 很痛苦,每次绑定视图持有者时,您都会花费一个新的 API 请求。

    所以 - 我不鼓励将这种自定义宽度图像的方法与适配器视图和回收器视图一起使用。如果你走这条路,请确保你身边有一个图像缓存库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-21
      • 2015-06-12
      • 1970-01-01
      • 2015-10-25
      • 2016-04-05
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      相关资源
      最近更新 更多