Merge pull request #91 from 7est/0831

Add Checkbox to Control Transparent Pixel Drawing
This commit is contained in:
MiraclePatrickLumowa authored and GitHub committed 2025-08-31 19:21:26 +08:00
commit f332d5b5ad
16 files changed
+141 -42

No files matched your search

+78 -26
View File
@@ -499,6 +499,7 @@ function applyTheme() {
availableColors: [],
activeColorPalette: [], // User-selected colors for conversion
paintWhitePixels: true, // Default to ON
paintTransparentPixels: false, // Default to OFF
currentCharges: 0,
maxCharges: 1, // Default max charges
cooldown: CONFIG.COOLDOWN_DEFAULT,
@@ -813,7 +814,7 @@ function applyTheme() {
const d = cached.data;
const a = d[idx + 3];
const alphaThresh = state.customTransparencyThreshold || CONFIG.TRANSPARENCY_THRESHOLD;
if (a < alphaThresh) {
if (!state.paintTransparentPixels && a < alphaThresh) {
// Treat as transparent / unavailable
// Lightweight debug: show when transparency causes skip (only if verbose enabled)
if (window._overlayDebug) console.debug('getTilePixelColor: transparent pixel, skipping', tileKey, x, y, a);
@@ -845,7 +846,7 @@ function applyTheme() {
const data = ctx.getImageData(x, y, 1, 1).data;
const a = data[3];
const alphaThresh = state.customTransparencyThreshold || CONFIG.TRANSPARENCY_THRESHOLD;
if (a < alphaThresh) {
if (!state.paintTransparentPixels && a < alphaThresh) {
if (window._overlayDebug) console.debug('getTilePixelColor: transparent pixel (fallback), skipping', tileKey, x, y, a);
return null;
}
@@ -3018,6 +3019,26 @@ function applyTheme() {
</div>
</div>
<!-- Paint Options Section -->
<div class="wplace-settings-section">
<label class="wplace-settings-section-label">
<i class="fas fa-paint-brush wplace-icon-paint"></i>
${Utils.t("paintOptions")}
</label>
<div class="wplace-settings-section-wrapper wplace-notifications-wrapper">
<!-- Paint White Pixels Toggle -->
<label class="wplace-notification-toggle">
<span>${Utils.t("paintWhitePixels")}</span>
<input type="checkbox" id="settingsPaintWhiteToggle" ${state.paintWhitePixels ? 'checked' : ''} class="wplace-notification-checkbox" />
</label>
<!-- Paint Transparent Pixels Toggle -->
<label class="wplace-notification-toggle">
<span>${Utils.t("paintTransparentPixels")}</span>
<input type="checkbox" id="settingsPaintTransparentToggle" ${state.paintTransparentPixels ? 'checked' : ''} class="wplace-notification-checkbox" />
</label>
</div>
</div>
<!-- Speed Control Section -->
<div class="wplace-settings-section">
<label class="wplace-settings-section-label">
@@ -3269,11 +3290,15 @@ function applyTheme() {
</label>
<label class="resize-checkbox-label">
<input type="checkbox" id="keepAspect" checked>
Keep Aspect Ratio
${Utils.t("keepAspectRatio")}
</label>
<label class="resize-checkbox-label">
<input type="checkbox" id="paintWhiteToggle" checked>
Paint White Pixels
${Utils.t("paintWhitePixels")}
</label>
<label class="resize-checkbox-label">
<input type="checkbox" id="paintTransparentToggle" checked>
${Utils.t("paintTransparentPixels")}
</label>
<div class="resize-zoom-controls">
<button id="zoomOutBtn" class="wplace-btn resize-zoom-btn" title="${Utils.t('zoomOut')}"><i class="fas fa-search-minus"></i></button>
@@ -3761,17 +3786,33 @@ function applyTheme() {
})
}
const overlayOpacitySlider = settingsContainer.querySelector("#overlayOpacitySlider");
const overlayOpacityValue = settingsContainer.querySelector("#overlayOpacityValue");
const enableBlueMarbleToggle = settingsContainer.querySelector("#enableBlueMarbleToggle");
const overlayOpacitySlider = settingsContainer.querySelector("#overlayOpacitySlider");
const overlayOpacityValue = settingsContainer.querySelector("#overlayOpacityValue");
const enableBlueMarbleToggle = settingsContainer.querySelector("#enableBlueMarbleToggle");
const settingsPaintWhiteToggle = settingsContainer.querySelector("#settingsPaintWhiteToggle");
const settingsPaintTransparentToggle = settingsContainer.querySelector("#settingsPaintTransparentToggle");
if (overlayOpacitySlider && overlayOpacityValue) {
overlayOpacitySlider.addEventListener('input', (e) => {
const opacity = parseFloat(e.target.value);
state.overlayOpacity = opacity;
overlayOpacityValue.textContent = `${Math.round(opacity * 100)}%`;
});
}
if (overlayOpacitySlider && overlayOpacityValue) {
overlayOpacitySlider.addEventListener('input', (e) => {
const opacity = parseFloat(e.target.value);
state.overlayOpacity = opacity;
overlayOpacityValue.textContent = `${Math.round(opacity * 100)}%`;
});
}
if (settingsPaintWhiteToggle) {
settingsPaintWhiteToggle.addEventListener('change', (e) => {
state.paintWhitePixels = e.target.checked;
saveBotSettings();
});
}
if (settingsPaintTransparentToggle) {
settingsPaintTransparentToggle.addEventListener('change', (e) => {
state.paintTransparentPixels = e.target.checked;
saveBotSettings();
});
}
// Speed slider event listener
const speedSlider = settingsContainer.querySelector("#speedSlider");
@@ -3822,6 +3863,7 @@ function applyTheme() {
const heightValue = resizeContainer.querySelector("#heightValue")
const keepAspect = resizeContainer.querySelector("#keepAspect")
const paintWhiteToggle = resizeContainer.querySelector("#paintWhiteToggle");
const paintTransparentToggle = resizeContainer.querySelector("#paintTransparentToggle");
const zoomSlider = resizeContainer.querySelector("#zoomSlider");
const zoomValue = resizeContainer.querySelector('#zoomValue');
const zoomInBtn = resizeContainer.querySelector('#zoomInBtn');
@@ -4133,6 +4175,7 @@ function applyTheme() {
zoomSlider.value = 1;
if (zoomValue) zoomValue.textContent = '100%';
paintWhiteToggle.checked = state.paintWhitePixels;
paintTransparentToggle.checked = state.paintTransparentPixels;
let _previewTimer = null;
let _previewJobId = 0;
@@ -4236,7 +4279,7 @@ function applyTheme() {
const idx = y * w + x;
const i4 = idx * 4;
const r = data[i4], g = data[i4 + 1], b = data[i4 + 2], a = data[i4 + 3];
const isEligible = a >= tThresh && (state.paintWhitePixels || !Utils.isWhitePixel(r, g, b));
const isEligible = (state.paintTransparentPixels || a >= tThresh) && (state.paintWhitePixels || !Utils.isWhitePixel(r, g, b));
eligible[idx] = isEligible ? 1 : 0;
work[idx * 3] = r;
work[idx * 3 + 1] = g;
@@ -4288,7 +4331,7 @@ function applyTheme() {
} else {
for (let i = 0; i < data.length; i += 4) {
const r = data[i], g = data[i + 1], b = data[i + 2], a = data[i + 3];
if (a < tThresh || (!state.paintWhitePixels && Utils.isWhitePixel(r, g, b))) {
if ((!state.paintTransparentPixels && a < tThresh) || (!state.paintWhitePixels && Utils.isWhitePixel(r, g, b))) {
data[i + 3] = 0;
continue;
}
@@ -4335,10 +4378,17 @@ function applyTheme() {
if (!isNaN(fit) && isFinite(fit)) applyZoom(fit);
};
paintWhiteToggle.onchange = (e) => {
state.paintWhitePixels = e.target.checked;
_updateResizePreview();
};
paintWhiteToggle.onchange = (e) => {
state.paintWhitePixels = e.target.checked;
_updateResizePreview();
saveBotSettings();
};
paintTransparentToggle.onchange = (e) => {
state.paintTransparentPixels = e.target.checked;
_updateResizePreview();
saveBotSettings();
};
let panX = 0, panY = 0;
const clampPan = () => {
@@ -4772,7 +4822,7 @@ function applyTheme() {
const i4 = idx * 4;
const r = data[i4], g = data[i4 + 1], b = data[i4 + 2], a = data[i4 + 3];
const masked = mask && mask[idx];
const isEligible = !masked && a >= tThresh2 && (state.paintWhitePixels || !Utils.isWhitePixel(r, g, b));
const isEligible = !masked && (state.paintTransparentPixels || a >= tThresh2) && (state.paintWhitePixels || !Utils.isWhitePixel(r, g, b));
eligible[idx] = isEligible ? 1 : 0;
work[idx * 3] = r;
work[idx * 3 + 1] = g;
@@ -4829,7 +4879,7 @@ function applyTheme() {
for (let i = 0; i < data.length; i += 4) {
const r = data[i], g = data[i + 1], b = data[i + 2], a = data[i + 3];
const masked = mask && mask[(i>>2)];
const isTransparent = a < tThresh2 || masked;
const isTransparent = (!state.paintTransparentPixels && a < tThresh2) || masked;
const isWhiteAndSkipped = !state.paintWhitePixels && Utils.isWhitePixel(r, g, b);
if (isTransparent || isWhiteAndSkipped) {
data[i + 3] = 0; // overlay transparency
@@ -4963,7 +5013,7 @@ function applyTheme() {
let totalValidPixels = 0;
for (let i = 0; i < pixels.length; i += 4) {
const isTransparent = pixels[i + 3] < (state.customTransparencyThreshold || CONFIG.TRANSPARENCY_THRESHOLD);
const isTransparent = !state.paintTransparentPixels && pixels[i + 3] < (state.customTransparencyThreshold || CONFIG.TRANSPARENCY_THRESHOLD);
const isWhiteAndSkipped = !state.paintWhitePixels && Utils.isWhitePixel(pixels[i], pixels[i + 1], pixels[i + 2]);
if (!isTransparent && !isWhiteAndSkipped) {
totalValidPixels++;
@@ -5208,7 +5258,7 @@ function applyTheme() {
const isEligibleAt = (x, y) => {
const idx = (y * width + x) * 4;
const r = pixels[idx], g = pixels[idx + 1], b = pixels[idx + 2], a = pixels[idx + 3];
if (a < tThresh2) return false;
if (!state.paintTransparentPixels && a < tThresh2) return false;
if (!state.paintWhitePixels && Utils.isWhitePixel(r, g, b)) return false;
return true;
};
@@ -5256,8 +5306,8 @@ function applyTheme() {
const alpha = pixels[idx + 3]
const tThresh2 = state.customTransparencyThreshold || CONFIG.TRANSPARENCY_THRESHOLD;
if (alpha < tThresh2 || (!state.paintWhitePixels && Utils.isWhitePixel(r, g, b))) {
if (alpha < tThresh2) {
if ((!state.paintTransparentPixels && alpha < tThresh2) || (!state.paintWhitePixels && Utils.isWhitePixel(r, g, b))) {
if (!state.paintTransparentPixels && alpha < tThresh2) {
skippedPixels.transparent++;
} else {
skippedPixels.white++;
@@ -5654,6 +5704,7 @@ function applyTheme() {
customTransparencyThreshold: state.customTransparencyThreshold,
customWhiteThreshold: state.customWhiteThreshold,
paintWhitePixels: state.paintWhitePixels,
paintTransparentPixels: state.paintTransparentPixels,
resizeSettings: state.resizeSettings,
originalImage: state.originalImage,
// Save ignore mask (as base64) with its dimensions
@@ -5699,6 +5750,7 @@ function applyTheme() {
state.customTransparencyThreshold = settings.customTransparencyThreshold ?? CONFIG.TRANSPARENCY_THRESHOLD;
state.customWhiteThreshold = settings.customWhiteThreshold ?? CONFIG.WHITE_THRESHOLD;
state.paintWhitePixels = settings.paintWhitePixels ?? true;
state.paintTransparentPixels = settings.paintTransparentPixels ?? false;
state.resizeSettings = settings.resizeSettings ?? null;
state.originalImage = settings.originalImage ?? null;
// Notifications