Spaces:
Paused
Paused
| /** | |
| * Copyright (c) Meta Platforms, Inc. and affiliates. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| export function convertVideoFrameToImageData( | |
| videoFrame: VideoFrame, | |
| ): ImageData | undefined { | |
| const canvas = new OffscreenCanvas( | |
| videoFrame.displayWidth, | |
| videoFrame.displayHeight, | |
| ); | |
| const ctx = canvas.getContext('2d'); | |
| ctx?.drawImage(videoFrame, 0, 0); | |
| return ctx?.getImageData(0, 0, canvas.width, canvas.height); | |
| } | |
| /** | |
| * This utility provides two functions: | |
| * `process`: to find the bounding box of non-empty pixels from an ImageData, when looping through all its pixels | |
| * `crop` to cut out the subsection found in `process` | |
| * @returns | |
| */ | |
| export function findBoundingBox() { | |
| let xMin = Number.MAX_VALUE; | |
| let yMin = Number.MAX_VALUE; | |
| let xMax = Number.MIN_VALUE; | |
| let yMax = Number.MIN_VALUE; | |
| return { | |
| process: function (x: number, y: number, hasData: boolean) { | |
| if (hasData) { | |
| xMin = Math.min(x, xMin); | |
| xMax = Math.max(x, xMax); | |
| yMin = Math.min(y, yMin); | |
| yMax = Math.max(y, yMax); | |
| } | |
| return [xMin, xMax, yMin, yMax]; | |
| }, | |
| crop(imageData: ImageData): ImageData | null { | |
| const canvas = new OffscreenCanvas(imageData.width, imageData.height); | |
| const ctx = canvas.getContext('2d'); | |
| const boundingBoxWidth = xMax - xMin; | |
| const boundingBoxHeight = yMax - yMin; | |
| if (ctx && boundingBoxWidth > 0 && boundingBoxHeight > 0) { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| ctx.putImageData(imageData, 0, 0); | |
| return ctx.getImageData( | |
| xMin, | |
| yMin, | |
| boundingBoxWidth, | |
| boundingBoxHeight, | |
| ); | |
| } else { | |
| return null; | |
| } | |
| }, | |
| getBox(): [[number, number], [number, number]] { | |
| return [ | |
| [xMin, yMin], | |
| [xMax, yMax], | |
| ]; | |
| }, | |
| }; | |
| } | |
| export function magnifyImageRegion( | |
| canvas: HTMLCanvasElement | null, | |
| x: number, | |
| y: number, | |
| radius: number = 25, | |
| scale: number = 2, | |
| ): string { | |
| if (canvas == null) { | |
| return ''; | |
| } | |
| const ctx = canvas.getContext('2d'); | |
| if (ctx) { | |
| const minX = x - radius < 0 ? radius - x : 0; | |
| const minY = y - radius < 0 ? radius - y : 0; | |
| const region = ctx.getImageData( | |
| Math.max(x - radius, 0), | |
| Math.max(y - radius, 0), | |
| radius * 2, | |
| radius * 2, | |
| ); | |
| // ImageData doesn't scale-transform correctly on canvas | |
| // So we first draw the original size on an offscreen canvas, and then scale it | |
| const regionCanvas = new OffscreenCanvas(region.width, region.height); | |
| const regionCtx = regionCanvas.getContext('2d'); | |
| regionCtx?.putImageData(region, minX > 0 ? minX : 0, minY > 0 ? minY : 0); | |
| const scaleCanvas = document.createElement('canvas'); | |
| scaleCanvas.width = Math.round(region.width * scale); | |
| scaleCanvas.height = Math.round(region.height * scale); | |
| const scaleCtx = scaleCanvas.getContext('2d'); | |
| scaleCtx?.scale(scale, scale); | |
| scaleCtx?.drawImage(regionCanvas, 0, 0); | |
| return scaleCanvas.toDataURL(); | |
| } | |
| return ''; | |
| } | |