0
votes

I have the following Ajax upload (Base64 canvas data from cropper.js), so the Ajax upload is not from a form.

    $('.gogo').on('touchstart mousedown', function(e){
    e.preventDefault();
    e.stopPropagation();
    var img = new Array();
    img[0] = fetchCrop1();
    img[1] = fetchCrop2();      
    $.ajax({
        cache: false,
        type : 'POST',
        url  : 'http://localhost:3001/img', 
        data: { img : img },
        contentType: false,
        processData: false,
        success : function(data) {
            console.log('AJAX: '+data);
        }
    });
});

and the Multer script from examples that I have seen

var storage =   multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, '/img');
},
  filename: function (req, file, callback) {
    callback(null, file.fieldname + '-' + Date.now());
  }
});

app.post('/img',function(req,res){
  var upload = multer({ storage : storage }).array('img',2);
  upload(req,res,function(err) {
    console.log(req.body);
    console.log(req.files);
    if(err) {
        return res.end("Error uploading file.");
    }
    res.end("File is uploaded");
  });
});

I have read numerous post with little luck as I keep getting req.body and req.files as {} and undefined.

I have tried different contentType, and single uploads but clearly I am missing something, or JQuery Ajax doesn't work with Multer multiple files?

I am relatively new to Node (LAMP man) and do find the JavaScript syntax a little alien.

I just want to upload two Base64 images to the server /img folder.

The Base64 is working fine from cropper.js I believe, code below for that function

function fetchCrop1(){
/* Note that images greater than 1000px are rejected by the server */
    var $image = $('#image');
    result = $image.cropper("getCroppedCanvas", "{ "width": 1000, 
    "height": 700 }", '');
    $(document).find('#dataImg').val(result.toDataURL('image/jpeg'));
    $('#dataImg').attr('value');
    $('#download').attr('href', result.toDataURL('image/jpeg'));    
    return $('#dataImg').attr('value');     
}    
1
multer processes multipart/form-data which you are not sending and also don't need to send. I'd suggest just using application/x-www-form-urlencoded instead.Musa
Thank you, just what I did in the end. I did try the solutions with formData and appending the two blobs but could not get them to work that way either.Ozbodd

1 Answers

0
votes

I chose not to use Multer and instead I am using the body-parser and sending the string to convert on the server side

app.post('/crop',function(req,res){
 var ts = null;
for(i=1;i<3;i++){
 if(i == 1){
 var x = req.body.img1;
 console.log(parseInt((x).replace(/=/g,"").length * 0.75));
 }else{
 var x = req.body.img2;  
 console.log(parseInt((x).replace(/=/g,"").length * 0.75));
 }
 var decodedImg = decodeBase64Image(x);
 var imageBuffer = decodedImg.data;
 var type = decodedImg.type;
 var extension = mime.extension(type);
 if(i == 1){
    var ts = Date.now();
    var fileName =  "image"+ts+"." + extension;
 }else{
    var fileName =  "image"+ts+"-th." + extension;
 }
 try{
    console.log(fileName,extension,type);
       fs.writeFileSync("img/" + fileName, imageBuffer, 'utf8');
    }
 catch(err){
    console.log(err)
 }
}
}); 

function decodeBase64Image(dataString) {
 var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/),
 response = {};

 if (matches.length !== 3) {
  return new Error('Invalid input string');
 }

 response.type = matches[1];
 response.data = new Buffer(matches[2], 'base64');

 return response;
}

and clients-side

 $('.gogo').on('touchstart mousedown', function(e){
    e.preventDefault();
    e.stopPropagation();
    //var img = new Array();
    img1 = fetchCrop1();
    img2 = fetchCrop2();        
    $.ajax({
        cache: false,
        type : 'POST',
        url  : 'http://localhost:3001/crop', 
        data: { img1 : img1, img2 : img2 },
        contentType: "application/x-www-form-urlencoded",
        success : function(data) {
            console.log('AJAX: '+data);
        }
    });
});

function fetchCrop1(){
/* Note that images greater than 1000px are rejected by the server */
    var $image = $('#image');
    result = $image.cropper("getCroppedCanvas", {width: 1000, height: 800});
    $(document).find('#dataImg1').val(result.toDataURL('image/jpeg'));
    return $('#dataImg1').attr('value');        
}    
function fetchCrop2(){
/* Note that images greater than 1000px are rejected by the server */
    var $image = $('#image');
    result = $image.cropper("getCroppedCanvas", {width: 300, height: 250});
    $(document).find('#dataImg2').val(result.toDataURL('image/jpeg'));
    return $('#dataImg2').attr('value');        
}

I am sure there are more graceful ways but it works (and is still WIP) (Using the cropper.js plugin).