Skip to content

Instantly share code, notes, and snippets.

@turbotobias
Last active March 10, 2022 09:11
Show Gist options
  • Save turbotobias/b4c30eb117a3778677a454ba79fbb33c to your computer and use it in GitHub Desktop.
Save turbotobias/b4c30eb117a3778677a454ba79fbb33c to your computer and use it in GitHub Desktop.
// you might have to do something in webpack to enable wasm/photon
import initPhoton, {
resize as photon__resize,
open_image as photon__open_image,
putImageData as photon__put_image_data,
} from "photon-web"
const image = ref<HTMLImageElement>()
const imageUpload = ref<HTMLInputElement>()
const storageImageUrl = ref("")
const lqip = ref("")
const allowedMimeTypes = ["image/png", "image/jpg", "image/webp", "image/jpeg", "image/gif", "image/svg"]
const resize = async (file: File, maxSize: number = 1200) => {
return new Promise<File | void>((resolve, reject) => {
try {
// prepare File that is an image for being drawn onto canvas
const reader = new FileReader()
reader.readAsDataURL(file)
// get the image from FileReader
reader.onloadend = (e) => {
const imageFromFileReader = e.target?.result
if (typeof imageFromFileReader !== "string" || !imageFromFileReader) {
return console.trace(
"could not get image (string) from file reader when drawing image onto canvas",
imageFromFileReader,
)
}
// put the FileReader image in an Image
const image = new Image()
image.src = imageFromFileReader
// load the image onto a canvas
image.onload = (ev) => {
// create the canvas
const canvasElement = document.createElement("canvas")
if (!canvasElement) {
throw Error("could not get canvas element")
}
// set original dimensions ()
canvasElement.width = image.width
canvasElement.height = image.height
// draw image onto canvas
const canvasContext = canvasElement.getContext("2d")
canvasContext?.drawImage(image, 0, 0)
// @todo use as backup
// get image (as base64 string) in jpeg format
// const imageBase64Jpeg = canvasElement.toDataURL("image/jpg", 100)
// shouldLog && console.log("image base 64 from canvas element", imageBase64Jpeg)
shouldLog && console.log("will photon.open_image canvasElement", canvasElement)
shouldLog && console.log("will photon.open_image canvasContext", canvasContext)
if (!canvasContext) throw Error("could not create canvas context for photon")
initPhoton()
.then((photon) => {
// set max image size (after compression)
let imageSizeReducedByPercentage: number = 0 // 0.1 = 10%
let imageNewWidth = image.width
let imageNewHeight = image.height
// image is large, reduce max size while maintaining aspect ratio
if (image.width > maxSize || image.height > maxSize) {
// image width is the basis for resize
if (image.width > image.height) {
imageSizeReducedByPercentage = Number((maxSize / image.width).toFixed(2))
console.log(`image width will be reduced to ${imageSizeReducedByPercentage}%`)
}
// image height is the basis for resize
else if (image.height > image.width) {
imageSizeReducedByPercentage = Number((maxSize / image.height).toFixed(2))
console.log(`image height will be reduced to ${imageSizeReducedByPercentage}%`)
}
// set reduced image size
imageNewWidth = image.height * imageSizeReducedByPercentage
imageNewHeight = image.height * imageSizeReducedByPercentage
}
// Convert the ImageData found in the canvas to a PhotonImage (so that it can communicate with the core Rust library)
let image_photon = photon__open_image(canvasElement, canvasContext)
// resize the image using rust over wasm ⚡
console.log(`should resize image to ${imageNewWidth}`)
const image_resized = photon__resize(image_photon, imageNewWidth, imageNewHeight, 1)
const { height, width } = image_resized.get_image_data()
canvasElement.height = height
canvasElement.width = width
console.log(`new image size ${imageNewWidth}`)
// place the smaller image back on the smaller canvas
photon__put_image_data(canvasElement, canvasContext, image_resized)
canvasElement.toBlob(async (blob) => {
if (!blob) throw Error("could not convert canvas to blob")
const fileImage = new File([blob], file.name, { type: "image/jpeg" })
resolve(fileImage)
}, "image/jpeg")
})
.catch((error) => {
console.trace("could not resize image with photon", error)
reject(error)
})
}
}
} catch (error) {
console.trace("could not reduce file image size with wasm+photon")
reject(error)
}
})
}
const dropHandler = (ev: DragEvent) => {
shouldLog && console.log("drop handler dataTransfer.items.length: ", ev.dataTransfer?.items?.length)
if (props.field?.disabled) return
let file: File | null = null
const dataTransfer = ev.dataTransfer as DataTransfer
if (dataTransfer.items) {
const dataTransferItemList = dataTransfer.items as DataTransferItemList
for (let i = 0; i < dataTransferItemList.length; i++) {
// If dropped items aren't files, reject them
if (dataTransferItemList[i].kind === "file") {
file = dataTransferItemList[i].getAsFile()
shouldLog && console.log("... file[" + i + "].name = " + file?.name)
}
}
} else {
const dataTransferItemList = dataTransfer.files as FileList
for (let i = 0; i < dataTransferItemList.length; i++) {
shouldLog && console.log("... file[" + i + "].name = " + dataTransferItemList[i].name)
file = dataTransferItemList[i]
}
}
dropToUpload.value = false
const imageFormatIsAccepted = (type: string) => {
const isValidType = allowedMimeTypes.includes(type)
return isValidType
}
if (!imageFormatIsAccepted(file?.type || "")) return
uploadImage(file!)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment