Informationen in Cats verstecken

24

Sie sind ein Geheimagent, der versucht, mit Ihrem Vaterland zu kommunizieren. Natürlich müssen die Informationen verborgen sein, damit niemand Ihre Nachricht abfängt. Was wäre besser geeignet als eine Katze? Jeder liebt lustige Bilder von Katzen [Zitat benötigt] , damit sie nicht den Verdacht haben, dass sich dort geheime Informationen verstecken!


Inspiriert von dem Algorithmus, den Monaco verwendet, um die Level-Informationen von gemeinsam genutzten Levels zu speichern , ist es Ihre Aufgabe, ein Programm zu schreiben, das Informationen in das niedrigstwertige Bit der Farben eines Bildes codiert.

Kodierungsformat:

  • Die ersten 24 Bits bestimmen die Länge der verbleibenden codierten Bytefolge in Bits
  • Das Bild wird von links nach rechts und von oben nach unten gelesen, wobei offensichtlich mit dem oberen linken Pixel begonnen wird
  • Die Kanäle werden von rot über grün nach blau ausgelesen
  • Das niedrigstwertige Bit von jedem Kanal wird gelesen
  • Bits werden in Big Endian-Reihenfolge gespeichert

Regeln:

  • Ihr Programm benötigt eine einzelne zu codierende Bytefolge und einen einzelnen Bilddateinamen für das Basisbild
  • Das resultierende Bild muss als True-Color-PNG-Datei ausgegeben werden
  • Sie können I / O in beliebiger Form verwenden (ARGV, STDIN, STDOUT, Schreiben / Lesen aus einer Datei), sofern Sie angeben, wie Sie Ihr Programm verwenden möchten
  • Sie müssen ein zufälliges Bild einer lustigen Katze auswählen und Ihr Programm darin kodieren, um zu zeigen, dass Ihr Programm funktioniert
  • Sie können davon ausgehen, dass Sie nur eine gültige Eingabe erhalten, wenn die Anzahl der Bits nicht ausreicht, das Bild nicht im Echtfarbenformat vorliegt, das Bild nicht vorhanden ist oder ähnliche Probleme auftreten, die Sie möglicherweise ausführen, was Sie möchten
  • Sie können davon ausgehen, dass das bereitgestellte Bild keinen Alphakanal enthält
  • Die Länge wird in UTF-8-Bytes ohne Stückliste gezählt

Sie können dieses PHP-Skript verwenden, um Ihre Lösung zu testen. Geben Sie als erstes Befehlszeilenargument den Namen der PNG-Datei an:

<?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
quelle
In Ihrer Spezifikation heißt es "Ihr Programm verwendet ein einzelnes Image als Basis". In Mathematica ist ein Bild eigentlich nur ein Ausdruck wie alles andere. Technisch gesehen würde diese Spezifikation es mir ermöglichen, das Laden von Dateien außerhalb des Codes durchzuführen, der die Berechnung durchführt (wobei der Eingabeparameter ein tatsächliches Bild anstelle des Dateinamens des Bildes ist). . Wenn Sie so etwas nicht wollen, können Sie angeben, dass das Programm den Dateinamen eines Bildes als Eingabe verwenden muss.
Martin Ender
4
ME helpimtrappedinacatfactory OW
TheDoctor
Müssen auch die nicht zur Codierung verwendeten Bits unberührt bleiben? Oder können wir sie auf das einstellen, was wir wollen (da dies die Bildqualität nicht wirklich beeinträchtigt und für die Dekodierung keine Rolle spielt)?
Martin Ender
1
Kann ich eine nicht integrierte Bibliothek zum Laden und Speichern der PNG-Datei verwenden, z. B. PIL in Python?
Claudiu
1
@ TimWolla Von der Katze? Bewahren Sie es im Haus auf und überwachen Sie die Abfallschale. Vom Foto? Wenn Sie ein Röntgenfoto mit ausreichend hoher Auflösung aufnehmen, können Sie möglicherweise den Zustand der einzelnen Transistoren im Flash-Chip sehen. Ich bin mir sicher, dass dies die effizienteste Methode ist, geheime Informationen weiterzugeben, obwohl die Katze möglicherweise andere Ideen hat.
Sonic Atom

Antworten:

3

Perl & ImageMagick (Linux), 198 190

Edit: Durch einen Zufall habe ich früher auf einem Computer mit Q8 (8 Bit Tiefe) Version von ImageMagick getestet. Für die Q16-Standardversion ist eine explizite Angabe in der Befehlszeile erforderlich -depth 8. Unter Linux muss für identifyresult auch newline entfernt werden. Beide Faktoren führen zu einer Zunahme der Codegröße. Daher poste ich die Linux-Version (wahrscheinlich auch Mac) als Antwort, wobei Korrekturen angewendet und auch einige Dinge, die nur Windows betreffen, entfernt wurden (cr-lf-Konvertierung, Binär-vs-Text usw.). Portable (etwas länger) Version wird gegen Ende veröffentlicht.

Mit Zeilenumbrüchen zur besseren Lesbarkeit:

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

Lauf:

perl cat.pl

Es liest aus STDIN, Bilddateiname in der ersten Zeile, 'geheime' Nachricht folgt, beendet mit ctrl-D. Der Name der Ausgabedatei ist original und .pngangehängt - nicht sehr schön, nur der Kürze halber.

Hier ist ein Bild mit einigen sehr geheimen Informationen:

Bildbeschreibung hier eingeben

Und mit einigen Kommentaren:

# 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

Next ist eine portable Version, die sowohl unter Windows ( ctrl-Zzum Beenden der Eingabe) als auch unter Linux ausgeführt wird. Die Byteanzahl beträgt 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
quelle
10

Mathematica, 255 234 206 Bytes

Ich habe 255beim Testen so viele s gesehen , dass ich mich über die Größe des Codes unangemessen freue. :) Und dann hat mein Ehrgeiz, noch mehr Golf zu spielen, mein Bestes gegeben ...

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

Es ist technisch gesehen eine Funktion und kein "Programm", aber auf diese Weise schreibt man in Mathematica so ziemlich "Programme", wenn dieses Konzept dort überhaupt gültig ist. Nenne es so

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

Es wird ein tatsächlicher Bildausdruck zurückgegeben (da dies die natürlichste Methode ist, ein Bild in Mathematica zurückzugeben). Wenn Sie also eine Datei möchten, müssen Sie sie exportieren:

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

Hier ist das erforderliche Beispiel:

Bildbeschreibung hier eingeben

Ich würde Ihnen gerne die decodierte Nachricht hier zeigen, aber sie passt nicht ... also führen Sie sie durch den Decoder des OP. ;)

Btw, ich könnte es für nur 7 Bytes (Änderung mit UTF-8 Geheimnisse arbeiten machen ToCharacterCode@#in #~ToCharacterCode~"utf8").

Ungolfed-Code:

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
quelle
"Ich würde dir die entschlüsselte Nachricht gerne hier zeigen, aber sie passt nicht ... also starte sie durch den Decoder des OP.;)" - Ich habe es getan und es gibt mir "????????? ++++++++ +++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... für 9773 Zeichen] "
TessellatingHeckler
1
@TessellatingHeckler, das stimmt. Versuchen Sie es in einer monospaced Schriftart und achten Sie darauf, dass neue Zeilen im UNIX-Stil enthalten sind (z. B. versuchen Sie es in einem Terminal oder einer PowerShell mit mindestens 180 Zeichen Breite oder wenn Sie es als Web-Skript in Ihrem Browser ausführen). dann
schau
2
Aha! Sehr meta. Hilft, dass ich auch in der KiTTY-Version von PuTTY bin 😸
TessellatingHeckler
5

PHP, 530 Byte

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

Laufen wie php 25443.php -i<input image> -o<output image> -t<file to hide>.

Und hier ist ein Beispielbild.

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

Ungolfed-Code ist im Beispielbild versteckt. Getestet mit dem Decoder von OP. Sorry für das nicht lustige Katzenbild.

Snack
quelle
1
Bitte geben Sie den Code ohne Golf in Ihre Antwort ein.
AL
1
Sie können verkürzen 0xffzu 255.
TimWolla
Sie können 4 Bytes speichern , wenn Sie short - Tags übernehmen: <?function.
Nyuszika7h