Minhas Apostas Antes de Comprimir as Cartas
Por Brenner Cruvinel • 6 minutos de leitura
a compressão não pode ter perda, mesmo que a gente tenha que inventar. eu escrevi essa frase no plano, com essa firmeza, depois do primeiro build. duas linhas depois eu dizia que vídeo lossless com as cartas ordenadas por similaridade era um caminho, e mais acima tinha descartado o jpegtran porque "sem perda não conta". só fui perceber quando sentei pra escrever as apostas e tive que definir o que eu ia medir, e medir exige dizer contra o quê. sem perda em relação a quê? eu não tinha resposta. eu tinha usado a mesma palavra pra três coisas e não tinha notado.
por que zstd não morde jpeg
um jpeg já passou por três etapas que esgotam a redundância que um compressor genérico sabe achar. a imagem vira coeficientes de frequência, os coeficientes de alta frequência são arredondados (é aí que a perda acontece), e o resultado passa por um codificador de entropia. o que sai é um fluxo de bits onde os padrões repetidos já foram comidos. o zstd procura exatamente padrão repetido. é como tentar dobrar um papel que já foi dobrado até o limite: não fica menor, só amassa.
então sem perda em cima de jpeg tem três sentidos, e só um merece o nome. o primeiro é repackar o jpeg de um jeito que a operação inversa devolve o arquivo original byte a byte. o jpeg xl faz isso: pega os coeficientes já arredondados e reescreve com um codificador de entropia melhor, guardando o suficiente pra desfazer. a perda do jpeg continua lá, mas a embalagem fica mais apertada.
o segundo é re-salvar o mesmo jpeg com jpegtran ou jpegoptim. os pixels ficam idênticos e os bytes mudam. sem perda pra quem olha, não pra quem confere o hash. e se a fonte já veio otimizada, como os arquivos do scryfall, o ganho tende a zero.
o terceiro é o que eu estava propondo sem saber: decodificar os pixels e recomprimir com outro codec sem perda, png, webp, ou vídeo em ffv1. parece o sentido mais puro e é o pior. o novo codec recebe pixels que carregam o ruído do arredondamento do jpeg como se fosse sinal, e gasta bit pra representar esse ruído com fidelidade. o resultado tem tudo pra ficar maior que o jpeg de origem, não menor. eu escrevi isso e ainda não acreditava, por isso a aposta.
tem uma quarta coisa, que não é um sentido e sim um buraco. existe um paper de 2016, da microsoft research, que comprime coleções de fotos jpeg sem perda em cima de trinta por cento, montando um pseudo-vídeo direto no domínio dos coeficientes, sem decodificar pixel nenhum. é exatamente o que a ideia inventada queria ser, feito do jeito certo. só que não existe implementação aberta, e eu não ia escrever um codec naquela semana. então o que eu podia medir era o teto com as ferramentas que existem. o teto de verdade, se aquele paper reproduz, está mais alto, e eu quero deixar isso dito antes de dar meu número.
o que eu apostei e por quê
anotei antes de rodar porque da última vez que publiquei um número sem aposta escrita tive que corrigir dois dias depois, e corrigir número publicado é pior do que errar aposta em público.
vídeo av1 com perda comprime bem mais que jpeg solto. sim, foi o que o primeiro build mostrou e o que eu tinha visto na dermatoscopia. quanto mais parecidas as cartas vizinhas, mais o vídeo ganha. sim, e com força: o banco tem 100 mil impressões pra 52 mil ilustrações, quase metade das cartas repete uma arte que já existe em outra, e todas dividem a mesma moldura. se existe ganho de vídeo, ele mora aí.
acelerar o vídeo corta bytes. eu tinha jogado um dos mp4 no capcut, acelerado sessenta vezes, e o arquivo saiu com metade do tamanho. aposto que sim, e se for verdade é a coisa mais barata da lista. tar mais zstd ganha alguma coisa? acho que não, pelo motivo da seção de cima. e a ordenação por similaridade vale também pra cartas únicas? acho que não, já vi ordenação não fazer nada em outro dataset, mas a moldura compartilhada me deixa em dúvida.
e a que eu mais queria: existe sem perda melhor que jpeg, "mesmo inventando". depois de escrever os três sentidos mudei de ideia no meio da aposta. o candidato passou a ser o jpeg xl, e o vídeo sem perda ordenado por similaridade, a ideia inventada, vai perder. as duas que eu mais queria que fossem verdade, o capcut e o sem perda, eram as que eu menos conseguia defender. isso costuma ser um sinal.
a bateria sem perda rodou na mesma noite, dez gerações em cima das mesmas 2048 cartas. tar mais zstd deu um pra um, cravado. re-salvar com jpegtran rendeu menos de um por cento, os jpeg do scryfall já vêm otimizados. o teto foi o repack em jpeg xl, uns 11% menor, com os 2048 arquivos originais reconstruídos e validados por hash. subir o esforço do encoder pro máximo rende menos de um por cento a mais por seis vezes o tempo, então o padrão ficou no esforço médio.
e a ideia inventada perdeu feio. ffv1 e x264 sem quantização, com as cartas ordenadas por similaridade, ficaram três a quatro vezes maiores que o jpeg de origem. a ordenação, nesse regime, moveu o tamanho em quase nada, uma fração de mega num arquivo de centenas. pixel decodificado de jpeg carrega ruído e nenhum codec prevê ruído, do jeito que eu tinha escrito de manhã sem acreditar.
isso virou o perfil de arquivo do nest: quem não aceita perder nada recebe o jpeg xl repack, 3,6 GB pro corpus inteiro, e cada jpeg volta bit a bit quando pedir. não é o número que eu queria. é o número que dá pra defender com hash, e eu prefiro esse. as outras apostas, as com perda, estavam rodando enquanto eu escrevia isso. a do capcut eu já tava com medo de olhar.