I'm using code from this and that answer to send a base64 encoded image to a python FastAPI backend.
The client side looks like this:
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
function makeBlob(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], { type: contentType });
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
...
toDataURL(
images[0], // images is an array of paths to images
function(dataUrl) {
console.log('RESULT:', dataUrl);
$.ajax({
url: "http://0.0.0.0:8000/check/",
type: 'POST',
processData: false,
contentType: 'application/octet-stream',
data: makeBlob(dataUrl)
}).done(function(data) {console.log("success");}).fail(function() {console.log("error");});
}
);
And the server side is as follows:
#app.post("/check")
async def check(file: bytes = File(...)) -> Any:
// do something here
I'm only showing the signature of the endpoint because for now nothing much is happening in it anyway.
Here is the output of the backend when I call it as shown above:
172.17.0.1:36464 - "OPTIONS /check/ HTTP/1.1" 200
172.17.0.1:36464 - "POST /check/ HTTP/1.1" 307
172.17.0.1:36464 - "OPTIONS /check HTTP/1.1" 200
172.17.0.1:36464 - "POST /check HTTP/1.1" 422
So, in short, I keep getting 422 error codes, which means that there is a mismatch between what I send and what the endpoint expects, but even after some reading I'm still not clear on what exactly is the issue. Any help would be most welcome!
As described in this answer, uploaded files are sent as form data. As per FastAPI documentation:
Data from forms is normally encoded using the "media type"
application/x-www-form-urlencoded when it doesn't include files.
But when the form includes files, it is encoded as
multipart/form-data. If you use File, FastAPI will know it has to get
the files from the correct part of the body.
Regardless of what type you used, either bytes or UploadFile, since...
If you declare the type of your path operation function parameter as
bytes, FastAPI will read the file for you and you will receive the
contents as bytes.
Hence, the 422 Unprocessable entity error. In your example, you send binary data (using application/octet-stream for content-type), however, your API's endpoint expects form data (i.e., multipart/form-data).
Option 1
Instead of sending a base64 encoded image, upload the file as is, either using an HTML form, as shown here, or Javascript, as shown below. As others pointed out, it is imperative that you set the contentType option to false, when using JQuery. Using Fetch API, as shown below, it is best to leave it out as well, and force the browser to set it (along with the mandatory multipart boundary). For async read/write in the FastAPI backend, please have a look at this answer.
app.py:
import uvicorn
from fastapi import File, UploadFile, Request, FastAPI
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
#app.post("/upload")
def upload(file: UploadFile = File(...)):
try:
contents = file.file.read()
with open("uploaded_" + file.filename, "wb") as f:
f.write(contents)
except Exception:
return {"message": "There was an error uploading the file"}
finally:
file.file.close()
return {"message": f"Successfuly uploaded {file.filename}"}
#app.get("/")
def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
templates/index.html
<script>
function uploadFile(){
var file = document.getElementById('fileInput').files[0];
if(file){
var formData = new FormData();
formData.append('file', file);
fetch('/upload', {
method: 'POST',
body: formData,
})
.then(response => {
console.log(response);
})
.catch(error => {
console.error(error);
});
}
}
</script>
<input type="file" id="fileInput" name="file"><br>
<input type="button" value="Upload File" onclick="uploadFile()">
If you would like to use Axioslibrary for the upload, please have a look at this answer.
Option 2
If you still need to upload a base64 encoded image, you can send the data as form data, using application/x-www-form-urlencoded as the content-type; while in your API's endpoint, you can define a Form field to receive the data. Below is a complete working example, where a base64 encoded image is sent, received by the server, decoded and saved to the disk. For base64 encoding, the readAsDataURL method is used on client side. Please note, the file writing to the disk is done using synchronous writing. In scenarios where multiple (or large) files need to be saved, it would be best to use async writing, as described here.
app.py
from fastapi import Form, Request, FastAPI
from fastapi.templating import Jinja2Templates
import base64
app = FastAPI()
templates = Jinja2Templates(directory="templates")
#app.post("/upload")
def upload(filename: str = Form(...), filedata: str = Form(...)):
image_as_bytes = str.encode(filedata) # convert string to bytes
img_recovered = base64.b64decode(image_as_bytes) # decode base64string
with open("uploaded_" + filename, "wb") as f:
f.write(img_recovered)
return {"message": f"Successfuly uploaded {filename}"}
#app.get("/")
def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
templates/index.html
<script type="text/javascript">
function previewFile() {
const preview = document.querySelector('img');
const file = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
preview.src = reader.result; //show image in <img tag>
base64String = reader.result.replace("data:", "").replace(/^.+,/, "");
uploadFile(file.name, base64String)
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
function uploadFile(filename, filedata){
var formData = new FormData();
formData.append("filename", filename);
formData.append("filedata", filedata);
fetch('/upload', {
method: 'POST',
body: formData,
})
.then(response => {
console.log(response);
})
.catch(error => {
console.error(error);
});
}
</script>
<input type="file" onchange="previewFile()"><br>
<img src="" height="200" alt="Image preview...">
Related
I built a simple project using javascript and FastAPI. I would like to POST canvas image data in javascript to the server(FastAPI).
But, I get the 422 Unprocessable Entity error
# FastAPI
#app.post("/post")
async def upload_files(input_data: UploadFile = File(...)):
return JSONResponse(status_code = 200, content={'result' : 'success'})
// javascript
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
imageData = ctx.getImageData(0, 0, 112, 112);
fetch("http://{IP}/post", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
input_data: imageData,
}),
})
.then((response) => response.json())
here is my code. I am new one in javascript. so I don't know how can post data to server.
How can I do? Thanks in advance.
MatsLindh's way is correct but you can try upload image by formdata so you haven't convert to base64 then convert back to image
const dataURItoBlob = function(dataURI : string) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString : string;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
const url = canvas.toDataURL()
const file = dataURItoBlob(url)
//add file to formdata
const form = new FormData()
form.append('file', item.file)
//post this form in body
UploadFile expects a file being posted to the endpoint in the multipart/form-data format - i.e. as a regular POST with a bit of added metadata.
Since you're retrieving the image data and submitting it as JSON body, that won't match the expected format. You also want to use canvas.toDataURL() to convert the content to base64 before trying to submit it through your API to avoid any UTF-8 issues with JSON.
const pngData = canvas.toDataURL();
// then in your request:
body: JSON.stringify({
input_data: pngData,
}),
To handle this request change your view function signature to receive an input_data parameter (and use a better endpoint name than post):
#app.post("/images")
async def upload_files(input_data: str = Body(...)):
# check the expected format (content-type;<base64 content>)
# .. and decode it with base64.b64decode()
return {'content': input_data}
I am converting canvas to url and sending it to python via ajax POST request using Flask. I am getting the url all right, even printed it and both are same. But I don't get how to get the image back. I search internet, most answers say to use decode method but I get error that decode cannot work on 'str' object. I also tried using StringIO with Image.open which also gives error. So, can anyone please tell me how to do that?
My JS:
$SCRIPT_ROOT = {
{
request.script_root | tojson | safe
}
};
$(function() {
$("#pic").bind('click', function() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
var imgURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: $SCRIPT_ROOT + '/send_pic',
data: {
imageBase64: imgURL
}
}).done(function() {
console.log("sent");
});
});
My python code:
#app.route('/send_pic',methods=['GET','POST'])
def button_pressed():
print("Image recieved")
data_url = request.values['imageBase64']
img = Image.open(StringIO(data_url))
img = np.array(img)
cv2.imshow(img)
cv2.waitKeys(0)
cv2.destroyAllWindows()
return ""
the value of data_url is :
data:image/png;base64,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
Thanks!!!
From your code I understand that in your endpoint you expect base64 data. If so you can try something like this:
import base64
from io import BytesIO
#app.route('/send_pic',methods=['GET','POST'])
def button_pressed():
print("Image recieved")
data_url = request.values['imageBase64']
# Decoding base64 string to bytes object
img_bytes = base64.b64decode(data_url)
img = Image.open(BytesIO(img_bytes))
img = np.array(img)
cv2.imshow(img)
cv2.waitKeys(0)
cv2.destroyAllWindows()
return ""
Edit:
If data you sending is not base64 then you can try to transform it using numpy like this:
from flask import request
...
img_data = np.fromstring(request.data, np.uint8)
# Do what you want with it
cv2.imshow(img)
Edit 2:
Based on value you provided you must split value from request to get base64 image data:
#app.route('/send_pic',methods=['GET','POST'])
def button_pressed():
print("Image recieved")
data_url = request.values['imageBase64']
# Decoding base64 string to bytes object
offset = data_url.index(',')+1
img_bytes = base64.b64decode(data_url[offset:])
img = Image.open(BytesIO(img_bytes))
img = np.array(img)
cv2.imshow(img)
cv2.waitKeys(0)
cv2.destroyAllWindows()
return ""
I always get this error in the downloaded zip file C:\Users\me\Downloads\test.zip: Unexpected end of archive
My current code is:
var blob = new Blob([data], { // data here is the binary content
type: 'octet/stream',
});
var zipUrl = window.URL.createObjectURL(blob);
var fileName = orderNo;
fileName += '.zip';
downloadFile(null, fileName, null, zipUrl, null); // just creates a hidden anchor tag and triggers the download
The response of the call is a binary (I think). Binary Content Here
But the preview is a base64. Base64 Content. And it is the correct one. The way I verify it is by using this fiddle.
You can refer to the screenshot of the network here
I put the base64 content in this line var sampleBytes = base64ToArrayBuffer(''); And the zip downloaded just opens fine.
Things I have tried so far.
Adding this headers to the GET call
var headers = {
Accept: 'application/octet-stream',
responseType: 'blob',
};
But I get Request header field responseType is not allowed by Access-Control-Allow-Headers in preflight response.
We're using an already ajax.service.js in our AngularJS project.
From this answer
var blob = new Blob([yourBinaryDataAsAnArrayOrAsAString], {type: "application/octet-stream"});
var fileName = "myFileName.myExtension";
saveAs(blob, fileName);
There are other things that I have tried that I have not listed. I will edit the questions once I find them again
But where I'm current at right now. The preview is correct base64 of the binary file. Is it possible to use that instead of the binary? (If it is I will not find the other methods that I've tested) I tried some binary to base64 converters but they don't work.
So I just went and ditched using the ajax.service.js, that we have, for this specific call.
I used the xhr snippet from this answer. I just added the headers necessary for our call: tokens and auth stuff.
And I used this code snippet for the conversion thing.
And the code looks like this:
fetchBlob(url, function (blob) {
// Array buffer to Base64:
var base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(blob)));
var blob = new Blob([base64ToArrayBuffer(base64)], {
type: 'octet/stream',
});
var zipUrl = window.URL.createObjectURL(blob);
var fileName = orderNo;
fileName += ' Attachments ';
fileName += moment().format('DD-MMM-YYYY');
fileName += '.zip';
downloadFile(null, fileName, null, zipUrl, null); // create a hidden anchor tag and trigger download
});
function fetchBlob(uri, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', uri, true);
xhr.responseType = 'arraybuffer';
var x = AjaxService.getAuthHeaders();
xhr.setRequestHeader('auth_stuff', x['auth_stuff']);
xhr.setRequestHeader('token_stuff', x['token_stuff']);
xhr.setRequestHeader('Accept', 'application/octet-stream');
xhr.onload = function (e) {
if (this.status == 200) {
var blob = this.response;
if (callback) {
callback(blob);
}
}
};
return xhr.send();
};
function base64ToArrayBuffer(base64) {
var binaryString = window.atob(base64);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
};
return bytes;
}
I am using the File reader in JavaScript,i need to Post my image to WebApi and convert it into byte Array and save it in server,Its working fine,Now my problem is base64 string increasing the size of image, Let say if i upload image of 30Kb, it is storing has 389Kb in server,How i can save in same size or reduce size of image need help
//File Reader
function OnFileEditImageEntry(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
var ImageBase64 = evt.target.result;
return ImageBase64 ;
};
reader.readAsDataURL(file);
}
//WEB API//
public IHttpActionResult UpdateUserDetails(ImageModel model)
{
try
{
if (model.ImageBase64 != "")
{
var PicDataUrl = "";
string ftpurl = "ftp://xxx.xxxxx.xxxx/";
var username = "xxx";
var password = "xxxxx";
string UploadDirectory = "xxxx/xx";
string FileName =model.ImageFileName;
String uploadUrl = String.Format("{0}{1}/{2}", ftpurl, UploadDirectory,FileName);
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
req.Proxy = null;
req.Method = WebRequestMethods.Ftp.UploadFile;
req.Credentials = new NetworkCredential(username, password);
req.EnableSsl = false;
req.UseBinary = true;
req.UsePassive = true;
byte[] data =Convert.FromBase64String(model.ImageBase64);
req.ContentLength = data.Length;
Stream stream = req.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
}
}
}
Send the raw binary instead of increasing the size ~30% with base64/FileReader
with fetch
// sends the raw binary
fetch('http://example.com/upload', {method: 'post', body: file})
// Append the blob/file to a FormData and send it
var fd = new FormData()
fd.append('file', file, file.name)
fetch('http://example.com/upload', {method: 'post', body: fd})
With XHR
// xhr = new ...
// xhr.open(...)
xhr.send(file) // or
xhr.send(fd) // send the FormData
Normally when uploading files, try to avoid sending a json as many developers tends to to wrong. Binary data in json is equal to bad practice (and larger size) eg:
$.post(url, {
name: '',
data: base64
})
Use the FormData#append as much as possible or if you feel like it:
fd.append('json', json)
I've got a drag and drop function which takes the file that's been dropped on it and converts it to Base64 data. Before, it was uploading to Imgur, whose API supports Base64 uploads, and now I'm working on moving to Amazon S3.
I've seen examples of people using XMLHTTP requests and CORS to upload data to S3, I'm using Amazon's AWS S3 SDK gem to avoid having to sign policies and other things, as the gem does that for me. So what I've done is send the Base64 data to a local controller metod which uses the gem to upload to S3.
The other posts using Ajax i've seen show that S3 supports raw data uploads, but the gem doesn't seem to, as whenever I view the uploads i get broken images. Am I uploading it incorrectly? Is the data in the wrong format? I've tried the basic Base64, atob Base64, and blob urls, but nothing works so far.
JS:
fr.onload = function(event) {
var Tresult = event.target.result;
var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
var blob = atob(Tresult.replace(/^data\:image\/\w+\;base64\,/, ''));
$.ajax({
type:"POST",
data:{
file:blob,
contentType: datatype,
extension:datatype.slice(datatype.search(/\//)+1)
},
url:'../uploads/images',
success:function(msg) {
handleStatus(msg,"success");
},
error:function(errormsg) {
handleStatus(errormsg,"error");
}
});
}
Controller method:
def supload
s3 = AWS::S3.new(:access_key_id => ENV['S3_KEY'],:secret_access_key => ENV['S3_SECRET'])
bucket = s3.buckets['bucket-name']
data = params[:file].to_s
type = params[:contentType].to_s
extension = params[:extension].to_s
name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
url = obj.public_url().to_s
render text: url
end
Edit:
To be clear, I've tried a couple of different formats, the one displayed above is decoded base64. Regular Base64 looks like this:
var Tresult = event.target.result;
var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
var blob = Tresult;
$.ajax({
type:"POST",
data:{
file:blob,
mimeType: datatype,
extension:datatype.slice(datatype.search(/\//)+1)
},
url:'../uploads/images',
success:function(msg) {
handleStatus(msg,"success");
},
error:function(errormsg) {
handleStatus(errormsg,"error");
}
});
and a blob url looks like this:
var blob = URL.createObjectURL(dataURItoBlob(Tresut,datatype));
...
function dataURItoBlob(dataURI, dataType) {
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: dataType});
}
Am I reading this right that you are:
Using AJAX to send a Base64-encoded file to Rails
Using Rails to upload the file to S3
Viewing the file in S3?
If that's the case, you need to decode the data in step 2 before sending it on to S3. Something like this might work:
require "base64"
def supload
s3 = AWS::S3.new(:access_key_id => ENV['S3_KEY'],:secret_access_key => ENV['S3_SECRET'])
bucket = s3.buckets['bucket-name']
data = Base64.decode64(params[:file].to_s)
type = params[:contentType].to_s
extension = params[:extension].to_s
name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
url = obj.public_url().to_s
render text: url
end