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 <noreply@anthropic.com>
This commit is contained in:
@@ -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});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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=>{
|
||||
|
||||
@@ -541,13 +541,11 @@ function pintaArtes(){
|
||||
if(a.lendo!=null){
|
||||
barra='<div class="prog"><i style="width:'+a.lendo+'%"></i></div>'+
|
||||
'<span class="progT">arquivo grande · gerando a prévia… '+a.lendo+'%</span>';
|
||||
}else if(a.decodeError==='grande'){
|
||||
aviso='<p class="avisoF"><b>Arquivo grande em JPG ou WebP.</b> Exporte em PNG para montar a folha.</p>';
|
||||
}else if(a.decodeError){
|
||||
aviso='<p class="avisoF"><b>Não conseguimos ler esta imagem.</b> Exporte novamente em PNG ou JPG.</p>';
|
||||
}else if(a.cm>larguraFilme()){
|
||||
aviso='<p class="avisoF"><b>Largura maior que o filme.</b> O filme aqui tem '+n1(larguraFilme())+' cm.</p>';
|
||||
}else if(a.cm>0 && a.src){
|
||||
}else if(a.cm>0 && (a.src||a.semPrevia)){
|
||||
const dpi=Math.round(dpiDe(a));
|
||||
medida='<b>'+n1(a.cm)+' × '+n1(a.cm*propDe(a))+' cm</b>';
|
||||
chips='<ul class="chips"><li class="chip '+(dpi>=DPI_AVISA?'ok':dpi>=DPI_RECUSA?'av':'er')+'">'+dpi+' DPI</li>'+
|
||||
@@ -564,8 +562,11 @@ function pintaArtes(){
|
||||
n1(sug.cm)+' cm.<button data-usar="'+i+'" data-cm="'+sug.alvo+'">Usar '+n1(sug.alvo)+' cm</button></div>'
|
||||
: '';
|
||||
}
|
||||
if(a.semPrevia && !a.decodeError)
|
||||
aviso+='<p class="repTxt"><b>Sem prévia para '+escapeHTML(extDe(a.f.name))+' deste tamanho.</b> '+
|
||||
'A arte entra na folha pela medida, e a equipe confere antes de imprimir. Em PNG, a prévia aparece.</p>';
|
||||
const mini = a.miniSrc ? '<img src="'+escapeHTML(a.miniSrc)+'" alt="">' : '<span>'+escapeHTML(extDe(a.f.name))+'</span>';
|
||||
const sub = a.cm>0 && a.src ? (a.q>1? a.q+' × ' : '')+'<b>'+n1(a.cm)+' × '+n1(a.cm*propDe(a))+' cm</b>' : '';
|
||||
const sub = a.cm>0 && (a.src||a.semPrevia) ? (a.q>1? a.q+' × ' : '')+'<b>'+n1(a.cm)+' × '+n1(a.cm*propDe(a))+' cm</b>' : '';
|
||||
return '<div class="rep art2'+(a===recemChegada?' nova':'')+'" data-arte="'+i+'">'+
|
||||
'<div class="repTopo"><div class="miniF">'+mini+'</div><div class="repInfo">'+
|
||||
'<div class="l1"><b>'+escapeHTML(a.f.name)+'</b>'+(a===recemChegada?'<em class="novaT">nova</em>':'')+
|
||||
@@ -622,7 +623,7 @@ function pintaArtes(){
|
||||
previaAoVivo();
|
||||
}
|
||||
function resumoArtes(){
|
||||
const r=$('rA'), prontas=artes.filter(a=>a.cm>0 && a.cm<=larguraFilme() && a.src);
|
||||
const r=$('rA'), prontas=artes.filter(a=>a.cm>0 && a.cm<=larguraFilme() && (a.src||a.semPrevia));
|
||||
if(!prontas.length){ r.style.display='none'; return; }
|
||||
const m=montagemCm/100; // a mesma folha que aparece ao lado
|
||||
const notas=prontas.map(a=>Math.max(6,Math.min(100,Math.round(dpiDe(a)/300*100))));
|
||||
|
||||
@@ -64,9 +64,7 @@ function avaliar(){
|
||||
}
|
||||
if(!artes.length) return {pronto:false, falta:'Arraste suas artes para começar.'};
|
||||
if(artes.some(a=>a.lendo!=null)) return {pronto:false, falta:'Gerando a prévia das artes grandes…'};
|
||||
if(artes.some(a=>a.decodeError==='grande'))
|
||||
return {pronto:false, falta:'Uma arte grande está em JPG ou WebP. Exporte-a em PNG para montar a folha.'};
|
||||
if(artes.some(a=>a.decodeError || !a.src || !(a.px>0) || !(a.py>0)))
|
||||
if(artes.some(a=>a.decodeError || !(a.src||a.semPrevia) || !(a.px>0) || !(a.py>0)))
|
||||
return {pronto:false, falta:'Não conseguimos ler uma das imagens. Exporte-a novamente em PNG ou JPG antes de continuar.'};
|
||||
if(artes.some(a=>!Number.isFinite(a.cm) || a.cm>larguraFilme()))
|
||||
return {pronto:false, falta:'A largura da arte precisa caber no filme de '+
|
||||
|
||||
@@ -128,7 +128,9 @@ function medir(a){
|
||||
return dimensoesImagem(a.f).then(async d=>{
|
||||
if(!d || !(d.w>0) || !(d.h>0)){ a.decodeError=true; return a; }
|
||||
a.px=d.w; a.py=d.h; a.prop=d.h/d.w; a.grande=true;
|
||||
if(!/\.png$/i.test(a.f.name)){ a.decodeError='grande'; return a; }
|
||||
// JPG and WebP cannot be read in parts: the art is placed by its
|
||||
// measurements, as a full box, and the team checks it before printing.
|
||||
if(!/\.png$/i.test(a.f.name)){ a.semPrevia=true; return a; }
|
||||
a.lendo=0; pintaArtes();
|
||||
let mostrado=0;
|
||||
const cv=await previaPngGrande(a.f, 1200, p=>{
|
||||
|
||||
Reference in New Issue
Block a user