const MAX_SIDE = 300 function render(img){ var resized = renderToCanvas(img, { correctOrientation: true }) var canvas = document.createElement('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) return canvas } 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 } }