Skip to content

Instantly share code, notes, and snippets.

@eagsalazar
Created June 22, 2016 08:34
Show Gist options
  • Save eagsalazar/83d5b222715f7267a4c0e02ec20b3c55 to your computer and use it in GitHub Desktop.
Save eagsalazar/83d5b222715f7267a4c0e02ec20b3c55 to your computer and use it in GitHub Desktop.
const MAX_WIDTH = 512
const applyBilinearInterpolation = (srcCanvasData, destCanvasData, scale) => {
function inner(f00, f10, f01, f11, x, y) {
const unX = 1.0 - x
const unY = 1.0 - y
return (f00 * unX * unY + f10 * x * unY + f01 * unX * y + f11 * x * y)
}
let i
let j
let iyv
let iy0
let iy1
let ixv
let ix0
let ix1
let idxD
let idxS00
let idxS10
let idxS01
let idxS11
let dx
let dy
let r
let g
let b
let a
for (i = 0; i < destCanvasData.height; ++i) {
iyv = i / scale
iy0 = Math.floor(iyv)
// Math.ceil can go over bounds
iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ?
(srcCanvasData.height - 1) :
Math.ceil(iyv))
for (j = 0; j < destCanvasData.width; ++j) {
ixv = j / scale
ix0 = Math.floor(ixv)
// Math.ceil can go over bounds
ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ?
(srcCanvasData.width - 1) :
Math.ceil(ixv))
idxD = (j + destCanvasData.width * i) * 4
// matrix to vector indices
idxS00 = (ix0 + srcCanvasData.width * iy0) * 4
idxS10 = (ix1 + srcCanvasData.width * iy0) * 4
idxS01 = (ix0 + srcCanvasData.width * iy1) * 4
idxS11 = (ix1 + srcCanvasData.width * iy1) * 4
// overall coordinates to unit square
dx = ixv - ix0
dy = iyv - iy0
// I let the r, g, b, a on purpose for debugging
r = inner(
srcCanvasData.data[idxS00],
srcCanvasData.data[idxS10],
srcCanvasData.data[idxS01],
srcCanvasData.data[idxS11],
dx, dy)
destCanvasData.data[idxD] = r
g = inner(
srcCanvasData.data[idxS00 + 1],
srcCanvasData.data[idxS10 + 1],
srcCanvasData.data[idxS01 + 1],
srcCanvasData.data[idxS11 + 1],
dx, dy)
destCanvasData.data[idxD + 1] = g
b = inner(
srcCanvasData.data[idxS00 + 2],
srcCanvasData.data[idxS10 + 2],
srcCanvasData.data[idxS01 + 2],
srcCanvasData.data[idxS11 + 2],
dx, dy)
destCanvasData.data[idxD + 2] = b
a = inner(
srcCanvasData.data[idxS00 + 3],
srcCanvasData.data[idxS10 + 3],
srcCanvasData.data[idxS01 + 3],
srcCanvasData.data[idxS11 + 3],
dx, dy)
destCanvasData.data[idxD + 3] = a
}
}
}
const scaleCanvasWithAlgorithm = canvas => {
const scaledCanvas = document.createElement('canvas')
const scale = MAX_WIDTH / canvas.width
scaledCanvas.width = canvas.width * scale
scaledCanvas.height = canvas.height * scale
const srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height)
const destImgData =
scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height)
applyBilinearInterpolation(srcImgData, destImgData, scale)
scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0)
return scaledCanvas
}
const getHalfScaleCanvas = canvas => {
const halfCanvas = document.createElement('canvas')
halfCanvas.width = canvas.width / 2
halfCanvas.height = canvas.height / 2
halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height)
return halfCanvas
}
const scaleImage = (img, type) => {
let canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height)
while (canvas.width >= (2 * MAX_WIDTH)) {
canvas = getHalfScaleCanvas(canvas)
}
if (canvas.width > MAX_WIDTH) {
canvas = scaleCanvasWithAlgorithm(canvas)
}
const imageData = canvas.toDataURL(type)
return imageData
}
const dataURItoBlob = dataURI => {
const byteString = atob(dataURI.split(',')[1])
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
const ab = new ArrayBuffer(byteString.length)
const dw = new DataView(ab)
for (let i = 0; i < byteString.length; i++) {
dw.setUint8(i, byteString.charCodeAt(i))
}
return new Blob([ab], { type: mimeString })
}
const scaleImageFile = (file, callback) => {
const img = document.createElement('img')
const reader = new FileReader()
reader.onload = e => {
img.src = e.target.result
const data = scaleImage(img, file.type)
const blob = dataURItoBlob(data)
blob.name = file.name
callback(blob)
}
reader.readAsDataURL(file)
}
export default scaleImageFile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment