From b7e2ea12d0094606dd1166679f5f75cbbdef62e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Wed, 30 Sep 2026 12:14:04 -0300 Subject: [PATCH] feat: accept large JPG and WebP artworks instead of refusing them Above 150 MB the browser cannot read JPG or WebP in parts, so a large artwork was refused. It is now measured from its header, graded and priced with the discount like any other, and placed on the sheet as a full box, which is exact for JPG. The card says there is no preview and that the team checks the art before printing. Co-Authored-By: Claude Opus 5.5 --- tests/artwork_browser_test.mjs | 11 +++++++++++ web/site-cart.js | 2 +- web/site-packing.js | 2 +- web/site-pdf.js | 11 ++++++----- web/site-quality.js | 4 +--- web/site-upload.js | 4 +++- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/artwork_browser_test.mjs b/tests/artwork_browser_test.mjs index 7dd952f..d7e946f 100644 --- a/tests/artwork_browser_test.mjs +++ b/tests/artwork_browser_test.mjs @@ -170,6 +170,17 @@ try{ await evaluate(`folhas=[];pintaFolha()`); await evaluate(`pickTipo('avulsa')`); assert.equal(await evaluate('modo'),'avulsa'); + // A large JPG artwork cannot be read in parts: it is measured from its + // header and placed as a full box, with the discount, instead of refused. + await evaluate(`(()=>{const h=new Uint8Array(20);h.set([0xFF,0xD8,0xFF,0xC0,0,17,8,0x09,0x3A,0x09,0x3A,3]); + const f=new File([h],'arte-grande.jpg');Object.defineProperty(f,'size',{value:400*1048576});sel([f]);})()`); + await waitFor(()=>evaluate(`artes.length===1 && artes[0].semPrevia===true`),'large JPG artwork measured from its header'); + await fill('[data-cm]',20); + await waitFor(()=>evaluate(`!!itemAtual?.production?.sources?.length`),'large JPG artwork packed'); + assert.deepEqual(await evaluate(`({dpi:Math.round(dpiDe(artes[0])),src:!!artes[0].src, + measurement:itemAtual.production.sources[0].measurement,note:$('lista').textContent.includes('Sem prévia')})`), + {dpi:300,src:false,measurement:'file',note:true}); + await evaluate(`artes=[];pintaArtes()`); await evaluate('sendImage()'); await waitFor(()=>evaluate(`artes.length===1 && !!artes[0].src`),'JPG artwork model'); assert.deepEqual(await evaluate(`({mode:modo,sheets:folhas.length,width:artes[0].cm,quantity:artes[0].q})`),{mode:'avulsa',sheets:0,width:0,quantity:1}); diff --git a/web/site-cart.js b/web/site-cart.js index bdef20a..c8ae5d8 100644 --- a/web/site-cart.js +++ b/web/site-cart.js @@ -91,7 +91,7 @@ function carrinho(){ measurement:x.med?'file':'customer'} : {kind:'artwork',width_cm:x.cm,length_cm:+(x.cm*propDe(x)).toFixed(4), copies:x.q,rotation_degrees:x.giro||0,mirrored:!!x.esp, - measurement:x.src?'file':'customer'}); + measurement:(x.src||x.semPrevia)?'file':'customer'}); let layout; if(ehFolha()){ let y=0; diff --git a/web/site-packing.js b/web/site-packing.js index 9edfdcf..5497b81 100644 --- a/web/site-packing.js +++ b/web/site-packing.js @@ -337,7 +337,7 @@ function previaAoVivo(){ tMont=setTimeout(()=>{ // o produto pode ter sido fechado nesses 140 ms (item foi para o carrinho) if(!modo) return; - const prontas=artes.filter(a=>a.cm>0 && a.cm<=larguraFilme() && a.src); + const prontas=artes.filter(a=>a.cm>0 && a.cm<=larguraFilme() && (a.src||a.semPrevia)); const W=Math.round(300*ZOOMS[zoomI]); $('vArea').classList.toggle('ampliado', zoomI>0); desenhaMontagem($('vArea'), prontas, 0, W, $('vUso'), r=>{ diff --git a/web/site-pdf.js b/web/site-pdf.js index 8f7eac1..838d6d2 100644 --- a/web/site-pdf.js +++ b/web/site-pdf.js @@ -541,13 +541,11 @@ function pintaArtes(){ if(a.lendo!=null){ barra='
'+ 'arquivo grande · gerando a prévia… '+a.lendo+'%'; - }else if(a.decodeError==='grande'){ - aviso='

Arquivo grande em JPG ou WebP. Exporte em PNG para montar a folha.

'; }else if(a.decodeError){ aviso='

Não conseguimos ler esta imagem. Exporte novamente em PNG ou JPG.

'; }else if(a.cm>larguraFilme()){ aviso='

Largura maior que o filme. O filme aqui tem '+n1(larguraFilme())+' cm.

'; - }else if(a.cm>0 && a.src){ + }else if(a.cm>0 && (a.src||a.semPrevia)){ const dpi=Math.round(dpiDe(a)); medida=''+n1(a.cm)+' × '+n1(a.cm*propDe(a))+' cm'; chips='