tldraw
Version:
A tiny little drawing editor.
96 lines (89 loc) • 2.37 kB
text/typescript
import { MediaHelpers, assertExists, clampToBrowserMaxCanvasSize } from '@tldraw/editor'
/** @public */
export interface BoxWidthHeight {
w: number
h: number
}
/**
* Contains the size within the given box size
*
* @param originalSize - The size of the asset
* @param containBoxSize - The container size
* @returns Adjusted size
* @public
*/
export function containBoxSize(
originalSize: BoxWidthHeight,
containBoxSize: BoxWidthHeight
): BoxWidthHeight {
const overByXScale = originalSize.w / containBoxSize.w
const overByYScale = originalSize.h / containBoxSize.h
if (overByXScale <= 1 && overByYScale <= 1) {
return originalSize
} else if (overByXScale > overByYScale) {
return {
w: originalSize.w / overByXScale,
h: originalSize.h / overByXScale,
}
} else {
return {
w: originalSize.w / overByYScale,
h: originalSize.h / overByYScale,
}
}
}
/**
* Resize an image Blob to be smaller than it is currently.
*
* @example
* ```ts
* const image = await (await fetch('/image.jpg')).blob()
* const size = await getImageSize(image)
* const resizedImage = await downsizeImage(image, size.w / 2, size.h / 2, { type: "image/jpeg", quality: 0.85 })
* ```
*
* @param image - The image Blob.
* @param width - The desired width.
* @param height - The desired height.
* @param opts - Options for the image.
* @public
*/
export async function downsizeImage(
blob: Blob,
width: number,
height: number,
opts = {} as { type?: string; quality?: number }
): Promise<Blob> {
const { w, h, image } = await MediaHelpers.usingObjectURL(
blob,
MediaHelpers.getImageAndDimensions
)
const { type = blob.type, quality = 0.85 } = opts
const [desiredWidth, desiredHeight] = clampToBrowserMaxCanvasSize(
Math.min(width * 2, w),
Math.min(height * 2, h)
)
const canvas = document.createElement('canvas')
canvas.width = desiredWidth
canvas.height = desiredHeight
const ctx = assertExists(
canvas.getContext('2d', { willReadFrequently: true }),
'Could not get canvas context'
)
ctx.imageSmoothingEnabled = true
ctx.imageSmoothingQuality = 'high'
ctx.drawImage(image, 0, 0, desiredWidth, desiredHeight)
return new Promise((resolve, reject) => {
canvas.toBlob(
(blob) => {
if (blob) {
resolve(blob)
} else {
reject(new Error('Could not resize image'))
}
},
type,
quality
)
})
}