0

I'm trying to PUT svg, a string and a png together to a Django REST api from a pure javascript client.

I'm currently stuck with error 400 "Upload a valid image. The file you uploaded was either not an image or a corrupted image." response from the backend.

The png is created with the Pablo-svg-library, which converts the svg to png (With "toImage()").

The file itself doesn't appear to be corrupt, it can be loaded with python pillow (Which is also used by Django's ImageField).

var file = new Blob([svgData], { type: 'text/xml'});
var img = Pablo(document.getElementById('stage')).toImage('png', appendImgToFormAndSend);

function appendImgToFormAndSend() {
    var picture = new Blob([img[0].src], { type: 'image/png'});

    var xhr = new XMLHttpRequest();
    xhr.open("PUT", "http://myapi.local/upload_all_the_data");

    var formData = new FormData();
    formData.append('picture', picture, 'picture1.png')
    formData.append('rawdata', file, 'rawdata');
    formData.append('url', location.href);

    xhr.send(formData)
};

xhr.onload = function() {
                console.log("ANSWER");
                console.log(this.responseText);
                var data = JSON.parse(this.responseText);
                console.log(data)
            }

Have I got a conceptual misunderstanding here?

Uploading the identical file through Django's admin template works fine (Although the raw-data of the png in the request looks quite different), so I assume the error-response above is misleading and the issue is with the request/encoding/filetype.

The payload from the js-code above looks like this:

-----------------------------1331527982888194116440756954

Content-Disposition: form-data; name="picture"; filename="picture1.png"

Content-Type: image/png



data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAYAA [snip]
-----------------------------1331527982888194116440756954

Content-Disposition: form-data; name="rawdata"; filename="rawdata"

Content-Type: text/xml



<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 400">
<text x="193.17" y="104.88" font-size="30px" style="stroke: black; fill: rgb(111, 126, 14);">Hello World</text>
<rect x="128.24" y="135.89" width="89.22" height="14.74" style="stroke: black; fill: rgb(69, 214, 137);"></rect>
<circle cx="287.04" cy="166.81" r="44.18" style="stroke: black; fill: rgb(39, 203, 202);"></circle>
<circle cx="69.34" cy="41.28" r="56.59" style="stroke: black; fill: rgb(140, 165, 11);"></circle>
<text x="480.22" y="21.02" font-size="30px" style="stroke: black; fill: rgb(127, 87, 191);">Hello World</text>
</svg>

-----------------------------1331527982888194116440756954

Content-Disposition: form-data; name="url"



http://myurl:8080/svg_editor/index.html?pk=5978bc3a-a275-4114-94a5-f90063ba3641

-----------------------------1331527982888194116440756954--

The request's payload from Django's admin template in contrast is encoded.

Christian Benke
  • 517
  • 7
  • 26
  • have you tried this? https://stackoverflow.com/questions/7606614/django-imagefield-upload-a-valid-image-the-file-you-uploaded-was-either-not-an – Anatsu Jun 18 '19 at 14:24
  • @Anatsu Yes, thank you. Uploading the same png through the django admin template works fine. I therefore assume it's connected to how I build the request. – Christian Benke Jun 18 '19 at 14:31

1 Answers1

1

The png I tried to PUT is represented in a data uri scheme. The way I created the Blob above is not correct. The raw data of the png first needs to be extracted from the data uri and only then can it be inserted in a Blob, together with the mimedata.

How this conversion is done properly has already been answered here: https://stackoverflow.com/a/5100158/570722

(I'm not including the given code-example here as it might change in the future and this highly-upvoted answer is more likely to be updated).

I also stated above that the png was correctly loaded with Pillow - however the png I tested was retrieved through the output of the developer-console. There the data uri was converted to an actual image by the browser - in conclusion I never tested the "image"-data that was uploaded to the backend (Which still was a data uri), but instead I tested an already decoded png.

Christian Benke
  • 517
  • 7
  • 26