0

I generate some images on frontend and I want to send them directly to backend for further processing. How can I do that without using a form data? Are there any options?

Image is generated from canvas (print screen actually) and should be posted to server as it is generated.

I use Node js for backend (Express server) and Angular for frontend.

Any help or insights are welcome!

Thanks in advance.

1 Answer 1

1

So you need to:

  1. draw on the canvas

    var canvas = document.createElement('canvas');
    canvas.width = 600;
    canvas.height = 600;
    var context = canvas.getContext('2d');
    
    context.beginPath();
    context.moveTo(100, 150);
    context.lineTo(450, 50);
    context.lineWidth = 10;
    
    // set line color
    context.strokeStyle = '#ff0000';
    context.stroke();
    
  2. encode the canvas data to a format of your choice (say jpg)

    function dataURItoBlob(dataURI) {
      var binary = atob(dataURI.split(',')[1]);
      var array = [];
      for (var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
      }
      return new Blob([new Uint8Array(array)], {
        type: 'image/jpeg'
      });
    }
    
    function canvasToJPG(cvs, done) {
      var quality = 90; // jpeg quality
    
      if (cvs.toBlob) // some browsers has support for toBlob
        cvs.toBlob(done, 'image/jpeg', quality / 100);
      else
        done(dataURItoBlob(cvs.toDataURL('image/jpeg', quality / 100)));
    }
    
  3. send it on the wire using AngularJS $http

    $http
    ({
        method: 'POST',
        url: '/upload',
        headers: {'Content-Type': 'image/jpeg'},
        data: data,
        transformRequest: []
    })
    .success(function ()
    {
        alert('image uploaded :)');
    })
    .error(function (err)
    {
        console.log('upload error',err);
        alert('something went wrong :( ');
    });
    

4a. get it from your ExpressJS route on node (say streaming it on the fs)

    app.post('/upload', function(req, res, next) {
      var wstream= fs.createWriteStream('uploaded.jpg'); // say you want to write the file to disk

      req.pipe(wstream) // pipe the http request body to the file stream
         .on('error',next) // something went wrong with the fs, return 500
         .on('finish',function () {
             res.status(204).send(); // success!
         });
    });

4b. get it from your ExpressJS route on node (say you want the raw JPG buffer)

    app.post('/upload', function(req, res, next) {
      var buff= [];

      req.on('data',function (data)
         {
            buff.push(data);
         })
         .on('error',next) 
         .on('end',function () {
             fs.writeFile('uploaded.jpg',Buffer.concat(buff),function (err)
             {
                 if (err) return next(err); // something went wrong with the fs, return 500

                 res.status(204).send(); // success!
             });
         });
    });

The complete sample:

var myapp = angular.module('myapp', []);

myapp.controller('upload', function($scope, $http) {
  $scope.drawAndUpload = function() {
    var canvas = document.createElement('canvas');
    canvas.width = 600;
    canvas.height = 600;
    var context = canvas.getContext('2d');

    context.beginPath();
    context.moveTo(100, 150);
    context.lineTo(450, 50);
    context.lineWidth = 10;

    // set line color
    context.strokeStyle = '#ff0000';
    context.stroke();

    var upload = function(data) {
      $http
        ({
          method: 'POST',
          url: '/upload',
          headers: {
            'Content-Type': 'image/jpeg'
          },
          data: data,
          transformRequest: []
        })
        .success(function() {
          alert('image uploaded :)');
        })
        .error(function(err) {
          console.log('upload error', err);
          alert('something went wrong :( ');
        });
    };

    canvasToJPG(canvas, upload);
  };
});

function dataURItoBlob(dataURI) {
  var binary = atob(dataURI.split(',')[1]);
  var array = [];
  for (var i = 0; i < binary.length; i++) {
    array.push(binary.charCodeAt(i));
  }
  return new Blob([new Uint8Array(array)], {
    type: 'image/jpeg'
  });
}

function canvasToJPG(cvs, done) {
  var quality = 90; // jpeg quality

  if (cvs.toBlob) // some browsers has support for toBlob
    cvs.toBlob(done, 'image/jpeg', quality / 100);
  else
    done(dataURItoBlob(cvs.toDataURL('image/jpeg', quality / 100)));
}
<html>

<head>
  <title>My Angular App</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
  <script src="app.js"></script>
</head>

<body ng-app="myapp" ng-controller="upload">
  <button ng-click="drawAndUpload()">Draw & Upload</button>
</body>

</html>

var express = require('express'),
    fs = require('fs');
var app = express();

app.use(express.static('www'));

app.post('/upload', function(req, res, next) {
  var buff= [];

  req.on('data',function (data)
     {
        buff.push(data); 
     })
     .on('error',next) // something went wrong with the fs, return 500
     .on('end',function () {
         fs.writeFile('uploaded.jpg',Buffer.concat(buff),function (err)
         {
             if (err) return next(err);

             res.status(204).send(); // success!
         });
     });
});

app.listen(8080);

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your very detailed solution! I've managed to do kinda the same thing, I also use a library for generating image from my js animation and transforming it to canvas and than to png :) the only problem I seem to have is that I have to send an image like every second to server and node won't accept(?) anything except blob.
I'm not sure I got your problem here... You don't want to send a Blob?
No, I don't :) I want it to be jpg/png :)
Well in my example the Blob contains the JPG bytes.. Looks like your library is returning to you something else maybe?
I have a custom function for converting canvas to png - but then it's converted to blob to send to the server side.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.