summaryrefslogtreecommitdiff
path: root/old/server/app/static/js/upload.js
diff options
context:
space:
mode:
authorAdam Harvey <adam@ahprojects.com>2018-12-23 01:37:03 +0100
committerAdam Harvey <adam@ahprojects.com>2018-12-23 01:37:03 +0100
commit4452e02e8b04f3476273574a875bb60cfbb4568b (patch)
tree3ffa44f9621b736250a8b94da14a187dc785c2fe /old/server/app/static/js/upload.js
parent2a65f7a157bd4bace970cef73529867b0e0a374d (diff)
parent5340bee951c18910fd764241945f1f136b5a22b4 (diff)
.
Diffstat (limited to 'old/server/app/static/js/upload.js')
-rw-r--r--old/server/app/static/js/upload.js319
1 files changed, 319 insertions, 0 deletions
diff --git a/old/server/app/static/js/upload.js b/old/server/app/static/js/upload.js
new file mode 100644
index 00000000..27437e43
--- /dev/null
+++ b/old/server/app/static/js/upload.js
@@ -0,0 +1,319 @@
+var messages = {
+ is_processing: "Running semantic segmentation...",
+ upload_failed: "Error attempting to upload the file.",
+ upload_cancelled: "Upload cancelled or browser dropped connection.",
+ unable_to_compute: "We're sorry! We were unable to compute your image.",
+ pending: "Sending to Generative Adversarial Network...",
+ complete: "Processing complete!",
+}
+
+var upload = (function(){
+ var upload = {}
+ var uploading = false
+
+ var MAX_SIDE = 512
+
+ upload.init = function(){
+ upload.bind()
+ }
+
+ upload.bind = function(){
+ $("input[type=file]").on('change', upload.change)
+ $("#upload_btn").on('click', upload.go)
+ document.body.addEventListener("dragover", upload.dragover)
+ document.body.addEventListener("dragleave", upload.dragover)
+ document.body.addEventListener("drop", upload.change)
+ }
+
+ upload.dragover = function(e){
+ e.stopPropagation()
+ e.preventDefault()
+ }
+
+ upload.change = function(e){
+ e.preventDefault()
+ var files = e.dataTransfer ? e.dataTransfer.files : e.target.files
+ if (files.length) {
+ var file = files[files.length - 1]
+ if (!file.type.match('image.*'))
+ return
+ var reader = new FileReader()
+ reader.onload = onReaderLoad
+ reader.readAsDataURL(file)
+ }
+ function onReaderLoad(e) {
+ // Don't leak!
+ reader.onload = null
+ var img = new Image
+ img.onload = function(){
+ img.onload = null
+ upload.ready(img)
+ }
+ img.src = e.target.result
+ }
+ }
+
+ upload.ready = function(img){
+ var resized = renderToCanvas(img, { correctOrientation: true })
+ var canvas = document.querySelector('#user_photo_canvas')
+ ctx = canvas.getContext('2d')
+ ctx.fillStyle = 'black'
+ ctx.fillRect(0, 0, MAX_SIDE, MAX_SIDE)
+ var x_offset = (MAX_SIDE - resized.width) / 2
+ var y_offset = (MAX_SIDE - resized.height) / 2
+
+ ctx.drawImage(resized, x_offset, y_offset)
+ app.didPickPhoto()
+ }
+
+ upload.go = function(){
+ if (uploading) return
+ uploading = true
+ app.didClickUpload()
+ try {
+ var canvas = document.querySelector('#user_photo_canvas')
+ var cb = canvas.toBlob(function(blob){
+ upload.send(blob)
+ }, 'image/jpeg', 89)
+ } catch(e){
+ app.updateProgress(messages.unable_to_compute)
+ }
+ }
+
+ upload.send = function(blob){
+ console.log("sending upload...")
+ var fd = new FormData()
+ fd.append('user_image', blob)
+ fd.append('ext', 'jpg')
+ fd.append('style', $("#dropdown").val())
+ fd.append('agree', $("#agree").val() || 0)
+
+ var xhr = new XMLHttpRequest()
+ xhr.upload.addEventListener("progress", upload.progress, false)
+ xhr.addEventListener("load", upload.complete, false)
+ xhr.addEventListener("error", upload.failed, false)
+ xhr.addEventListener("abort", upload.canceled, false)
+ xhr.open("POST", "/upload")
+ xhr.send(fd)
+ }
+
+ upload.progress = function (e) {
+ if (e.lengthComputable) {
+ var percentComplete = Math.round(e.loaded * 100 / e.total)
+ if (percentComplete > 99) {
+ app.updateProgress(messages.is_processing)
+ } else {
+ app.updateProgress("Uploaded " + percentComplete.toString() + '%')
+ }
+ }
+ else {
+ app.updateProgress(messages.unable_to_compute)
+ }
+ }
+
+ upload.complete = function (e) {
+ uploading = false
+ try {
+ var data = JSON.parse(e.target.responseText)
+ } catch (e) {
+ return app.updateProgress(messages.upload_failed)
+ }
+ app.uploadDidComplete()
+ upload.data = data
+ upload.task_progress(data.task_url)
+ }
+
+ upload.failed = function (evt) {
+ uploading = false
+ app.updateProgress(messages.upload_failed)
+ }
+
+ upload.cancelled = function (evt) {
+ uploading = false
+ app.updateProgress(messages.upload_cancelled)
+ }
+
+ upload.task_progress = function (status_url) {
+ var is_public = $("#agree").val() || 0
+ var uuid = upload.data.uuid
+ $.getJSON(status_url, function(data){
+ console.log(data)
+ var alive = true
+ var delay = 500
+ switch(data.state) {
+ case 'PENDING':
+ app.updateProgress(messages.pending)
+ delay = 2000
+ break
+ case 'PROCESSING':
+ app.updateProgress(data.message, data.percent)
+ delay = 500
+ break
+ case 'SUCCESS':
+ app.updateProgress(messages.complete)
+ if (is_public) {
+ history.pushState({}, 'DullDream', '/d/' + uuid)
+ } else {
+ history.pushState({}, 'DullDream', '/p/' + uuid)
+ }
+ app.processingComplete(uuid, is_public) // truthy if private
+ alive = false
+ break
+ default:
+ // NB: error state
+ alive = false
+ break
+ }
+ if (alive) {
+ setTimeout(function() {
+ upload.task_progress(status_url)
+ }, delay)
+ }
+ })
+ }
+
+
+ function renderToCanvas(img, options) {
+ if (!img) return
+ options = options || {}
+
+ // Canvas max size for any side
+ var maxSize = MAX_SIDE
+ var canvas = document.createElement('canvas')
+ var ctx = canvas.getContext('2d')
+ var initialScale = options.scale || 1
+ // Scale to needed to constrain canvas to max size
+ var scale = getScale(img.width * initialScale, img.height * initialScale, maxSize, maxSize, true)
+ // Still need to apply the user defined scale
+ scale *= initialScale
+ var width = canvas.width = Math.round(img.width * scale)
+ var height = canvas.height = Math.round(img.height * scale)
+ var correctOrientation = options.correctOrientation
+ var jpeg = !!img.src.match(/data:image\/jpeg|\.jpeg$|\.jpg$/i)
+ var hasDataURI = !!img.src.match(/^data:/)
+
+ ctx.save()
+
+ // Can only correct orientation on JPEGs represented as dataURIs
+ // for the time being
+ if (correctOrientation && jpeg && hasDataURI) {
+ applyOrientationCorrection(canvas, ctx, img.src)
+ }
+ // Resize image if too large
+ if (scale !== 1) {
+ ctx.scale(scale, scale)
+ }
+
+ ctx.drawImage(img, 0, 0)
+ ctx.restore()
+
+ return canvas
+ }
+
+ function getScale(width, height, viewportWidth, viewportHeight, fillViewport) {
+ fillViewport = !!fillViewport
+ var landscape = (width / height) > (viewportWidth / viewportHeight)
+ if (landscape) {
+ if (fillViewport) {
+ return fitVertical()
+ } else if (width > viewportWidth) {
+ return fitHorizontal()
+ }
+ } else {
+ if (fillViewport) {
+ return fitHorizontal()
+ } else if (height > viewportHeight) {
+ return fitVertical()
+ }
+ }
+ return 1
+
+ function fitHorizontal() {
+ return viewportWidth / width
+ }
+
+ function fitVertical() {
+ return viewportHeight / height
+ }
+ }
+
+ function applyOrientationCorrection(canvas, ctx, uri) {
+ var orientation = getOrientation(uri)
+ // Only apply transform if there is some non-normal orientation
+ if (orientation && orientation !== 1) {
+ var transform = orientationToTransform[orientation]
+ var rotation = transform.rotation
+ var mirror = transform.mirror
+ var flipAspect = rotation === 90 || rotation === 270
+ if (flipAspect) {
+ // Fancy schmancy swap algo
+ canvas.width = canvas.height + canvas.width
+ canvas.height = canvas.width - canvas.height
+ canvas.width -= canvas.height
+ }
+ if (rotation > 0) {
+ applyRotation(canvas, ctx, rotation)
+ }
+ }
+ }
+
+ function applyRotation(canvas, ctx, deg) {
+ var radians = deg * (Math.PI / 180)
+ if (deg === 90) {
+ ctx.translate(canvas.width, 0)
+ } else if (deg === 180) {
+ ctx.translate(canvas.width, canvas.height)
+ } else if (deg == 270) {
+ ctx.translate(0, canvas.height)
+ }
+ ctx.rotate(radians)
+ }
+
+ function getOrientation (uri) {
+ var exif = new ExifReader
+ // Split off the base64 data
+ var base64String = uri.split(',')[1]
+ // Read off first 128KB, which is all we need to
+ // get the EXIF data
+ var arr = base64ToUint8Array(base64String, 0, Math.pow(2, 17))
+ try {
+ exif.load(arr.buffer)
+ return exif.getTagValue('Orientation')
+ } catch (err) {
+ return 1
+ }
+ }
+
+ function base64ToUint8Array(string, start, finish) {
+ var start = start || 0
+ var finish = finish || string.length
+ // atob that shit
+ var binary = atob(string)
+ var buffer = new Uint8Array(binary.length)
+ for (var i = start; i < finish; i++) {
+ buffer[i] = binary.charCodeAt(i)
+ }
+ return buffer
+ }
+
+ /**
+ * Mapping from EXIF orientation values to data
+ * regarding the rotation and mirroring necessary to
+ * render the canvas correctly
+ * Derived from:
+ * http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/
+ */
+ var orientationToTransform = {
+ 1: { rotation: 0, mirror: false },
+ 2: { rotation: 0, mirror: true },
+ 3: { rotation: 180, mirror: false },
+ 4: { rotation: 180, mirror: true },
+ 5: { rotation: 90, mirror: true },
+ 6: { rotation: 90, mirror: false },
+ 7: { rotation: 270, mirror: true },
+ 8: { rotation: 270, mirror: false }
+ }
+
+
+ return upload
+})() \ No newline at end of file