Ocultando informações em gatos

24

Você é um agente secreto tentando se comunicar com sua pátria. É claro que a informação precisa estar oculta para que ninguém escute a sua mensagem. O que seria mais adequado do que um gato? Todo mundo adora fotos engraçadas de gatos [carece de fontes?] , Para que eles não vão suspeitar informações esconderijo secreto lá!


Inspirado no algoritmo que o jogo Monaco usa para salvar as informações de níveis compartilhados , é sua tarefa escrever um programa que codifique as informações nas partes menos significativas das cores de uma imagem.

Formato de codificação:

  • Os primeiros 24 bits determinam o comprimento da cadeia de bytes codificada restante em bits
  • A imagem é lida da esquerda para a direita e de cima para baixo, obviamente começando no pixel superior esquerdo
  • Os canais são lidos de vermelho para verde e azul
  • O bit menos significativo de cada canal é lido
  • Os bits são salvos na ordem Big Endian

Regras:

  • Seu programa usa uma única sequência de bytes para ser codificada e um nome de arquivo de imagem único para a imagem base
  • A imagem resultante deve ser exibida como um arquivo PNG de cor verdadeira
  • Você pode usar E / S da forma que desejar (ARGV, STDIN, STDOUT, gravação / leitura de um arquivo), desde que indique como usar seu programa
  • Você deve escolher uma imagem aleatória de um gato engraçado e codificar seu programa para mostrar que seu programa funciona
  • Você pode presumir que você recebeu apenas uma entrada válida, se a quantidade de bits não for suficiente, a imagem não estiver no formato de cores verdadeiras, a imagem não existir ou problemas semelhantes, você pode fazer o que deseja
  • Você pode assumir que a imagem fornecida não contém nenhum canal alfa
  • O comprimento é contado em bytes UTF-8 sem BOM

Você pode usar esse script PHP para testar sua solução, fornecer o nome do arquivo PNG como o primeiro argumento da linha de comando:

<?php
if ($argc === 1) die('Provide the filename of the PNG to read from');
$imageSize = @getimagesize($argv[1]);

if ($imageSize === false) die('Not a PNG file');
list($width, $height) = $imageSize;

$image = imagecreatefrompng($argv[1]);
$read = 0;
$bits = '';
for ($y = 0; $y < $height; $y++) {
    for ($x = 0; $x < $width; $x++) {
        $colorAt = imagecolorat($image, $x, $y);
        $red = ($colorAt >> 16) & 0xFF;
        $green = ($colorAt >> 8) & 0xFF;
        $blue = ($colorAt >> 0) & 0xFF;

        $bits .= ($red & 1).($green & 1).($blue & 1);
        $read += 3;
        if ($read == 24) {
            $length = (int) bindec($bits);
            $bits = '';
        }
        else if ($read > 24 && ($read - 24) > $length) {
            $bits = substr($bits, 0, $length);
            break 2;
        }
    }
}
if (strlen($bits) !== $length) die('Not enough bits read to fulfill the length');
$parts = str_split($bits, 8);
foreach ($parts as $part) {
    echo chr(bindec($part));
}
TimWolla
fonte
Sua especificação diz "seu programa usa uma única imagem como base". No Mathematica, uma imagem é na verdade apenas uma expressão como todo o resto; portanto, tecnicamente, essa especificação me permitiria carregar o arquivo fora do código que executa o cálculo (com o parâmetro de entrada sendo uma imagem real em vez do nome do arquivo da imagem) . Se você não deseja coisas assim, pode especificar que o programa precisa usar o nome do arquivo de uma imagem como entrada.
Martin Ender
4
ME helpimtrappedinacatfactory OW
TheDoctor
Além disso, os bits não usados ​​para codificação precisam permanecer intocados? Ou podemos configurá-los para o que quisermos (já que isso realmente não afeta a qualidade da imagem e não importa para decodificação)?
22868 Martin Ender #
11
Posso usar uma biblioteca não embutida para carregar e salvar o arquivo png, por exemplo, PIL em Python?
Claudiu
11
@TimWolla Do gato? Mantenha-o dentro de casa e monitore a bandeja de areia. Da foto? Se você tirar uma foto de raio-x de alta resolução, poderá ver o estado dos transistores individuais no chip flash. Estou certo de que esse deve ser o método mais eficiente de transmitir informações secretas já criadas, embora o gato possa ter outras idéias.
Sonic Atom

Respostas:

3

Perl e ImageMagick (Linux), 198 190

Edit: Por alguma coincidência, eu testei anteriormente em um computador com a versão Q8 (profundidade de 8 bits) do ImageMagick instalada. A versão Q16 'padrão' requer explícita -depth 8na linha de comando. No Linux, o identifyresultado requer que a nova linha seja removida também. Ambos os fatores levam ao aumento do tamanho do código, portanto, eu posto a versão Linux (provavelmente Mac também) como resposta, com as correções aplicadas e também com algumas coisas somente para Windows removidas (conversão cr-lf, binário vs texto etc.). A versão portátil (um pouco mais longa) é publicada perto do fim.

Com novas linhas para facilitar a leitura:

$/=$1;
<>=~/\n/;
$_=`identify -format %wx%h $\``;
chop;
open O,"|convert -size $_ -depth 8 rgb: $`.png";
$_=`convert $\` rgb:`;
print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr

Corre:

perl cat.pl

Ele lê STDIN, nome do arquivo de imagem na primeira linha, a mensagem 'secreta' segue e termina com ctrl-D. O nome do arquivo de saída é original com .pnganexado - não é muito bom, é feito apenas por uma questão de brevidade.

Aqui está uma imagem com algumas informações muito secretas ocultas:

insira a descrição da imagem aqui

E com alguns comentários:

# Undef input record separator, because we'll slurp input.

$/=$1;

# Read from STDIN, separate first line. 
# $` (prematch) contains image file name,
# $' (postmatch) - text to encode.

<>=~/\n/;

# Get IM's 'identify' output, width and height of the image. 
# Note: we don't have to separate them, \d+x\d+ string will 
# do just fine.

$_=`identify -format %wx%h $\``;
chop;

# Open output pipe - IM's 'convert' command that takes raw RGB data from 
# STDIN and writes output to PNG file. Interpolated into this command
# line is previous IM's 'identify' result. Convert wants '-size' command
# option in case of raw RGB input - for obvious reason.

open O,"|convert -size $_ -depth 8 rgb: $`.png";

# Get raw RGB data into $_.

$_=`convert $\` rgb:`;

# Last line does all the job. 

# y//\376/cr --- create string same length as $_, fill with 0xFE
# $_&y//\376/cr --- zero least significant bit for all image bytes (1).
# pack(NX,2048*length$') --- multiply by 8 (bytes to bits count) and 
#         shift left by 8 (because we'll pack long integer into 3 bytes) -
#         i.e. multiply by 2048.
# unpack('B*',pack(NX,2048*length$').$') ---- append 'secret text' to 
#       its encoded length and convert to 'binary' (consisting of 1 and 
#       0 characters) string.
# ... &y//\1/cr --- equivalent of tr/01/\0\1/. We don't have to worry 
#       that raw RGB length is larger than encoded text length, because
#       '&' truncates longer string argument (2).
# Then bitwise-'or' (1) and (2) strings.

print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr

Em seguida, é a versão portátil, roda no Windows (use ctrl-Zpara finalizar a entrada) e no Linux; a contagem de bytes é 244.

$_=do{local$/;<>};
/\n/;
$_=`identify -format %wx%h $\``;
chomp;
open I,'-|:raw',"convert $` rgb:";
open O,'|-:raw',"convert -size $_ -depth 8 rgb: $`.png";
$_=do{local$/;<I>};
print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr
user2846289
fonte
10

Mathematica, 255 234 206 bytes

Eu já vi tantos 255s ao testar isso, estou irracionalmente feliz com o tamanho do código. :) E então a minha ambição de jogar golfe ainda me tirou o melhor ...

f=(j=ImageData[Import@#2,t="Byte"];k=(d=IntegerDigits)[j,2,8]~Flatten~2;n=1;(k[[n++,-1]]=#)&/@d[Length@#,2,24]~Join~#&[Join@@d[ToCharacterCode@#,2,8]];ArrayReshape[#~FromDigits~2&/@k,Dimensions@j]~Image~t)&

Tecnicamente, é uma função e não um "programa", mas, novamente, é assim que você escreve "programas" no Mathematica, se esse conceito é válido até lá. Chame como

f["my secret", "fully/qualified/cat.png"]

Ele retornará uma expressão de imagem real (porque essa é a maneira mais natural de retornar uma imagem no Mathematica); portanto, se você quiser um arquivo, precisará exportá-lo:

Export["output-cat.png", f["my secret", "input-cat.png"]]

Aqui está o exemplo necessário:

insira a descrição da imagem aqui

Eu adoraria mostrar a mensagem decodificada aqui, mas ela não se encaixa ... então execute-a no decodificador do OP. ;)

Btw, eu poderia fazê-lo funcionar com segredos UTF-8 por apenas 7 bytes (mudar ToCharacterCode@#para #~ToCharacterCode~"utf8").

Código não destruído:

f[secret_, filename_] := (
  bits = Join @@ IntegerDigits[ToCharacterCode[secret], 2, 8];
  bits = Join[d[Length @ bits, 2, 24], bits];
  data = ImageData[Import@#2, "Byte"];
  dims = Dimensions@data;
  data = Flatten[IntegerDigits[data, 2, 8], 2];
  m = n = 1;
  While[m <= Length @ bits,
    data[[n++, -1]] = bits[[m++]]
  ];
  Image[ArrayReshape[FromDigits[#, 2] & /@ data, dims], "Byte"]
)
Martin Ender
fonte
"Adoraria mostrar a mensagem decodificada aqui, mas ela não se encaixa ... então, execute-a no decodificador do OP.;)" - eu fiz e isso me dá "????????? ??? +++++++ ?? ++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... para 9773 caracteres] "
TessellatingHeckler
11
@TessellatingHeckler, está correto. tente em uma fonte monoespaçada e esteja ciente de que há novas linhas no estilo UNIX (por exemplo, tente em um terminal ou PowerShell com pelo menos 180 caracteres de largura ou se você o estiver executando como um script da web em seu navegador, então veja a fonte);)
Martin Ender
2
Eu vejo! Muito meta. Ajuda que estou na versão vaquinha do PuTTY também 😸
TessellatingHeckler
5

PHP, 530 bytes

<?php function p($i,$j){return str_pad(decbin($i),$j,0,0);}extract(getopt("i:o:t:"));$t=file_get_contents($t);$_=imagecreatefrompng($i);list($w,$h)=getimagesize($i);$b="";for($i=0;$i<strlen($t);)$b.=p(ord($t[$i++]),8);$l=strlen($b);$b=p($l,24).$b;$l+=24;for($i=$x=$y=0;$y<$h;$y++){for(;$x<$w;){$C=imagecolorat($_,$x,$y);$R=($C>>16)&0xff;$G=($C>>8)&0xff;$B=$C&0xff;$i<$l&&$R=$b[$i++]|$R&~1;$i<$l&&$G=$b[$i++]|$G&~1;$i<$l&&$B=$b[$i++]|$B&~1;imagesetpixel($_,$x++,$y,imagecolorallocate($_,$R,$G,$B));if($i>$l){imagepng($_,$o);die;}}}

Corra como php 25443.php -i<input image> -o<output image> -t<file to hide>.

E aqui está uma imagem de amostra.

http://i.imgur.com/hevnrbm.png

O código não-oculto está oculto na imagem de amostra. Testado com o decodificador do OP. Desculpe pela imagem do gato não é engraçado.

Lanche
fonte
11
Por favor, adicione o código não protegido na sua resposta.
AL
11
Você pode reduzir 0xffpara 255.
TimWolla
Você pode salvar 4 bytes se você assumir tags curtas: <?function.
precisa saber é o seguinte