Contents:
In this assignment, you will build Photostall, a GUI to an image convolution service. Image convolution is commonly used in image processing, computer vision and deep learning. For example, it can be used to blur or sharpen an image, to find edges, and more.
Photostall is a client-server application. That is, it has two components:
The Photostall GUI is written using HTML and JavaScript.
To learn about HTML, see the W3 Schools HTML tutorial.
To learn about JavaScript, see the MDN JavaScript tutorial.
Here are some tools you will need for this assignment:
npm -v
should print a version number. If not, then install npm.
npm is a JavaScript package manager
that helps manage the dependencies for the UI (that is, the libraries that the UI code uses).
npm install
from src/main/resources
.
(This installs dependencies.)
mvn -v
should print a version number and some other information. If not, then install Maven.
Maven is a build system that is the predecessor of Gradle.
Since Photostall is not part of the Campus Maps application, you will use a separate Git repository. You can clone it from the command line:
git clone git@gitlab.cs.washington.edu:cse331-18au-students/hw9/cse331-18au-hw9-CSENetID.git
To import the project into IntelliJ, follow the same instructions you used to add your original project to IntelliJ. Since this project uses Maven instead of Gradle, the external model you are importing the project from is Maven, not Gradle.
The server is already implemented for you. You must run the server:
mvn spring-boot:run
ConvolutionApplication.java
Once the server is running, visit http://localhost:8080/swagger-ui.html to interact with the API. Click on "public-api", then the green button "POST", then "Try it out", then edit the model example value.
https://images4.sw-cdn.net/product/picture/710x528_445898_471395_1459311369.jpg
. (This is the famous Utah Teapot.)It might take a long time to copy resources. Be patient, and do not kill the process.
If you get an error of the form
Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.0.RELEASE:run (default-cli) on project hw9: An exception occurred while running. null
then running mvn clean
may be a solution.
If you get an error of one of the following forms:
APPLICATION FAILED TO START The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured. org.apache.catalina.LifecycleException: Protocol handler start failed
then perhaps you already have a process running on port 8080.
This can happen if you ran the process earlier and didn't kill it.
You can reboot your computer, or you can run
netstat -vanp tcp | grep 8080
to get the pid to kill.
You will write a user interface to let users interact with the convolution service in a more friendly way.
You will write the UI in file src/main/resources/src/App.js
.
To run the React server, run npm start
from src/main/resources
.
Once your server is running, visit
http://localhost:3000 to view
your UI.
(You should try to run this even before you have written any code, and you will see a default web app provided by the staff.)
Your interface should allow a user to input the URL and the convolution. (Your UI won't do anything with those arguments yet.) Here is a very basic way to implement the UI:
The staff recommends that you use the
Material UI library, which
provides "React components that implement Google's Material Design."
This dependency has already been added for you (in file src/main/resources/package.json
), so you can import
its classes in file App.js
, for instance using import Button from '@material-ui/core/Button';
.
You are permitted to add other dependencies, but the staff does not support other dependencies and cannot help with any problems you might encounter.
Your UI exists and has graphical components, but it is not yet functional
because you have not yet invoked the convolution service.
To do that, the UI should issue
an asynchronous request using fetch
, then update the image display area after receiving
a response from the server.
The reason to issue a request asynchronously rather than synchronously is to prevent the backend service from blocking the main UI thread. Because the main UI thread is still running, it can be responsive to user actions while waiting for a backend response.
To issue requests to a server asynchronously, you should use node-fetch
.
(Another implementation of fetch is
JavaScript Fetch, but the staff recommends node-fetch
.)
node-fetch
is a JavaScript library that handles asynchronous requests.
fetch('http://localhost:8080/convolve', { arguments })) .then(response => do some work) // possibly more chained .then(arg => action) lines
In the above code, the fetch
line is performed immediately, and the .then
function is invoked on the response, when it eventually arrives.
The argument to then
is a function whose formal parameter is named response
. That function will be invoked on whatever fetch
returns. It needs to do two things:
response.arrayBuffer()
), then
this code will do part of the work:
new Buffer(myArrayBuffer,
'binary').toString(CONVERTED_FORMAT)
, but you will
also need to prepend headers to that string representation.
this.setState(...)
to change the data that is used to generate the webpage.
Here is some more help about calling fetch
:
require
statements to import the library.
This will not work in our repository and you should use:
import * as fetch from "node-fetch";.
fetch
. Copy and paste the code, but make some changes:
http://localhost:8080/convolve
application/json
is accurate.
.then(res => res.json())
,
because you don't need to convert the response, which is a binary image (of type image/jpeg
), to
JSON. (The formal parameter name res
stands for
"response".)
.then(arg => body)
calls.
To update the
image display area when you receive a server response, you should use React's
setState
function. You might also use lifecycle functions like
componentDidMount
; see the documentation of the state and lifecycle of a React
component.
Do not use ReactDOM.render
in your application.
Only index.js
(which you do not need to edit)
should call ReactDOM.render
.
The Document Object Model (DOM) is a representation of HTML and XML documents.
The DOM represents the document as nodes and objects.
A JavaScript program can change the DOM, which changes what the user sees in the browser.
Using React allows React to manage the webpage and saves time as React no longer needs to keep communicating with the DOM. Calling ReactDOM.render
will require React to communicate with the DOM which affects performance and defeats the purpose of React.
You are responsible for making a GUI that performs the required tasks, and is easy to use and intuitive. You are permitted, but not required, to be creative and improve upon this basic design. (Don't do this until after you have completed the entire assignment.)
Here are a few suggestions of optional API expansions:
alt="image description"
to the <img>
tag.
Additional functionality should augment, not replace, the requirements of the assignment. Please record all additional functionality you attempted to add in src/main/resources/answers.txt
.
In case you add functionality or provide a UI that goes beyond the requirements of the assignment, you are eligible for extra credit. This extra credit will either allow you to get back points you have lost on this assignment, or will be used when final grades are being decided.
Approximately 100 lines of JavaScript are enough to complete the basic requirements of this assignment. It is acceptable to write the entire implementation in one file. However, if you add a lot of functionality and a lot more code, consider splitting it into multiple files.
It is easiest to have a different handleChange...
function for each component of your GUI.
The JavaScript function console.log
can be useful for logging (that is, for printf debugging).
The output will appear in the client's (browser's) console.
To see it:
The JavaScript syntax param => body
creates a function (like a lambda expression does in Java).
That is, the following two code snippets are essentially equivalent:
double = param => 2 * param function double(param) { return 2 * param; }
Complete the Canvas Quiz associated with this assignment. You will receive full credit for this section if you complete the quiz. Your answers will be anonymous to the instructors. This quiz is due 24 hours after the assignment due date. You cannot use late days for this quiz.
We don't have any specific files that you must submit as part of the
assignment. The only exception to the previous statement is the requirement
of answers.txt
if you add additional functionality. The staff
strongly urges you to test your UI on a lab machine.
Your UI must load when we visit
http://localhost:3000.
Refer to the assignment submission handout for complete turnin instructions.