|
import { SyntheticEvent, useEffect, useState } from 'react' |
|
|
|
export function dataURItoBlob(dataURI: string) { |
|
const mime = dataURI.split(',')[0].split(':')[1].split(';')[0] |
|
const binary = atob(dataURI.split(',')[1]) |
|
const array = [] |
|
for (let i = 0; i < binary.length; i += 1) { |
|
array.push(binary.charCodeAt(i)) |
|
} |
|
return new Blob([new Uint8Array(array)], { type: mime }) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function downloadImage(uri: string, name: string) { |
|
const link = document.createElement('a') |
|
link.href = uri |
|
link.download = name |
|
|
|
|
|
link.dispatchEvent( |
|
new MouseEvent('click', { |
|
bubbles: true, |
|
cancelable: true, |
|
view: window, |
|
}) |
|
) |
|
|
|
setTimeout(() => { |
|
|
|
|
|
link.remove() |
|
}, 100) |
|
} |
|
|
|
export function shareImage(base64: string, name: string) { |
|
const blob = dataURItoBlob(base64) |
|
const filesArray = [new File([blob], name, { type: 'image/jpeg' })] |
|
const shareData = { |
|
files: filesArray, |
|
} |
|
|
|
const nav: any = navigator |
|
const canShare = nav.canShare && nav.canShare(shareData) |
|
const userAgent = navigator.userAgent || navigator.vendor |
|
const isMobile = /android|iPad|iPhone|iPod/i.test(userAgent) |
|
if (canShare && isMobile) { |
|
navigator.share(shareData) |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
export function loadImage(image: HTMLImageElement, src: string) { |
|
return new Promise((resolve, reject) => { |
|
const initSRC = image.src |
|
const img = image |
|
img.onload = resolve |
|
img.onerror = err => { |
|
img.src = initSRC |
|
reject(err) |
|
} |
|
img.src = src |
|
}) |
|
} |
|
|
|
export function useImage(file?: File): [HTMLImageElement, boolean] { |
|
const [image] = useState(new Image()) |
|
const [isLoaded, setIsLoaded] = useState(false) |
|
|
|
useEffect(() => { |
|
if (file === undefined) { |
|
return |
|
} |
|
image.onload = () => { |
|
setIsLoaded(true) |
|
} |
|
setIsLoaded(false) |
|
image.src = URL.createObjectURL(file) |
|
return () => { |
|
image.onload = null |
|
} |
|
}, [file, image]) |
|
|
|
return [image, isLoaded] |
|
} |
|
|
|
|
|
interface ResizeImageFileResult { |
|
file: File |
|
resized: boolean |
|
originalWidth?: number |
|
originalHeight?: number |
|
} |
|
export function resizeImageFile( |
|
file: File, |
|
maxSize: number |
|
): Promise<ResizeImageFileResult> { |
|
const reader = new FileReader() |
|
const image = new Image() |
|
const canvas = document.createElement('canvas') |
|
|
|
const resize = (): ResizeImageFileResult => { |
|
let { width, height } = image |
|
|
|
if (width > height) { |
|
if (width > maxSize) { |
|
height *= maxSize / width |
|
width = maxSize |
|
} |
|
} else if (height > maxSize) { |
|
width *= maxSize / height |
|
height = maxSize |
|
} |
|
|
|
if (width === image.width && height === image.height) { |
|
return { file, resized: false } |
|
} |
|
|
|
canvas.width = width |
|
canvas.height = height |
|
const ctx = canvas.getContext('2d') |
|
if (!ctx) { |
|
throw new Error('could not get context') |
|
} |
|
canvas.getContext('2d')?.drawImage(image, 0, 0, width, height) |
|
const dataUrl = canvas.toDataURL('image/jpeg') |
|
const blob = dataURItoBlob(dataUrl) |
|
const f = new File([blob], file.name, { |
|
type: file.type, |
|
}) |
|
return { |
|
file: f, |
|
resized: true, |
|
originalWidth: image.width, |
|
originalHeight: image.height, |
|
} |
|
} |
|
|
|
return new Promise((resolve, reject) => { |
|
if (!file.type.match(/image.*/)) { |
|
reject(new Error('Not an image')) |
|
return |
|
} |
|
reader.onload = (readerEvent: any) => { |
|
image.onload = () => resolve(resize()) |
|
image.src = readerEvent.target.result |
|
} |
|
reader.readAsDataURL(file) |
|
}) |
|
} |
|
|
|
export function keepGUIAlive() { |
|
async function getRequest(url = '') { |
|
const response = await fetch(url, { |
|
method: 'GET', |
|
cache: 'no-cache', |
|
}) |
|
return response.json() |
|
} |
|
|
|
const keepAliveServer = () => { |
|
const url = document.location |
|
const route = '/flaskwebgui-keep-server-alive' |
|
getRequest(url + route).then(data => { |
|
return data |
|
}) |
|
} |
|
|
|
const intervalRequest = 3 * 1000 |
|
keepAliveServer() |
|
setInterval(keepAliveServer, intervalRequest) |
|
} |
|
|
|
export function isRightClick(ev: SyntheticEvent) { |
|
const mouseEvent = ev.nativeEvent as MouseEvent |
|
return mouseEvent.button === 2 |
|
} |
|
|
|
export function isMidClick(ev: SyntheticEvent) { |
|
const mouseEvent = ev.nativeEvent as MouseEvent |
|
return mouseEvent.button === 1 |
|
} |
|
|
|
export function srcToFile(src: string, fileName: string, mimeType: string) { |
|
return fetch(src) |
|
.then(function (res) { |
|
return res.arrayBuffer() |
|
}) |
|
.then(function (buf) { |
|
return new File([buf], fileName, { type: mimeType }) |
|
}) |
|
} |
|
|
|
export async function askWritePermission() { |
|
try { |
|
|
|
|
|
const { state } = await navigator.permissions.query({ |
|
name: 'clipboard-write' as PermissionName, |
|
}) |
|
return state === 'granted' |
|
} catch (error) { |
|
|
|
return false |
|
} |
|
} |
|
|
|
function canvasToBlob(canvas: HTMLCanvasElement, mime: string): Promise<any> { |
|
return new Promise((resolve, reject) => |
|
canvas.toBlob(async d => { |
|
if (d) { |
|
resolve(d) |
|
} else { |
|
reject(new Error('Expected toBlob() to be defined')) |
|
} |
|
}, mime) |
|
) |
|
} |
|
|
|
const setToClipboard = async (blob: any) => { |
|
const data = [new ClipboardItem({ [blob.type]: blob })] |
|
await navigator.clipboard.write(data) |
|
} |
|
|
|
export async function copyCanvasImage(canvas: HTMLCanvasElement) { |
|
const blob = await canvasToBlob(canvas, 'image/png') |
|
try { |
|
await setToClipboard(blob) |
|
} catch { |
|
console.log('Copy image failed!') |
|
} |
|
} |
|
|