| import { app } from '../../scripts/app.js'
|
| import { api } from '../../scripts/api.js'
|
|
|
| function offsetDOMWidget(
|
| widget,
|
| ctx,
|
| node,
|
| widgetWidth,
|
| widgetY,
|
| height
|
| ) {
|
| const margin = 10
|
| const elRect = ctx.canvas.getBoundingClientRect()
|
| const transform = new DOMMatrix()
|
| .scaleSelf(
|
| elRect.width / ctx.canvas.width,
|
| elRect.height / ctx.canvas.height
|
| )
|
| .multiplySelf(ctx.getTransform())
|
| .translateSelf(0, widgetY + margin)
|
|
|
| const scale = new DOMMatrix().scaleSelf(transform.a, transform.d)
|
| Object.assign(widget.inputEl.style, {
|
| transformOrigin: '0 0',
|
| transform: scale,
|
| left: `${transform.e}px`,
|
| top: `${transform.d + transform.f}px`,
|
| width: `${widgetWidth}px`,
|
| height: `${(height || widget.parent?.inputHeight || 32) - margin}px`,
|
| position: 'absolute',
|
| background: !node.color ? '' : node.color,
|
| color: !node.color ? '' : 'white',
|
| zIndex: 5,
|
| })
|
| }
|
|
|
| export const hasWidgets = (node) => {
|
| if (!node.widgets || !node.widgets?.[Symbol.iterator]) {
|
| return false
|
| }
|
| return true
|
| }
|
|
|
| export const cleanupNode = (node) => {
|
| if (!hasWidgets(node)) {
|
| return
|
| }
|
|
|
| for (const w of node.widgets) {
|
| if (w.canvas) {
|
| w.canvas.remove()
|
| }
|
| if (w.inputEl) {
|
| w.inputEl.remove()
|
| }
|
|
|
| w.onRemoved?.()
|
| }
|
| }
|
|
|
| const CreatePreviewElement = (name, val, format) => {
|
| const [type] = format.split('/')
|
| const w = {
|
| name,
|
| type,
|
| value: val,
|
| draw: function (ctx, node, widgetWidth, widgetY, height) {
|
| const [cw, ch] = this.computeSize(widgetWidth)
|
| offsetDOMWidget(this, ctx, node, widgetWidth, widgetY, ch)
|
| },
|
| computeSize: function (_) {
|
| const ratio = this.inputRatio || 1
|
| const width = Math.max(220, this.parent.size[0])
|
| return [width, (width / ratio + 10)]
|
| },
|
| onRemoved: function () {
|
| if (this.inputEl) {
|
| this.inputEl.remove()
|
| }
|
| },
|
| }
|
|
|
| w.inputEl = document.createElement(type === 'video' ? 'video' : 'img')
|
| w.inputEl.src = w.value
|
| if (type === 'video') {
|
| w.inputEl.setAttribute('type', 'video/webm');
|
| w.inputEl.autoplay = true
|
| w.inputEl.loop = true
|
| w.inputEl.controls = false;
|
| }
|
| w.inputEl.onload = function () {
|
| w.inputRatio = w.inputEl.naturalWidth / w.inputEl.naturalHeight
|
| }
|
| document.body.appendChild(w.inputEl)
|
| return w
|
| }
|
|
|
| const gif_preview = {
|
| name: 'efficiency.gif_preview',
|
| async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
| switch (nodeData.name) {
|
| case 'KSampler (Efficient)':{
|
| const onExecuted = nodeType.prototype.onExecuted
|
| nodeType.prototype.onExecuted = function (message) {
|
| const prefix = 'ad_gif_preview_'
|
| const r = onExecuted ? onExecuted.apply(this, message) : undefined
|
|
|
| if (this.widgets) {
|
| const pos = this.widgets.findIndex((w) => w.name === `${prefix}_0`)
|
| if (pos !== -1) {
|
| for (let i = pos; i < this.widgets.length; i++) {
|
| this.widgets[i].onRemoved?.()
|
| }
|
| this.widgets.length = pos
|
| }
|
| if (message?.gifs) {
|
| message.gifs.forEach((params, i) => {
|
| const previewUrl = api.apiURL(
|
| '/view?' + new URLSearchParams(params).toString()
|
| )
|
| const w = this.addCustomWidget(
|
| CreatePreviewElement(`${prefix}_${i}`, previewUrl, params.format || 'image/gif')
|
| )
|
| w.parent = this
|
| })
|
| }
|
| const onRemoved = this.onRemoved
|
| this.onRemoved = () => {
|
| cleanupNode(this)
|
| return onRemoved?.()
|
| }
|
| }
|
| if (message?.gifs && message.gifs.length > 0) {
|
| this.setSize([this.size[0], this.computeSize([this.size[0], this.size[1]])[1]]);
|
| }
|
| return r
|
| }
|
| break
|
| }
|
| }
|
| }
|
| }
|
|
|
| app.registerExtension(gif_preview)
|
|
|