Technical Articles
Post image file from SAPUI5 to flask app on CF
Hi All,
I am writing this blog to describe how to develop SAPUI5 and Flask app on Cloud Foundry.
Basically it it difficult to process image data with javascript, so I used python for image processing.
If you don’t know how to deploy application to Cloud Foundry, see another article “Create simple Flask REST API using Cloud Foundry”.
If you want to know more about logging from python on Cloud Foundry, see another article “Output logs from Python Flask application deployed on Cloud Foundry”.
How my program works
1. Open SAPUI5
Open SAPUI5 app with chrome extension “Allow-Control-Allow-Origin”. I somehow open “extended_runnable_file.html” from Web IDE test and get error. When opened url path is “extended_runnable_file.html”, then change it to “index.html”.
Click on camera Icon.
2. Select an image file
Select an image file to pass to Flask application.
3. See returned result
Returned result is displayed as an alert screen.
Programs
Flask app on Cloud Foundry
Application is on my GitHub Repository “cloudfoundry-python-flask-image”.
Environment
- Region: CF Trial (Europe – Frankfurt)
- Python Buildpack version: 1.6.20
- Python Version: 3.5.5
- Used Python Libraries: Flask, pillow, numpy, sap_cf_logging
Python Application(procImage.py)
I used pillow library for image processing. Received image data via POST method is resized using “thumnail” function. And I change data format using numpy library.
from flask import Flask, jsonify, request, make_response
from PIL import Image
import numpy as np
import logging, math, os
from sap.cf_logging import flask_logging
app = Flask(__name__)
#Iitialize logging
flask_logging.init(app, logging.INFO)
cf_port = os.getenv('PORT')
# Only get method by default
@app.route('/', methods=["GET", "POST"])
def hello():
logger = logging.getLogger('my.logger')
logger.info(request.files)
image = Image.open(request.files['sampleImage'].stream)
logger.info(image)
#Calculate resize ratio
ratio = math.sqrt(image.width * image.height / 400)
#If need to make image file smaller
if ratio > 1:
image.thumbnail((int(image.width / ratio), int(image.height / ratio)))
logger.info(image)
(im_width, im_height) = image.size
#Change file format for general TensorFlow format
image_np = np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8)
image_list = image_np.tolist()
return make_response(jsonify(image_list))
if __name__ == '__main__':
if cf_port is None:
app.run(host='0.0.0.0', port=5000, debug=True)
else:
app.run(host='0.0.0.0', port=int(cf_port), debug=True)
SAPUI5 app developed via Web IDE full-stack
The program is on my GitHub repository “YoheiFukuhara/post-image-from-sapui5-to-flask”.
Environment
- SAPUI5 version: 1.60.1
- IDE: Web IDE full-stack on SAP Cloud Platform
Main View(post.view.xml)
Here FileUploader’s attribute is “https://<url>”, so it fails with CORS basically. It is very easy to avoid CORS by configuring Destination. Why I don’t use “Destination”is just I want to make the app simpler. I avoid CORS error by using chrome extension “Allow-Control-Allow-Origin”.
An attribute “name” is so important, since the name “sampleImage” is used in Flask.
<mvc:View controllerName="test.post-image-to-flask.controller.post" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns:unified="sap.ui.unified" xmlns="sap.m">
<App id="idAppControl">
<pages>
<Page title="Post image file to Flask application on Cloud Foundry">
<content>
<unified:FileUploader name="sampleImage" uploadUrl="https://flask-image-patient-lynx.cfapps.eu10.hana.ondemand.com/" buttonOnly="true" icon="sap-icon://camera" iconOnly="true"
sameFilenameAllowed="true" fileType="png,jpeg,jpg,bmp,tiff,tif" mimeType="image/png,image/jpg,image/jpeg,image/bmp,image/tiff"
uploadComplete="fileUploadComplete" uploadOnChange="true" sendXHR="true"/>
</content>
</Page>
</pages>
</App>
</mvc:View>
Main Controller(post.controller.js)
Function is called when POST request is completed.
/*eslint-disable no-console, no-alert, */
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("test.post-image-to-flask.controller.post", {
fileUploadComplete: function (oControlEvent) {
console.log("response from CF flask API:", oControlEvent.getParameters().responseRaw);
alert(oControlEvent.getParameters().responseRaw);
}
});
});
Conclusion
This is very common way to process image. I hope it makes your development easier.