How to use Paste.js to capture an image pasted into a text area

This post is part of a series. This list contains all of the posts:

How to use Paste.js to capture an image pasted into a text area

For this blog, I wanted to be able to copy and paste an image from my clipboard into the textarea, capture the image, save it on my server and convert it to a markdown url pointing to the link. I struggled for a long time trying to implement this in javascript before giving up and searching for a library. Within 5 minutes I had a proof of concept with Paste.js, and with 15 minutes the feature was fully implemented.

I raised a pull request on cdnjs requesting that they host paste.js, and they did so in three days.

<script src="https://cdnjs.cloudflare.com/ajax/libs/paste.js/0.0.21/paste.min.js></script>
<script>

 // Get paste.js to watch our text area
 $('#post-content').pastableTextarea();

 $('#post-content').on('pastImage', function(ev, data) {
  // paste.js detected an image being pasted
  // dataURL is the base64/png of the pasted image
  console.log("dataURL: " + data.dataURL);

  // Prompt user for a file name to save the image as
  var file_name = prompt("Enter a file name", ".jpg");

  // Send image and filename to server
  ajax_data_url(data.dataURL, file_name);

 }).on('pasteImageError', function(ev, data) {
  // I suppose this is for incompatible browsers
  console.log("error: " + data.message);

 }).on('pasteText', function(ev, data) {
  // paste.js detected text being pasted and will
  // automatically insert into the text area for us
  console.log("text: " + data.text);

 });
</script>

<body>
    <textarea id="post-content"></textarea>
</body>

The data.dataURL will look something like this:

matthew_moisen_paste_js_data_url.jpg

The ajax to send that back to the server to be saved looks like:

<script>
 ajax_data_url = function(data_url, file_name) {
  var csrf = "{{ csrf_token() }}";

  var payload = {
    "data_url": data_url, 
    "file_name": file_name,
    "csrf": csrf
  };

  $ajax({
    url: "/api/image-upload',
    data: JSON.stringify(payload),
    contentType: 'application/json',
    dataType: 'json',
    success: function(data) {
      var post_content = $('#post-content').val() + data['md'];
      $('#post-content').val(post_content);
    },
    error: function(jqXHR, textStatus, errorThrown) {
      var responseJSON = jqXHR.responseJSON;
      console.log("error saving image: " + responseJSON);
    },

  });
 }
</script>

In the backend, I want Python and Flask to convert the base64/png to jpg, save it on the server, and return a markdown link to the front end.

PIL is a cool library that can convert from png to jpg. I couldn't install it via pip install PIL without receiving the error "Could not find a version that satisfies the requirement PIL". Instead I had to use the following"

pip install pillow

Here is the backend logic in Flask:

from PIL import Image
import io
import base64

@app.route('/api/image-upload/')
def image_upload():
    data = request.json['data']
    file_name = data['file_name']
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_name)

    if os.path.isfile(file_path):
        return jsonify({"error": "Not a unique filename"}), 400

    // remove the prefix to the base64 image 
    img = data.split('data:image/png;base64,')[1]

    // Convert base64 to jpeg bytes
    image = Image.open(io.BytesIO(base64.b64decode(img)))

    // Save file in jpeg
    image.save(file_path, 'JPEG')

    // Convert file path to markdown and return to front end
    markdown = '![{}](/static/image/{file_name}) \n'.format(
        file_name=file_name
    )

    return jsonify({"md": markdown}), 200

This post is part of a series. This list contains all of the posts:


Comments

Add Comment

Name

Email

Comment

Are you human? * ten = 40