Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
ComfyUI
Commits
8112a0d9
Unverified
Commit
8112a0d9
authored
Dec 06, 2023
by
Dr.Lt.Data
Committed by
GitHub
Dec 06, 2023
Browse files
improve: Mask Editor (#2171)
* renewal mask editor * fix: ignoring keydown when 2nd open
parent
ef295420
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
251 additions
and
105 deletions
+251
-105
web/extensions/core/maskeditor.js
web/extensions/core/maskeditor.js
+251
-105
No files found.
web/extensions/core/maskeditor.js
View file @
8112a0d9
...
...
@@ -33,6 +33,18 @@ function loadedImageToBlob(image) {
return
blob
;
}
function
loadImage
(
imagePath
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
const
image
=
new
Image
();
image
.
onload
=
function
()
{
resolve
(
image
);
};
image
.
src
=
imagePath
;
});
}
async
function
uploadMask
(
filepath
,
formData
)
{
await
api
.
fetchApi
(
'
/upload/mask
'
,
{
method
:
'
POST
'
,
...
...
@@ -50,25 +62,25 @@ async function uploadMask(filepath, formData) {
ClipspaceDialog
.
invalidatePreview
();
}
function
prepare
RGB
(
image
,
backup
Canvas
,
backup
Ctx
)
{
function
prepare
_mask
(
image
,
mask
Canvas
,
mask
Ctx
)
{
// paste mask data into alpha channel
backup
Ctx
.
drawImage
(
image
,
0
,
0
,
backup
Canvas
.
width
,
backup
Canvas
.
height
);
const
backup
Data
=
backup
Ctx
.
getImageData
(
0
,
0
,
backup
Canvas
.
width
,
backup
Canvas
.
height
);
mask
Ctx
.
drawImage
(
image
,
0
,
0
,
mask
Canvas
.
width
,
mask
Canvas
.
height
);
const
mask
Data
=
mask
Ctx
.
getImageData
(
0
,
0
,
mask
Canvas
.
width
,
mask
Canvas
.
height
);
//
refine mask image
for
(
let
i
=
0
;
i
<
backup
Data
.
data
.
length
;
i
+=
4
)
{
if
(
backup
Data
.
data
[
i
+
3
]
==
255
)
backup
Data
.
data
[
i
+
3
]
=
0
;
//
invert mask
for
(
let
i
=
0
;
i
<
mask
Data
.
data
.
length
;
i
+=
4
)
{
if
(
mask
Data
.
data
[
i
+
3
]
==
255
)
mask
Data
.
data
[
i
+
3
]
=
0
;
else
backup
Data
.
data
[
i
+
3
]
=
255
;
mask
Data
.
data
[
i
+
3
]
=
255
;
backup
Data
.
data
[
i
]
=
0
;
backup
Data
.
data
[
i
+
1
]
=
0
;
backup
Data
.
data
[
i
+
2
]
=
0
;
mask
Data
.
data
[
i
]
=
0
;
mask
Data
.
data
[
i
+
1
]
=
0
;
mask
Data
.
data
[
i
+
2
]
=
0
;
}
backup
Ctx
.
globalCompositeOperation
=
'
source-over
'
;
backup
Ctx
.
putImageData
(
backup
Data
,
0
,
0
);
mask
Ctx
.
globalCompositeOperation
=
'
source-over
'
;
mask
Ctx
.
putImageData
(
mask
Data
,
0
,
0
);
}
class
MaskEditorDialog
extends
ComfyDialog
{
...
...
@@ -184,14 +196,13 @@ class MaskEditorDialog extends ComfyDialog {
this
.
element
.
appendChild
(
bottom_panel
);
document
.
body
.
appendChild
(
brush
);
var
brush_size_slider
=
this
.
createLeftSlider
(
self
,
"
Thickness
"
,
(
event
)
=>
{
this
.
brush_size_slider
=
this
.
createLeftSlider
(
self
,
"
Thickness
"
,
(
event
)
=>
{
self
.
brush_size
=
event
.
target
.
value
;
self
.
updateBrushPreview
(
self
,
null
,
null
);
});
var
clearButton
=
this
.
createLeftButton
(
"
Clear
"
,
()
=>
{
self
.
maskCtx
.
clearRect
(
0
,
0
,
self
.
maskCanvas
.
width
,
self
.
maskCanvas
.
height
);
self
.
backupCtx
.
clearRect
(
0
,
0
,
self
.
backupCanvas
.
width
,
self
.
backupCanvas
.
height
);
});
var
cancelButton
=
this
.
createRightButton
(
"
Cancel
"
,
()
=>
{
document
.
removeEventListener
(
"
mouseup
"
,
MaskEditorDialog
.
handleMouseUp
);
...
...
@@ -213,34 +224,37 @@ class MaskEditorDialog extends ComfyDialog {
bottom_panel
.
appendChild
(
clearButton
);
bottom_panel
.
appendChild
(
this
.
saveButton
);
bottom_panel
.
appendChild
(
cancelButton
);
bottom_panel
.
appendChild
(
brush_size_slider
);
bottom_panel
.
appendChild
(
this
.
brush_size_slider
);
imgCanvas
.
style
.
position
=
"
absolute
"
;
maskCanvas
.
style
.
position
=
"
absolute
"
;
imgCanvas
.
style
.
position
=
"
relative
"
;
imgCanvas
.
style
.
top
=
"
200
"
;
imgCanvas
.
style
.
left
=
"
0
"
;
maskCanvas
.
style
.
position
=
"
absolute
"
;
maskCanvas
.
style
.
top
=
imgCanvas
.
style
.
top
;
maskCanvas
.
style
.
left
=
imgCanvas
.
style
.
left
;
}
show
()
{
async
show
()
{
this
.
zoom_ratio
=
1.0
;
this
.
pan_x
=
0
;
this
.
pan_y
=
0
;
if
(
!
this
.
is_layout_created
)
{
// layout
const
imgCanvas
=
document
.
createElement
(
'
canvas
'
);
const
maskCanvas
=
document
.
createElement
(
'
canvas
'
);
const
backupCanvas
=
document
.
createElement
(
'
canvas
'
);
imgCanvas
.
id
=
"
imageCanvas
"
;
maskCanvas
.
id
=
"
maskCanvas
"
;
backupCanvas
.
id
=
"
backupCanvas
"
;
this
.
setlayout
(
imgCanvas
,
maskCanvas
);
// prepare content
this
.
imgCanvas
=
imgCanvas
;
this
.
maskCanvas
=
maskCanvas
;
this
.
backupCanvas
=
backupCanvas
;
this
.
maskCtx
=
maskCanvas
.
getContext
(
'
2d
'
);
this
.
backupCtx
=
backupCanvas
.
getContext
(
'
2d
'
);
this
.
maskCtx
=
maskCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
this
.
setEventHandler
(
maskCanvas
);
...
...
@@ -252,6 +266,8 @@ class MaskEditorDialog extends ComfyDialog {
mutations
.
forEach
(
function
(
mutation
)
{
if
(
mutation
.
type
===
'
attributes
'
&&
mutation
.
attributeName
===
'
style
'
)
{
if
(
self
.
last_display_style
&&
self
.
last_display_style
!=
'
none
'
&&
self
.
element
.
style
.
display
==
'
none
'
)
{
document
.
removeEventListener
(
"
mouseup
"
,
MaskEditorDialog
.
handleMouseUp
);
self
.
brush
.
style
.
display
=
"
none
"
;
ComfyApp
.
onClipspaceEditorClosed
();
}
...
...
@@ -264,7 +280,8 @@ class MaskEditorDialog extends ComfyDialog {
observer
.
observe
(
this
.
element
,
config
);
}
this
.
setImages
(
this
.
imgCanvas
,
this
.
backupCanvas
);
// The keydown event needs to be reconfigured when closing the dialog as it gets removed.
document
.
addEventListener
(
'
keydown
'
,
MaskEditorDialog
.
handleKeyDown
);
if
(
ComfyApp
.
clipspace_return_node
)
{
this
.
saveButton
.
innerText
=
"
Save to node
"
;
...
...
@@ -275,97 +292,157 @@ class MaskEditorDialog extends ComfyDialog {
this
.
saveButton
.
disabled
=
false
;
this
.
element
.
style
.
display
=
"
block
"
;
this
.
element
.
style
.
width
=
"
85%
"
;
this
.
element
.
style
.
margin
=
"
0 7.5%
"
;
this
.
element
.
style
.
height
=
"
100vh
"
;
this
.
element
.
style
.
top
=
"
50%
"
;
this
.
element
.
style
.
left
=
"
42%
"
;
this
.
element
.
style
.
zIndex
=
8888
;
// NOTE: alert dialog must be high priority.
await
this
.
setImages
(
this
.
imgCanvas
);
this
.
is_visible
=
true
;
}
isOpened
()
{
return
this
.
element
.
style
.
display
==
"
block
"
;
}
setImages
(
imgCanvas
,
backupCanvas
)
{
const
imgCtx
=
imgCanvas
.
getContext
(
'
2d
'
);
const
backupCtx
=
backupCanvas
.
getContext
(
'
2d
'
);
invalidateCanvas
(
orig_image
,
mask_image
)
{
this
.
imgCanvas
.
width
=
orig_image
.
width
;
this
.
imgCanvas
.
height
=
orig_image
.
height
;
this
.
maskCanvas
.
width
=
orig_image
.
width
;
this
.
maskCanvas
.
height
=
orig_image
.
height
;
let
imgCtx
=
this
.
imgCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
let
maskCtx
=
this
.
maskCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
imgCtx
.
drawImage
(
orig_image
,
0
,
0
,
orig_image
.
width
,
orig_image
.
height
);
prepare_mask
(
mask_image
,
this
.
maskCanvas
,
maskCtx
);
}
async
setImages
(
imgCanvas
)
{
let
self
=
this
;
const
imgCtx
=
imgCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
const
maskCtx
=
this
.
maskCtx
;
const
maskCanvas
=
this
.
maskCanvas
;
backupCtx
.
clearRect
(
0
,
0
,
this
.
backupCanvas
.
width
,
this
.
backupCanvas
.
height
);
imgCtx
.
clearRect
(
0
,
0
,
this
.
imgCanvas
.
width
,
this
.
imgCanvas
.
height
);
maskCtx
.
clearRect
(
0
,
0
,
this
.
maskCanvas
.
width
,
this
.
maskCanvas
.
height
);
// image load
const
orig_image
=
new
Image
();
window
.
addEventListener
(
"
resize
"
,
()
=>
{
// repositioning
imgCanvas
.
width
=
window
.
innerWidth
-
250
;
imgCanvas
.
height
=
window
.
innerHeight
-
200
;
// redraw image
let
drawWidth
=
orig_image
.
width
;
let
drawHeight
=
orig_image
.
height
;
if
(
orig_image
.
width
>
imgCanvas
.
width
)
{
drawWidth
=
imgCanvas
.
width
;
drawHeight
=
(
drawWidth
/
orig_image
.
width
)
*
orig_image
.
height
;
}
if
(
drawHeight
>
imgCanvas
.
height
)
{
drawHeight
=
imgCanvas
.
height
;
drawWidth
=
(
drawHeight
/
orig_image
.
height
)
*
orig_image
.
width
;
}
imgCtx
.
drawImage
(
orig_image
,
0
,
0
,
drawWidth
,
drawHeight
);
// update mask
maskCanvas
.
width
=
drawWidth
;
maskCanvas
.
height
=
drawHeight
;
maskCanvas
.
style
.
top
=
imgCanvas
.
offsetTop
+
"
px
"
;
maskCanvas
.
style
.
left
=
imgCanvas
.
offsetLeft
+
"
px
"
;
backupCtx
.
drawImage
(
maskCanvas
,
0
,
0
,
maskCanvas
.
width
,
maskCanvas
.
height
,
0
,
0
,
backupCanvas
.
width
,
backupCanvas
.
height
);
maskCtx
.
drawImage
(
backupCanvas
,
0
,
0
,
backupCanvas
.
width
,
backupCanvas
.
height
,
0
,
0
,
maskCanvas
.
width
,
maskCanvas
.
height
);
});
const
filepath
=
ComfyApp
.
clipspace
.
images
;
const
touched_image
=
new
Image
();
touched_image
.
onload
=
function
()
{
backupCanvas
.
width
=
touched_image
.
width
;
backupCanvas
.
height
=
touched_image
.
height
;
prepareRGB
(
touched_image
,
backupCanvas
,
backupCtx
);
};
const
alpha_url
=
new
URL
(
ComfyApp
.
clipspace
.
imgs
[
ComfyApp
.
clipspace
[
'
selectedIndex
'
]].
src
)
alpha_url
.
searchParams
.
delete
(
'
channel
'
);
alpha_url
.
searchParams
.
delete
(
'
preview
'
);
alpha_url
.
searchParams
.
set
(
'
channel
'
,
'
a
'
);
touched_image
.
src
=
alpha_url
;
let
mask_image
=
await
loadImage
(
alpha_url
)
;
// original image load
orig_image
.
onload
=
function
()
{
window
.
dispatchEvent
(
new
Event
(
'
resize
'
));
};
const
rgb_url
=
new
URL
(
ComfyApp
.
clipspace
.
imgs
[
ComfyApp
.
clipspace
[
'
selectedIndex
'
]].
src
);
rgb_url
.
searchParams
.
delete
(
'
channel
'
);
rgb_url
.
searchParams
.
set
(
'
channel
'
,
'
rgb
'
);
orig_image
.
src
=
rgb_url
;
this
.
image
=
orig_image
;
this
.
image
=
new
Image
();
this
.
image
.
onload
=
function
()
{
maskCanvas
.
width
=
self
.
image
.
width
;
maskCanvas
.
height
=
self
.
image
.
height
;
self
.
invalidateCanvas
(
self
.
image
,
mask_image
);
self
.
initializeCanvasPanZoom
();
};
this
.
image
.
src
=
rgb_url
;
}
setEventHandler
(
maskCanvas
)
{
maskCanvas
.
addEventListener
(
"
contextmenu
"
,
(
event
)
=>
{
event
.
preventDefault
();
});
initializeCanvasPanZoom
()
{
// set initialize
let
drawWidth
=
this
.
image
.
width
;
let
drawHeight
=
this
.
image
.
height
;
let
width
=
this
.
element
.
clientWidth
;
let
height
=
this
.
element
.
clientHeight
;
if
(
this
.
image
.
width
>
width
)
{
drawWidth
=
width
;
drawHeight
=
(
drawWidth
/
this
.
image
.
width
)
*
this
.
image
.
height
;
}
if
(
drawHeight
>
height
)
{
drawHeight
=
height
;
drawWidth
=
(
drawHeight
/
this
.
image
.
height
)
*
this
.
image
.
width
;
}
this
.
zoom_ratio
=
drawWidth
/
this
.
image
.
width
;
const
canvasX
=
(
width
-
drawWidth
)
/
2
;
const
canvasY
=
(
height
-
drawHeight
)
/
2
;
this
.
pan_x
=
canvasX
;
this
.
pan_y
=
canvasY
;
this
.
invalidatePanZoom
();
}
invalidatePanZoom
()
{
let
raw_width
=
this
.
image
.
width
*
this
.
zoom_ratio
;
let
raw_height
=
this
.
image
.
height
*
this
.
zoom_ratio
;
if
(
this
.
pan_x
+
raw_width
<
10
)
{
this
.
pan_x
=
10
-
raw_width
;
}
if
(
this
.
pan_y
+
raw_height
<
10
)
{
this
.
pan_y
=
10
-
raw_height
;
}
let
width
=
`
${
raw_width
}
px`
;
let
height
=
`
${
raw_height
}
px`
;
let
left
=
`
${
this
.
pan_x
}
px`
;
let
top
=
`
${
this
.
pan_y
}
px`
;
this
.
maskCanvas
.
style
.
width
=
width
;
this
.
maskCanvas
.
style
.
height
=
height
;
this
.
maskCanvas
.
style
.
left
=
left
;
this
.
maskCanvas
.
style
.
top
=
top
;
this
.
imgCanvas
.
style
.
width
=
width
;
this
.
imgCanvas
.
style
.
height
=
height
;
this
.
imgCanvas
.
style
.
left
=
left
;
this
.
imgCanvas
.
style
.
top
=
top
;
}
setEventHandler
(
maskCanvas
)
{
const
self
=
this
;
maskCanvas
.
addEventListener
(
'
wheel
'
,
(
event
)
=>
this
.
handleWheelEvent
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
pointerdown
'
,
(
event
)
=>
this
.
handlePointerDown
(
self
,
event
));
document
.
addEventListener
(
'
pointerup
'
,
MaskEditorDialog
.
handlePointerUp
);
maskCanvas
.
addEventListener
(
'
pointermove
'
,
(
event
)
=>
this
.
draw_move
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
touchmove
'
,
(
event
)
=>
this
.
draw_move
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
pointerover
'
,
(
event
)
=>
{
this
.
brush
.
style
.
display
=
"
block
"
;
});
maskCanvas
.
addEventListener
(
'
pointerleave
'
,
(
event
)
=>
{
this
.
brush
.
style
.
display
=
"
none
"
;
});
document
.
addEventListener
(
'
keydown
'
,
MaskEditorDialog
.
handleKeyDown
);
if
(
!
this
.
handler_registered
)
{
maskCanvas
.
addEventListener
(
"
contextmenu
"
,
(
event
)
=>
{
event
.
preventDefault
();
});
this
.
element
.
addEventListener
(
'
wheel
'
,
(
event
)
=>
this
.
handleWheelEvent
(
self
,
event
));
this
.
element
.
addEventListener
(
'
pointermove
'
,
(
event
)
=>
this
.
pointMoveEvent
(
self
,
event
));
this
.
element
.
addEventListener
(
'
touchmove
'
,
(
event
)
=>
this
.
pointMoveEvent
(
self
,
event
));
this
.
element
.
addEventListener
(
'
dragstart
'
,
(
event
)
=>
{
if
(
event
.
ctrlKey
)
{
event
.
preventDefault
();
}
});
maskCanvas
.
addEventListener
(
'
pointerdown
'
,
(
event
)
=>
this
.
handlePointerDown
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
pointermove
'
,
(
event
)
=>
this
.
draw_move
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
touchmove
'
,
(
event
)
=>
this
.
draw_move
(
self
,
event
));
maskCanvas
.
addEventListener
(
'
pointerover
'
,
(
event
)
=>
{
this
.
brush
.
style
.
display
=
"
block
"
;
});
maskCanvas
.
addEventListener
(
'
pointerleave
'
,
(
event
)
=>
{
this
.
brush
.
style
.
display
=
"
none
"
;
});
document
.
addEventListener
(
'
pointerup
'
,
MaskEditorDialog
.
handlePointerUp
);
this
.
handler_registered
=
true
;
}
}
brush_size
=
10
;
...
...
@@ -378,8 +455,10 @@ class MaskEditorDialog extends ComfyDialog {
const
self
=
MaskEditorDialog
.
instance
;
if
(
event
.
key
===
'
]
'
)
{
self
.
brush_size
=
Math
.
min
(
self
.
brush_size
+
2
,
100
);
self
.
brush_slider_input
.
value
=
self
.
brush_size
;
}
else
if
(
event
.
key
===
'
[
'
)
{
self
.
brush_size
=
Math
.
max
(
self
.
brush_size
-
2
,
1
);
self
.
brush_slider_input
.
value
=
self
.
brush_size
;
}
else
if
(
event
.
key
===
'
Enter
'
)
{
self
.
save
();
}
...
...
@@ -389,6 +468,10 @@ class MaskEditorDialog extends ComfyDialog {
static
handlePointerUp
(
event
)
{
event
.
preventDefault
();
this
.
mousedown_x
=
null
;
this
.
mousedown_y
=
null
;
MaskEditorDialog
.
instance
.
drawing_mode
=
false
;
}
...
...
@@ -398,24 +481,70 @@ class MaskEditorDialog extends ComfyDialog {
var
centerX
=
self
.
cursorX
;
var
centerY
=
self
.
cursorY
;
brush
.
style
.
width
=
self
.
brush_size
*
2
+
"
px
"
;
brush
.
style
.
height
=
self
.
brush_size
*
2
+
"
px
"
;
brush
.
style
.
left
=
(
centerX
-
self
.
brush_size
)
+
"
px
"
;
brush
.
style
.
top
=
(
centerY
-
self
.
brush_size
)
+
"
px
"
;
brush
.
style
.
width
=
self
.
brush_size
*
2
*
this
.
zoom_ratio
+
"
px
"
;
brush
.
style
.
height
=
self
.
brush_size
*
2
*
this
.
zoom_ratio
+
"
px
"
;
brush
.
style
.
left
=
(
centerX
-
self
.
brush_size
*
this
.
zoom_ratio
)
+
"
px
"
;
brush
.
style
.
top
=
(
centerY
-
self
.
brush_size
*
this
.
zoom_ratio
)
+
"
px
"
;
}
handleWheelEvent
(
self
,
event
)
{
if
(
event
.
deltaY
<
0
)
self
.
brush_size
=
Math
.
min
(
self
.
brush_size
+
2
,
100
);
else
self
.
brush_size
=
Math
.
max
(
self
.
brush_size
-
2
,
1
);
event
.
preventDefault
();
self
.
brush_slider_input
.
value
=
self
.
brush_size
;
if
(
event
.
ctrlKey
)
{
// zoom canvas
if
(
event
.
deltaY
<
0
)
{
this
.
zoom_ratio
=
Math
.
min
(
10.0
,
this
.
zoom_ratio
+
0.2
);
}
else
{
this
.
zoom_ratio
=
Math
.
max
(
0.2
,
this
.
zoom_ratio
-
0.2
);
}
this
.
invalidatePanZoom
();
}
else
{
// adjust brush size
if
(
event
.
deltaY
<
0
)
this
.
brush_size
=
Math
.
min
(
this
.
brush_size
+
2
,
100
);
else
this
.
brush_size
=
Math
.
max
(
this
.
brush_size
-
2
,
1
);
this
.
brush_slider_input
.
value
=
this
.
brush_size
;
this
.
updateBrushPreview
(
this
);
}
}
pointMoveEvent
(
self
,
event
)
{
this
.
cursorX
=
event
.
pageX
;
this
.
cursorY
=
event
.
pageY
;
self
.
updateBrushPreview
(
self
);
if
(
event
.
ctrlKey
)
{
event
.
preventDefault
();
self
.
pan_move
(
self
,
event
);
}
}
pan_move
(
self
,
event
)
{
if
(
event
.
buttons
==
1
)
{
if
(
this
.
mousedown_x
)
{
let
deltaX
=
this
.
mousedown_x
-
event
.
clientX
;
let
deltaY
=
this
.
mousedown_y
-
event
.
clientY
;
self
.
pan_x
=
this
.
mousedown_pan_x
-
deltaX
;
self
.
pan_y
=
this
.
mousedown_pan_y
-
deltaY
;
self
.
invalidatePanZoom
();
}
}
}
draw_move
(
self
,
event
)
{
if
(
event
.
ctrlKey
)
{
return
;
}
event
.
preventDefault
();
this
.
cursorX
=
event
.
pageX
;
...
...
@@ -439,6 +568,9 @@ class MaskEditorDialog extends ComfyDialog {
y
=
event
.
targetTouches
[
0
].
clientY
-
maskRect
.
top
;
}
x
/=
self
.
zoom_ratio
;
y
/=
self
.
zoom_ratio
;
var
brush_size
=
this
.
brush_size
;
if
(
event
instanceof
PointerEvent
&&
event
.
pointerType
==
'
pen
'
)
{
brush_size
*=
event
.
pressure
;
...
...
@@ -489,8 +621,8 @@ class MaskEditorDialog extends ComfyDialog {
}
else
if
(
event
.
buttons
==
2
||
event
.
buttons
==
5
||
event
.
buttons
==
32
)
{
const
maskRect
=
self
.
maskCanvas
.
getBoundingClientRect
();
const
x
=
event
.
offsetX
||
event
.
targetTouches
[
0
].
clientX
-
maskRect
.
left
;
const
y
=
event
.
offsetY
||
event
.
targetTouches
[
0
].
clientY
-
maskRect
.
top
;
const
x
=
(
event
.
offsetX
||
event
.
targetTouches
[
0
].
clientX
-
maskRect
.
left
)
/
self
.
zoom_ratio
;
const
y
=
(
event
.
offsetY
||
event
.
targetTouches
[
0
].
clientY
-
maskRect
.
top
)
/
self
.
zoom_ratio
;
var
brush_size
=
this
.
brush_size
;
if
(
event
instanceof
PointerEvent
&&
event
.
pointerType
==
'
pen
'
)
{
...
...
@@ -540,6 +672,17 @@ class MaskEditorDialog extends ComfyDialog {
}
handlePointerDown
(
self
,
event
)
{
if
(
event
.
ctrlKey
)
{
if
(
event
.
buttons
==
1
)
{
this
.
mousedown_x
=
event
.
clientX
;
this
.
mousedown_y
=
event
.
clientY
;
this
.
mousedown_pan_x
=
this
.
pan_x
;
this
.
mousedown_pan_y
=
this
.
pan_y
;
}
return
;
}
var
brush_size
=
this
.
brush_size
;
if
(
event
instanceof
PointerEvent
&&
event
.
pointerType
==
'
pen
'
)
{
brush_size
*=
event
.
pressure
;
...
...
@@ -551,8 +694,8 @@ class MaskEditorDialog extends ComfyDialog {
event
.
preventDefault
();
const
maskRect
=
self
.
maskCanvas
.
getBoundingClientRect
();
const
x
=
event
.
offsetX
||
event
.
targetTouches
[
0
].
clientX
-
maskRect
.
left
;
const
y
=
event
.
offsetY
||
event
.
targetTouches
[
0
].
clientY
-
maskRect
.
top
;
const
x
=
(
event
.
offsetX
||
event
.
targetTouches
[
0
].
clientX
-
maskRect
.
left
)
/
self
.
zoom_ratio
;
const
y
=
(
event
.
offsetY
||
event
.
targetTouches
[
0
].
clientY
-
maskRect
.
top
)
/
self
.
zoom_ratio
;
self
.
maskCtx
.
beginPath
();
if
(
event
.
button
==
0
)
{
...
...
@@ -570,15 +713,18 @@ class MaskEditorDialog extends ComfyDialog {
}
async
save
()
{
const
backupCtx
=
this
.
backupCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
const
backupCanvas
=
document
.
createElement
(
'
canvas
'
);
const
backupCtx
=
backupCanvas
.
getContext
(
'
2d
'
,
{
willReadFrequently
:
true
});
backupCanvas
.
width
=
this
.
image
.
width
;
backupCanvas
.
height
=
this
.
image
.
height
;
backupCtx
.
clearRect
(
0
,
0
,
this
.
backupCanvas
.
width
,
this
.
backupCanvas
.
height
);
backupCtx
.
clearRect
(
0
,
0
,
backupCanvas
.
width
,
backupCanvas
.
height
);
backupCtx
.
drawImage
(
this
.
maskCanvas
,
0
,
0
,
this
.
maskCanvas
.
width
,
this
.
maskCanvas
.
height
,
0
,
0
,
this
.
backupCanvas
.
width
,
this
.
backupCanvas
.
height
);
0
,
0
,
backupCanvas
.
width
,
backupCanvas
.
height
);
// paste mask data into alpha channel
const
backupData
=
backupCtx
.
getImageData
(
0
,
0
,
this
.
backupCanvas
.
width
,
this
.
backupCanvas
.
height
);
const
backupData
=
backupCtx
.
getImageData
(
0
,
0
,
backupCanvas
.
width
,
backupCanvas
.
height
);
// refine mask image
for
(
let
i
=
0
;
i
<
backupData
.
data
.
length
;
i
+=
4
)
{
...
...
@@ -615,7 +761,7 @@ class MaskEditorDialog extends ComfyDialog {
ComfyApp
.
clipspace
.
widgets
[
index
].
value
=
item
;
}
const
dataURL
=
this
.
backupCanvas
.
toDataURL
();
const
dataURL
=
backupCanvas
.
toDataURL
();
const
blob
=
dataURLToBlob
(
dataURL
);
let
original_url
=
new
URL
(
this
.
image
.
src
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment