diff options
Diffstat (limited to 'src/client/views/nodes/generativeFill/GenerativeFill.tsx')
-rw-r--r-- | src/client/views/nodes/generativeFill/GenerativeFill.tsx | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx index 6d8ba9222..261eb4bb4 100644 --- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx +++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx @@ -21,19 +21,16 @@ import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { ImageEditorData } from '../ImageBox'; import { OpenWhereMod } from '../OpenWhere'; import './GenerativeFill.scss'; -import Buttons from './GenerativeFillButtons'; -import { BrushHandler } from './generativeFillUtils/BrushHandler'; +import { EditButtons, CutButtons } from './GenerativeFillButtons'; +import { BrushHandler, BrushType } from './generativeFillUtils/BrushHandler'; import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler'; import { PointerHandler } from './generativeFillUtils/PointerHandler'; import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants'; import { CursorData, ImageDimensions, Point } from './generativeFillUtils/generativeFillInterfaces'; import { DocumentView } from '../DocumentView'; - -// enum BrushStyle { -// ADD, -// SUBTRACT, -// MARQUEE, -// } +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { ImageField } from '../../../../fields/URLField'; +import { resolve } from 'url'; interface GenerativeFillProps { imageEditorOpen: boolean; @@ -82,6 +79,9 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD const parentDoc = useRef<Doc | null>(null); const childrenDocs = useRef<Doc[]>([]); + // constants for image cutting + const cutPts = useRef<Point[]>([]); + // Undo and Redo const handleUndo = () => { const ctx = ImageUtility.getCanvasContext(canvasRef); @@ -161,7 +161,8 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD x: currPoint.x - e.movementX / canvasScale, y: currPoint.y - e.movementY / canvasScale, }; - BrushHandler.createBrushPathOverlay(lastPoint, currPoint, cursorData.width / 2 / canvasScale, ctx, eraserColor /* , brushStyle === BrushStyle.SUBTRACT */); + const pts = BrushHandler.createBrushPathOverlay(lastPoint, currPoint, cursorData.width / 2 / canvasScale, ctx, eraserColor, BrushType.CUT); + cutPts.current.push(...pts); }; drawingAreaRef.current?.addEventListener('pointermove', handlePointerMove); @@ -278,7 +279,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD const maskBlob = await ImageUtility.canvasToBlob(canvasMask); const imgBlob = await ImageUtility.canvasToBlob(canvasOriginalImg); const res = await ImageUtility.getEdit(imgBlob, maskBlob, input !== '' ? input + ' in the same style' : 'Fill in the image in the same style', 2); - // const res = await ImageUtility.mockGetEdit(img.src); // create first image if (!newCollectionRef.current) { @@ -334,6 +334,68 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD setLoading(false); }; + const cutImage = async () => { + const img = currImg.current; + const canvas = canvasRef.current; + if (!canvas || !img) return; + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const ctx = ImageUtility.getCanvasContext(canvasRef); + if (!ctx) return; + ctx.globalCompositeOperation = 'source-over'; + setLoading(true); + setEdited(true); + // get the original image + const canvasOriginalImg = ImageUtility.getCanvasImg(img); + if (!canvasOriginalImg) return; + // draw the image onto the canvas + ctx.drawImage(img, 0, 0); + // get the mask which i assume is the thing the user draws on + // const canvasMask = ImageUtility.getCanvasMask(canvas, canvasOriginalImg); + // if (!canvasMask) return; + // canvasMask.width = canvas.width; + // canvasMask.height = canvas.height; + // now put the user's path around the mask + if (cutPts.current.length) { + ctx.beginPath(); + ctx.moveTo(cutPts.current[0].x, cutPts.current[0].y); // later check edge case where cutPts is empty + for (let i = 0; i < cutPts.current.length; i++) { + ctx.lineTo(cutPts.current[i].x, cutPts.current[i].y); + } + ctx.closePath(); + ctx.stroke(); + ctx.fill(); + // ctx.clip(); + } + const url = canvas.toDataURL(); // this does the same thing as convert img to canvasurl + if (!newCollectionRef.current) { + if (!isNewCollection && imageRootDoc) { + // if the parent hasn't been set yet + if (!parentDoc.current) parentDoc.current = imageRootDoc; + } else { + if (!(originalImg.current && imageRootDoc)) return; + // create new collection and add it to the view + newCollectionRef.current = Docs.Create.FreeformDocument([], { + x: NumCast(imageRootDoc.x) + NumCast(imageRootDoc._width) + offsetX, + y: NumCast(imageRootDoc.y), + _width: newCollectionSize, + _height: newCollectionSize, + title: 'Image edit collection', + }); + DocUtils.MakeLink(imageRootDoc, newCollectionRef.current, { link_relationship: 'Image Edit Version History' }); + // opening new tab + CollectionDockingView.AddSplit(newCollectionRef.current, OpenWhereMod.right); + } + } + const image = new Image(); + image.src = url; + await createNewImgDoc(image, true); + // add the doc to the main freeform + // eslint-disable-next-line no-use-before-define + setLoading(false); + cutPts.current.length = 0; + }; + // adjusts all the img positions to be aligned const adjustImgPositions = () => { if (!parentDoc.current) return; @@ -439,6 +501,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD <div className="generativeFillContainer" style={{ display: imageEditorOpen ? 'flex' : 'none' }}> <div className="generativeFillControls"> <h1>Image Editor</h1> + {/* <IconButton text="Cut out" icon={<FontAwesomeIcon icon="scissors" />} /> */} <div style={{ display: 'flex', alignItems: 'center', gap: '1.5rem' }}> <FormControlLabel control={ @@ -455,7 +518,8 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD labelPlacement="end" sx={{ whiteSpace: 'nowrap' }} /> - <Buttons getEdit={getEdit} loading={loading} onReset={handleReset} /> + <EditButtons onClick={getEdit} loading={loading} onReset={handleReset} /> + <CutButtons onClick={cutImage} loading={loading} onReset={handleReset} /> <IconButton color={activeColor} tooltip="close" icon={<CgClose size="16px" />} onClick={handleViewClose} /> </div> </div> @@ -526,6 +590,24 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD }} /> </div> + <div onPointerDown={e => e.stopPropagation()} style={{ height: 225, width: '100%', display: 'flex', justifyContent: 'center', cursor: 'pointer' }}> + <Slider + sx={{ + '& input[type="range"]': { + WebkitAppearance: 'slider-vertical', + }, + }} + orientation="vertical" + min={1} + max={500} + defaultValue={150} + size="small" + valueLabelDisplay="auto" + onChange={(e: any, val: any) => { + setCursorData(prev => ({ ...prev, width: val as number })); + }} + /> + </div> </div> {/* Edits thumbnails */} <div className="editsBox"> |