diff --git a/public/app.js b/public/app.js
index 2434ffe..5293338 100644
--- a/public/app.js
+++ b/public/app.js
@@ -7610,6 +7610,54 @@ document.addEventListener('DOMContentLoaded', () => {
const sceneLayersItems = document.getElementById('sceneLayersItems');
// Cria um item de camada de imagem direto no canvas (background ou sticker)
+ // Remoção de fundo branco via Canvas API — gera PNG com transparência real
+ async function removeWhiteBackground(imgUrl, threshold = 235) {
+ return new Promise((resolve) => {
+ const img = new Image();
+ img.crossOrigin = 'anonymous'; // necessário para getImageData funcionar
+ img.onload = () => {
+ const offscreen = document.createElement('canvas');
+ offscreen.width = img.naturalWidth;
+ offscreen.height = img.naturalHeight;
+ const ctx = offscreen.getContext('2d', { willReadFrequently: true });
+ ctx.drawImage(img, 0, 0);
+
+ const imageData = ctx.getImageData(0, 0, offscreen.width, offscreen.height);
+ const data = imageData.data;
+ // threshold: pixels com R,G,B >= threshold são considerados "fundos a remover"
+ // softRange: faixa de suavização para bordas anti-aliased
+ const softRange = 20;
+
+ for (let i = 0; i < data.length; i += 4) {
+ const r = data[i];
+ const g = data[i + 1];
+ const b = data[i + 2];
+
+ // Pega o mínimo dos canais (garante que só pixels "esbranquiçados" sejam afetados)
+ const minChannel = Math.min(r, g, b);
+
+ if (minChannel >= threshold) {
+ // Área central do branco: totalmente transparente
+ data[i + 3] = 0;
+ } else if (minChannel >= threshold - softRange) {
+ // Zona de borda: transição linear suave para preservar contornos
+ const ratio = (minChannel - (threshold - softRange)) / softRange;
+ data[i + 3] = Math.round((1 - ratio) * data[i + 3]);
+ }
+ // Pixels abaixo do threshold - softRange: mantém opacidade original
+ }
+
+ ctx.putImageData(imageData, 0, 0);
+ resolve(offscreen.toDataURL('image/png'));
+ };
+ img.onerror = () => {
+ console.warn('[removeWhiteBackground] Falha ao carregar imagem, usando original:', imgUrl);
+ resolve(imgUrl);
+ };
+ img.src = imgUrl;
+ });
+ }
+
function addSceneLayerToCanvas(layerData) {
if (!canvasModeActive || !cartazPrintableArea) return;
@@ -7622,44 +7670,50 @@ document.addEventListener('DOMContentLoaded', () => {
item.style.top = (layerData.top || 10) + '%';
item.style.width = (layerData.width || 35) + '%';
item.style.height = (layerData.height || 35) + '%';
- item.style.zIndex = layerData.isBackground ? '1' : String(10 + (layerData.zOffset || 0));
+ item.style.zIndex = layerData.isBackground ? '0' : String(10 + (layerData.zOffset || 0));
item.style.background = 'transparent';
if (layerData.isBackground) {
- // Fundo: cobrindo 100% do canvas
item.style.left = '0';
item.style.top = '0';
item.style.width = '100%';
item.style.height = '100%';
item.style.zIndex = '0';
- item.style.isolation = 'isolate'; // Isola o fundo para evitar bleeding do blend-mode dos filhos
item.style.pointerEvents = 'none';
item.innerHTML = ``;
item.title = '🖼️ Cenário de Fundo';
- } else {
- // Elementos: mix-blend-mode: multiply faz o fundo branco desaparecer (efeito sticker)
- item.style.isolation = 'isolate';
- item.innerHTML = `
`;
- item.title = '🎬 ' + (layerData.name || 'Elemento');
- }
- const handle = document.createElement('div');
- handle.className = 'canvas-resize-handle';
- item.appendChild(handle);
-
- cartazPrintableArea.appendChild(item);
-
- if (!layerData.isBackground) {
- setupCanvasItemEvents(item);
- // Permitir que o fundo seja selecionável após clicar nele diretamente
- } else {
- // para o fundo, adicionar capacidade de clicar para habilitar arrastar
+ const handle = document.createElement('div');
+ handle.className = 'canvas-resize-handle';
+ item.appendChild(handle);
+ cartazPrintableArea.appendChild(item);
item.style.pointerEvents = 'auto';
setupCanvasItemEvents(item);
+
+ } else {
+ // Adiciona o item ao canvas com um placeholder de loading
+ item.innerHTML = `