Hình vuông Steganographic


14

Hình vuông Steganographic

Công việc của bạn là lấy một chuỗi và tạo một NxNhình ảnh đại diện cho chuỗi này. Bạn cũng phải viết thuật toán lấy trong ảnh và biến nó trở lại thành một chuỗi. Việc tính điểm sẽ bao gồm số byte của cả hai thuật toán:

Thuật toán "Mã hóa" + Thuật toán "Giải mã" .

Bạn nên đăng riêng từng bài, với số byte cho cả thuật toán mã hóa và giải mã được hiển thị riêng lẻ.


Thuật toán ví dụ

Ví dụ: đây là "Câu đố lập trình và Golf Code" bằng thuật toán lập thể dựa trên ASCII đơn giản trong kênh Blue:

#2e7250,#6ea972,#04eb6f,#0fc767,#74ab72,#ee6161
#b73b6d,#1aae6d,#f37169,#bda56e,#1fe367,#e99620
#706450,#0d3575,#146b7a,#4ea47a,#2a856c,#95d065
#3f2d73,#cef720,#bab661,#d1b86e,#f22564,#12b820
#0f3d43,#c86e6f,#1ee864,#a66565,#247c20,#c3bb47
#0e296f,#89d46c,#585b66,#c08f20,#455c20,#136f20

Hình ảnh thực tế ( Hình ảnh được tạo bởi thuật toán.)

Hình ảnh nổ tung.

Bạn có thể thấy kênh màu xanh chỉ đơn giản giữ các giá trị ascii cho hình ảnh này:

50 =  80(P) 72 = 114(r) 6f = 111(o) 67 = 103(g) 72 = 114(r) 61 =  97(a) 
6d = 109(m) 6d = 109(m) 69 = 105(i) 6e = 110(n) 67 = 103(g) 20 =  32( ) 
50 =  80(P) 75 = 117(u) 7a = 122(z) 7a = 122(z) 6c = 108(l) 65 = 101(e) 
73 = 115(s) 20 =  32( ) 61 =  97(a) 6e = 110(n) 64 = 100(d) 20 =  32( ) 
43 =  67(C) 6f = 111(o) 64 = 100(d) 65 = 101(e) 20 =  32( ) 47 =  71(G) 
6f = 111(o) 6c = 108(l) 66 = 102(f) 20 =  32( ) 20 =  32( ) 20 =  32( )

Trong khi các kênh còn lại giữ các giá trị được tạo ngẫu nhiên để "tăng thêm" sự đa dạng của màu sắc trong hình ảnh. Khi kéo thông điệp ra khỏi hình ảnh, chúng ta chỉ cần bỏ qua các giá trị kênh khác và kéo bit hex trong kênh màu xanh, xây dựng lại chuỗi:

"Programming Puzzles and Code Golf"

Lưu ý các khoảng trắng được sử dụng để đệm chuỗi trong ô vuông không được bao gồm trong đầu ra được giải mã cuối cùng. Mặc dù bạn phải đệm chuỗi trong ảnh, bạn có thể cho rằng chuỗi đầu vào sẽ không kết thúc bằng dấu cách.


Quy tắc

  • Bạn phải mã hóa 1 ký tự cho mỗi pixel, kênh được chọn để mã hóa char là tùy ý.
  • Các kênh của các màu RGB khác phải được chọn ngẫu nhiên, khác với kênh bạn chọn để mã hóa chuỗi thành; điều này có nghĩa là các kênh không được mã hóa cuối cùng của bạn sẽ cần phải nằm giữa 0x0000-0xFFFF(được chọn ngẫu nhiên).
  • Biểu thị kết quả cuối cùng dưới dạng mảng 2D của các giá trị màu RGB là ổn 0x000000-0xFFFFFF, không cần sử dụng tạo hình ảnh trừ khi bạn muốn vui vẻ với nó hoặc nếu nó ít byte hơn. Nếu bạn chọn xuất ra dưới dạng chuỗi hex, hãy đặt tiền tố cho chuỗi hex bằng #EG #FFFFFFhoặc #05AB1E. Bạn có thể phân tách bằng các tab, dấu phẩy hoặc bất kỳ thứ gì khác có thể cảm nhận được theo chiều ngang, nhưng nó phải duy trì mẫu hình vuông; nói cách khác, bạn phải sử dụng phân tách dòng mới phù hợp.
  • Đầu ra phải ở trong một hình vuông và chuỗi phải được đệm bằng khoảng trắng ở cuối để chứa điều này. Điều này có nghĩa là N≈SQRT(Input#Length()). Nếu chiều dài đầu vào không phải là một hình vuông hoàn hảo, bạn nên làm tròn Nvà đệm với khoảng trắng.
  • Như đã nêu trước đây, nếu bạn đang đệm với khoảng trắng trong hình ảnh, bạn không được bao gồm các ký tự được đệm trong đầu ra "giải mã" cuối cùng.
  • Bạn có thể cho rằng:
    • Chuỗi đầu vào sẽ không kết thúc bằng dấu cách.
    • Chuỗi đầu vào sẽ chỉ sử dụng các ký tự ASCII có thể in được.
  • Đây là , số byte thấp nhất sẽ thắng.

Chỉ cần làm rõ, các giải pháp phải mã hóa / giải mã chính xác một ký tự cho mỗi pixel?
Sản phẩm ETH

@ETHproductions nghe có vẻ như là một thử thách tiếp theo tốt, nhưng với mục đích của cuộc thi này, bạn chọn một kênh mã hóa và mã hóa 1 ký tự cho mỗi pixel.
Bạch tuộc ma thuật Urn

Có lẽ tôi sẽ không sử dụng cái này, nhưng: có ổn không khi "overpad" hình ảnh có nhiều khoảng trống hơn mức cần thiết? Và bạn có thể cho rằng hình ảnh sẽ có cùng số lượng overpadding như bộ mã hóa sẽ tạo ra không?

@ ais523 Tôi không thể thấy cách tiếp cận này sẽ làm bất cứ điều gì nhưng yêu cầu nhiều byte hơn để thực hiện. Mặc dù vậy, tôi sẽ đi cùng, vì thử thách đã quá cũ để tạo ra những thay đổi lớn như thế.
Bạch tuộc ma thuật Urn

1
Phải, tôi không chắc liệu nó có được cho phép trong câu hỏi ban đầu không, thay vì đề xuất thay đổi. (Tôi đã suy nghĩ về việc đóng gói đầu vào thành một hình chữ nhật, việc tính toán tọa độ byte ngắn dễ dàng hơn và do đó có thể ngắn hơn so với việc đóng gói nó vào một hình vuông, sau đó đệm hình chữ nhật ra một hình vuông lớn hơn.)

Câu trả lời:


2

05AB1E , 34 + 12 = 46 byte

Sử dụng kênh màu đỏ.
05AB1E sử dụng mã hóa CP-1252 .

Mã hóa:

DgDtî©n-Äð×JvyÇh`4F15Ý.Rh«}})'#ì®ä

D                                   # duplicate input
 gDtî©n-Ä                           # abs(len(input)-round_up(sqrt(len(input)))^2)
         ð×J                        # join that many spaces to end of input
            v                       # for each char in string
             yÇ                     # get ascii value
               h`                   # convert to base-16 number
                 4F                 # 4 times do:
                   15Ý.Rh           # push random base-16 number
                         «          # concatenate
                          }}        # end inner and outer loop
                            )       # wrap in list
                             '#ì    # prepend a "#" to each element in list
                                ®ä  # split in pieces round_up(sqrt(len(input))) long

Hãy thử trực tuyến!

Giải mã:

˜vy3£¦HçJ}ðÜ

˜               # deep flatten input to a list
 v              # for each color in the list
  y3£           # take the first 3 chars
     ¦          # remove the hash sign
      H         # convert from base-16 to base-10
       ç        # get the ascii char with that value
        J       # join to string
         }      # end loop
          ðÜ    # remove trailing spaces

Hãy thử trực tuyến!

Phương pháp đệm thay thế với số byte bằng nhau

Dgð×J¹gtî©n£

Tôi nghĩ rằng bạn phải đặc biệt tham gia vào dòng mới, theo câu hỏi? (Tuy nhiên, câu trả lời của bạn có thể sẽ đánh bại tôi ngay cả khi nó thích nghi để làm điều đó, bởi vì tôi chỉ dành năm byte để giải quyết phần đó của câu hỏi và bạn đã đi trước nhiều hơn thế.)

@ ais523: Các quy tắc nói rằng mảng 2D là ổn. Có phải tôi đã hiểu nhầm điều đó?
Emigna

"Bạn có thể phân tách bằng các tab, dấu phẩy hoặc bất kỳ thứ gì khác có thể cảm nhận được theo chiều ngang, nhưng nó phải duy trì mẫu hình vuông; nói cách khác, bạn phải sử dụng phân tách dòng mới phù hợp." ngụ ý mạnh mẽ rằng nó cần phải là một chuỗi, vì các mảng 2D vốn không chứa các dòng mới. Nói cách khác, tôi hiểu "mảng" là mô tả hình dạng của đầu ra, không phải kiểu dữ liệu của đầu ra.

@ ais523: Tôi đã yêu cầu OP làm rõ. Như bạn nói, đó không phải là một thay đổi lớn để thực hiện, nhưng có lẽ bạn cũng có thể lưu một số byte nếu định dạng không cần thiết.
Emigna

@ ais523 một trong hai cách là chấp nhận được.
Bạch tuộc ma thuật Urn

4

C, 201 (Mã hóa) + 175 (Giải mã) = 376 byte

Để mã hoá:

E(char*J){size_t L=ceil(sqrt(strlen(J)));int U;srand(time(NULL));for(int i=0;i<L;i++){for(int f=0;f<L;f++){printf("#%02X%02X%02X ",rand()%256,(U<strlen(J))?(int)J[U]:32,rand()%256);U+=1;}printf("\n");}}

Mã hóa từng ký tự của chuỗi đầu vào trong kênh màu lục của phổ RGB trong khi đặt hai kênh khác làm giá trị hex ngẫu nhiên. Lấy đầu vào thông qua STDIN dưới dạng một chuỗi và xuất ra STDOUT một chuỗi nhiều màu của mã màu hex theo hình vuông. Giả sử bạn đã cài đặt Python 3 và ImageMagick và tệp trên được biên dịch thành một tệp có tên a.outtrong thư mục làm việc hiện tại (CWD), bạn có thể trực tiếp lấy hình ảnh kết quả, được đặt tên Output.png, cho CWD từ đầu ra văn bản bằng lệnh sau:

./a.out "<Multiline Input>"|python3 -c "import sys,subprocess;Input=sys.stdin.read();print('# ImageMagick pixel enumeration: {0},{0},255,rgb\n'.format(len(Input.split('\n')[1].split()))+'\n'.join(['%d,%d:(%d,%d,%d)'%(g,i,int(j[1:][:2],16),int(j[1:][2:4],16),int(j[1:][4:6],16))for g,h in enumerate(Input.split('\n'))for i,j in enumerate(h.split())]))"|convert - -scale 1000% Output.png

Dưới đây là hình ảnh đầu ra mẫu được tạo bởi dấu phẩy trên bằng cách sử dụng Programming Puzzles and Code Golflàm chuỗi đầu vào:

Đầu ra mẫu

Để giải mã:

D(int c,char**U){char T[c];for(int Y=1;Y<c;Y++){char G[2]={U[Y][3],U[Y][4]};T[Y-1]=(char)strtol(G,NULL,16);}int C=c-1;T[C]='\0';while(T[C]==' '){T[C]='\0';C-=1;}printf("%s\n",T);}

Đưa đầu vào qua STDIN một chuỗi các chuỗi mã màu hex được phân tách bằng dấu cách với mỗi chuỗi được đặt trong dấu ngoặc kép ( ") ( char** argvin main) và khi được gọi trong main, int argccho đầu vào số nguyên. Xuất ra STDOUT một chuỗi đơn / nhiều dòng biểu thị thông điệp được giải mã.

Tôi sẽ cố gắng chơi golf nhiều hơn bất cứ khi nào và bất cứ nơi nào tôi có thể.


Ngoài ra, nếu bạn cùng cả hai phương thức vào cùng một tệp, bạn có thể sử dụng mainphương thức sau để kết hợp tất cả các phương thức với mỗi hàm nhận đúng đầu vào:

int main(int argc,char**argv){if(strcmp(argv[1],"E")==0){Encode(argv[2]);}else{Decode(argc,argv);}}

và sử dụng điều này, để mã hóa, bạn phải cung cấp Elàm đối số đầu tiên để gọi phương thức mã hóa theo sau là đối số chuỗi đơn, trong khi để giải mã, tất cả những gì bạn cần cung cấp là chuỗi các chuỗi mã màu hex được phân tách bằng dấu cách dấu ngoặc kép ( ").


Cuối cùng, nếu bạn muốn, bạn có thể lấy phiên bản chuẩn bị đầy đủ, sẵn sàng để sử dụng ở đây , mặc dù nó không được đánh gôn, nhưng cũng không đưa ra bất kỳ cảnh báo hoặc lỗi nào khi biên dịch.


3

Python 2, 164 160 + 94 93 = 253 byte

Đã lưu 1 + 1 byte nhờ Wheat Wizard.

-5 byte nhờ Kade

Hình ảnh mã hóaBộ mã hóa: chuỗi phải được đặt trong dấu ngoặc kép, ví dụ: "CodeGolf"đầu ra là hình ảnh PPM màu ascii.

from random import*
s=input()
n=int((len(s)-1)**0.5)+1
s=s.ljust(n*n)
r=randint
print"P3 %d %d 255 "%(n,n)+''.join("%d "*3%(r(0,255),r(0,255),ord(c))for c in s)

Bộ giải mã hình ảnhBộ giải mã: Lấy tên tệp đầu vào làm đối số dòng lệnh

from sys import*
print''.join(chr(int(c))for c in open(argv[1]).read().split()[6::3]).strip()

Sử dụng:

 python golf_stegansquare_enc.py > stega.ppm

 python golf_stegansquare_dec.py stega.ppm

Thí dụ:

Lập trình câu đố và Code GolfLập trình câu đố và Code Golf

LoremLorem ipsum dolor ngồi amet, consetetur sadipscing elitr, sed diam nonumy eirmod TIME invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. Tại vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, không có biển takimata Sanctuarytus est Lorem ipsum dolor ngồi amet. Lorem ipsum dolor ngồi amet, consetetur sadipscing elitr, sed diam nonumy eirmod TIME invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. Tại vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, không có biển takimata Sanctuarytus est Lorem ipsum dolor ngồi amet.


Bạn có thể xóa khoảng cách giữa paren gần và sau đófor
Post Rock Garf Hunter

@ETHproductions: sqrt (25-1) = sqrt (24) <5 và> 4. inttừ đây là 4, sau đó là +1ed, vì vậy 5
Karl Napf

Ôi, tệ quá, tôi không thấy -1.
Sản xuất ETH

1
Bạn có thể loại bỏ khoảng trống giữa print'trong bộ giải mã. Tôi cũng khá chắc chắn rằng bạn có thể làm int((len(s)+1)**.5)để lưu một số byte.
Kade

1
Tôi đang sửa lại câu cuối cùng của bình luận trước đây của tôi, tuy nhiên bạn có thể rút ngắn việc in bằng cách thay đổi ' '.join("%d %d %d"thành ''.join(3*"%d "vì tôi khá chắc chắn rằng một không gian dấu là ổn.
Kade

2

Scala, 97 + 68 = 165 byte

Mã hóa (97 byte):

s=>s.map(_+((math.random*65535).toInt<<8)).iterator.grouped(math.sqrt(s.size)toInt)withPadding 32

Lấy một chuỗi và truy xuất một trình lặp các chuỗi số nguyên.

Giải mã (68 byte):

a=>" +$".r.replaceAllIn(a.flatten.map(h=>(h&0xFF)toChar)mkString,"")

Lấy một Iterator of Sequences of Integers và trả về một chuỗi.

Giải trình:

s=>                         //define an anonymous function
  s.map(                      //map each char of the string
    _+(                         //to the ascii value plus
      (math.random*65535).toInt)  //a random integer between 0 and 65535
      <<8                         //shifted 8 bits to the left
    )
  )
  .iterator                     //create an iterator
  .grouped(                     //group them in groups of size...
    math.sqrt(s.size)toInt        //sqrt of the size of the input, rounded up
  )withPadding 32               //pad with spaces to make a square

.

a=>
  " +$"              //take this string
  .r                 //parse it as a regex
  .replaceAllIn(     //replace every occurence of the regex in...
    a.flatten          //a flattened
    .map(h=>           //each element mapped
      (h&0xFF)toChar)    //to the character of the lower 8 bits
    mkString,          //joined to a string
    ""               //with an empty string
  )

2

Perl, (103 + 1) + (36 + 2) = 142 byte

Bộ mã hóa văn bản thành hình ảnh (chạy với -phình phạt 1 byte; -p0(đối với một byte hình phạt bổ sung) là cần thiết nếu bạn muốn xử lý các dòng mới trong chuỗi đầu vào):

$_.=$"while($a=(length)**.5)=~/\./;$_=unpack"H*";s/../sprintf"#%04x$&,",rand+4**8/eg;s/(.*?\K,){$a}/
/g

Bộ giải mã hình ảnh thành văn bản (chạy với -p0hình phạt 2 byte):

$\.=chr hex for/..\W/g;$\=~s/ *$//}{

Điều này sử dụng #abcdefđịnh dạng hình ảnh dựa trên văn bản và mã hóa trong kênh màu xanh. Đây là một ví dụ về một đầu ra có thể được đưa raProgramming Puzzles and Code Golf làm đầu vào:

# b4d250, # bccb72, # 43f06f, # 4d6767, # 74ba72, # 269461
# e4f26d, # f63d6d, # 701c69, # bbf56e, # 6ef967, # d78d20
# 4e0d50, # 9b2775, # afd37a, # 12a47a, # 63e46c, # 0e9565
# 4cad73, # e43420, # 6da761, # 5a306e, # 8fba64, # 58f720
# d52443, # b4446f, # fbaf64, # 4a4365, # 1a5020, # f3ea47
# 354c6f, # 52cb6c, # 11a766, # 4c380a, # 553820, # b31120

Giải thích về bộ mã hóa:

$_.=$"             # append a space ($") to the input ($_)
  while            # as long as the following condition holds:
(($a=length)**.5)  # the square root of the input length (save this in $a)
=~/\./;            # has no decimal points in its string represenation
$_=unpack"H*";     # convert the input from base-256 to hexadecimal
s/../              # replace two characters of the input
  sprintf          # with a string formed from the template
  "#%04x$&,",      # four hex digits, the two matched characters, and a comma
  rand+4**8        # those hex digits are a random number from 0 to 4**8 (= 65536)
/eg;               # and do this for every non-overlapping match
s/(.*?             # find the minimum number of characters needed to match
   \K,)            # replacing the part of the match after the last matched comma
  {$a}/            # a string containing $a commas
/gx                # with a newline, for every non-overlapping match

Tôi thực sự rất vui khi sử dụng công \Kviệc này; nó chỉ định nơi thay thế và đặt nó bên trong một vòng lặp, có vẻ như sự xuất hiện trên lần lặp vòng lặp cuối cùng là điều đáng quan tâm. Vì vậy, s/(.*?\K,){$a}/\n/gsẽ khớp với một chuỗi có độ dài tối thiểu của biểu mẫu bất kỳ dấu phẩy bất cứ thứ gì dấu phẩy, bất kỳ dấu phẩy nào, có $adấu phẩy, nhưng phần thực tế được thay thế của trận đấu sẽ chỉ là dấu phẩy cuối cùng. Điều này có tác dụng thay thế mỗi $adấu phẩy bằng một dòng mới, cho chúng ta hình vuông cho hình ảnh.

Ưu điểm lớn của Perl cho thử thách này (ngoài bộ chuyển đổi chuỗi ký tự sang thập lục phân tích hợp, rất tiện lợi) là nó có bộ giải mã rất ngắn (thực tế là rất ngắn, mặc dù Perl có tích hợp sẵn cho chuyển đổi thập lục phân thành một chuỗi, nó ngắn hơn không sử dụng nó). Đây là cách nó hoạt động:

$\.=chr      # append to $\ the character code
  hex        # of the hexadecimal-string-to-number-translation
for/..\W/g;  # of each two characters that appear before a
             # non-alphanumeric character (not counting overlapping matches)
$\=~s/ *$//  # delete all spaces at the end of $\
}{           # in this context, this means "implicitly print $\,
             # prevent any other implicit printing"

Các trường hợp duy nhất của hai ký tự ngay trước ký tự không chữ và số là các kênh màu xanh (mà chúng tôi muốn giải nén), xuất hiện ngay trước dấu phẩy và dòng mới; và hai nhân vật xuất hiện trước mặt nhau #hơn là nhân vật đầu tiên. Chúng tôi không muốn loại trận đấu sau, nhưng chắc chắn chúng trùng lặp với danh mục trước và do đó sẽ bị loại trừ bởi kiểm tra đối sánh chồng chéo.


1

MySQL, 438 + 237 = 675 byte

Có một dòng mới ở cuối đầu ra, nhưng nó không hiển thị sau khi được giải mã. Hàm hex (quá tải số nguyên) sẽ loại bỏ các số 0 đứng đầu, vì vậy tôi phải đệm nó bằng một chuỗi 0. Tôi có thể lưu một số byte nếu tôi có thể khai báo cả hai hàm giữa các dấu phân cách.

Mã hóa

delimiter //create function a(i text)returns text begin declare r int;declare q,p text;while mod(length(i),sqrt(length(i)))<>0 do set i:=concat(i,' ');end while;set r:=1;set q:="";while r<=length(i) do set p:=",";if mod(r,sqrt(length(i)))=0 then set p:="\r\n";end if;set q:=concat(q,'#',right(concat(0,hex(floor(rand()*256))),2),right(concat(0,hex(floor(rand()*256))),2),hex(mid(i,r,1)),p);set r:=r+1;end while;return q;end//
delimiter ;

Giải mã

delimiter //create function b(i text)returns text begin declare x int;declare y text;set x:=0;set y:="";while instr(i,'#')>0 do set i:=substr(i,instr(i,'#')+5);set y:=concat(y,unhex(left(i,2)));end while;return trim(y);end//
delimiter ;

Sử dụng:

select a('test')
select b('#7D1874,#FFB465')
select b(a('test'))

1

C #, 312 + 142 = 454 byte

Mã hóa:

using System;I=>{var r=new Random();int i=I.Length;int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;while(i++<S){I+=' ';}var R="";for(i=0;i<S;){R+=i%N<1&i>0?"\n":i<1?"":" ";R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');}return R;};

Giải mã:

using System;I=>{var s=I.Replace('\n',' ').Split(' ');var R="";foreach(var t in s)R+=(char)System.Convert.ToInt32(t[5]+""+t[6],16);return R.TrimEnd(' ');};

Chương trình đầy đủ:

using System;
class Steganographic
{
    static void Main()
    {
        Func<string, string> E = null;
        Func<string, string> D = null;

        E=I=>
        {
            var r=new Random();
            int i=I.Length;
            int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;
            while(i++<S){I+=' ';}
            var R="";
            for(i=0;i<S;)
            {
                R+=i%N<1&i>0?"\n":i<1?"":" ";
                R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');
            }
            return R;
        };

        D=I=>
        {
            var s=I.Replace('\n',' ').Split(' ');
            var R="";
            foreach(var t in s)
                R+=(char)Convert.ToInt32(t[5]+""+t[6],16);
            return R.TrimEnd(' ');
        };

        string encoded = E("Programming Puzzles and Code Golf");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        encoded = E("Hello, World!");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        Console.Read(); // For Visual Studio
    }
}

1

Toán học, 111 + 65 = 176 byte

Mã hoá

Join[255~RandomInteger~{n=⌈Sqrt@Length@#⌉,n,2},ArrayReshape[#,{n,n,1},32],3]~Image~"Byte"&@*ToCharacterCode

Bộ giải mã

StringTrim[""<>FromCharacterCode@ImageData[#,"Byte"][[;;,;;,3]]]&

1

Đang xử lý, 220 209 194 + 171 167 151 = 391 380 376 361 345 byte

Cập nhật:

Loại bỏ vô dụng noStroke()và làm cho cả hai vòng lặp for-statementers.

Loại bỏ vô dụng image(p,0,0);, cung cấp cho bộ giải mã tên tệp làm tham số

Thuật toán mã hóa

void g(String h){int s=ceil(sqrt(h.length()));for(int y=0,x;y<s;y++)for(x=0;x<s;rect(x,y,1,1),x++)stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));get(0,0,s,s).save("t.png");}

Gọi hàm: g("Programming Puzzles and Code Golf");

Đây là một hàm lấy trong Chuỗi và tạo đầu ra, trước khi lưu nó dưới dạng t.png. Nó sử dụng redgiá trị để lưu trữ văn bản ẩn.

Thuật toán giải mã

void u(String f){PImage p=loadImage(f);f="";for(int j=0,i;j<p.height;j++)for(i=0;i<p.width;i++)f+=(char)red(p.get(i,j));print(f.replaceAll(" +$",""));}

Chức năng gọi bằng cách: u(file_name);

Đây cũng là một chức năng tìm kiếm hình ảnh được chỉ định bởi tham số, và sau đó xuất chuỗi ẩn (vì nó ngắn hơn trả về một chuỗi).

Mã mở rộng

(Thuật toán mã hóa)

void g(String h) {
  int s=ceil(sqrt(h.length()));
  for(int y=0,x;y<s;y++)
    for(x=0;x<s;rect(x,y,1,1),x++)
      stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));
  get(0,0,s,s).save("t.png");
}

Chuỗi được truyền khi hàm được gọi. Dòng đầu tiên của hàm tính độ dài cạnh của hình vuông bằng cách lấy ceilcăn bậc hai của nó. Sau đó, chúng ta nhập một vòng lặp for, trong đó chúng ta đặt stroke(màu của cạnh) có giá trị ASCII của ký tự là màu đỏ và giá trị ngẫu nhiên cho màu xanh lam và xanh lục. Sau khi thực hiện việc này, chúng tôi tạo một rect(hình chữ nhật) có width = 1và height = 1, tức là pixel (vì một số lý do kỳ lạ, tôi không thể sử dụng pointđúng cách). Trong dòng cuối cùng, hình ảnh kết quả sau đó được lưu dưới dạng t.png.

(Thuật toán giải mã)

void u(String f) {
  PImage p=loadImage(f);
  f="";
  for(int j=0,i;j<p.height;j++)
    for(i=0;i<p.width;i++)
      f+=(char)red(p.get(i,j));
  print(f.replaceAll(" +$",""));
}

Hàm này có tên của tệp là tham số (dưới dạng chuỗi). Sau đó, hình ảnh trong tập tin được lưu trữ trong một biến sẽ được sử dụng sau này. Sau khi hoàn thành việc đó, chúng tôi đặt chuỗi thành ""thay vì tạo một chuỗi mới chỉ để giữ chuỗi ẩn. Sau đó, chúng tôi lặp lại thông qua hình ảnh thông qua hai vòng lặp lồng nhau và chúng tôi thêm vào chuỗi giá trị ký tự của giá trị màu đỏ của pixel. Cuối cùng, chúng tôi in chuỗi kết quả sau khi loại bỏ khoảng trắng hàng đầu khỏi nó (sử dụng biểu thức chính quy). Lý do chúng tôi in văn bản ẩn thay vì trả lại là vì cách này ngắn hơn và chúng tôi lưu byte.


Thử thách mã hóa văn bản thô:

nhập mô tả hình ảnh ở đây


1

Jelly, 40 + 20 = 60 byte trong bảng mã của Jelly

Bộ mã hóa (văn bản → hình ảnh):

”#;;ØHX¤¥4¡
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
L½Ċç@

Hãy thử trực tuyến!

Bộ giải mã (hình ảnh → văn bản):

ḣ2ØHiЀ’ḅ⁴Ọ
ṣ”#Ç€œr⁶

Hãy thử trực tuyến!

Một ví dụ đầu ra mà chương trình có thể tạo ra (nó lưu thông tin trong kênh màu đỏ):

#504219,#720200,#6F38F1,#67055F,#7228C7,#61AC95
#6DD797,#6D20CB,#6962FA,#6E69B1,#67C41C,#209436
#50CB19,#75C9FC,#7A1B06,#7A695B,#6C5D5B,#6539A6
#735925,#20C80F,#612C38,#6EBF9E,#64C79E,#200915
#4337C5,#6F4704,#64FB5F,#65B2D1,#20E075,#47BC7C
#6F0C16,#6CD8EF,#66060B,#203C6C,#20D6E9,#20C0D7

Trong những thử thách lớn hơn này, sự căng thẳng của Jelly bắt đầu giảm xuống một chút, cần một vài ký tự "cấu trúc" để giải quyết sự mơ hồ phân tích cú pháp, nhưng dù sao nó vẫn rất ngắn gọn. Đây là cách bộ mã hóa hoạt động:

Subroutine 1: convert digits to randomly padded hex string
”#;;ØHX¤¥4¡
”#;                     prepend #
    ØHX                 random hexadecimal digit
       ¤                parse ØH and X as a unit
   ;                    append
        ¥               parse ; and ØHX¤ as a unit
         4¡             repeat four times

Subroutine 2: convert string λ to square with size ρ
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
 ⁶                      space
   ⁹²                   ρ squared
     ¤                  parse ⁹² as a unit
  x                     repeat string (i.e. ρ² spaces)
      ¤                 parse ⁶x⁹²¤ as a unit
»                       take maximum
Because space has the lowest value of any printable ASCII character,
this has the effect of padding λ to length ρ² with spaces.
       O                take codepoints of string
        b⁴              convert to base 16
           ịØH          use as indexes into a list of hexadecimal digits
          ‘             0-indexed (Jelly uses 1-indexing by default)
              ǀ        run subroutine 1 on each element
                s       split into groups of size ρ
                  €     inside each group
                 j ”,   join on commas
                     Y  join on newlines

Main program: basically just calculates ρ and lets subroutine 2 do the work
L½Ċç@
L                       length of input
 ½                      square rooted
  Ċ                     rounded up to the next highest integer
   ç@                   call subroutine 2 with the original input and the above

Và đây là cách bộ giải mã hoạt động:

Subroutine: convert hexadecimal color string (without #) to character
ḣ2ØHiЀ’ḅ⁴Ọ
ḣ2                      take first two characters
  ØHi                   find indexes in a string of hexadecimal digits
     Ѐ                 for each of those characters
       ’                0-indexed (Jelly uses 1-indexing by default)
        ḅ⁴              convert from base 16
          Ọ             convert integer to character

Main program:
ṣ”#Ç€œr⁶
ṣ”#                     split on # signs
   ǀ                   run the subroutine for each element
     œr⁶                remove spaces from the right
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.