feat: pack large artworks in Artes avulsas from a streamed copy
Some checks failed
Build and deploy / Validate source (push) Successful in 6s
Build and deploy / Integration suite on a real stack (push) Failing after 2m36s
Build and deploy / Secret scan and release gate (push) Successful in 8s
Build and deploy / Publish images (push) Has been skipped

Artes avulsas decoded every file whole, and the packing decoded each one
again on every repaint, so a large artwork failed to load. A PNG over 150
MB is now measured from its header (pixel size, so DPI and grade stay
exact) and packed from a 1200-pixel copy read as a stream, with progress on
its card; every artwork's image is loaded once and reused by the packing.
A large JPG or WebP asks for a PNG, and the grade card no longer calls a
file unreadable while it is still being read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cauê Faleiros
2026-09-29 16:02:35 -03:00
parent 64e47ee481
commit f4aacb5776
4 changed files with 51 additions and 4 deletions

View File

@@ -492,11 +492,23 @@ function sugestao(a){
}
const n1=v=>v.toFixed(1).replace('.',',');
// Moves one artwork's progress in place, without repainting the list.
function pintaProgressoArte(a){
const el=$('lista').querySelector('.art[data-arte="'+artes.indexOf(a)+'"]');
const barra=el && el.querySelector('.prog i'), texto=el && el.querySelector('.progT');
if(!barra){ pintaArtes(); return; }
barra.style.width=a.lendo+'%'; if(texto) texto.textContent='arquivo grande · gerando a prévia… '+a.lendo+'%';
}
function pintaArtes(){
invalidaItemAtual();
$('lista').innerHTML=artes.map((a,i)=>{
let barra='', dica='', calc='<span>informe a largura para ver a qualidade</span>';
if(a.decodeError){
if(a.lendo!=null){
barra='<div class="prog"><i style="width:'+a.lendo+'%"></i></div>';
calc='<span class="progT">arquivo grande · gerando a prévia… '+a.lendo+'%</span>';
}else if(a.decodeError==='grande'){
calc='<span class="er">Arquivo grande em JPG ou WebP: exporte em PNG para montar a folha</span>';
}else if(a.decodeError){
calc='<span class="er">Não conseguimos ler esta imagem; exporte novamente em PNG ou JPG</span>';
}else if(a.cm>larguraFilme()){
calc='<span class="er">Largura maior que o filme de '+n1(larguraFilme())+' cm</span>';
@@ -518,7 +530,7 @@ function pintaArtes(){
n1(sug.cm)+' cm.<button data-usar="'+i+'" data-cm="'+sug.alvo+'">Usar '+n1(sug.alvo)+' cm</button></div>'
: '';
}
return '<div class="art'+(a===recemChegada?' nova':'')+'"><div class="l1"><b>'+escapeHTML(a.f.name)+'</b>'+
return '<div class="art'+(a===recemChegada?' nova':'')+'" data-arte="'+i+'"><div class="l1"><b>'+escapeHTML(a.f.name)+'</b>'+
'<span style="color:var(--fraco);font-size:10.5px">'+
(a.px>0?a.px+' × '+a.py+' px':'a ler')+'</span>'+
'<button data-rm="'+i+'">×</button></div><div class="cps">'+