问题
The simple problem
I have a thumbnail from the Google Drive API and I need to save a copy because it has a validity expiration.
Context
I am building a backend for admins to add content to the website and I use Google Drive as resource management tool. I am running it on Meteor, so it's Nodejs on server-side.
Attempts
Use the well-known canvas method to retrieve the data url
getImageDataURL = function (URL, cb) { var img = document.createElement("img"); var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); img.setAttribute('crossorigin','anonymous'); img.onload = function () { canvas.width = this.width; canvas.height = this.height; ctx.drawImage(img, 0, 0); cb && cb(canvas.toDataURL("image/jpg")); }; img.src = URL; };
But it fails because of CORS restrictions (the thumbnail comes from Google domain).
"Okay, so since it'll be stored on the server, I might as well do the job directly there."
Well, it was okay to get the image content, but by some unknowns dark curses I didn't managed to convert the content into the right base64 format. The resulting string is almost similar to the expected output but with around 10% of mismatching characters... I tried a HUGE amount of functions to do the base64 conversion but I can't get it right. I ended up with this simple code witch I think is right, there is definitively something I'm missing with the content encoding... (This is meteor code, using collection-hooks package)Medias.before.insert(function (userId, doc) { var res = HTTP.get(doc.thumb); doc.thumb = "data:"+res.headers["content-type"]+";base64,"+new Buffer(res.content, 'ascii').toString('base64'); });
I tried with and without the Buffer wrapper and with all possible Buffer encoding params, 'ascii' is what produces the right output compared to other legacy conversion functions, like this one : http://hellerim.net/base64_src.php.
"Proxy the god damn image then!"
Yep, tried, got issues with html headers... (http-methods package)HTTP.methods({ '/getImage/:url': function(){ var req = HTTP.get(this.params.url); this.addHeader('access-control-allow-origin', '*'); this.addHeader('content-disposition', req.headers['content-disposition']); this.addHeader('content-type', req.headers['content-type']); //this.addHeader('content-length', req.headers['content-length']); return req.content; } });
If I don't set the 'content-type' I get the data, as text of course. Otherwise I get nothing.
"Right, this is because 'content-length' is missing!"
... If I add it, my server crashes with the lovely errorCan't render headers after they are sent to the client
. Once again I stopped here because I'm not a meteor expert and I have no idea of what's going on under the table. There must be some headers added automatically and I must be messing with some process by arbitrarily defining the content-length or I don't know, hell!"Wow, dude, you like it hard! Why don't you just store them as files?"
First, I'd prefer storing it into the DB because is much more simple to manage and I believe using dataURL is best for quick thumbnails display. Secondly because accessing meteor public folder is prohibited, so I'd have to manually store files to somewhere else on the server, witch is ugly and then provide an access point to allow their retrieval, what a mess. In addition I tried mongodb's gridfs file storage. Couldn't get it to work, the meteor wrapper (CollectionFS package) is too buggy and it's a lot of infrastructure for simply storing thumbnails.
So, if anyone has an idea related to the 3 first points, I buy him a beer right away! I've been stuck on this for more than a week now, I'm out of ammo!
Thanks =)
来源:https://stackoverflow.com/questions/24905173/generate-data-url-from-image