How to convert Uint8ClampedArray to node-like Buffer; - javascript

I am working on a node module that uses xmlrpc to post images to wordpress. The
postIMGRPC method accepts the raw image data and submits it via the wp.uploadFile uri. I have successfully tested the method in node using an image file:
var imgData;
fs.readFile("anyImage.jpg", function(e,d){ imgData = d } );
wp.postIMGRPC("anyImage.jpg", imgData, 1)
.then(function(r){console.log(r)})
Now, I would like to be able to grab the imgData of a canvas in client-side javascript, and submit it in the same fashion via my node.js module:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("myImg");
ctx.drawImage(img,0,0);
var imgData = ctx.getImageData(0,0,250,300);
var data = imgData.data;
However, when I attempt to pass data (type Uint8ClampedArray) to my node module, the file uploaded is a blank image. I have tried:
wp.postIMGRPC("anyImage.jpg", imgDataFromJS, 1)
.then(function(r){console.log(r)})
as well as
buf = new Buffer(imgDataFromJS)
wp.postIMGRPC("anyImage.jpg", buf, 1)
.then(function(r){console.log(r)})
How do I convert the Uint8ClampedArray from imgData to a Buffer that is similar to the one returned by fs.readFile()?

Use Buffer.from, as in:
...
var imgData = ctx.getImageData(0,0,250,300);
var data = imgData.data;
var buf = Buffer.from(data);

Related

Store image content not image path in mongodb

I have seen many questions and solutions for this now. I am new to Mongo DB and MEAN stack development. I want to know whether there is anyway to store image content itself rather than path of the image file in Mongo DB. All the solutions suggests to store image as buffer and then use it back in the source by converting buffer to base64. I did it but the resulting output get resolves to path to the image file rather than the image content. I am looking to save image itself in DB.
// saving image
var pic = {name : "profilePicture.png",
img : "images/default-profile-pic.png",
contentType : "image/png"
};
//schema
profilePic:{ name: String, img: Buffer, contentType: String }
//retrieving back
var base64 = "";
var bytes = new Uint8Array( profilePic.img.data );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
base64 += String.fromCharCode( bytes[ i ] );
}
var proPic = "data:image/png;base64," + base64;
console.log(proPic);
//console output
data:image/png;base64,images/default-profile-pic.png
The output for proPic resolves to "data:image/png;base64,images/default-profile-pic.png"
few links that I referred before posting this
How to do Base64 encoding in node.js?
How to convert image into base64 string using javascript
The problem is simply, that you don't read and encode the picture. Instead you use the path as a string.
Serverside using Node
If you want to perform it on the serverside with an image on the filesystem you can use something along following:
var fs = require('fs');
// read and convert the file
var bitmap = fs.readFileSync("images/default-profile-pic.png");
var encImage = new Buffer(bitmap).toString('base64');
// saving image
var pic = {name : "profilePicture.png",
img : encImage,
contentType : "image/png"
};
....
Clientside
Again we need to load the image and encode it as base64. There is an answer about doing this on the client here.
using the first approach the result would be something like following:
function toDataUrl(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
toDataUrl("images/default-profile-pic.png", function(encImage){
// saving image
var pic = {name : "profilePicture.png",
img : encImage,
contentType : "image/png"
};
//Proceed in the callback or use a method to pull out the data
....
});
Below two links saved my time. If we use "ng-file-upload" our life becomes easy from there.
https://github.com/danialfarid/ng-file-upload#install
https://github.com/danialfarid/ng-file-upload
Below is what worked for me
//my html code
<div>
<button type="file" ngf-select="onFileSelect($file)" ng-model="file" name="file" ngf-pattern="'image/*'"
ngf-accept="'image/*'" ngf-max-size="15MB" class="btn btn-danger">
Edit Profile Picture</button>
</div>
//my js function
function onFileSelect(file){
//var image = document.getElementById('uploadPic').files;
image = file;
if (image.type !== 'image/png' && image.type !== 'image/jpeg') {
alert('Only PNG and JPEG are accepted.');
return;
}
$scope.uploadInProgress = true;
$scope.uploadProgress = 0;
var reader = new window.FileReader();
reader.readAsDataURL(image);
reader.onloadend = function() {
base64data = reader.result;
$scope.profile.profilePic = base64data;
ProfileService.updateProfile($scope.profile).then(function(response){
$rootScope.profile = response;
$scope.profilePicture = $rootScope.profile.profilePic;
});
}
}
// when reading from the server just put the profile.profilePic value to src
src="data:image/png;base64,{base64 string}"
// profile schema
var ProfileSchema = new mongoose.Schema({
userid:String,
//profilePic:{ name: String, img: Buffer, contentType: String },
profilePic:String
}
I wouldn't say this is the best solution but a good place to start.Also this limits you from uploading file size more than 16 MB in which case you can use"GridFs" in the above implementation initially the file is converted to "blob" and then I am converting it to "base64" format and adding that to my profile's string variable.
Hope this helps someone in saving their time.

Cropit upload canvas image to NodeJS

I am trying to upload a cropped image with the Cropit jQuery plugin which uses the canvas in the front end. Basically trying to recreate process described here:
How to crop and upload photo using cropit jquery plugin with php
My Node.js effort:
var img = //DATA RECEIVED FROM THE POST REQUEST
var decoded = decodeURIComponent(require('url').parse(img, true).path.replace(/\++/g, ' '))
var exp = decoded.replace('data:image/jpeg;base64','').split(',');
var base64 = exp.shift();
var data = base64url.decode(base64);
fs.writeFile('./public/woooo.jpg', data,function(err,done){
if (err){
console.log(err)
}
})
The result is an image file which cannot be opened. Why? What am I doing wrong? Anyone else has managed this?
Found it:
var decoded = decodeURIComponent(require('url').parse(img, true).path.replace(/\++/g, ' '))//base64url.decode(img);
var exp = decoded.split(',');
var base64 = exp.shift();
var data = base64url.decode(base64);
var data_c = data.replace('data:image/jpeg;base64,','')
var buffer = new Buffer(data_c, 'base64');
fs.writeFileSync('./public/woo.jpg', buffer);

Load file into IMAGE object using Phantom.js

I'm trying to load image and put its data into HTML Image element but without success.
var fs = require("fs");
var content = fs.read('logo.png');
After reading content of the file I have to convert it somehow to Image or just print it to canvas. I was trying to conver binary data to Base64 Data URL with the code I've found on Stack.
function base64encode(binary) {
return btoa(unescape(encodeURIComponent(binary)));
}
var base64Data = 'data:image/png;base64,' +base64encode(content);
console.log(base64Data);
Returned Base64 is not valid Data URL. I was trying few more approaches but without success. Do you know the best (shortest) way to achieve that?
This is a rather ridiculous workaround, but it works. Keep in mind that PhantomJS' (1.x ?) canvas is a bit broken. So the canvas.toDataURL function returns largely inflated encodings. The smallest that I found was ironically image/bmp.
function decodeImage(imagePath, type, callback) {
var page = require('webpage').create();
var htmlFile = imagePath+"_temp.html";
fs.write(htmlFile, '<html><body><img src="'+imagePath+'"></body></html>');
var possibleCallback = type;
type = callback ? type : "image/bmp";
callback = callback || possibleCallback;
page.open(htmlFile, function(){
page.evaluate(function(imagePath, type){
var img = document.querySelector("img");
// the following is copied from http://stackoverflow.com/a/934925
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
// Copy the image contents to the canvas
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Get the data-URL formatted image
// Firefox supports PNG and JPEG. You could check img.src to
// guess the original format, but be aware the using "image/jpg"
// will re-encode the image.
window.dataURL = canvas.toDataURL(type);
}, imagePath, type);
fs.remove(htmlFile);
var dataUrl = page.evaluate(function(){
return window.dataURL;
});
page.close();
callback(dataUrl, type);
});
}
You can call it like this:
decodeImage('logo.png', 'image/png', function(imgB64Data, type){
//console.log(imgB64Data);
console.log(imgB64Data.length);
phantom.exit();
});
or this
decodeImage('logo.png', function(imgB64Data, type){
//console.log(imgB64Data);
console.log(imgB64Data.length);
phantom.exit();
});
I tried several things. I couldn't figure out the encoding of the file as returned by fs.read. I also tried to dynamically load the file into the about:blank DOM through file://-URLs, but that didn't work. I therefore opted to write a local html file to the disk and open it immediately.

Save captured png as arraybuffer

I'm trying to save an image to dropbox, and having trouble getting the convertion correct. I have an img (captured using this sample) and I want to store it to dropbox that accepts an ArrayBuffer (sample here)
This is the code I found that should to the two conversions, first to a base64, then into a ArrayBuffer
function getBase64Image(img) {
// Create an empty canvas element
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
// Copy the image contents to the canvas
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
// Get the data-URL formatted image
// Firefox supports PNG and JPEG. You could check img.src to
// guess the original format, but be aware the using "image/jpg"
// will re-encode the image.
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
function base64ToArrayBuffer(string_base64) {
var binary_string = window.atob(string_base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
var ascii = binary_string.charCodeAt(i);
bytes[i] = ascii;
}
return bytes.buffer;
}
Saving is started like this
var img = $('#show-picture')[0];
var data = base64ToArrayBuffer( getBase64Image(img));
dropbox.client.writeFile(moment().format('YYYYMMDD-HH-mm-ss')+'.png', data, function (error, stat) {
if (error) {
return dropbax.handleError(error);
}
// The image has been succesfully written.
});
Problem is that I get a corrupted file saved, and is a bit confused on what's wrong.
*EDIT *
Here's the link to the original file
https://www.dropbox.com/s/ekyhvu2t6d8ldh3/original.PNG and here to the corrupted. https://www.dropbox.com/s/f0oevj1z33brpur/20131219-22-23-14.png
I'm using this version of the dropbox.js: //cdnjs.cloudflare.com/ajax/libs/dropbox.js/0.10.2/dropbox.min.js
As you can see the corrupted is slighty bigger 23,3KB vs 32,6 KB
Thanks for any help
Larsi
Moving my comment to an answer, since it seems that this works in the latest Datastore JS SDK but perhaps not in dropbox.js 0.10.2.
What browser and what version of the Dropbox library? And what's wrong with the image that's saved? (I assume by "corrupted" you mean that it won't open in whatever tool you're using... any more hints? Is the file size reasonable?) I just did a very similar test (toDataURL, atob, and Uint8Array) with Chrome on OS X and dropbox.com/static/api/dropbox-datastores-1.0-latest.js, and it seems to work.

Base64 png to Canvas

I'm struggeling with drawing a image on a Canvas.
What I have done so far is that I have inserted imagedata from a Canvas into a database.
The problem is that when I try to create an image of the data and draw it back on the Canvas later it does not draw the same, only some pixels may be drawen while the rest is just blank like nothing should be drawen there.
I'm getting the image data like this:
var CanvasData = document.getElementById('canvas');
CanvasData = CanvasData.toDataURL("image/png");
And drawing the image back on the Canvas like this (the data is stored in a database):
var result = xmlhttp.responseText;
var CanvasDraw = document.getElementById('canvas');
var ctxChange = CanvasDraw.getContext('2d');
imagedata = new Image();
imagedata.src = result;
imagedata.onload = function(){
ctxChange.drawImage(imagedata, 0, 0);
}
Here's a link to pastebin for an example of imagedata: http://pastebin.com/XGmV49k9
Result is the data that is returned from a AJAX call and is the same as what is stored in the database.
Thanks for any help.
Seems that error in this line:
imagedata.src = result;
Should be:
imagedata.src = CanvasData;

Categories

Resources