使用Windows Azure Blob存储创建缩略图图像

时间:2013-03-16 13:54:25

标签: node.js azure sdk

我正在尝试使用azure-sdk-for-node将流式图像保存到Windows Azure blob存储,但没有成功。下面是我调用的函数,并使用缩略图属性传递视频对象。最初我使用请求对象获取图像,该对象从另一个网站获取图像并将其转换为base64对象,而base64对象又转换为流对象,因为Azure blob服务使用createBlockBlobFromStream方法,因为我无法使用createBlockBlobFromFile或createBlockBlobFromText将图像上传到blob存储。

var azure = require('azure')
    , uuid = require('node-uuid')
    , http = require('http')
    , url = require('url')
    , mmm = require('mmmagic')
    , Magic = mmm.Magic
    , stream = require('stream');

function createVideoThumbnail(video, callback){
    var bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);
    var sURL = video.Thumbnail;
    var oURL = url.parse(sURL);
    var client = http.createClient(80, oURL.hostname);
    var request = client.request('GET', oURL.pathname, {'host': oURL.hostname});

    request.end();
    request.on('response', function (response) {
        var type = response.headers["content-type"];
        var prefix = "data:" + type + ";base64,";
        var body = "";

        response.setEncoding('binary');
        response.on('end', function () {
            var base64 = new Buffer(body, 'binary').toString('base64');
            var data = prefix + base64;
            console.log('base64 image data ' + video.Thumbnail + ': ' + data + '\n');

            var decodedImage = new Buffer(data, 'base64');
            var magic = new Magic(mmm.MAGIC_MIME_TYPE);

            magic.detect(decodedImage, function(err, result) {
                if(err) {
                    throw err;
                }

                var bytes = 0;
                var imageStream = new stream.Stream();
                imageStream.writable = true;

                imageStream.write = function(buf) {
                    bytes += buf.length;
                    imageStream.emit('data', buf);
                };

                imageStream.end = function(buf) {
                    //if(arguments.length) {
                        imageStream.write(buf);
                    //}

                    imageStream.writable = false;
                    imageStream.emit('end');
                    console.log(bytes + ' bytes written');
                };

                var options = {}
                console.log('mmm = ' + result + '\n');
                options.contentType = result;
                options.contentTypeHeader = result;

                console.log('\n');
                bs.createBlockBlobFromStream(config.imageContainer, uuid().replace(/-/gi, "").toLowerCase() + '.jpg', imageStream, decodedImage.length, options, function(error, blobResult, response) {
                    if (error)
                        console.log('got error = ' + JSON.stringify(error) + '\n');

                    if (blobResult)
                        console.log('blobResult = ' + JSON.stringify(blobResult) + '\n');

                    if (response)
                        console.log('response = ' + JSON.stringify(response) + '\n');

                    // now store in Azure blob storage
                    callback();
                });

                imageStream.end(decodedImage);
            });
        });
        response.on('data', function (chunk) {
            if (response.statusCode == 200) body += chunk;
        });
    });
}

这就是我所说的:

createVideoThumbnail(video, function(){
    console.log("returning from create thumbnails\n\n");
});

该功能无法正常工作,无法打印出最终的日志声明:

console.log("returning from create thumbnails\n\n");

然而,base64确实可以工作,因为我得到了这个编码:

数据:图像/ JPEG; BASE64,/ 9J / 4AAQSkZJRgABAQAAAQABAAD / 2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7 / 2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7 / wAARCABaAKADASIAAhEBAxEB / 8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL / 8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 + Tl5ufo6erx8vP09fb3 + PN6 / 8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL / 8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3 + PN6 / 9oADAMBAAIRAxEAPwDx3QNShMv2IyqFcFrVieGHdCfUVFqDrY3BKsVU9favMba7uJn + XcoB3Lg42n1FbWdZu0G6eSQnjLLnNVLFJaMiOElLVGuNTZL8Wkaw7N + 4llzmrtjek35RFtwCrdI8g8fWub13w34r03S11m 502V7Fh81xECVj6fexyv1PBpng2R5rg3EsmFijYn3JGAKqNXm1uOpT0s + hZsLtzrN / AfuTHgKMAMvTiqEtlJLqoEQJVvm4 / UUljeIJrwjiQlsHuOat6TPcazcrbWdrJNqCZ2RxxlvM9xirdrIhxcbNEWtWVw9nMvlP8o3HI9K5GvZLT4d + PbxEmfwzdhGwfnkRTj3BbNeZeJ / d + raBqMlvqmmXVkC7eX50ZUOoPVT0P4Vk5Rlsy4ppamRSqCzADqakji3ruMiL9SasWNuxuk3EbTk7l5pWHc29LiARFHQCuv0R2DooGQpBzjpXKW8bpt8srIP9k5 / Sty1vV0yxe9kwZUGIlPRnPTPt3 / Ct4WMJamlqogfxG1yFCvDEsLYORu6nj8QPwq9G7vcrbgZc4LDvnHTNYXh0R3HEzqJvvmQniRie9a0tzHYpNfuwBjGAc5JJrVfzC5erPfvhtqDXng20aU7mhLQ / QKSAPyxXRs + V4GOa89 + BRnbwGstwMvNdSSH26cfpXcSTeWhLfhXyOJi3Xko92elD4ESsy4JPFVp2DLzziqr3UgZjj5fSljlEgY5wfSlKhOmrtFpor3tvBOpWeCORcfxLmuQkULvITyFGQWL9B2NdfeORDIwIyFNcdIQ8IB2kgfxdCfpWlDszopSqJe7sV / d / AMHfDaaxPctHKluW3R20r52e3Bzj0zXomn + BPDEAj / 0KJ1TlRjgVtC2i1KNbq3G2VT6Yz7VoW4iChcHI7HiscZKfPzdGenSoRpxUexFDZWSQ / Z4rdBEQVKbRtIPBBHcYrxv4mfAi0vbp9T8FTRaTcyHMtm + RbPnuuATGfYAj2Fe6w + Vn7q / nTnZS3QflWNDE1KL91mVfDQq7o + YPB37POszaiZfEmoW1raH7yWrF5W9skAD68 / SvffB /克/ QfC1mLXQtLhtVwN8gXMkh9WY8mujVgDgA / lUgO4dM / jW1XG1ays3ZeRlTwtOn5sgeBivJrE8S + F9K8Ra XNpusWkV1bSjBVxnHoQeoPuOR2rpApPGAKBC7MMdPpWMKkoO6ZpOCmuWR8E / FjwXdeA / FMumN + 8s5CXtZHXJZPQn1H + B71z2juDO29EB28MK + sv2vfC6XngCHXFj / f2E6kvjojEKR + JK / 9818jRhre6WRY2WNxwccfh + NfSYar7WCkzwq9L2cnE6KAL5oYjBHOR1qr4mu5bueC2RGZgOUiXlmP / wBbFSxzIliZ5flUDPI6gf4n + tYSXj / aUnIc7iS + 1sHk9j2rs2RzxXU2rWcWSCS / DQ6 / 6u2Vu / QX / pXS6HbT3dsdX1VG + wwHesR4Nw5OBx + gFc7o + q6dbT + dHokV3L2V1aRgfUsTj9K7HSLvxT4nkltdLSNJ4YjKbeO281o1BxuGDwfqB1qotJ3YJSlJWR698H7maPw9LbtEok88yvGrgCMMBgfpXV3M8kqx74mjOMshIJH4ivMPgxa / 2Nrl / YajNdR6nPCkhiulZGkUE / MoPYc9K9QuoxKd4wWHb1rwq7jDFNvY7KWkLNEDPyxPJPaolm2ENkfypwiuGyI4JSD2VT / Sll0rUxtMtjcRJ / eeMqPzIrpla2o0Q6jLts5SD1U8g5rk9xYcL35rodR0m4uWWztJ7VLyZgkULX8asxJ6BC3JP0rznVvEcMGVtVW5mVirLuCqT0wScfpXHSou2x6OFqQhB6nuPhbVrWeKOS1l3hyOp6GurmsY5GEoJBYcgeteR2ULeG / EcSbAbO8yo / 2JANwx9QD + VelaLqAubffHJkp0XPJHp9a6FShVhzdDsjUcnbqX49qziDI8zbkL0Jx1xT5pUQZGPpmsC7abWb2Caykksb6yk3qs6 / K4wQQceoP8q56Hxjq0N / QZ + I7KKyNupeOKNlwEVSS2SeScVwVcLBaxNKnuxvck + IHxK8NeDWSPWLt3u5AGjtYF3ykeuDwo + pGe1c54Y + PXgrWNSSwuGvtJd3xHLdRr5WT6sGO38cAeor5v13WJda8S3G q30kM93cTGRmKRtn0GMuMAYAHtUE2C5mijZVP39iYAP4RqB + ​​ddccFFRs9zy / aucj9CNKimniDFGYEZVhzkfWrUr2cH + vvLSHb97zJ1XH1ya + aPAV / e6h4G0Vri8keRYtmZJSflWWVFXBf029q6 / wAEW1vqC6slzHG5 / s5JFLRhiu3AyOD / AD / OoWXQb1ZEsZKN9Dsfjc + h678N9S0eHXtINzPGDErXabWIYEfNnA5Ar5lsfhhr1xHHp0Ot6G0ZfzGt40lmlIIBG0rEeo9DXsEUkbfDV0C7JLe9AB + 6cFXPByp / HB / AVW8DaibHxlYXtzdtCi + UDK7cKPlUk5z2z3ruo01RioxOOrU9o25HlWo / Cm3vJAl34m + zRRoGCW + mu2en / PRO + X / nWl4e + CegvanU5b / V9TtYpEVxGIYQCzFRn53I5B7V1OpGSXWLtrNC8csf7sxKfmAGBjhT2rX0rxHbaR4R1TSdVuDbXdwIDAtywXBV2LZ3scdRyMV0Nyepg7JaGH4S + H / HW / 1SOy0zTNSiklYAyTagzZwGbqIcdhxkVc1DwrJBM2laRps1lqLIZJJYZJJJigcjOHlAKnAOQB14qfwJcS6N4is9TgFncGGZZUWK4jPmDPTcoyuVJr1XRteivTDe3ltEl / bboCd28SRnkJnABYADt6 + tTUqcsbM6cJSdSV4u1jnLjw5caN4fstcVbcXsTfZZXls45Jo4S + AC5WQ5Oc8H8K5CHxTrPnCL + 0rkcN80cqRjdtOPurGRziu18ZeO / DmjRrpuoyx3 + lTJny4gsjQMfuqfY44PUY57V5dpV / od8rXFkt9H85RhJc8ZPYDHI / E1zqpC12jXEYacXdSvc9F + KFjcaULS6ttSviLmBifMvLhz9zcDy7Dnn + nevM7F4ZNRQyNFOSr / ADNsZc7Tx8yA9fet / WdaSS0t / t1qblYB5cXm3EjFRjHAJI6Dtiq1pr2jOoj + yw24H / Tun8wM / nTeISWkWzOGDr SjdI73xpN4bs9e8P3mjyWrPDdxSOLVgQqAgkbVyOo746nr2 + cvHtvFZ + MdasTdsBDfzRjgE4V2A5r1PUtUNwqxWt0 / KY + 6jEKD9OlYd / Z2d3C0dzawzLk53KDzULFJvY6KWXyUbtnV / Gqe6i8OW17bSJE1teI4GOWPIH86b4U1a / XV1kjZ1e12faYyGVX3KG + 64BHBBBxg1p + O7XRrtNP / AOEgmMekwTPPcKCQZNsblVBHIyf8O9eJ6x4gFx4kH / CBWV1Zwz7Y385zK0m3d8zMegAOMA9hU4NpUNTWrVdPE2SPcPikNakfS / Enga7jFy77Lq0Z1AnXHBO4jpj9a4DTvEza54xutK8VTx2Wpzj7ObZPugbSMbhwSQSeteS6x4q8Qtq0pa4KTRysoCkgKR6c8VUtrXWL7UpL + ZpftOTLvdsElRng + vFOdNW8jtpyVd8kU7iavoer6P4w / wCEcv1nadJwkQyxDgn5WXnGDVWPTLy51I2sNnLNMz7AioCxOcYHB5r1zR / ibZb7JPGXheO / udPl321yMedGVOQT07gZ5HuKuXPxN8OWMss / hbwt5eoysW + 1XOMJnqVAJz3 / AIH + NEak76xM4YTkm01c0YNO1D4e + GtE026ihmvXtmnuY2mIEJ3lsHap45A9yDWV468X694K8O6de3Flapc6srCG3MjuPIXB3OwK9SwwuOnXHSucvNd1O / vWvtauZ / trEqrvzwOwHYc8dh26V7b8f /艾+ N / h3BNYx51PSojPaKg5kUqN8eO5IVSPdcd6Sqcs1GT3DMMFCjRjKC957nzTcfFnxYxAt / sFquSQkcG4c8Hhy2ep61nXfjXxleSeYdXuID / 0xZIMfQKB + VcrPG8UhRxgjiiON5CAvf3ruSR4DbO40PWrzWXFpq2tXMk6t9 + a4LFx9SeapeKPDUyTG9tZkeN + fvDqOtc19kxgtJt9zQ7XAHlx3Erp7EgVpfTVGVne6Z2nhfx1qWip9nnf + HCOeS jDoa9gsvEMNn8PbG1tdZme7uEN2lyzg + VMxJdT7ZJ / PPavmMqQ2HJHvW3omq3UdnJo4k329w6kA / wEHPH1rKpHnR2YbEOhfzPY / BHw28beOfMfT9PkNjK4L3M7iJDk9QW + 8B1 + UGuitNEGhiTTVgIMMjJI27JLLwWH5e1e0fCzUZ9P8HaVZpwY7ZBj8BXj + v6tcr4l1CQIzo1zJgDoQXPP1rlxEFCKHSxEqsncyvEEhKrGqp1yc8 + 3NYwZX4AG3HBz0q / Q + tWzTATR7TswdyYqC1e2uZR5JIBI4BztH40oaRPo8NaNJGjZsViRFDfKOe1SSOobbjB6mt6y8I3t7oy6jZ3NtHuyxR22ttGfw7etcvcyHKn + DdyRz71g4Pd9TGNWE21F7HovjbQm8Q6DJY71jfIeNj2Yf / rNZt / Z2nhjwhLcSxQRxWNtkADgtjH6n + ddekueNo / KQ + v6XHrWh3elzr8lxGVzjoeoP4EA15qntF7XKUFfm6nyDPby3l552GeSeTdn + Jizeg / HirlhpmqSaoLC1E0lwkm1PJy5J9AByT9K7m4 + GfjSPUltI9KaWFV2JIkw2cdDnPTnPrzXq / hPwxoPgDSJ9c1Iw21wsQa7u5HyE9VTvgnsOTwPSvVqYmKS5dW9kXKNGh7yf6Hm + mfBTxtd2Rlnjs7dpDuYS3BEnX0UEA4z + dYF74C8R6NqX9n39hJFPcP5duUXdvJP8DA459z35re8VftF6gmomPwxpdv9kjbHm3oLNL77QRtH4n8K2vCH7SOlzyxR + KdCe0YEZuLRvMQH12nkfgTU8uKSu0n5HPDN6anqrnaeBPg9bWq2N74luFuJYY122ifcQhi2Gf8Aj5PsPwr2B1SKFijKuwZBA6YritG + J3w / 1e1Wa28V6agIzsmlEbD6hsGuG + Mfxv8AD + i6NcWHhjUYdT1SZCiPAweOHP8AEWHHHp / SuBUa9WouZMjEY2NSLblc + bfiYtgPHWvW9jtW1h1C5W Hb0CB2wB + QrmrVyJEAO35uTio3d3dpHYsznLMeppAxC4HHOc19CtDwG7l0vFvJZt5zwAOtWFQyKGfj0Qf1rMjcIcqOfU1ILhh1dj9OKu5DRbntvl5ApmmxiPUoHdtqLKpY + gzzURvGIxjj60sd0M8jFIVmfdGg30FvpEc0UivEsAZHU5BG3II9q8haVI2d3bMjOWYFskZzjGKyfgp4ye88Mah4WnuAt1FbsbF25yp4K9RnaTnHpn0rRGl6qvH2iwb / ALd3X + T1zYmMp2SNMPJU73MW8EUkrGT58tyS2eO1NsbOIyB44yrjkbeCfr2rTm8Oag2T51mpP91G / qTSRaNrVu5aN7KUE5 + YsuP0NS4S5bJHurMKHLYctzexfuDI4TG04Y5Oe1RyTCIucdAoC + pJp8ljruSxgscnpiduv / fFQyabq5IZ7S3yDkkXB6 / 98 + 1YqlPqhRxlDe57jEcD7wFXI3G3O8VlxfdqUE7TzXiM60i5d6hZ2NnLeXl0kMES7ndjgCvnP4wa / f8Aj29WytZpYdNgcm3gUcu399x3Pt2H456n41Tzf2rY2 / nSeSYyxj3HbnPXHTNYXhZE2O + xd2cZxzXu4LDwhDn3bPCxmJlOTj0R4jq + l3mmX7WdzGfMHTbyD9KntNGnlUF1ZSe1egfGBVUWMiqFfzSNwGD0rJ0Il4fnJb6816EI3OHmdjEHhaVkDfaVX2K5pY / CzgkvchgPRcV04 + 8B2zT8Da1a + zRHOzlLnTIoIXEzqqDqSKwbpIY2AikZ / XcuMV3d0AdpIBNcx4gVfNLbRuwOcc1nJWLizIjjL5wDx6DNTC3T + KXB / vKRVvRe9akgG0cDvUpDb1MQWcbAbZUb6NSmxI9av3EcflqfLXOPSktOCQKdhXZBpVzd6RqUGoWbkSwOGX0PsfY9K + jvDmsQ6xpEGoW / 3JkztPVT3H4Gvn + RVx90flXpPwYZv7Kv03Has4IGeBlamSsDPRXmyQAnSlWQ / wB3FQ p941MOlSA / cG6jI96bNsIHAXA7d6cAM9BVS9JATBx8w6VQj //ž

mmm = application / octet-stream 5283字节写

但我没有收到任何这些日志声明:

if (error)
    console.log('got error = ' + JSON.stringify(error) + '\n');

if (blobResult)
    console.log('blobResult = ' + JSON.stringify(blobResult) + '\n');

if (response)
    console.log('response = ' + JSON.stringify(response) + '\n');

所以我假设它挂在某处或者我没有正确构建我的代码。谁能看到我做错了什么?

干杯 罗布

我的消息来源:

http://social.msdn.microsoft.com/Forums/en-US/wavirtualmachinesforlinux/thread/47bfe142-c459-4815-b09e-bd0a07ca18d5

Node.js base64 encode a downloaded image for use in data URI

2 个答案:

答案 0 :(得分:0)

这是我的简化版。由于魔法需要对整个文件进行操作,因此使用流式博客API毫无意义,而是为文本api编写。 body将是图像的缓冲区,我怀疑azure会对它进行编码感到满意,如果确实需要它,请调用toString('encoding')。

var azure = require('azure')
    , uuid = require('node-uuid')
    , request = require('request')
    , mmm = require('mmmagic')
    , Magic = mmm.Magic
    , stream = require('stream')
    , bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);

function createVideoThumbnail(video, callback){
  var sURL = video.Thumbnail;
  request(sURL, {encoding:null}, function (err, res, body) {
    // encoding:null makes request return a buffer, which is ideal to run magic.detect on
    magic.detect(body, function (err, res) {
      console.log(res);
      var container = config.imageContainer;
      var blob = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
      var text = body; //might need to be converted into a string, I don't have azure setup to test
      var options = {
        contentType: res,
        contentTypeHeader: res
      };
      bs.createBlockBlobFromText(container, blob, text, options, function(error, blobResult, response) {
        if (error)
          console.log('got error =', error);  
          // if you give console.log multiple arguments, it will format each of them, 
          // no need to manipulate objects into strings manually

        if (blobResult)
          console.log('blobResult =', blobResult);

        if (response)
          console.log('response =', response);

        // now store in Azure blob storage
        callback();
      });
    });
  });
}

编辑:临时文件版本

var azure = require('azure')
    , uuid = require('node-uuid')
    , request = require('request')
    , mmm = require('mmmagic')
    , Magic = mmm.Magic
    , fs = require('fs')
    , bs = azure.createBlobService(config.storageAccount, config.storageAccessKey, config.blobHost);

function createVideoThumbnail(video, callback){
  var sURL = video.Thumbnail;
  var name = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
  var ws = fs.createWriteStream('./tmp/' + name);
  request(sURL, {encoding:null})
    .pipe(ws).on('close', function () {
    console.log('downloaded');
    magic.detectFile('./tmp/' + name, function (err, res) {
      var container = config.imageContainer;
      var blob = uuid().replace(/-/gi, "").toLowerCase() + '.jpg';
      var options = {
        contentType: res,
        contentTypeHeader: res
      };
      bs.createBlockBlobFromFile(container, name, './tmp/' + name, function (err) {
        callback();
      });
    });
  });
}

答案 1 :(得分:0)

感谢msdn论坛上的Valery Jacobs能够得出答案。使用stream,request和util对象是一个很好的干净可靠的解决方案。

:)

http://social.msdn.microsoft.com/Forums/en-US/windowsazurepurchasing/thread/25c7705a-4ea0-4d9c-af09-cb48a031d06c