Приховування інформації в Кішок


24

Ви секретний агент, який намагається спілкуватися зі своєю вітчизною. Звичайно, інформацію потрібно приховати, щоб ніхто не підпускав ваші повідомлення. Що б краще підходило, ніж кішка? Усі люблять смішні фотографії котів [потрібна цитата] , тому вони не підозрюють, що там ховається таємна інформація!


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

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

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

Правила:

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

Ви можете використовувати цей скрипт 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 Q8 (8 бітною глибиною). Версія 'Standard' Q16 вимагає явного -depth 8в командному рядку. В Linux identifyрезультат також потребує видалення нового рядка. Обидва фактори призводять до збільшення розміру коду, тому я розміщую версію Linux (мабуть, також для Mac) як відповідь, із застосованими виправленнями, а також із видаленими лише елементами Windows (CR-lf конверсія, бінарний vs текст тощо). Портативна (трохи довша) версія розміщена наприкінці.

З новими рядками для читабельності:

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

Математика, 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"]]

Ось необхідний приклад:

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

Я хотів би показати вам розшифроване повідомлення тут, але воно не підходить ... тому запустіть його через декодер ОП. ;)

До речі, я міг би змусити його працювати з UTF-8 секретів для всього 7 байт (зміна ToCharacterCode@#в #~ToCharacterCode~"utf8").

Невикористаний код:

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

"Я хотів би показати вам розшифроване повідомлення тут, але воно не підходить ... тому запустіть його через декодер ОП.)" - Я це зробив, і він дає мені "????????? ??? +++++++ ?? ++++++++++++++++++++================== ~ === ~ ============ ~ :::: ~~~~~ = [... для 9773 символів] "
— TessellationHeckler

1
@TessellatingHeckler, це правильно. спробуйте його з односхилим шрифтом і пам’ятайте, що там є нові рядки в стилі UNIX (наприклад, спробуйте в терміналі або PowerShell шириною не менше 180 символів, або якщо ви використовуєте його як веб-скрипт у своєму браузері, потім перегляньте джерело);)
— Мартін Ендер

2
Розумію! Дуже мета. Допомагає, що я теж у версії PuTTY KiTTY 😸
— 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

Код без вольфу прихований у зразковому зображенні. Випробуваний за допомогою декодера OP. Вибачте за не смішну картинку кота.


1
Будь-ласка, додайте у відповідь код, який не використовується.
— AL

1
Можна скоротити 0xffдо 255.
— TimWolla

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