aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/generativeFill/generativeFillUtils
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
committerbobzel <zzzman@gmail.com>2025-02-10 19:07:20 -0500
commitc9686eaebffb3547b7e0f20aec64754627af76ce (patch)
tree7ebf1c38323a8d7af554ba564acf95cfe79b7709 /src/client/views/nodes/generativeFill/generativeFillUtils
parentb72d018698ad1d2e713f0fcbef392d23bf1cf545 (diff)
parente93ca53af693fa1ec2186ca9417af122bb5e8e09 (diff)
updated from master
Diffstat (limited to 'src/client/views/nodes/generativeFill/generativeFillUtils')
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts35
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts6
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts312
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/PointerHandler.ts11
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts9
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts20
6 files changed, 0 insertions, 393 deletions
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts
deleted file mode 100644
index 8a66d7347..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { GenerativeFillMathHelpers } from './GenerativeFillMathHelpers';
-import { eraserColor } from './generativeFillConstants';
-import { Point } from './generativeFillInterfaces';
-import { points } from '@turf/turf';
-
-export enum BrushType {
- GEN_FILL,
- CUT,
-}
-
-export class BrushHandler {
- static brushCircleOverlay = (x: number, y: number, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string /* , erase: boolean */) => {
- ctx.globalCompositeOperation = 'destination-out';
- ctx.fillStyle = fillColor;
- ctx.shadowColor = eraserColor;
- ctx.shadowBlur = 5;
- ctx.beginPath();
- ctx.arc(x, y, brushRadius, 0, 2 * Math.PI);
- ctx.fill();
- ctx.closePath();
- };
-
- static createBrushPathOverlay = (startPoint: Point, endPoint: Point, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string, brushType: BrushType) => {
- const dist = GenerativeFillMathHelpers.distanceBetween(startPoint, endPoint);
- const pts: Point[] = [];
- for (let i = 0; i < dist; i += 5) {
- const s = i / dist;
- const x = startPoint.x * (1 - s) + endPoint.x * s;
- const y = startPoint.y * (1 - s) + endPoint.y * s;
- pts.push({ x: startPoint.x, y: startPoint.y });
- BrushHandler.brushCircleOverlay(x, y, brushRadius, ctx, fillColor);
- }
- return pts;
- };
-}
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts
deleted file mode 100644
index 6da8c3da0..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { Point } from './generativeFillInterfaces';
-
-export class GenerativeFillMathHelpers {
- static distanceBetween = (p1: Point, p2: Point) => Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
- static angleBetween = (p1: Point, p2: Point) => Math.atan2(p2.x - p1.x, p2.y - p1.y);
-}
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts
deleted file mode 100644
index 24dba1778..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-import { RefObject } from 'react';
-import { bgColor, canvasSize } from './generativeFillConstants';
-
-export interface APISuccess {
- status: 'success';
- urls: string[];
-}
-
-export interface APIError {
- status: 'error';
- message: string;
-}
-
-export class ImageUtility {
- /**
- *
- * @param canvas Canvas to convert
- * @returns Blob of canvas
- */
- static canvasToBlob = (canvas: HTMLCanvasElement): Promise<Blob> =>
- new Promise(resolve => {
- canvas.toBlob(blob => {
- if (blob) {
- resolve(blob);
- }
- }, 'image/png');
- });
-
- // given a square api image, get the cropped img
- static getCroppedImg = (img: HTMLImageElement, width: number, height: number): HTMLCanvasElement | undefined => {
- // Create a new canvas element
- const canvas = document.createElement('canvas');
- canvas.width = width;
- canvas.height = height;
- const ctx = canvas.getContext('2d');
- if (ctx) {
- // Clear the canvas
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- if (width < height) {
- // horizontal padding, x offset
- const xOffset = (canvasSize - width) / 2;
- ctx.drawImage(img, xOffset, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
- } else {
- // vertical padding, y offset
- const yOffset = (canvasSize - height) / 2;
- ctx.drawImage(img, 0, yOffset, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
- }
- return canvas;
- }
- return undefined;
- };
-
- // converts an image to a canvas data url
- static convertImgToCanvasUrl = async (imageSrc: string, width: number, height: number): Promise<string> =>
- new Promise<string>((resolve, reject) => {
- const img = new Image();
- img.onload = () => {
- const canvas = this.getCroppedImg(img, width, height);
- if (canvas) {
- const dataUrl = canvas.toDataURL();
- resolve(dataUrl);
- }
- };
- img.onerror = error => {
- reject(error);
- };
- img.src = imageSrc;
- });
-
- // calls the openai api to get image edits
- static getEdit = async (imgBlob: Blob, maskBlob: Blob, prompt: string, n?: number): Promise<APISuccess | APIError> => {
- const apiUrl = 'https://api.openai.com/v1/images/edits';
- const fd = new FormData();
- fd.append('image', imgBlob, 'image.png');
- fd.append('mask', maskBlob, 'mask.png');
- fd.append('prompt', prompt);
- fd.append('size', '1024x1024');
- fd.append('n', n ? JSON.stringify(n) : '1');
- fd.append('response_format', 'b64_json');
-
- try {
- const res = await fetch(apiUrl, {
- method: 'POST',
- headers: {
- Authorization: `Bearer ${process.env.OPENAI_KEY}`,
- },
- body: fd,
- });
- const data = await res.json();
- console.log(data.data);
- return {
- status: 'success',
- urls: (data.data as { b64_json: string }[]).map(urlData => `data:image/png;base64,${urlData.b64_json}`),
- };
- } catch (err) {
- console.log(err);
- return { status: 'error', message: 'API error.' };
- }
- };
-
- // mock api call
- static mockGetEdit = async (mockSrc: string): Promise<APISuccess | APIError> => ({
- status: 'success',
- urls: [mockSrc, mockSrc, mockSrc],
- });
-
- // Gets the canvas rendering context of a canvas
- static getCanvasContext = (canvasRef: RefObject<HTMLCanvasElement>): CanvasRenderingContext2D | null => {
- if (!canvasRef.current) return null;
- const ctx = canvasRef.current.getContext('2d');
- if (!ctx) return null;
- return ctx;
- };
-
- // Helper for downloading the canvas (for debugging)
- static downloadCanvas = (canvas: HTMLCanvasElement) => {
- const url = canvas.toDataURL();
- const downloadLink = document.createElement('a');
- downloadLink.href = url;
- downloadLink.download = 'canvas';
-
- downloadLink.click();
- downloadLink.remove();
- };
-
- // Download the canvas (for debugging)
- static downloadImageCanvas = (imgUrl: string) => {
- const img = new Image();
- img.src = imgUrl;
- img.onload = () => {
- const canvas = document.createElement('canvas');
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- const ctx = canvas.getContext('2d');
- ctx?.drawImage(img, 0, 0, canvasSize, canvasSize);
-
- this.downloadCanvas(canvas);
- };
- };
-
- // Clears the canvas
- static clearCanvas = (canvasRef: React.RefObject<HTMLCanvasElement>) => {
- const ctx = this.getCanvasContext(canvasRef);
- if (!ctx || !canvasRef.current) return;
- ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
- };
-
- // Draws the image to the current canvas
- static drawImgToCanvas = (img: HTMLImageElement, canvasRef: React.RefObject<HTMLCanvasElement>, width: number, height: number) => {
- const drawImg = (htmlImg: HTMLImageElement) => {
- const ctx = this.getCanvasContext(canvasRef);
- if (!ctx) return;
- ctx.globalCompositeOperation = 'source-over';
- ctx.clearRect(0, 0, width, height);
- ctx.drawImage(htmlImg, 0, 0, width, height);
- };
-
- if (img.complete) {
- drawImg(img);
- } else {
- img.onload = () => {
- drawImg(img);
- };
- }
- };
-
- // Gets the image mask for the openai endpoint
- static getCanvasMask = (srcCanvas: HTMLCanvasElement, paddedCanvas: HTMLCanvasElement): HTMLCanvasElement | undefined => {
- const canvas = document.createElement('canvas');
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- const ctx = canvas.getContext('2d');
- if (!ctx) return undefined;
- ctx?.clearRect(0, 0, canvasSize, canvasSize);
- ctx.drawImage(paddedCanvas, 0, 0);
-
- // extract and set padding data
- if (srcCanvas.height > srcCanvas.width) {
- // horizontal padding, x offset
- const xOffset = (canvasSize - srcCanvas.width) / 2;
- ctx?.clearRect(xOffset, 0, srcCanvas.width, srcCanvas.height);
- ctx.drawImage(srcCanvas, xOffset, 0, srcCanvas.width, srcCanvas.height);
- } else {
- // vertical padding, y offset
- const yOffset = (canvasSize - srcCanvas.height) / 2;
- ctx?.clearRect(0, yOffset, srcCanvas.width, srcCanvas.height);
- ctx.drawImage(srcCanvas, 0, yOffset, srcCanvas.width, srcCanvas.height);
- }
- return canvas;
- };
-
- // Fills in the blank areas of the image with an image reflection (to fill in a square-shaped canvas)
- static drawHorizontalReflection = (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, xOffset: number) => {
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
- const { data } = imageData;
- for (let i = 0; i < canvas.height; i++) {
- for (let j = 0; j < xOffset; j++) {
- const targetIdx = 4 * (i * canvas.width + j);
- const sourceI = i;
- const sourceJ = xOffset + (xOffset - j);
- const sourceIdx = 4 * (sourceI * canvas.width + sourceJ);
- data[targetIdx] = data[sourceIdx];
- data[targetIdx + 1] = data[sourceIdx + 1];
- data[targetIdx + 2] = data[sourceIdx + 2];
- }
- }
- for (let i = 0; i < canvas.height; i++) {
- for (let j = canvas.width - 1; j >= canvas.width - 1 - xOffset; j--) {
- const targetIdx = 4 * (i * canvas.width + j);
- const sourceI = i;
- const sourceJ = canvas.width - 1 - xOffset - (xOffset - (canvas.width - j));
- const sourceIdx = 4 * (sourceI * canvas.width + sourceJ);
- data[targetIdx] = data[sourceIdx];
- data[targetIdx + 1] = data[sourceIdx + 1];
- data[targetIdx + 2] = data[sourceIdx + 2];
- }
- }
- ctx.putImageData(imageData, 0, 0);
- };
-
- // Fills in the blank areas of the image with an image reflection (to fill in a square-shaped canvas)
- static drawVerticalReflection = (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, yOffset: number) => {
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
- const { data } = imageData;
- for (let j = 0; j < canvas.width; j++) {
- for (let i = 0; i < yOffset; i++) {
- const targetIdx = 4 * (i * canvas.width + j);
- const sourceJ = j;
- const sourceI = yOffset + (yOffset - i);
- const sourceIdx = 4 * (sourceI * canvas.width + sourceJ);
- data[targetIdx] = data[sourceIdx];
- data[targetIdx + 1] = data[sourceIdx + 1];
- data[targetIdx + 2] = data[sourceIdx + 2];
- }
- }
- for (let j = 0; j < canvas.width; j++) {
- for (let i = canvas.height - 1; i >= canvas.height - 1 - yOffset; i--) {
- const targetIdx = 4 * (i * canvas.width + j);
- const sourceJ = j;
- const sourceI = canvas.height - 1 - yOffset - (yOffset - (canvas.height - i));
- const sourceIdx = 4 * (sourceI * canvas.width + sourceJ);
- data[targetIdx] = data[sourceIdx];
- data[targetIdx + 1] = data[sourceIdx + 1];
- data[targetIdx + 2] = data[sourceIdx + 2];
- }
- }
- ctx.putImageData(imageData, 0, 0);
- };
-
- // Gets the unaltered (besides filling in padding) version of the image for the api call
- static getCanvasImg = (img: HTMLImageElement): HTMLCanvasElement | undefined => {
- const canvas = document.createElement('canvas');
- canvas.width = canvasSize;
- canvas.height = canvasSize;
- const ctx = canvas.getContext('2d');
- if (!ctx) return undefined;
- // fix scaling
- const scale = Math.min(canvasSize / img.width, canvasSize / img.height);
- const width = Math.floor(img.width * scale);
- const height = Math.floor(img.height * scale);
- ctx?.clearRect(0, 0, canvasSize, canvasSize);
- ctx.fillStyle = bgColor;
- ctx.fillRect(0, 0, canvasSize, canvasSize);
-
- // extract and set padding data
- if (img.naturalHeight > img.naturalWidth) {
- // horizontal padding, x offset
- const xOffset = Math.floor((canvasSize - width) / 2);
- ctx.drawImage(img, xOffset, 0, width, height);
-
- // draw reflected image padding
- this.drawHorizontalReflection(ctx, canvas, xOffset);
- } else {
- // vertical padding, y offset
- const yOffset = Math.floor((canvasSize - height) / 2);
- ctx.drawImage(img, 0, yOffset, width, height);
-
- // draw reflected image padding
- this.drawVerticalReflection(ctx, canvas, yOffset);
- }
- return canvas;
- };
-
- /**
- * Converts a url to base64 (tainted canvas workaround)
- */
- static urlToBase64 = async (imageUrl: string): Promise<string | undefined> => {
- try {
- const res = await fetch(imageUrl);
- const blob = await res.blob();
-
- return new Promise<string>((resolve, reject) => {
- const reader = new FileReader();
- reader.onload = () => {
- const base64Data = reader.result?.toString().split(',')[1];
- if (base64Data) {
- resolve(base64Data);
- } else {
- reject(new Error('Failed to convert.'));
- }
- };
- reader.onerror = () => {
- reject(new Error('Error reading image data'));
- };
- reader.readAsDataURL(blob);
- });
- } catch (err) {
- console.error(err);
- }
- return undefined;
- };
-}
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/PointerHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/PointerHandler.ts
deleted file mode 100644
index 260923a64..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/PointerHandler.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Point } from './generativeFillInterfaces';
-
-export class PointerHandler {
- static getPointRelativeToElement = (element: HTMLElement, e: React.PointerEvent | PointerEvent, scale: number): Point => {
- const boundingBox = element.getBoundingClientRect();
- return {
- x: (e.clientX - boundingBox.x) / scale,
- y: (e.clientY - boundingBox.y) / scale,
- };
- };
-}
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts
deleted file mode 100644
index 4772304bc..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export const canvasSize = 1024;
-export const freeformRenderSize = 300;
-export const offsetDistanceY = freeformRenderSize + 400;
-export const offsetX = 200;
-export const newCollectionSize = 500;
-
-export const activeColor = '#1976d2';
-export const eraserColor = '#e1e9ec';
-export const bgColor = '#f0f4f6';
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts
deleted file mode 100644
index 1e7801056..000000000
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export interface CursorData {
- x: number;
- y: number;
- width: number;
-}
-
-export interface Point {
- x: number;
- y: number;
-}
-
-export enum BrushMode {
- ADD,
- SUBTRACT,
-}
-
-export interface ImageDimensions {
- width: number;
- height: number;
-}