From be3d54d42de70e3d6566431d350c598d2151d133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Sat, 23 May 2026 14:19:37 +0300 Subject: [PATCH] chore: update author name in package.json and refine file URL handling in renderer.js --- package.json | 5 ++- renderer.js | 119 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 9acf8d6..2de1f9b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "electron", "glassmorphism" ], - "author": "Antigravity", + "author": "Trunçgil Technology", "license": "MIT", "devDependencies": { "electron": "^31.3.0", @@ -34,7 +34,8 @@ "files": [ "**/*", "!.venv/**", - "!node_modules/**" + "!node_modules/**", + "node_modules/cropperjs/**" ], "asarUnpack": [ "backend/**" diff --git a/renderer.js b/renderer.js index e0584fb..58fd92f 100644 --- a/renderer.js +++ b/renderer.js @@ -343,7 +343,7 @@ function handleImageSelection(filePath) { resetBgSettings(); // Show image in preview element - elements.imageElement.src = `file://${filePath}`; + elements.imageElement.src = toFileUrl(filePath); // Set file metadata in control tower const stats = getFileStats(filePath); @@ -367,7 +367,7 @@ function handleImageSelection(filePath) { // Initialize CropperJS on image initCropper(); }; - img.src = `file://${filePath}`; + img.src = toFileUrl(filePath); } function getFileStats(path) { @@ -388,6 +388,19 @@ function formatBytes(bytes, decimals = 2) { return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } +function toFileUrl(filePath) { + const normalized = filePath.replace(/\\/g, '/'); + return normalized.startsWith('/') + ? `file://${normalized}` + : `file:///${normalized}`; +} + +function unlockPostProcessingControls() { + elements.secCanvasBg.classList.remove('disabled-group'); + elements.secExport.classList.remove('disabled-group'); + elements.ctrlAutoTrim.disabled = false; +} + // --- CROPPERJS CONTROLLER HUB --- function initCropper() { if (cropper) { @@ -412,7 +425,9 @@ function initCropper() { // Wire toolbar click listeners elements.ctrlCropDrag.classList.add('active'); elements.ctrlCropBox.classList.remove('active'); - elements.ctrlAutoTrim.disabled = true; // Disabled until background is removed + elements.ctrlAutoTrim.disabled = !processedTempPath; + + applyWorkspaceBackground(); } function setupToolbarListeners() { @@ -1133,23 +1148,18 @@ async function executeBackgroundRemoval() { if (result.success) { processedTempPath = result.outputPath; showToast(getTrans('toastTitleSuccess'), getTrans('toastTrimCompleteMsg'), "success"); - - // Update workspace preview image source to output transparent PNG - // Add timestamp to bypass browser cache refreshing - const freshSrc = `file://${processedTempPath}?t=${Date.now()}`; - - // Re-initialize CropperJS on the new image src + unlockPostProcessingControls(); + + const freshSrc = `${toFileUrl(processedTempPath)}?t=${Date.now()}`; + elements.imageElement.onload = () => { + elements.imageElement.onload = null; + try { + initCropper(); + } catch (err) { + console.error('Cropper init failed:', err); + } + }; elements.imageElement.src = freshSrc; - - // Wait for image source update to build the cropper safely - setTimeout(() => { - initCropper(); - - // Unlock background customization and export - elements.secCanvasBg.classList.remove('disabled-group'); - elements.secExport.classList.remove('disabled-group'); - elements.ctrlAutoTrim.disabled = false; // Unlock trim feature! - }, 300); } else { elements.errorOverlayLog.innerText = result.error || getTrans('toastSetupErrorMsg'); @@ -1184,44 +1194,81 @@ function switchBgMode(mode) { if (mode === 'transparent') { elements.tabBgTrans.classList.add('active'); - elements.canvasBgOverlay.style.opacity = '0'; } else if (mode === 'solid') { elements.tabBgSolid.classList.add('active'); elements.subpanelSolid.classList.remove('hidden'); - elements.canvasBgOverlay.style.background = activeSolidColor; - elements.canvasBgOverlay.style.opacity = '1'; } else if (mode === 'gradient') { elements.tabBgGrad.classList.add('active'); elements.subpanelGradient.classList.remove('hidden'); - - // Draw current active gradient stops onto the workspace preview - const cssGrad = buildCssGradientString(activeGradientStops); - elements.canvasBgOverlay.style.background = cssGrad; - elements.canvasBgOverlay.style.opacity = '1'; } + + applyWorkspaceBackground(); } function buildCssGradientString(stops) { return `linear-gradient(135deg, ${stops[0].color}, ${stops[1].color})`; } +function applyWorkspaceBackground() { + const wrapper = elements.canvasWrapper; + wrapper.style.background = ''; + wrapper.style.backgroundImage = ''; + wrapper.style.backgroundColor = ''; + + if (activeBgMode === 'transparent') { + wrapper.classList.add('checkerboard'); + return; + } + + wrapper.classList.remove('checkerboard'); + + const bgValue = activeBgMode === 'solid' + ? activeSolidColor + : buildCssGradientString(activeGradientStops); + + wrapper.style.background = bgValue; + + // Keep cropper inner layers transparent so the wrapper background shows through + wrapper.querySelectorAll('.cropper-wrap, .cropper-bg, .cropper-canvas').forEach((el) => { + el.style.background = 'transparent'; + el.style.backgroundImage = 'none'; + }); +} + +function selectGradientSwatch(btn) { + const gradKey = [...btn.classList].find((cls) => cls.startsWith('grad-')); + if (!gradKey || !GRADIENTS[gradKey]) return; + + document.querySelectorAll('.grad-swatch').forEach((s) => s.classList.remove('active')); + btn.classList.add('active'); + activeGradientStops = GRADIENTS[gradKey].map((stop) => ({ ...stop })); + + if (activeBgMode === 'gradient') { + applyWorkspaceBackground(); + } +} + function setupBgSwatches() { // Solid Swatches const solidSwatches = document.querySelectorAll('.swatch:not(.custom)'); solidSwatches.forEach(swatch => { swatch.addEventListener('click', (e) => { solidSwatches.forEach(s => s.classList.remove('active')); - e.target.classList.add('active'); + e.currentTarget.classList.add('active'); - activeSolidColor = e.target.getAttribute('data-color'); - elements.canvasBgOverlay.style.background = activeSolidColor; + activeSolidColor = e.currentTarget.getAttribute('data-color'); + if (activeBgMode === 'solid') { + applyWorkspaceBackground(); + } }); }); // Custom Color Picker elements.customColorPicker.addEventListener('input', (e) => { activeSolidColor = e.target.value; - elements.canvasBgOverlay.style.background = activeSolidColor; + if (activeBgMode === 'solid') { + applyWorkspaceBackground(); + } // Highlight custom swatch borders elements.btnCustomColorPicker.classList.add('active'); @@ -1232,14 +1279,7 @@ function setupBgSwatches() { const gradSwatches = document.querySelectorAll('.grad-swatch'); gradSwatches.forEach(swatch => { swatch.addEventListener('click', (e) => { - gradSwatches.forEach(s => s.classList.remove('active')); - e.target.classList.add('active'); - - const gradKey = e.target.className.split(' ').find(cls => cls.startsWith('grad-')); - if (GRADIENTS[gradKey]) { - activeGradientStops = GRADIENTS[gradKey]; - elements.canvasBgOverlay.style.background = e.target.getAttribute('data-gradient'); - } + selectGradientSwatch(e.currentTarget); }); }); } @@ -1276,7 +1316,6 @@ async function executeExport() { ctx.fillStyle = activeSolidColor; ctx.fillRect(0, 0, finalCanvas.width, finalCanvas.height); } else if (activeBgMode === 'gradient') { - // Render the 135deg gradient vector on final output canvas const grad = ctx.createLinearGradient(0, 0, finalCanvas.width, finalCanvas.height); activeGradientStops.forEach(stop => { grad.addColorStop(stop.offset, stop.color);