Sending image from flask to javascript - javascript

I am trying to send an image from the flask server to the web script. The first server connects to another API and gets an image. I don't want to save this image just forward it to the web application script.
#app.route('/api/image', methods=['GET'])
def return_image():
r = requests.get(f"{api_url}/image")
return send_file(
BytesIO(r.content),
mimetype='image/jpeg',
as_attachment=True,
attachment_filename='test.jpg')
I am trying to get this image by ajax request and display it.
function updateImage() {
$.ajax({
url: "/api/image",
type: "GET",
dataType: 'image/jpg',
success: function (res) {
$(theImg).attr("src", 'data:image/png;base64,'+ res);
M.toast({
html: 'Loading image: Success'
})
},
error: function () {
M.toast({
html: 'Loading image: Fail'
})
}
});
}
I tried to make this work but wasn't able to. I really appreciate your help.

At a glance your JS writes a data-uri to the src attribute, but res is actually the binary data with a image/png mimetype.
So you either need to base64 encode r.content on the server side, here's an example which actually creates the entire uri server side, then return that string and have your JS add that to the src attribute.
Or if you just want make your JS support the exisitng endpoint you could probably create a blob based on /api/image response, then write that to the img tag.

Related

Flask 'render_template' after client POST request

So, I'm working on a small web application that has a small canvas, the user is supposed to draw something and then I want to do some python with the image from that canvas. Like this:
This is working fine. When I press "Click me!", I call a JS function that POST the image to my Flask server. And this is also working, the thing is that after I receive the image, I want to render a new page to show some results, but this page is not rendering at all.
Now, I'm completely new to Javascript, barely know anything, basically every JS I'm using is copy pasted from the internet, so I'm assuming I must be missing something very simple, I just don't know what.
Here is the server code:
from flask import Flask, render_template, request
import re
from io import BytesIO
import base64
from PIL import Image
app = Flask(__name__)
#app.route("/")
def hello_world():
return render_template('drawing.html')
#app.route("/hook", methods=['POST', 'GET'])
def hook():
image_data = re.sub('^data:image/.+;base64,', '', request.form['imageBase64'])
im = Image.open(BytesIO(base64.b64decode(image_data)))
im.show()
return render_template('results.html')
The first route just opens the canvas, the second is executed after the client's request, which has this function:
function surprise() {
var dataURL = canvas.toDataURL();
$.ajax({
type: "POST",
url: "http://127.0.0.1:5000/hook",
data:{
imageBase64: dataURL
}
}).done(function() {
console.log('sent');
});}
Apparently, this is working. I have the line:
im.show()
Just so I can see the image and I get exactly the drawing from the canvas, which I'm now supposed to work on:
but the results page is not rendered afterwards, nothing happens. Why?
The problem is that you are returning the page to view in response to the call that posts the image. Instead, you should return a response (for example in a json format) containing the information regarding the result of the call just made (i.e. the post of the image) and consequently, on the client side, you must redirect the user to the appropriate page .
To understand why it is not working, print the content of the response returned from the call made
var response = '';
$.ajax({ type: "POST",
url: "http://127.0.0.1:5000/hook",
data:{
imageBase64: dataURL
},
success : function(text)
{
response = text;
}
});
alert(response);

Download file from server with Flask and JS

I am trying to download a file when a user clicks on a particular button. This file is an image which gets created when the said button is pressed. What I want is, it should automatically download the image on the client's device.
I am using Flask on the server code, and ideally, the send_file function of Flask should trigger this auto download as it adds the Content-Disposition header.
On the client side, I have a JS code which uses fetch API to send a POST request to the server with some data, which is used for generating the image which is to be downloaded.
This is the JS code:
function make_image(text){
const json={
text: text
};
const options={
method: "POST",
body: JSON.stringify(json),
headers:{
'Content-Type':'application/json',
}
};
fetch('/image',options)
.then(res=>{
res.json(); //Gives an error: Uncaught (in promise) SyntaxError: Unexpected token � in JSON at position 0
}).catch(err=>console.log(err));
}
And this is the Python code on the server:
#app.route('/image',methods=['POST'])
def generate_image():
cont = request.get_json()
t=cont['text']
print(cont['text'])
name = pic.create_image(t)
time.sleep(2)
return send_file(f"{name}.png",as_attachment=True,mimetype="image/png")
But nothing is happening. The image doesnt get downloaded. However,the image is getting created on the server and is not corrupt
How do I resolve this? And is there some other way to do what I am trying to do?
You can do the below
return send_from_directory(dir, file_name, as_attachment=True)
This will download the file on the user's machine.
Edit:
BTW, if you create an html form like below, you do not need javascript.
<form action='action here' method='post'>
<input type='submit'>
</form>
As #clockwatcher mentioned a different question, I used the download.js module to handle the download of the image.
So my JS code looks like this now:
function make_image(text){
const json={
text: text
};
const options={
method: "POST",
body: JSON.stringify(json),
headers:{
'Content-Type':'application/json',
}
};
fetch('/image',options)
.then(res=>{
return res.blob();
}).then(blob=>{
download(blob)
}).catch(err=>console.log(err));
}
And an addition to the script tag in the html:
<script src="https://cdnjs.cloudflare.com/ajax/libs/downloadjs/1.4.8/download.min.js"></script>
With no change in the Python server code.
It works now

Save File through JQuery AJAX Call

I am using JQuery to send an AJAX request to a Node server (using Hapi). The server responds with a PDF file correctly, but I am trying to save the file locally. The catch is that the PDF should only return if the POST sent the right data. It's "protected" in other words and I don't want to just expose it publicly.
Frontend code:
$.get('http://localhost:3000').done(function (data) {
console.log(data);
});
Backend code:
server.route({
method: 'GET',
path: '/',
handler: async (request, h) => {
return h.file('./static/sample.pdf', {
mode: 'attachment',
filename: 'sample.pdf'
})
}
});
I receive the data but nothing happens in the front-end UI. How can I download the PDF that is sent automatically?
You can achieve that with html5 using
Download it!
Notice that this works only for same-origin URLs, or the blob: and data: schemes. And this gets overridden by the Content-Disposition header from the server.
If you want to do this programatically you could do this
const element = document.createElement("a")
element.setAttribute(
"href",
// you could also use base64 encoding here like data:application/pdf;base64,
"data:text/plain;charset=utf-8," + encodeURIComponent('pdf binary content here')
)
element.setAttribute("download", "file.pdf")
element.style.display = "none"
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
Anyway this is only a useful method if u want to create/modify the downloaded data from the client side, but if u are getting it as it is from the server side then its better just to open a new url, letting the browser handle it.

Why is my Giphy API's POST request returning status 400?

I'm trying to upload a gif from the webcam feed to Giphy through their API and it returns status 400 - "Please supply a file upload or a 'source_image_url'". My function does this:
upload = new FormData();
upload.append("file", gif, "usergif.gif");
console.log(upload.get("file"));
fetch("https://upload.giphy.com/v1/gifs?file=" upload + "&api_key=" + apiKey, { method: "POST" })
.then(response => {
console.log(response.status);
return response.json;
}
)
The gif variable inside upload.append() has a value of recorder.getBlob() (I'm using the RecorderRTC API), I also tried to use as a source upload.file and even upload.get("file"), also used URL.createObjectUrl(gif) and changed file= for source_image_url= in the fetch request, even tried to send the gif variable without the use of FormData() but nothing worked.
Do you have a clue?
For those interested, the solution was that when using the POST method, you gotta specify a body header with the file to be uploaded

Django ajaxuploader 400 badrequest error

Submitted.html
The JS is also surrounded by a document.ready function
var uploader = new qq.FileUploader({
action: "{% url 'QCOMLTE:imager' %}",
element: $('#file-uploader')[0],
multiple: true,
onComplete: function(id, fileName, responseJSON) {
if(responseJSON.success) {
alert("success!");
} else {
alert("upload failed!");
}
},
onAllComplete: function(uploads) {
// uploads is an array of maps
// the maps look like this: {file: FileObject, response: JSONServerResponse}
alert("All complete!");
},
params: {
'csrf_token': "{{ csrf_token }}",
'csrf_name': 'csrfmiddlewaretoken',
'csrf_xname': 'X-CSRFToken'
}
});
elsewhere in the html body
<div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
urls.py
urlpatterns = patterns('',
url(r"^Submitted/$", views.HybridDetailView.as_view(), name='Submitted'),
url(r'^(?P<object_type>\w+)/process/$', views.process, name='process'),
url(r'^(?P<object_type>\w+)/$', views.generic_view, name='generic'),
url("$^", views.head, name='head'),
url("uploader", views.upload, name= 'imager'),
)
views.py
#AjaxFileUploader
def upload(request):
response = {'files': []}
script_dir = os.path.dirname(__file__)
# Loop through our files in the files list uploaded
print('request',request)
print(request.FILES)
for item in request.FILES.getlist('files[]'):
file = UploadedFile(item)
with open(script_dir + '/Excel/' + file.name) as destination:
for chunk in file.chunks():
destination.write(chunk)
response['files'].append(file)
print('appended')
return HttpResponse(json.dumps(response), content_type='application/json')
also contains 'ajaxuploader' in the installed apps list
When I try to submit a file through the button it sends the post call but receives a 400 (BAD REQUEST) Error.
It's not even reaching the python from what I can tell, at least not the view code. It seems to form the request URL correctly
http://localhost:8000/QCOMLTE/uploader?qqfile=powered_by.png
And when you go to the URL it sends a message stating that post calls are only allowed.
This is similar to Default django-ajax-uploader with s3 backend gives MalformedXML error
Except that I'm not using any backends, just trying to grab the file/s and save them to a directory.
UPDATE 8/25/14:
Removed the decorator from the view. This results in the error not being sent. After printing the request it becomes evident that the file is being sent to the GET path instead of the FILE path. I don't know how to change this.
After finding this Need a minimal Django file upload example
I preceded to try and imitate it, to find that the FILE and POST requests were actually going through, unlike the ajax/jquery I was using. The JQuery was
$('#uploadform').submit(function (e){
console.log('submitting')
var data = new FormData($('#uploadform').get(0));
$.ajax({
type: 'POST',
url: "{% url 'QCOMLTE:imager' %}",
data: data,
success: function(data){console.log(data)},
error: function(data){console.log(data)},
cache: false,
processData: false,
contentType: false
});
e.preventDefault()
});
except the type was below URL.
I tried changing it to a $.post request and it was trying to post to the wrong URL then...
So I decided to change it back, and this time put type at the top of the ajax call. It then worked... and still does after much testing.

Categories

Resources