Como posso armazenar os metadados do jogo em um arquivo .png?

208

O Spore permite que criaturas criadas por jogadores sejam compartilhadas exportando um .pngarquivo. Essa .pngé uma foto da criatura, mas se for importada para o jogo, as informações da criatura (como texturas, tamanho e forma) também serão fornecidas.

Como posso implementar esse recurso?

ibrabeicker
fonte
5
Deveria ter uma pontuação muito maior, essa é uma pergunta muito interessante.
Pierre Arlaud
3
O canal alfa poderia ser parcialmente abusado para este ...
Tobias KIENZLER
3
De uso possivelmente: stackoverflow.com/questions/9542359/...
lógica de unidade
11
Eu acho que é melhor armazenar esses dados em outro arquivo. Nesse arquivo, deve haver o nome do arquivo de textura relacionado a uma entidade na qual você deseja que os dados sejam armazenados. Primeiro por uma questão de explicitação (o formato png é para gráficos - "Portable Network Graphics"), segundo: considere uma situação em que você deseja armazenar mais imagens com uma entidade, você pode simplesmente adicionar referências a esse arquivo personalizado. Você provavelmente terá problemas para armazenar imagens diferentes (tamanho diferente, profundidade diferente etc.) em um PNG.
luke1985
3
O canal alfa foi mencionado muito e, é claro, os PNGs suportam metadados de qualquer maneira, mas eu pensei em compartilhar uma técnica que usei - percorrendo da esquerda para a direita, de cima para baixo e pelos canais em uma ordem fixa , e arredondar os valores para probabilidades ou pares - não importa se é para cima ou para baixo. Uma mudança de 1 em QUALQUER canal não faz diferença perceptível e, em uma imagem de 256x256 (a 4 bits por pixel, é claro), você pode armazenar impressionantes 32 KB de dados. Se você precisar de ainda mais, você poderia arredondar para% 4 em vez - muito e ele começa a se parecer com uma mente GIF velho ..
Octopoid

Respostas:

56

Se tudo o que você realmente precisava era o arquivo PNG, é provável que eles simplesmente adicionassem as informações ao arquivo. Esta é realmente uma prática de esteganografia . Na maioria das vezes, isso é usado para ocultar cargas úteis ou mensagens secretas em coisas aparentemente públicas. No entanto, é provável que, neste caso, esse método seja o que foi usado. A estegrafia típica não permite ocultar o conteúdo, mas não há razão para que não se possa simplesmente anexar os dados da imagem no final do arquivo e recuperá-los.

Várias ferramentas codificam esses dados para você, uma pesquisa no google traz pelo menos isso e isso .

Um PNG possui a assinatura de bytes $89no início, portanto, é possível que as informações tenham sido inseridas após a própria estrutura PNG e simplesmente analisadas pelo jogo SPORE.

No entanto, pesquisas adicionais fornecidas por outras respostas e uma pesquisa no google revelam que Spore estava realmente usando apenas uma versão do Stegongraphy para ocultar as informações nos bits alfa. Com isso em mente, podemos descartar a possibilidade de dados anexados ou metadados.

Deve-se notar que os metadados ainda são uma opção muito viável, se os dados estiverem sendo analisados ​​localmente. Se essas informações puderem ser compartilhadas na Web ou recodificadas, não é garantido que a exportação mantenha todas as suas informações. Quando dados de pixel são usados, eles podem sobreviver a conversões sem perdas sem problemas.

Vaughan Hilts
fonte
3
Tanto quanto eu sei, esporos metadados armazenados dentro do canal alfa do PNG.
Tara
28
Por que usar o canal alfa ou a esteganografia quando o PNG suporta blocos de metadados arbitrários?
Russell Borogove
8
“Um PNG tem a assinatura de bytes" 89 "no início, portanto, é muito provável que as informações tenham sido inseridas antes ou depois da estrutura PNG e simplesmente analisadas pelo jogo SPORE.” Se fosse esse o caso, não seria ' não seja mais um arquivo PNG. Ou seja, os visualizadores de imagens comuns não seriam capazes de exibi-lo.
precisa
3
@RussellBorogove uma razão bastante boa: se o PNG for decodificado / codificado por algo além do Spore, os pedaços arbitrários de metadados terão mais probabilidade de serem ignorados ou perdidos do que os dados reais da imagem. A codificação dos dados na imagem aumenta a probabilidade de que, se você puder vê-los, poderá carregá-los .
Tim S.
@svick Na verdade, eu brinquei com um arquivo que era um PNG e RAR válidos. O cabeçalho RAR foi iniciado após o PNG e os extratores RAR estavam corretos. Também pode funcionar bem da outra maneira.
Cortices
153

O formato PNG tem suporte para metadados mais ou menos arbitrários. O padrão PNG define um arquivo PNG, essencialmente uma série de blocos, alguns dos quais são necessários (e contêm os dados da imagem). Outros, no entanto, são opcionais. Por exemplo, há uma parte para armazenar informações de gama ou dados de histograma.

Em particular, há um tEXtpedaço que pode ser usado para armazenar pares de texto chave / valor arbitrários. Isso pode ser usado para enviar qualquer tipo de dados arbitrários que você desejar, desde que você possa representá-los como texto (o que é bastante provável).

Você precisará de uma biblioteca PNG que permita acessar e manipular esses pedaços adicionais (como a biblioteca de referência ), ou precisará escrever um. Depois, basta escolher como codificar os dados que você deseja como pares de chave / valor. Eu sugiro o seguinte:

  • escolha nomes-chave que sejam prefixados com o nome ou código de seu projeto como forma de criar um sistema bruto de "espaço para nome" e evite possíveis conflitos com o uso dos dados por outros aplicativos
  • não tente armazenar texturas reais dessa maneira, armazene referências às texturas que apontam para o banco de dados de ativos do seu jogo
  • dados como tamanho de criatura ou objeto, peso etc. - escalares simples, basicamente - podem ser armazenados trivialmente

No interesse de fazer uma resposta mais completa, também apontarei que existe outra abordagem (previamente documentada pelas respostas de @Vaughn e @ Alexis): codifique os dados adicionais que você deseja diretamente nos pixels da imagem, distribuindo os dados pelos os bits de ordem inferior dos canais de cores. Essa abordagem não requer o uso de metadados extras, o que significa que você pode implementá-los completamente sem depender deles ou se preocupar com programas externos que lidam incorretamente com esses metadados. Ele também possui um fator "legal" muito alto e, como você usa apenas bits de baixa ordem, a imagem ainda parece correta para o olho humano. No entanto, isso significa que o tamanho da sua imagem é o principal fator de controle da quantidade de dados que você pode armazenar; se precisar de mais armazenamento, aloque mais pixels na imagem.

Como outros já apontaram, esse processo é conhecido como esteganografia .

Josh
fonte
3
Alguém poderia simplesmente enviar os dados através Base64 e armazená-lo como um único valor
CodesInChaos
11
@ da4c30ff Por mais práticos que sejam os metadados, a esteganografia tem um certo fator legal de fantasia de espião, difícil de resistir à nossa multidão. Se eu estivesse fazendo isso pessoalmente, usaria o método proposto por Josh Petrie para escalabilidade, mas ficaria muito tentado a usar a esteganografia para ocultar uma soma de verificação na própria imagem para verificar se a imagem e o texto pertencem um ao outro - não porque isso é útil ou seguro, mas apenas porque é legal. ;)
DMGregory
O que exatamente "texto" significa aqui? Somente ASCII (caractere <= 127)? Qualquer byte, exceto 0? Algum byte? Ou alguma outra coisa? (Isso vai afetar a codificação que você precisa usar para gravar dados binários Por exemplo, se você precisa de base64 ou não..)
svick
11
Atualizei a resposta com um link para o padrão do bloco de texto; mas basicamente, o texto é interpretado de acordo com a ISO 8859-1 (caracteres de 8 bits, byte único e caracteres latinos 1).
Josh
51

O desenvolvedor do Mônaco realmente fez um excelente artigo sobre como eles e Spore conseguiram isso.

O resumo básico do que eles fazem é bastante simples:

  • Converta seus dados em binários
  • Converta sua imagem de destino em um bitmap bruto
  • Caminhe pelos pixels da imagem em algum padrão previsível (eles simplesmente saem da esquerda para a direita no canto superior esquerdo).
  • Escreva um bit no bit de ordem mais baixa de cada canal de cores de cada pixel
  • Exporte o bitmap modificado para png novamente

Basta fazer isso no sentido inverso para recuperar seus dados.

A idéia básica por trás do processo é que existem muitos pixels em uma imagem, e os bits de ordem mais baixa de cada canal de cor não fazem grande diferença. Além disso, cerca da metade dos bits que você escreve será exatamente o que já existia na imagem. O que você recebe de volta é essencialmente a imagem certa, mas com artefatos estranhos. Ele leva um tempo para notar que esses artefatos são realmente perceptíveis se você realmente aumentar o contraste / saturação e aumentar o zoom. No entanto, ele possui imagens de origem com muito ruído inicial.

Do artigo:

Observe na última imagem como há uma linha horizontal quase imperceptível no ruído. Esse é o fim dos dados de nível. O que isso significa é que eu posso encaixar todos os dados de nível em uma imagem de 265 x 120 pixels, usando apenas o bit menos significativo.

Um adendo complicado:

Algo que eu poderia fazer, e acredito que o pessoal do Spore também fez, é usar TODOS os bits de cores em pixels que são 100% transparentes. Como esses pixels são transparentes, não importa em que cor você os define.

No entanto, não posso fazer isso, pois estou usando a imagem inteira, o que significa que não tenho pixels transparentes para trabalhar.

Por que favorecer essa técnica em vez de apenas armazená-la nos metadados?

  • É mais divertido! :)
  • Os serviços podem alterar metadados (possivelmente como um recurso de privacidade / segurança), mas não devem alterar os pixels dos png, a menos que tenham requisitos agressivos de hospedagem de imagens (olhando para você, facebook). Mas se eles estão reexportando completamente sua imagem, não há nada que você possa fazer com segurança .

Crédito extra: para reduzir a perceptibilidade do ruído, você pode usar um PRNG com uma semente fixa para selecionar os pixels a serem modificados. Você também pode modificar apenas alguns dos canais de cores de maneira semelhante.

Alexis Beingessner
fonte
6
Existem algoritmos esteganográficos mais robustos contra o ajuste de escala / cor da imagem do que o método Monaco. (Embora eles geralmente armazenar dados a uma densidade substancialmente mais baixa) Um exemplo é o de marca d'água utilizada no mundo de imagens Warcraft: ownedcore.com/forums/world-of-warcraft/...
DMGregory
@DMGregory Nice find! O algoritmo preciso que você escolher deve, obviamente, ser decidido pelo seu caso de uso específico (espaço, durabilidade, sigilo etc.).
Alexis Beingessner
11
Por mais legal que isso possa parecer, é uma má idéia. As imagens PNG usam compactação de imagem sem perdas; brincar com os baixos bits da imagem, provavelmente, tornar o arquivo maior , ao mesmo tempo em que (ligeiramente) reduz a qualidade da imagem. Absolutamente qualquer informação pode ser codificada como "texto", portanto, usar um pedaço de metadados é a maneira obviamente correta de fazer isso; alguém mexendo em pedaços de imagem sem realmente precisar de esteganografia está apenas dando voltas.
Dfeuer
11
@dfeuer - Aparentemente, Spore e Mônaco estavam usando estruturas de jogos que possuem um pipeline de carregamento de ativos que reduz o .PNG a um bitmap simples, para que os blocos de metadados não estivessem conseguindo.
Russell Borogove
11
@fefe Eu fiz alguns testes ingênuos. A abordagem de metadados parece adicionar cerca de 80% do tamanho adicionado pela abordagem estenográfica ao gravar 100kB de bits aleatórios em uma imagem de 1920x1080px. Testado em uma imagem em branco e uma captura de tela da área de trabalho. Não é exatamente uma diferença catastrófica, mas os dados de carne são certamente melhores (e mais consistentes) se você estiver realmente preocupado com mais de 40kB. Observe que os metadados ainda eram bastante ineficientes. Ganhei 181kB por escrever 100kB de dados! Pode haver espaço para otimizar como a string é codificada ou algo assim.
Alexis Beingessner
7

Baixei e examinei algumas criaturas Spore da Sporepedia. Daqueles eu aprendi que:

  • As imagens não contêm informações além dos dados de imagem padrão.
  • Os dados estenográficos foram armazenados sem considerar a imagem, pode-se imaginar que as partes transparentes foram usadas exclusivamente, mas não são.
  • O uso do armazenamento depende da quantidade de informações que precisam ser armazenadas, algumas das imagens usaram apenas o bit menos significativo para armazenamento de dados, algumas usaram os dois bits menos significativos, outras podem usar mais.
  • O formato Spore evita o uso de um bit em apenas parte da imagem; o bit menos significativo muda em toda a imagem; se o segundo bit menos significativo for usado, ele será usado em toda a imagem. Presumivelmente, isso é feito usando preenchimento aleatório. Isso evita uma mudança na qualidade que pode ser mais perturbadora para o espectador do que o próprio ruído.
  • Todos os quatro canais são usados ​​igualmente; o canal de opacidade não recebe tratamento especial; portanto, alguns dos pixels transparentes são ligeiramente opacos, enquanto outros pixels opacos são levemente transparentes.

Vale a pena notar que é exatamente isso que o Spore faz, é um método que coloca a simplicidade antes da maioria das outras preocupações.

A escolha de usar a estenografia em vez de um bloco de dados adicional significa que os dados sobreviverão se a imagem for recodificada, por exemplo, por um site, embora não sobreviva ao dimensionamento ou à compressão JPEG.

Eu acho que a alternativa mais importante é realmente codificar apenas um ID na imagem e deixar os dados reais serem armazenados em um servidor central, onde esse ID pode ser trocado pelos dados exatos da criatura. Esse ID seria curto o suficiente para ser codificado em um formato de estenografia tolerante à escala e à compactação.

Possíveis melhorias simples no formato Spore incluem:

  • Use apenas ou prefira usar os valores de cor dos pixels transparentes, pois eles não fazem diferença visual.
  • Use o canal azul mais e o canal verde menos, a cor azul tem um menor impacto percebido na imagem.
  • Mantendo a luminância de cada pixel inalterada e codificando os dados em chroma, um pouco de ruído nesse parâmetro é praticamente indetectável para os seres humanos.
aaaaaaaaaaaa
fonte