Cropit upload canvas image to NodeJS - javascript

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);

Related

Sending image from server to client via base64 encoding

I'm facing an issues sending an Image (np.ndarray) over my python server to my javascript client.
Starting with the python server, I process the img like this:
1) Load img as np.ndarray
2) enc_img = base64.b64encode(img.copy(order='C'))
3) utf8_img = enc_img.decode("utf-8")
4) json = {
...
"img": utf8_img,
...
}
5) req_return = json.dumps(json, ensure_ascii=False)
// The fct below I found on SO ..
For the client (javascript) I do the following:
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode(parseInt(p1, 16))
}))
}
img_64 = b64EncodeUnicode(jsonRes.fs_dict.face)
var src = "data:image/jpg;base64,";
src += img_64;
var newImage = document.createElement('img');
newImage.src = src;
newImage.width = newImage.height = "100";
document.querySelector('#face_img').innerHTML = newImage.outerHTML;
To sum it up, I want to send an image over the API and convert it into a valid base64 format to display via html. After experimenting a little I sometimes got "no valid base64 format" but with the provided code I'm not getting any error. The image doesn't show up though.
It is important to not save the file in my scenario.
So I figured the problem. I had troubles encoding the image (nparray) to a proper base64 encoding.
pil_img = Image.fromarray(nparray_img)
buff = BytesIO()
pil_img.save(buff, format="JPEG")
enc_img = base64.b64encode(buff.getvalue()).decode("utf-8")
this resolved the encoding issues for me.
I then return a dictionary containing the img like so:
res = {
"img": enc_img
}
return res
After converting it to JSON via
json.dumps(res), I send it via the API to my JavaScript Client.
When receiving the JSON, I first parse it to access the dictionary again like so:
jsonRes = JSON.parse(xhr.responseText);
img = jsonRes.img;
and finally output it via HTML by using jQuery:
var source = "data:image/jpg;base64,";
source += img;
$(document).ready(function() {
$('#face_img').attr('src',source).height(100).width(100).show();
});
The
('#face_img')
is an ID of my HTML, looking like the following:
<img id="face_img" src="" alt="img_face" />
Hope this helps someone.

Convert base64 to png in meteor app

I have a meteor application and in this one I get a base64 image. I want to save the image on a Digital Ocean instance, so I would convert it in a png or an other image format and send it to the server to get an url of the image.
But I didn't find a meteor package that does this.
Do you know how I can do that ?
I was running into a similar issue.
run the following:
meteor npm install --save file-api
This will allow the following code on the server for example:
import FileAPI from 'file-api';
const { File } = FileAPI;
const getFile = function(name,image){
const i = image.indexOf('base64,');
const buffer = Buffer.from(image.slice(i + 7), 'base64');
const file = new File({buffer: buffer, name, type: 'image/jpeg'});
return file;
}
Simply call it with any name of file you prefer, and the base64 string as the image parameter.
I hope this helps. I have tested this and it works on the server. I have not tested it on the client but I don't see why it wouldn't work.
I solved my problem using fs.writeFile from File System.
This is my javascript code on client side, I got a base64 image (img) from a plugin and when I click on my save button, I do this :
$("#saveImage").click(function() {
var img = $image.cropper("getDataURL")
preview.setAttribute('src', img);
insertionImage(img);
});
var insertionImage = function(img){
//some things...
Meteor.call('saveTileImage', img);
//some things...
}
And on the server side, I have :
Meteor.methods({
saveTileImage: function(fileData) {
var fs = Npm.require('fs');
var path = process.env.PWD + '/var/uploads/';
base64Data = fileData.replace(/^data:image\/png;base64,/, "");
base64Data += base64Data.replace('+', ' ');
binaryData = new Buffer(base64Data, 'base64').toString('binary');
var imageName = "tileImg_" + currentTileId + ".png";
fs.writeFile(path + imageName, binaryData, "binary", Meteor.bindEnvironment(function (err) {
if (err) {
throw (new Meteor.Error(500, 'Failed to save file.', err));
} else {
insertionTileImage(imageName);
}
}));
}
});
var insertionTileImage = function(fileName){
tiles.update({_id: currentTileId},{$set:{image: "upload/" + fileName}});
}
So, the meteor methods saveTileImage transform the base64 image into a png file and insertionTileImage upload it to the server.
BlobUrl, would it be a better option for you?
Save the images to a server as you like in base64 or whatever, and then when you are viewing the image on a page, generate the blobUrl of it. The url being used only at that time, preventing others from using your url on various websites and not overloading your image server ...

Convert binary file to JavaScript string and then to Uint8Array

I'm trying to create a web application that can be used via a file:// URI. This means that I can't use AJAX to load binary files (without turning off security features in the browser, which I don't want to do as a matter of principle).
The application uses a SQLite database. I want to provide the database to a sql.js constructor, which requires it in Uint8Array format.
Since I can't use AJAX to load the database file, I could instead load it with <input type="file"> and FileReader.prototype.readAsArrayBuffer and convert the ArrayBuffer to a Uint8Array. And that's working with the following code:
input.addEventListener('change', function (changeEvent) {
var file = changeEvent.currentTarget.files[0];
var reader = new FileReader();
reader.addEventListener('load', function (loadEvent) {
var buffer = loadEvent.target.result;
var uint8Array = new Uint8Array(buffer);
var db = new sql.Database(uint8Array);
});
reader.readAsArrayBuffer(file);
});
However, <input type="file"> requires user interaction, which is tedious.
I thought I might be able to work around the no-AJAX limitation by using a build tool to convert my database file to a JavaScript object / string and generate a ".js" file providing the file contents, and then convert the file contents to a Uint8Array, somehow.
Psuedocode:
// In Node.js:
var fs = require('fs');
var sqliteDb = fs.readFileSync('path/to/sqlite.db');
var string = convertBufferToJsStringSomehow(sqliteDb);
fs.writeFileSync('build/db.js', 'var dbString = "' + string + '";');
// In the browser (assume "build/db.js" has been loaded via a <script> tag):
var uint8Array = convertStringToUint8ArraySomehow(dbString);
var db = new sql.Database(uint8Array);
In Node.js, I've tried the following:
var TextEncoder = require('text-encoding').TextEncoder;
var TextDecoder = require('text-encoding').TextEncoder;
var sql = require('sql.js');
var string = new TextDecoder('utf-8').decode(fs.readFileSync('path/to/sqlite.db'));
// At this point, I would write `string` to a ".js" file, but for
// the sake of determining if converting back to a Uint8Array
// would work, I'll continue in Node.js...
var uint8array = new TextEncoder().encode(string);
var db = new sql.Database(uint8array);
db.exec('SELECT * FROM tablename');
But when I do that, I get the error "Error: database disk image is malformed".
What am I doing wrong? Is this even possible? The database disk image isn't "malformed" when I load the same file via FileReader.
Using the following code, I was able to transfer the database file's contents to the browser:
// In Node.js:
var fs = require('fs');
var base64 = fs.readFileSync('path/to/sqlite.db', 'base64');
fs.writeFileSync('build/db.js', 'var dbString = "' + base64 + '";');
// In the browser (assume "build/db.js" has been loaded via a <script> tag):
function base64ToUint8Array (string) {
var raw = atob(string);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (var i = 0; i < rawLength; i += 1) {
array[i] = raw.charCodeAt(i);
}
return array;
}
var db = new sql.Database(base64ToUint8Array(dbString));
console.log(db.exec('SELECT * FROM tablename'));
And that's working with the following code:
input.addEventListener('change', function (changeEvent) {
var file = changeEvent.currentTarget.files[0];
var reader = new FileReader();
reader.addEventListener('load', function (loadEvent) {
var buffer = loadEvent.target.result;
var uint8Array = new Uint8Array(buffer);
var db = new sql.Database(uint8Array);
});
reader.readAsArrayBuffer(file);
});
However, <input type="file"> requires user interaction, which is
tedious.
Using current working approach would be less tedious than attempting to create workarounds. If user intends to use application, user can select file from their filesystem to run application.

Use image data from XMLHttpRequest responsetext to display image

I'm using JavaScript to get an image from the XMLHttpRequest response text and set the image src to it:
document.getElementById("img").src = "data:image/png;base64," + xhr.responseText;
From the nodejs script, the image is sent like:
var img = fs.readFileSync('image.png');
res.end(img, 'base64');
The response text doesn't come in base64 and has weird symbols:
�PNG���IHDR���������,���2PLTE
�������������������������#����Ai���
...
I found this question and tried to convert it to base 64:
for (var responseText = xhr.responseText, responseTextLen = responseText.length, bin = "", i = 0; i < responseTextLen; ++i) {
bin += String.fromCharCode(responseText.charCodeAt(i) & 255);
}
document.getElementById("img").src = "data:image/png;base64," + btoa(bin);
The result was:
img id="img"
src="data:image/png;base64,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">
The image still doesn't show. What am I doing wrong?
It sounds like you're looking for buf.toString([encoding][, start][, end]).
Consider the following code:
var fs = require('fs');
var base64_image = fs.readFileSync('image.png').toString('base64');
console.log(base64_image);
This will return image.png as a base64 encoded string in the console.
So you probably want to remove that for () loop and change:
var img = fs.readFileSync('image.png');
To this:
var img = fs.readFileSync('image.png').toString('base64');
I hope that helps!
As Dal suggested, I did the base64 encoding on the server side:
var img = fs.readFileSync('plot.png', 'base64');
res.end(img);
I added the 'base64' encoding option to the readFileSync() instead of the res.end() so img would get sent as a string instead of a buffer as described here.
On the client side, I used this:
document.getElementById("img").src = "data:image/png;base64," + xhr.responseText;

How to convert Uint8ClampedArray to node-like Buffer;

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);

Categories

Resources