From b1c2cf4068693e911baef29ac50123d1fa2d124f Mon Sep 17 00:00:00 2001 From: kk8bit Date: Tue, 22 Sep 2026 20:24:42 +0800 Subject: [PATCH] Guard GuLuLu's pixel hit-test against an unloaded or broken image updatePixelDataCache() drew the sprite into an offscreen canvas and read its alpha channel without checking that the image had actually decoded. Read too early, every pixel came back transparent and the sprite could not be clicked or dragged until something else forced a recompute; with a broken image (the 404 from the folder-casing bug, or a user-supplied replacement) drawImage threw InvalidStateError into the mousemove handlers. Skip the update until img.complete && naturalWidth > 0, clear the cache on img.onerror, and catch failures from drawImage/getImageData. Every consumer of pixelDataCache already tolerates null. Guards proposed by EndoTheDev in PR #22; the path change from that PR was superseded by the import.meta.url fix in 0.71.1. --- CHANGELOG.md | 2 ++ README.md | 2 ++ web/gululu.js | 24 ++++++++++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ae75aa..9382114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## [未发布 Unreleased] +- GuLuLu 的像素点击判定增加图片加载保护:图片未就绪、加载失败或被替换成无法加载的文件时不再抛错,也不会把小人误判为「整只透明、点不到」(思路来自 EndoTheDev 的 PR #22) +- GuLuLu's pixel hit-testing now guards against the image not being ready, failing to load or being replaced with an unloadable file: no more exceptions, and the sprite no longer becomes unclickable (approach from EndoTheDev's PR #22) - 资源监视器面板改为独立合成层(`will-change: transform`),它每帧重绘时不再连带重绘被它盖住的那块主画布 - The resource monitor panel now gets its own compositor layer (`will-change: transform`), so its per-frame redraw no longer forces the main canvas region beneath it to repaint - 资源监视器的数据行和顶部的工作流进度条改为只创建一次:条形每帧用 transform 平滑跟随曲线(不触发布局),文字每 100ms 更新。此前每帧重写整块 innerHTML 并新建 canvas 量字宽,每秒数百次 DOM 重建,是拖动画布时掉帧的来源之一;现在单次开销降到 0.01ms 以下 diff --git a/README.md b/README.md index 1288030..e7ea6b5 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ This is a custom node utility package developed for ComfyUI. Initially created f ## 最新更新 / Last Update ### [未发布 Unreleased] +- GuLuLu 的像素点击判定增加图片加载保护:图片未就绪、加载失败或被替换成无法加载的文件时不再抛错,也不会把小人误判为「整只透明、点不到」(思路来自 EndoTheDev 的 PR #22) +- GuLuLu's pixel hit-testing now guards against the image not being ready, failing to load or being replaced with an unloadable file: no more exceptions, and the sprite no longer becomes unclickable (approach from EndoTheDev's PR #22) - 资源监视器面板改为独立合成层(`will-change: transform`),它每帧重绘时不再连带重绘被它盖住的那块主画布 - The resource monitor panel now gets its own compositor layer (`will-change: transform`), so its per-frame redraw no longer forces the main canvas region beneath it to repaint - 资源监视器的数据行和顶部的工作流进度条改为只创建一次:条形每帧用 transform 平滑跟随曲线(不触发布局),文字每 100ms 更新。此前每帧重写整块 innerHTML 并新建 canvas 量字宽,每秒数百次 DOM 重建,是拖动画布时掉帧的来源之一;现在单次开销降到 0.01ms 以下 diff --git a/web/gululu.js b/web/gululu.js index a561d9e..1979823 100644 --- a/web/gululu.js +++ b/web/gululu.js @@ -109,6 +109,11 @@ const KayGuLuLuManager = { this.container.id = "kay-gululu-container"; const img = document.createElement("img"); img.src = this.imgSrc; + // 图片缺失或被用户换成加载不了的文件时,不要让后面的像素判定抛错 + img.onerror = () => { + console.warn("[KayTool] GuLuLu image failed to load:", img.src); + this.pixelDataCache = null; + }; img.alt = "GuLuLu"; img.onload = () => { this.updatePixelDataCache(); @@ -251,13 +256,24 @@ const KayGuLuLuManager = { if (containerRect.width === 0 || containerRect.height === 0) { return; } + // 像素判定依赖图片已经解码好;没就绪时读到的是整张透明,会让小人「点不到」, + // 坏图则会让 drawImage 直接抛 InvalidStateError。没就绪就跳过,等下次再算。 + const img = this.container?.querySelector("img"); + if (!img || !img.complete || img.naturalWidth === 0) { + this.pixelDataCache = null; + return; + } this.pixelCanvas.width = containerRect.width; this.pixelCanvas.height = containerRect.height; this.pixelCtx.clearRect(0, 0, this.pixelCanvas.width, this.pixelCanvas.height); - this.pixelCtx.drawImage(this.container.querySelector("img"), 0, 0, containerRect.width, containerRect.height); - this.pixelDataCache = this.pixelCtx.getImageData(0, 0, this.pixelCanvas.width, this.pixelCanvas.height); - - this.calculateEffectiveBounds(); + try { + this.pixelCtx.drawImage(img, 0, 0, containerRect.width, containerRect.height); + this.pixelDataCache = this.pixelCtx.getImageData(0, 0, this.pixelCanvas.width, this.pixelCanvas.height); + this.calculateEffectiveBounds(); + } catch (e) { + console.warn("[KayTool] GuLuLu pixel cache update failed:", e); + this.pixelDataCache = null; + } }, calculateEffectiveBounds() {