Сокрытие информации в кошках


24

Вы секретный агент, пытающийся общаться со своим отечеством. Конечно, информация должна быть скрыта, чтобы никто не пропустил ваше сообщение. Что будет лучше, чем кошка? Каждый любит смешные фотографии кошек [править] , так что они не будут подозревать , секретная информация скрывается там!


Вдохновленный алгоритмом игры, которую использует Монако для сохранения информации об уровнях общих уровней, ваша задача - написать программу, которая закодировала бы информацию в наименее значимый бит цветов изображения.

Формат кодирования:

  • Первые 24 бита определяют длину оставшейся кодированной строки байтов в битах
  • Изображение читается слева направо и сверху вниз, очевидно, начиная с верхнего левого пикселя.
  • Каналы читаются с красного на зеленый и синий
  • Читается младший значащий бит из каждого канала
  • Биты сохраняются в порядке Big Endian

Правила:

  • Ваша программа принимает одну строку байтов для кодирования и одно имя файла изображения для базового изображения
  • Полученное изображение должно быть в формате PNG.
  • Вы можете использовать ввод / вывод в любой удобной для вас форме (ARGV, STDIN, STDOUT, запись / чтение из файла), если вы указываете, как использовать вашу программу
  • Вы должны выбрать случайное изображение забавного кота и закодировать в нем свою программу, чтобы показать, что ваша программа работает
  • Вы можете предположить, что вам предоставлен только верный ввод, если количество битов недостаточно, изображение не в формате истинного цвета, изображение не существует или аналогичные проблемы, вы можете делать то, что вы хотите
  • Вы можете предположить, что предоставленное изображение не содержит альфа-канала
  • Длина считается в байтах UTF-8 без спецификации

Вы можете использовать этот PHP-скрипт для тестирования вашего решения, указав имя PNG-файла в качестве первого аргумента командной строки:

<?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));
}

Ваша спецификация гласит: «Ваша программа использует в качестве основы одно изображение». В Mathematica изображение на самом деле является просто выражением, как и все остальное, поэтому технически эта спецификация позволила бы мне выполнять загрузку файла вне кода, выполняющего вычисления (с входным параметром, являющимся фактическим изображением вместо имени файла изображения) , Если вам не нужны такие вещи, вы можете указать, что программе необходимо принять имя файла изображения в качестве входного.
Мартин Эндер

4
ME helpimtrappedinacatfactory OW
TheDoctor

Кроме того, биты, не используемые для кодирования, должны оставаться нетронутыми? Или мы можем установить их на то, что мы хотим (так как это не повлияет на качество изображения и не имеет значения для декодирования)?
Мартин Эндер

1
Могу ли я использовать не встроенную библиотеку для загрузки и сохранения файла png, например, PIL в Python?
Клавдиу

1
@TimWolla от кота? Держите его в помещении и следите за лотком для мусора. С фото? Если вы сделаете рентгеновский снимок с достаточно высоким разрешением, вы сможете увидеть состояние отдельных транзисторов в чипе флэш-памяти. Я уверен, что это, должно быть, самый эффективный метод передачи секретной информации, когда-либо созданный, хотя у кошки могут быть другие идеи.
Sonic Atom

Ответы:


3

Perl & ImageMagick (Linux), 198 190

Редактировать: По стечению обстоятельств, ранее я тестировал на компьютере с установленной версией ImageMagick версии 8 (глубина 8 бит). «Стандартная» версия Q16 требует явного указания -depth 8в командной строке. В Linuxidentify результат также требует удаления новой строки. Оба фактора приводят к увеличению размера кода, поэтому я публикую в качестве ответа версию для Linux (возможно, и для Mac), с внесенными исправлениями, а также с удалением некоторых вещей, предназначенных только для Windows (преобразование cr-lf, двоичный файл против текстового и т. Д.). Портативная (чуть длиннее) версия выложена ближе к концу.

С переводами строки для удобства чтения:

$/=$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

Бег:

perl cat.pl

Он читает из STDIN, имя файла изображения в первой строке, затем следует «секретное» сообщение, оканчивающееся на ctrl-D. Имя выходного файла оригинальное с.png добавлением - не очень приятно, это сделано только для краткости.

Вот изображение с некоторой очень секретной информацией, скрытой внутри:

введите описание изображения здесь

И с некоторыми комментариями:

# 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

Далее - портативная версия, работает как в Windows (используется ctrl-Zдля завершения ввода), так и в Linux, количество байт составляет 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

10

Mathematica, 255 234 206 байтов

Я видел так много 255s во время тестирования этого, я безумно рад размеру кода. :) А потом мои амбиции поиграть в гольф еще сильнее одолели меня ...

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)&

Технически это функция, а не «программа», но, опять же, это в значительной степени то, как вы пишете «программы» в Mathematica, если эта концепция там даже действительна. Назови это как

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

Он вернет фактическое выражение изображения (потому что это наиболее естественный способ вернуть изображение в Mathematica), поэтому, если вам нужен файл, вам нужно его экспортировать:

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

Вот обязательный пример:

введите описание изображения здесь

Я хотел бы показать вам декодированное сообщение здесь, но оно не подходит ... так что запустите его через декодер OP. ;)

Кстати, я мог бы заставить его работать с секретами UTF-8 всего за 7 байт (сменить ToCharacterCode@#на #~ToCharacterCode~"utf8").

Ungolfed код:

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"]
)

«Я бы хотел показать вам расшифрованное сообщение здесь, но оно не подходит ... так что запустите его через декодер OP.;)» - я сделал, и это дает мне «????????? ??? +++++++ ?? ++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... для 9773 символов] "
TessellatingHeckler

1
@ TessellatingHeckler, это правильно. попробуйте его моноширинным шрифтом и помните, что в нем есть новые строки в стиле UNIX (например, попробуйте в терминале или PowerShell шириной не менее 180 символов или если вы запускаете его как веб-скрипт в браузере, затем просмотрите источник);)
Martin Ender

2
Я вижу! Очень мета. Помогает, что я тоже в версии PuTTY для KiTTY T
TessellatingHeckler

5

PHP, 530 байт

<?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;}}}

Беги как php 25443.php -i<input image> -o<output image> -t<file to hide>.

А вот пример изображения.

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

Код Ungolfed скрыт в образце. Протестировано с декодером ОП. Извините за не смешную кошачью картинку.


1
Пожалуйста, добавьте незагрязненный код в свой ответ.
AL

1
Вы можете сократить 0xffдо 255.
TimWolla

Вы можете сохранить 4 байта , если вы предполагаете , короткие теги: <?function.
nyuszika7h
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.