aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/nodes/generativeFill/GenerativeFill.tsx49
-rw-r--r--src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx38
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts19
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts15
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts21
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts1
-rw-r--r--src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts1
7 files changed, 71 insertions, 73 deletions
diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
index 547a76348..998961f20 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
@@ -3,12 +3,12 @@ import React = require('react');
import { useEffect, useRef, useState } from 'react';
import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
import { BrushHandler } from './generativeFillUtils/BrushHandler';
-import { Box, Checkbox, FormControlLabel, IconButton, Slider, TextField } from '@mui/material';
+import { IconButton } from 'browndash-components';
+import { Checkbox, FormControlLabel, Slider, TextField } from '@mui/material';
import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces';
import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
import { PointerHandler } from './generativeFillUtils/PointerHandler';
-import { BsEraser, BsX } from 'react-icons/bs';
-import { CiUndo, CiRedo } from 'react-icons/ci';
+import { IoMdUndo, IoMdRedo } from 'react-icons/io';
import { MainView } from '../../MainView';
import { Doc, DocListCast } from '../../../../fields/Doc';
import { Networking } from '../../../Network';
@@ -19,6 +19,7 @@ import { CollectionDockingView } from '../../collections/CollectionDockingView';
import { OpenWhereMod } from '../DocumentView';
import Buttons from './GenerativeFillButtons';
import { List } from '../../../../fields/List';
+import { CgClose } from 'react-icons/cg';
enum BrushStyle {
ADD,
@@ -432,9 +433,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
sx={{ whiteSpace: 'nowrap' }}
/>
<Buttons getEdit={getEdit} loading={loading} onReset={handleReset} />
- <IconButton onClick={handleViewClose}>
- <BsX color={activeColor} />
- </IconButton>
+ <IconButton color={activeColor} tooltip="close" icon={<CgClose size={'16px'} />} onClick={handleViewClose} />
</div>
</div>
{/* Main canvas for editing */}
@@ -459,40 +458,34 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
</div>
{/* Icons */}
<div className="iconContainer">
- <IconButton
- onClick={() => {
- setBrushStyle(BrushStyle.ADD);
- }}>
- <BsEraser color={brushStyle === BrushStyle.ADD ? activeColor : 'inherit'} />
- </IconButton>
{/* Undo and Redo */}
<IconButton
+ style={{ cursor: 'pointer' }}
onPointerDown={e => {
e.stopPropagation();
handleUndo();
}}
onPointerUp={e => {
e.stopPropagation();
- }}>
- <CiUndo />
- </IconButton>
+ }}
+ color={activeColor}
+ tooltip="Undo"
+ icon={<IoMdUndo />}
+ />
<IconButton
+ style={{ cursor: 'pointer' }}
onPointerDown={e => {
e.stopPropagation();
handleRedo();
}}
onPointerUp={e => {
e.stopPropagation();
- }}>
- <CiRedo />
- </IconButton>
- <Box
- sx={{
- height: 225,
- width: '100%',
- display: 'flex',
- justifyContent: 'center',
- }}>
+ }}
+ color={activeColor}
+ tooltip="Redo"
+ icon={<IoMdRedo />}
+ />
+ <div onPointerDown={e => e.stopPropagation()} style={{ height: 225, width: '100%', display: 'flex', justifyContent: 'center', cursor: 'pointer' }}>
<Slider
sx={{
'& input[type="range"]': {
@@ -500,14 +493,16 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
},
}}
orientation="vertical"
- min={10}
+ min={25}
max={500}
defaultValue={150}
+ size="small"
+ valueLabelDisplay="auto"
onChange={(e, val) => {
setCursorData(prev => ({ ...prev, width: val as number }));
}}
/>
- </Box>
+ </div>
</div>
{/* Edits thumbnails*/}
<div className="editsBox">
diff --git a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
index 398ba5333..0dfcebea3 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
@@ -1,7 +1,8 @@
-import { Button } from '@mui/material';
-import { Oval } from 'react-loader-spinner';
import './GenerativeFillButtons.scss';
import React = require('react');
+import ReactLoading from 'react-loading';
+import { activeColor } from './generativeFillUtils/generativeFillConstants';
+import { Button, Type } from 'browndash-components';
interface ButtonContainerProps {
getEdit: () => Promise<void>;
@@ -12,17 +13,28 @@ interface ButtonContainerProps {
const Buttons = ({ loading, getEdit, onReset }: ButtonContainerProps) => {
return (
<div className="generativeFillBtnContainer">
- <Button onClick={onReset}>Reset</Button>
- <Button
- variant="contained"
- onClick={() => {
- getEdit();
- }}>
- <span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
- Get Edit
- {loading && <Oval height={20} width={20} color="#ffffff" visible={true} ariaLabel="oval-loading" secondaryColor="#ffffff89" strokeWidth={3} strokeWidthSecondary={3} />}
- </span>
- </Button>
+ <Button text="RESET" type={Type.PRIM} color={activeColor} onClick={onReset} />
+ {loading ? (
+ <Button
+ text="GET EDITS"
+ type={Type.TERT}
+ color={activeColor}
+ icon={<ReactLoading type="spin" color={'#ffffff'} width={20} height={20} />}
+ iconPlacement="right"
+ onClick={() => {
+ if (!loading) getEdit();
+ }}
+ />
+ ) : (
+ <Button
+ text="GET EDITS"
+ type={Type.TERT}
+ color={activeColor}
+ onClick={() => {
+ if (!loading) getEdit();
+ }}
+ />
+ )}
</div>
);
};
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts
index ace7ebcae..f4ec70fbc 100644
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts
+++ b/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts
@@ -3,16 +3,6 @@ import { eraserColor } from './generativeFillConstants';
import { Point } from './generativeFillInterfaces';
export class BrushHandler {
- static brushCircle = (x: number, y: number, brushRadius: number, ctx: CanvasRenderingContext2D) => {
- ctx.globalCompositeOperation = 'destination-out';
- ctx.shadowColor = '#ffffffeb';
- ctx.shadowBlur = 5;
- ctx.beginPath();
- ctx.arc(x, y, brushRadius, 0, 2 * Math.PI);
- ctx.fill();
- ctx.closePath();
- };
-
static brushCircleOverlay = (x: number, y: number, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string, erase: boolean) => {
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = fillColor;
@@ -24,15 +14,6 @@ export class BrushHandler {
ctx.closePath();
};
- static createBrushPath = (startPoint: Point, endPoint: Point, brushRadius: number, ctx: CanvasRenderingContext2D) => {
- const dist = GenerativeFillMathHelpers.distanceBetween(startPoint, endPoint);
-
- for (let i = 0; i < dist; i += 5) {
- const s = i / dist;
- BrushHandler.brushCircle(startPoint.x * (1 - s) + endPoint.x * s, startPoint.y * (1 - s) + endPoint.y * s, brushRadius, ctx);
- }
- };
-
static createBrushPathOverlay = (startPoint: Point, endPoint: Point, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string, erase: boolean) => {
const dist = GenerativeFillMathHelpers.distanceBetween(startPoint, endPoint);
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts
index 027b99a52..97e03ff20 100644
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts
+++ b/src/client/views/nodes/generativeFill/generativeFillUtils/GenerativeFillMathHelpers.ts
@@ -1,11 +1,10 @@
-import { Point } from "./generativeFillInterfaces";
+import { Point } from './generativeFillInterfaces';
export class GenerativeFillMathHelpers {
- // math helpers
- static distanceBetween = (p1: Point, p2: Point) => {
- return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
- };
- static angleBetween = (p1: Point, p2: Point) => {
- return Math.atan2(p2.x - p1.x, p2.y - p1.y);
- };
+ static distanceBetween = (p1: Point, p2: Point) => {
+ return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
+ };
+ static angleBetween = (p1: Point, p2: Point) => {
+ return 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
index 4ff70c86c..c6ecedb6b 100644
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts
+++ b/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts
@@ -12,6 +12,11 @@ export interface APIError {
}
export class ImageUtility {
+ /**
+ *
+ * @param canvas Canvas to convert
+ * @returns Blob of canvas
+ */
static canvasToBlob = (canvas: HTMLCanvasElement): Promise<Blob> => {
return new Promise(resolve => {
canvas.toBlob(blob => {
@@ -45,6 +50,7 @@ export class ImageUtility {
}
};
+ // converts an image to a canvas data url
static convertImgToCanvasUrl = async (imageSrc: string, width: number, height: number): Promise<string> => {
return new Promise<string>((resolve, reject) => {
const img = new Image();
@@ -62,6 +68,7 @@ export class ImageUtility {
});
};
+ // 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();
@@ -92,6 +99,7 @@ export class ImageUtility {
}
};
+ // mock api call
static mockGetEdit = async (mockSrc: string): Promise<APISuccess | APIError> => {
return {
status: 'success',
@@ -99,6 +107,7 @@ export class ImageUtility {
};
};
+ // 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');
@@ -106,6 +115,7 @@ export class ImageUtility {
return ctx;
};
+ // Helper for downloading the canvas (for debugging)
static downloadCanvas = (canvas: HTMLCanvasElement) => {
const url = canvas.toDataURL();
const downloadLink = document.createElement('a');
@@ -116,6 +126,7 @@ export class ImageUtility {
downloadLink.remove();
};
+ // Download the canvas (for debugging)
static downloadImageCanvas = (imgUrl: string) => {
const img = new Image();
img.src = imgUrl;
@@ -130,12 +141,14 @@ export class ImageUtility {
};
};
+ // 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 = (img: HTMLImageElement) => {
const ctx = this.getCanvasContext(canvasRef);
@@ -154,7 +167,7 @@ export class ImageUtility {
}
};
- // The image must be loaded!
+ // Gets the image mask for the openai endpoint
static getCanvasMask = (srcCanvas: HTMLCanvasElement, paddedCanvas: HTMLCanvasElement): HTMLCanvasElement | undefined => {
const canvas = document.createElement('canvas');
canvas.width = canvasSize;
@@ -162,8 +175,6 @@ export class ImageUtility {
const ctx = canvas.getContext('2d');
if (!ctx) return;
ctx?.clearRect(0, 0, canvasSize, canvasSize);
- // ctx.fillStyle = bgColor;
- // ctx.fillRect(0, 0, canvasSize, canvasSize);
ctx.drawImage(paddedCanvas, 0, 0);
// extract and set padding data
@@ -181,6 +192,7 @@ export class ImageUtility {
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.data;
@@ -209,6 +221,7 @@ export class ImageUtility {
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.data;
@@ -237,7 +250,7 @@ export class ImageUtility {
ctx.putImageData(imageData, 0, 0);
};
- // The image must be loaded!
+ // 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;
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts
index 1fe151b46..dc94a9368 100644
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts
+++ b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts
@@ -1,4 +1,3 @@
-// constants
export const canvasSize = 512;
export const freeformRenderSize = 300;
export const offsetDistanceY = freeformRenderSize + 400;
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts
index 83a21a1a5..1e7801056 100644
--- a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts
+++ b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillInterfaces.ts
@@ -1,4 +1,3 @@
-// interfaces
export interface CursorData {
x: number;
y: number;