Generowanie plików bitmapowych PBM z tekstu ASCII


19

Format PBM (Portable BitMap) to bardzo prosty czarno-biały format bitmap ASCII.

Oto przykład litery „J” (skopiowany z linku wikipedii):

P1
# To jest przykładowa mapa bitowa litery „J”
6 10
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
0 0 0 0 1 0
1 0 0 0 1 0
0 1 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0

Czas zbudować małe narzędzie do generowania plików w tym fajnym małym formacie!

Twoim celem jest napisanie najkrótszego programu (w dowolnym języku), który będzie zgodny z następującymi zasadami:

  1. Twój program pobiera jeden ciąg ze standardowego wejścia (na przykład CODEGOLF.STACKEXCHANGE.COM!)
  2. Generuje plik PBM z bitmapową (czytelną) reprezentacją ciągu.
  3. Każda postać jest zbudowana jako siatka 8x8.
  4. Musisz obsługiwać znaki [AZ] (wszystkie wielkie litery), spację, punkt („.”) I wykrzyknik („!”).
  5. Żadne zewnętrzne biblioteki nie są dozwolone (z pewnością nie związane z PBM)!
  6. Używany zestaw znaków nie może być po prostu zewnętrzny dla twojego programu. Częścią wyzwania jest efektywne przechowywanie postaci ...

Testowanie poprawności formatu PBM można wykonać za pomocą GIMP (lub innych). Nie pokazuj przykładowych danych wejściowych i wyjściowych!

Najkrótsze rozwiązanie otrzyma punkty odpowiedzi w dniu 31.01.2012.

Miłej zabawy w golfa!

PS: Dodałem nagrodę (procentowo ogromną część mojej reputacji codegolf), aby (mam nadzieję) przyciągnąć więcej konkurentów.


Przez „jego reprezentację bitmapową” masz na myśli reprezentację znaków zbliżoną do czegoś, co wygląda jak litery? Jak blisko? Czy byłoby dozwolone coś w rodzaju bitmapowej reprezentacji kodu binarnego lub kodu Braille'a lub Morse'a?
Howard

@Howard: pomysł polega na wygenerowaniu obrazu PBM, który zawiera oryginalny tekst wejściowy w „renderowanym” (bitmapie), ale wciąż czytelnym dla człowieka formacie ( lettersinnymi słowy). Podobnie jak w przypadku przykładu związanego z.
ChristopheD

Dodałem tag złożoność kolmogorov, ponieważ większość programu to 30 bitmap.
Peter Taylor

@Peter Taylor: Dobra uwaga, dzięki!
ChristopheD

Czuję, że będziemy mieć długą i bolesną debatę na temat tego, co stanowi „bibliotekę zewnętrzną”.
JB

Odpowiedzi:


9

GolfScript, 133 bajty

Opiera się to na moim 164-bajtowym rozwiązaniu Perl i używa tej samej, wypełnionej czcionką czcionki 4 na 5 pikseli. Ponownie dam najpierw czytelną wersję:

{91,65>"!. "+?}%:s"P4"\,8*8'FONT DATA HERE'{16base}%[3]/{:p;{[p=0]0=}s%}%]n*

Tutaj FONT DATA HEREoznacza 71 bajtów binarnie spakowanych danych czcionek. Kodowanie jest nieco inne niż w wersji Perla: zamiast rozdzielać spakowany ciąg znaków na białe znaki, najpierw go rozwijam, a następnie dzielę na skrobanie 3(wybrane, ponieważ po prostu nie występuje nigdzie w czcionce).

Ponieważ dane czcionki w rzeczywistym skrypcie zawierają znaki niedrukowalne, podaję je jako zrzut heksowy poniżej. Użyj, xxd -raby zmienić zrzut heksów z powrotem w wykonywalny kod GolfScript:

0000000: 7b39 312c 3635 3e22 212e 2022 2b3f 7d25  {91,65>"!. "+?}%
0000010: 3a73 2250 3422 5c2c 382a 3827 36e6 eff6  :s"P4"\,8*8'6...
0000020: 9219 8996 e6e7 7959 95f4 3999 9888 921a  ......yY..9.....
0000030: 8fd9 9998 2959 9514 3fe8 9eeb f21c 89b9  ....)Y..?.......
0000040: e9e6 2959 6564 3999 9889 929a 8999 8ba1  ..)Yed9.........
0000050: 295f 9283 9e6e f869 269f 9968 79e2 6299  )_...n.i&..hy.b.
0000060: 2f48 3327 7b31 3662 6173 657d 255b 335d  /H3'{16base}%[3]
0000070: 2f7b 3a70 3b7b 5b70 3d30 5d30 3d7d 7325  /{:p;{[p=0]0=}s%
0000080: 7d25 5d6e 2a                             }%]n*

W przeciwieństwie do skryptu Perl, ten kod drukuje żadnych znaków spoza zestawu A- Z, !, ., spacejak śmieszne wyglądające trochę zawijasów. Zastąpienie squiggles pustymi miejscami kosztuje 2 dodatkowe znaki; ich całkowite usunięcie kosztowałoby 4.

To mój pierwszy program GolfScript, więc nie zdziwiłbym się, gdyby pozostało trochę miejsca na optymalizację. Oto jak to działa:

  • {91,65>"!. "+?}%:sodwzorowuje prawidłowych znaków wejściowych ( A- Z, !, ., space) do numerów 0 - 28 i przypisuje wynik do s. Wszelkie znaki poza prawidłowym zestawem są odwzorowywane na -1, co powoduje powstanie zawirowań po wydrukowaniu.

  • "P4"\,8*8wypycha wartości „P4”, 8-krotność długości wejścia i 8 na stos. Po wydrukowaniu na końcu utworzą nagłówek PBM.

  • {16base}%[3]/pobiera poprzedzający ciąg danych czcionki, dzieli każdy bajt na dwie wartości, i dzieli wynik na bloki rozdzielone wartością 3. {:p;{[p=0]0=}s%}%następnie zapętla te bloki, najpierw przypisując każdy blok do zmiennej, pa następnie zapętla przemapowany ciąg wejściowy s, zastępując każdy znak wartością o odpowiednim przesunięciu w p. Zabawnie wyglądająca konstrukcja [p=0]0=działa tak samo p=, z tym wyjątkiem, że zwraca 0 dla wszelkich przesunięć poza koniec p; Nie podoba mi się to, ale nie udało mi się znaleźć krótszego sposobu, aby sobie z tym poradzić.

  • Na koniec ]n*bierze wszystko ze stosu (trzy wartości nagłówka i tablicę danych obrazu) i łączy je razem z znakami nowej linii do drukowania.


Poważnie krótkie (według dowolnej miary). Ładny!
ChristopheD,

12

Perl, 164 bajty, bez kompresji zlib / gzip

Po przespaniu się z problemem udało mi się wymyślić znacznie krótsze rozwiązanie niż moje pierwsze. Sztuką jest skorzystanie z niewielkiej luki w zasadach: postacie muszą zmieścić się w rozmiarach 8 na 8 pikseli, ale nic nie mówi, że muszą wypełnić całą tę przestrzeń. Narysowałem więc własną czcionkę 4 na 5 pikseli, co pozwoliło mi upakować dwa znaki w 5 bajtach.

Dane wyjściowe wyglądają następująco:

"WITAJ ŚWIECIE!" (skalowane x 4)

    „OH! SZYBKIE BRĄZOWE FOX SKOKUJĄ NA LENISTEGO PSA”. (oryginalny rozmiar)

Zanim podam rzeczywisty kod z osadzonymi danymi czcionek, pozwól mi pokazać wersję bez golfa:

y/A-Z!./\0-\033/ for @a = <> =~ /./g;
say "P4 " . 8*@a . " 8";
for $p (qw'PACKED FONT DATA') {
    print chr vec $p, ord, 4 for @a;
}

W rzeczywistym kodzie PACKED FONT DATAzastępuje go ciąg binarny składający się z ośmiu wierszy oddzielonych spacjami (cztery wiersze 14-bajtowe i jeden 13-bajtowy oraz trzy pojedyncze bajty puste dla wierszy pustych). Celowo zaprojektowałem czcionkę, aby spakowane dane nie zawierały białych znaków, pojedynczych cudzysłowów ani ukośników odwrotnych, aby można je było zakodować qw'...'.

Ponieważ spakowany ciąg czcionek zawiera znaki niedrukowalne, rzeczywisty skrypt podałem jako zrzut heksadecymalny. Użyj, xxd -raby zmienić go z powrotem w wykonywalny kod Perla:

0000000: 792f 412d 5a21 2e2f 002d 1b2f 666f 7240  y/A-Z!./.-./for@
0000010: 613d 3c3e 3d7e 2f2e 2f67 3b73 6179 2250  a=<>=~/./g;say"P
0000020: 3420 222e 382a 4061 2e22 2038 223b 666f  4 ".8*@a." 8";fo
0000030: 7224 7028 7177 2700 20e6 e6ff 9612 8999  r$p(qw'. .......
0000040: e6e6 7759 99f5 0420 9999 8898 128a df99  ..wY... ........
0000050: 9928 5999 1504 20ef 98ee fb12 8cb9 e9e9  .(Y... .........
0000060: 2659 6965 0420 9999 8899 928a 9989 ab21  &Yie. .........!
0000070: 599f 8220 e9e6 8f96 62f9 9986 972e 2699  Y.. ....b.....&.
0000080: f284 2000 2000 2729 7b70 7269 6e74 2063  .. . .'){print c
0000090: 6872 2076 6563 2470 2c6f 7264 2c34 666f  hr vec$p,ord,4fo
00000a0: 7240 617d                                r@a}

Oto jak to działa:

  • Pierwszy wiersz (w wersji do gry w golfa) odczytuje jeden wiersz danych wejściowych, dzieli go na tablicę znaków (wygodnie pomijając wszelkie znaki nowej linii) i odwzorowuje litery Ana Zoraz znaki !i .kody znaków od 0 do 28, które zwykle odpowiadają niedrukowalnym znakom sterującym w ASCII / Unicode. (Niewielkim skutkiem ubocznym jest to, że wszystkie tabulacje na wejściu są drukowane jako Js.) Znak spacji pozostaje niezapisany, ponieważ pętla wyjściowa zamienia wszelkie kody powyżej 28 na puste.

  • Drugi wiersz po prostu wypisuje nagłówek PBM. Korzysta z funkcji Perl 5.10 say, więc musisz uruchomić ten skrypt perl -M5.010, aby działał.

  • Pętla wyjściowa pobiera rozdzieloną spacjami listę wierszy upakowanych obrazów i przypisuje kolejno każdy z nich $p. (Czcionkę zaprojektowałem tak, aby spakowane dane nie zawierały żadnych białych znaków ani 'znaków.) Następnie zapętla znaki wejściowe @a, używając vecpolecenia Perla do wyodrębnienia 4-bitowego skrawka odpowiadającego odwzorowanemu kodowi znaków z wiersza obrazu, wstawia go do 8-bitowego bajtu i drukuje.


Stara odpowiedź, 268 bajtów:

To szybka i brudna pierwsza próba. Ukradłem czcionkę PleaseStand i skompresowałem ją wraz z kodem źródłowym. Ponieważ wynikowy skrypt jest w większości niedrukowalny, oto zrzut heksowy; użyj, xxd -raby zmienić go w wykonywalny kod Perla:

0000000: 7573 6520 436f 6d70 7265 7373 275a 6c69  use Compress'Zli
0000010: 623b 6576 616c 2075 6e63 6f6d 7072 6573  b;eval uncompres
0000020: 7320 2778 da85 d03d 4b03 4118 85d1 452c  s 'x...=K.A...E,
0000030: b69c 72cb 7519 4894 552c 2c02 3319 ee5c  ..r.u.H.U,,.3..\
0000040: d7b8 5a89 6093 4634 7e82 c490 6c91 8597  ..Z.`.F4~...l...
0000050: 80fe 7267 d660 23ae e52d 0e0f dcd6 f8c3  ..rg.`#..-......
0000060: e9d1 5e6e ccec a15c ddb5 c5d5 495e 94a3  ..^n...\....I^..
0000070: 83b7 c7f9 73f3 5216 f9a8 787a 5fea 666c  ....s.R...xz_.fl
0000080: 9dd1 b763 dd98 76f8 2df6 0799 5811 7144  ...c..v.-...X.qD
0000090: 4acc ee9d b8b0 c90f 7e4a 8264 6016 cbd7  J.......~J.d`...
00000a0: 79f3 1b91 047c 4055 409e 9e54 1dda ed41  y....|@U@..T...A
00000b0: 9a20 8080 6adc 5c47 8488 7495 f621 01d7  . ..j.\G..t..!..
00000c0: 6b6c 902e b6c8 2a6a 6643 f56f e99c 115d  kl....*jfC.o...]
00000d0: 5c7a f1b2 13d0 3453 790f da74 c813 751d  \z....4Sy..t..u.
00000e0: 11ce d821 ad90 247f 2292 5b54 c14f 3c4e  ...!..$.".[T.O<N
00000f0: 49c5 4c53 a1a7 c478 391c 714c f113 0747  I.LS...x9.qL...G
0000100: ab6c 4482 9fd2 177a 5677 6327            .lD....zVwc'

Zdekompresowany kod Perla składa się z następującej preambuły:

y;A-Z.! ;;cd,say"P4 ",8*length," 8"for$t=<>

a następnie osiem powtórzeń następującego kodu:

;$_=$t;y(A-Z.! )'BITMAP DATA HERE';print

z BITMAP DATA HEREzastąpionym 29 bajtami kodującymi jeden wiersz czcionki.


Nowsze rozwiązanie jest wyjątkowo miłe. Nigdy nie wyobrażałem sobie, że można to zrobić za pomocą 165 znaków.
ChristopheD

6

8086 Kod maszynowy

190 bajtów (122 bajtów przy użyciu systemu BIOS)

Oto plik WinCP / MSDos zakodowany w formacie Base64 .COM:

M8COwCaKDoUEitEmxD4MAaCAAP7IfliK8MHgA7cK9ve9egEAZ
vy0APb3AUb6iMi0APb3AUb+x0YACg2DxQK+ggCK7qz24YvYJo
ohswjQ5LAwFACIRgBF/st18v7NdeRH/sp10sZGACS6cAG0Cc0
hw1AxCg0wMDAgMDA=

(Użyj czegoś takiego ), aby zdekodować tekst i zapisać jako „pbm.com”. Następnie w wierszu polecenia wpisz:

pbm tekst do zakodowania> outputfilename.pbm

Przetestowałem to na moim komputerze WinXP, używając zarówno standardowego wiersza polecenia, jak i DosBox V0.74.

AKTUALIZACJA

Ta wersja ma 190 bajtów i używa małej czcionki Ilmari Karonen (tutaj nie ma dostępu do biografii!): -

voAArf7Iflq7YwG/vgG6Cg20Bfbk9vIAZfsy5PbyAUX5Vqw48HQoLEFzCDQG/sAMGSQfM8
nQ6NfA0QPS6IjEsQSwJtDsENCq4vewMKrr04DDEF6A+7N1ycYFJLqzAbQJzSHDdnb/loIZ
mXZ2flmZ9QAAIJmZEZGCFb+ZmSFZmYUPDy9/kXf9ghPZeXkmWWllAAAgmZkRmZIVmRldKF
mfEgAAAHl2H5Zi+ZkWnicmmfIAICBQMQoNMDAwIDUKDQ==

Niezwykle miłe rozwiązanie. W tej chwili jest to pretendent do nagrody, która zostanie przyznana za około 20 godzin. Dobra robota!
ChristopheD

Czy możesz również opublikować swój kod asemblera?
Sir_Lagsalot

1
Po przyjrzeniu się demontażowi i przetestowaniu kodu wygląda na to, że używasz czcionki bitmapowej dostarczonej przez bios. Potwierdza to fakt, że Twój program może wyświetlać małe litery, symbole i znaki interpunkcyjne, które nie są wymagane przez wyzwanie. Zatem czcionka jest zewnętrzna dla twojego programu i nie jest przez nią przechowywana (przynajmniej moim zdaniem).
Sir_Lagsalot

@ Skiki: czy możesz to potwierdzić? Nadal stanowi wyjątkowo miłe rozwiązanie, ale jest nieco niezgodne ze specyfikacją.
ChristopheD

1
@ChristopheD: Cóż, JB skomentował: „Czuję, że będziemy mieć długą i bolesną debatę na temat tego, co stanowi zewnętrzną bibliotekę”. - można argumentować, że putsw Ruby jest biblioteka zewnętrzna. Tak, korzysta z czcionek bios, do których dostęp uzyskuje się poprzez odsunięcie wskaźnika (brak loadoperacji wprowadzania czcionek do pamięci RAM). Być może zbyt wyginanie zasad. Uciekłbym z tego, gdyby nie te nieznośne dzieci ;-)
Skizz

6

Skrypt powłoki (kod + dane = 295 znaków)

Mam nadzieję, że tail, gzip i dd nie liczą się jako „biblioteki zewnętrzne”. Uruchom jako echo -n 'YOUR TEXT HERE' | ./text.sh > out.pbm. Czcionka, której użyłem, to Small Fonts rozmiar 7,5, chociaż musiałem odciąć descender od Q.

Przykładowe dane wyjściowe

SZYBKIE BRĄZOWE FOX SKOKUJĄ NA LENIĄCE PSY.  NAPRAWDĘ!

Kod (137 znaków)

i=`od -tu1|cut -c9-`
echo P4
for a in {0..7}
do for b in $i
do tail -2 $0|zcat|dd bs=1 count=1 skip=$((8*b+a))
done
done>8
wc -c 8
cat 8

Kompletny skrypt

(użyj, xxd -raby odtworzyć oryginalny plik)

0000000: 693d 606f 6420 2d74 7531 7c63 7574 202d  i=`od -tu1|cut -
0000010: 6339 2d60 0a65 6368 6f20 5034 0a66 6f72  c9-`.echo P4.for
0000020: 2061 2069 6e20 7b30 2e2e 377d 0a64 6f20   a in {0..7}.do 
0000030: 666f 7220 6220 696e 2024 690a 646f 2074  for b in $i.do t
0000040: 6169 6c20 2d32 2024 307c 7a63 6174 7c64  ail -2 $0|zcat|d
0000050: 6420 6273 3d31 2063 6f75 6e74 3d31 2073  d bs=1 count=1 s
0000060: 6b69 703d 2428 2838 2a62 2b61 2929 0a64  kip=$((8*b+a)).d
0000070: 6f6e 650a 646f 6e65 3e38 0a77 6320 2d63  one.done>8.wc -c
0000080: 2038 0a63 6174 2038 0a1f 8b08 0000 0000   8.cat 8........
0000090: 0000 ffed cdb1 0a83 3014 8561 910e 8e8e  ........0..a....
00000a0: 193b dca1 631f 2084 9353 6ba3 a3e0 e2a8  .;..c. ..Sk.....
00000b0: 2fe0 d8e1 22d8 276f 9a50 e813 940e fdb8  /...".'o.P......
00000c0: 70f9 a753 247f 7829 f0b5 b9e2 c718 2322  p..S$.x)......#"
00000d0: 1ba9 e9a8 9688 6895 892a 7007 f0fe 701e  ......h..*p...p.
00000e0: b879 ef48 6e8c aa4f 219c d984 750d 0d91  .y.Hn..O!...u...
00000f0: e9b2 8c63 d779 3fcf c3d0 f76d eb7c e2d2  ...c.y?....m.|..
0000100: 1880 d4d7 4b6e 9296 b065 49ab 75c6 cc92  ....Kn...eI.u...
0000110: 1411 63f6 7de7 3489 9031 847c 3c9a 531d  ..c.}.4..1.|<.S.
0000120: e9a1 aa8f 803e 01                        .....>.

Wyjaśnienie

  • odto standardowy program narzędziowy „octal dump”. Ta -tu1opcja nakazuje zamiast tego utworzenie dziesiętnego zrzutu pojedynczych bajtów (wystarczające obejście dla braku bash'a braku asc (), ord (), .charCodeAt () itp.)
  • P4to magiczna liczba dla pliku PBM w formacie binarnym, który pakuje osiem pikseli w każdym bajcie (w porównaniu P1do pliku PBM w formacie ASCII). Zobaczysz, jak to się przyda.
  • Na wiersz końcowego wyniku program pobiera ośmiopikselowy bajt (odpowiadający kodowi ASCII i numerowi wiersza) z sekcji danych skompresowanych gzip na końcu przy użyciu dd. ( tail -2 $0wyodrębnia dwa ostatnie wiersze skryptu; skompresowane dane zawierają jeden bajt wysuwu linii 0x0a.) Zdarza się, że osiem pikseli to szerokość pojedynczego znaku. Puste bajty wypełniające luki między obsługiwanymi znakami są łatwo kompresowalne, ponieważ wszystkie są takie same.
  • Wszystko to zapisywane jest w pliku o nazwie „8”. Ponieważ jest dokładnie osiem wierszy (a także osiem pikseli na bajt), liczba bajtów jest szerokością danych wyjściowych w pikselach. Wysokość wyjścia jest również uwzględniona w tym, że wc -cdrukuje nazwę pliku wejściowego „8” po liczbie bajtów.
  • Teraz, gdy nagłówek jest gotowy, dane obrazu są drukowane. Bash zauważa tylko, że ostatnie dwa wiersze nie są prawidłowymi poleceniami (ostatni faktycznie nieważny UTF-8) po wykonaniu wszystkiego, co było wcześniej.
  • Użyłem KZIP tylko do kompresji sekcji danych, tak jak Ilmari Karonen przez całe poddanie się wyzwaniu 12 dni świątecznych. Jak opisano tam, zasadniczo konieczne jest użycie edytora szesnastkowego, aby zastąpić format nagłówka ZIP nagłówkiem gzip. Dołączenie CRC-32 i rozmiaru pliku z oryginalnego nagłówka ZIP wydaje się niepotrzebne.

2
Naprawdę fajne (i krótkie) rozwiązanie! W skryptach powłoki użycie dd, tail i gzip nie powinno być traktowane jako zewnętrzne imho.
ChristopheD

1
Czy możesz dodać wyjaśnienie, jak to działa? Byłbym bardzo wdzięczny.
Pan Llama,

2
Bardzo miło, wielkie dzięki za wyjaśnienie. Jednak użycie wersji „P4” nie jest tak naprawdę zgodne z tym, co OP powiedział „bardzo prosty czarno-biały format bitmap ASCII ”.
eregon

5

Python 2, 248 247 bajtów

s=raw_input();k=len(s);print"P1",k*8,8
for i in range(k*24):a=s[i/3%k];j=max(".!".find(a)+1,ord(a)-62)*3;print int("00080084IMVAENBSIFERBSUF4UFQQEMVDT4NAP4MNDSI9MRTMRBARA4NBQRAMNBE4E94NURDARDNRDMLD95DSL7"[j:j+3],32)>>(i/3/k*3+i%3)&1," 0"*(i%3/2*5)

Wykorzystuje czcionkę 3x5, zapakowaną w ciąg do drukowania, 3 bajty na znak. Czcionka jest wyraźnie czytelna, chociaż n jest małymi literami, a v może być mylone z au, jeśli nie jest widziane w kontekście.

Rzeczywisty rozmiar:
rzeczywisty rozmiar

Powiększony x3:
powiększony x3

Wyjściem jest PBM typu P1, jak na przykładzie w wyzwaniu. To było zabawne wyzwanie.


4

Ruby 1.9, 346 bajtów (kod 122 + dane 224 bajty)

Oto wynik:

CODEGOLF

(Fajnie, prawda?)

z=0..7;puts"P1\n#{(s=gets).size*8} 8",z.map{|i|s.bytes.flat_map{|o|z.map{|j|'DATA'.unpack('Q<*')[o>64?o-63:o/46][i*8+j]}}*' '}

Czcionka została wygenerowana przez figlet -f banner -w 1000 $LETTERSi ten skrypt .

Uruchom z echo -n 'CODEGOLF.STACKEXCHANGE.COM!' | ruby script.rb > image.pbm.

Skrypt generuje wszystkie wiersze i po prostu je drukuje.

Oto zrzut heksowy (użycie xxd -r):

0000000: 7a3d 302e 2e37 3b70 7574 7322 5031 5c6e  z=0..7;puts"P1\n
0000010: 237b 2873 3d67 6574 7329 2e73 697a 652a  #{(s=gets).size*
0000020: 387d 2038 222c 7a2e 6d61 707b 7c69 7c73  8} 8",z.map{|i|s
0000030: 2e62 7974 6573 2e66 6c61 745f 6d61 707b  .bytes.flat_map{
0000040: 7c6f 7c7a 2e6d 6170 7b7c 6a7c 271c 1c1c  |o|z.map{|j|'...
0000050: 0800 1c1c 0000 0000 001c 1c1c 0008 1422  ..............."
0000060: 417f 4141 003f 4141 3f41 413f 003e 4101  A.AA.?AA?AA?.>A.
0000070: 0101 413e 003f 4141 4141 413f 007f 0101  ..A>.?AAAAA?....
0000080: 1f01 017f 007f 0101 1f01 0101 003e 4101  .............>A.
0000090: 7941 413e 0041 4141 7f41 4141 001c 0808  yAA>.AAA.AAA....
00000a0: 0808 081c 0040 4040 4041 413e 0042 2212  .....@@@@AA>.B".
00000b0: 0e12 2242 0001 0101 0101 017f 0041 6355  .."B.........AcU
00000c0: 4941 4141 0041 4345 4951 6141 007f 4141  IAAA.ACEIQaA..AA
00000d0: 4141 417f 003f 4141 3f01 0101 003e 4141  AAA..?AA?....>AA
00000e0: 4151 215e 003f 4141 3f11 2141 003e 4101  AQ!^.?AA?.!A.>A.
00000f0: 3e40 413e 007f 0808 0808 0808 0041 4141  >@A>.........AAA
0000100: 4141 413e 0041 4141 4122 1408 0041 4949  AAA>.AAAA"...AII
0000110: 4949 4936 0041 2214 0814 2241 0041 2214  III6.A"..."A.A".
0000120: 0808 0808 007f 2010 0804 027f 0027 2e75  ...... ......'.u
0000130: 6e70 6163 6b28 2751 3c2a 2729 5b6f 3e36  npack('Q<*')[o>6
0000140: 343f 6f2d 3633 3a6f 2f34 365d 5b69 2a38  4?o-63:o/46][i*8
0000150: 2b6a 5d7d 7d2a 2720 277d                 +j]}}*' '}

Przy użyciu goruby zajmuje 93 bajty kodu:

ps"P1\n#{(s=gt).sz*8} 8",8.mp{|i|s.y.fl{|o|8.mp{|j|'DATA'.ua('Q<*')[o>64?o-63:o/46][i*8+j]}}*' '}

Używając ZLib przycinamy rozmiar danych do 142 bajtów zamiast 224, ale dodaje 43 bajty w kodzie, więc 307 bajtów:

#coding:binary
require'zlib';z=0..7;puts"P1\n#{(s=gets).size*8} 8",z.map{|i|s.bytes.flat_map{|o|z.map{|j|Zlib.inflate("DATA").unpack('Q<*')[o>64?o-63:o/46][i*8+j]}}*' '}

Co daje w sumie 268 podczas używania Goruby:

#coding:binary
rq'zlib';ps"P1\n#{(s=gt).sz*8} 8",8.mp{|i|s.y.fl{|o|8.mp{|j|Zlib.if("DATA").ua('Q<*')[o>64?o-63:o/46][i*8+j]}}*' '}

2

Java 862 826:

Oto inne podejście. Myślę, że „awt” nie liczy się jako lib zewnętrzny.

import java.awt.*;
class B extends Frame{String s="ABCDEFGHIJKLMNOPQRSTUVWXYZ .!";int l=29;static Robot r;int[][][]m=new int[l][8][8];
public void paint(Graphics g){for(int y=0;y<8;++y){int py=(y<3)?y:y+1;for(int a=0;a<l;++a)
for(int x=0;x<8;++x)
m[a][x][y]=(r.getPixelColor(8*a+x+17+x/4,py+81)).getRGB()<-1?1:0;}
System.out.println("P1\n"+(getTitle().length()*8)+" 8");
for(int y=0;y<8;++y){for(char c:getTitle().toCharArray()){int a=s.indexOf(c);
for(int x=0;x<8;++x)System.out.print(m[a][x][y]);}
System.out.println();}
System.exit(0);}
public B(String p){super(p);
setBackground(Color.WHITE);
setSize(400,60);
Label l=new Label(s);
l.setFont(new Font("Monospaced",Font.PLAIN,13));
add(l);
setLocation(9,49);    
setVisible(true);}    
public static void main(String a[])throws Exception{r=new Robot();    
new B(a[0]);}}

I bez golfa:

import java.awt.*;

class PBM extends Frame
{
    String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ .!";
    int l=29;
    Robot robot;
    int[][][] map = new int[l][8][8];

    static boolean init = false;

    public void paint (Graphics g)
    {    
        for (int y = 0; y < 8; ++y)    
        {    
            int py = (y < 3) ? y : y +1;    
            for (int a = 0; a < l; ++a)
            {    
                for (int x = 0; x < 8; ++x)    
                {    
                    map[a][x][y] = (robot.getPixelColor (8*a+x+17+x/4, py+81)).getRGB () < -1 ? 1 : 0;    
                }    
            }    
        }

        System.out.println("P1\n"+(getTitle().length()*8)+" 8");

        for (int y = 0; y < 8; ++y) {    
            for (char c : getTitle ().toCharArray ()) {    
                int a = s.indexOf (c);    
                for (int x = 0; x < 8; ++x) {    
                    System.out.print (map[a][x][y]);    
                }
            }
            System.out.println ();
        }
        System.exit (0);
    }   

    public PBM (String p) throws Exception    
    {    
        super (p);    
        robot = new Robot ();    
        setBackground (Color.WHITE);    
        setSize (400, 60);    
        Label l=new Label(s);    
        l.setFont (new Font ("Monospaced", Font.PLAIN, 13));
        add(l);
        setLocation (9,49);
        setVisible (true);
    }

    public static void main (String args[]) throws Exception
    {
        new PBM (args[0]);
    }    
}

Robot to ciekawy sposób, w jaki Java wywołuje getPixel. Tworzę Etykietę z alfabetem i sprawdzam, gdzie jest piksel dla każdej litery.

W metodzie malowania int py = (y < 3) ? y : y +1;i (8*a+x+17+x/4, py+81)jest to skomplikowany sposób, aby dostosować pozycję czcionki. Huuuh! w przeciwnym razie potrzebowałoby 9 linii, a co 4 literę jest dodatkowy piksel w poziomie. Próba i błąd doprowadziły mnie do tego rozwiązania.

Następnie zapisywany jest nagłówek PBM i każdy wiersz wiadomości. Wiadomość jest przekazywana jako tytuł ramki.

Otóż ​​to. Nie był to najkrótszy kod, ale nie było konieczne ręczne malowanie czcionek.

Może być krótszy w BeanShell lub Scala.

A teraz - jak to wygląda?

java B "JAVA.CAFE BABE" > jcb.pbm

Zastosowano wiele zoomów: java.cafe kochanie PNG

Unzoomed: java.cafe kochanie JPG

Nie chodzi o to, że liczba znaków jest liczbą znaków z rozwiązania Perla przetasowanymi.

(grał trochę bardziej w golfa. Uczyniono Robota statycznym, co pozwala uniknąć jednej deklaracji wyjątku).


Oryginalne podejście, ładnie wykonane!
ChristopheD

1
+1 za oryginalność, ale eww ... jeśli chcesz skalować bitmapę, użyj interpolacji najbliższego sąsiada.
Ilmari Karonen,

Użyłem eog(Eye of Gnome) i zrzutu ekranu. Prześlę nieskalowaną jpgwersję; może Twoja przeglądarka używa interpolacji najbliższego sąsiada :).
użytkownik nieznany

1

C ++ ZA DUŻO, ABY WYGRAĆ

Napisałem w pełni funkcjonalny program do rysowania PPM w C ++, z własną czcionką bitmapową. Nawet usunięcie wszystkich niepotrzebnych funkcji jest wciąż ogromne w porównaniu z odpowiedziami tutaj z powodu definicji czcionki.

Tak czy inaczej, oto wynik dla HELLO WORLD: wprowadź opis zdjęcia tutaj

I kod:

ppmdraw.h

#ifndef PPMDRAW_H
#define PPMDRAW_H

#include <fstream>
#include <sstream>
#include <map>
#include <bitset>
#include <vector>

struct pixel{
    unsigned char r;
    unsigned char g;
    unsigned char b;

    bool equals(pixel p){
        return (r == p.r && g == p.g && b == p.b);
    }
};

class PPMDraw
{
    public:
        PPMDraw(int w, int h);

        virtual ~PPMDraw();

        void fill(unsigned char r, unsigned char g, unsigned char b);

        void set_color(unsigned char r, unsigned char g, unsigned char b);

        void draw_point(int x, int y);

        void draw_char(int x, int y, char c);
        void draw_string(int x, int y, std::string text);

        bool save(std::string file);

    private:

        int width;
        int height;

        pixel * image;

        std::vector<bool> checked;

        unsigned char red;
        unsigned char green;
        unsigned char blue;

        void init_alpha();
        std::map<char, std::bitset<48> > font;

};

#endif // PPMDRAW_H

ppmdraw.cpp

#include "PPMDraw.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cmath>
#include <map>
#include <bitset>
#include <vector>

// standard constructor
PPMDraw::PPMDraw(int w, int h){
    width = w;
    height = h;

    // make an array to hold all the pixels, r, g, b for each
    image = new pixel[width * height];

    // a bitset to use for functions that have to check which pixels have been worked on
    checked = std::vector<bool>();
    for(int i = 0; i < width * height; i++){
        checked.push_back(false);
    }

    init_alpha();
}


PPMDraw::~PPMDraw(){
    if(image != nullptr){
        delete[] image;
    }
}



void PPMDraw::fill(unsigned char r, unsigned char g, unsigned char b){
    for(int i = 0; i < width * height; i++){
        image[i + 0] = pixel{r, g, b};
    }
}

void PPMDraw::set_color(unsigned char r, unsigned char g, unsigned char b){
    red = r;
    green = g;
    blue = b;
}

void PPMDraw::draw_point(int x, int y){
    if(x >= 0 && x < width && y >= 0 && y < height){
        image[y * width + x] = pixel{red, green, blue};
    }
}

void PPMDraw::draw_char(int x, int y, char c){
    std::bitset<48> letter = font[c];
    int n = 47;
    for(int i = 0; i < 6; i++){
        for(int j = 0; j < 8; j++){
            if(letter[n]){
                draw_point(x + i, y + j);
            }
            n--;
        }
    }
}
void PPMDraw::draw_string(int x, int y, std::string text){
        for(unsigned int i = 0; i < text.length(); i++){
            draw_char(x + 6 * i, y, text[i]);
        }

}



bool PPMDraw::save(std::string file){
    std::ofstream save(file.c_str(), std::ios_base::out | std::ios_base::binary);
    if(save.is_open()){
        save << "P6" << std::endl;
        save << width << " " << height << std::endl;
        save << "255" << std::endl;
        unsigned char * temp = new unsigned char[height * width * 3];
        for(int i  = 0; i < height * width; i++){
            temp[i * 3 + 0] = image[i].r;
            temp[i * 3 + 1] = image[i].g;
            temp[i * 3 + 2] = image[i].b;
        }
        save.write(reinterpret_cast<const char *> (temp), height*width*3*sizeof(unsigned char));
        delete temp;
        save.close();
        return true;
    }else{
        return false;
    }


}

void PPMDraw::init_alpha(){
    // Define a simple font for drawing text
    font[' '] = std::bitset<48>  (std::string("000000000000000000000000000000000000000000000000"));
    font['!'] = std::bitset<48>  (std::string("000000000000000011110110000000000000000000000000"));
    font['"'] = std::bitset<48>  (std::string("000000001100000000000000110000000000000000000000"));
    font['#'] = std::bitset<48>  (std::string("001010001111111000101000111111100010100000000000"));
    font['$'] = std::bitset<48>  (std::string("001001000101010011111110010101000100100000000000"));
    font['%'] = std::bitset<48>  (std::string("000000100100110000010000011000001000010000000000"));
    font['&'] = std::bitset<48>  (std::string("000111001110001010110010110011000000001000000000"));
    font['\\'] = std::bitset<48>  (std::string("100000000110000000010000000011000000001000000000"));
    font['('] = std::bitset<48>  (std::string("000000000000000001111100100000100000000000000000"));
    font[')'] = std::bitset<48>  (std::string("000000001000001001111100000000000000000000000000"));
    font['*'] = std::bitset<48>  (std::string("010010000011000011100000001100000100100000000000"));
    font['+'] = std::bitset<48>  (std::string("000100000001000001111100000100000001000000000000"));
    font[','] = std::bitset<48>  (std::string("000000000000000000000110000000000000000000000000"));
    font['-'] = std::bitset<48>  (std::string("000100000001000000010000000100000001000000000000"));
    font['.'] = std::bitset<48>  (std::string("000000000000000000000100000000000000000000000000"));
    font['/'] = std::bitset<48>  (std::string("000000100000110000010000011000001000000000000000"));
    font['0'] = std::bitset<48>  (std::string("011111001000001010000010100000100111110000000000"));
    font['1'] = std::bitset<48>  (std::string("000000001000001011111110000000100000000000000000"));
    font['2'] = std::bitset<48>  (std::string("010011101001001010010010100100100111001000000000"));
    font['3'] = std::bitset<48>  (std::string("010001001000001010000010100100100110110000000000"));
    font['4'] = std::bitset<48>  (std::string("111100000001000000010000000100001111111000000000"));
    font['5'] = std::bitset<48>  (std::string("111001001001001010010010100100101001110000000000"));
    font['6'] = std::bitset<48>  (std::string("011111001001001010010010100100101000110000000000"));
    font['7'] = std::bitset<48>  (std::string("100000001000000010000110100110001110000000000000"));
    font['8'] = std::bitset<48>  (std::string("011011001001001010010010100100100110110000000000"));
    font['9'] = std::bitset<48>  (std::string("011000001001000010010000100100000111111000000000"));
    font[':'] = std::bitset<48>  (std::string("000000000000000001000100000000000000000000000000"));
    font[';'] = std::bitset<48>  (std::string("000000000000000001000110000000000000000000000000"));
    font['<'] = std::bitset<48>  (std::string("000000000001000000101000010001000000000000000000"));
    font['='] = std::bitset<48>  (std::string("001010000010100000101000001010000000000000000000"));
    font['>'] = std::bitset<48>  (std::string("000000000100010000101000000100000000000000000000"));
    font['?'] = std::bitset<48>  (std::string("010000001000000010001010100100000110000000000000"));
    font['@'] = std::bitset<48>  (std::string("011111001000001010111010101010100111001000000000"));
    font['A'] = std::bitset<48>  (std::string("011111101001000010010000100100000111111000000000"));
    font['B'] = std::bitset<48>  (std::string("111111101001001010010010100100100110110000000000"));
    font['C'] = std::bitset<48>  (std::string("011111001000001010000010100000100100010000000000"));
    font['D'] = std::bitset<48>  (std::string("111111101000001010000010100000100111110000000000"));
    font['E'] = std::bitset<48>  (std::string("111111101001001010010010100100101000001000000000"));
    font['F'] = std::bitset<48>  (std::string("111111101001000010010000100100001000000000000000"));
    font['G'] = std::bitset<48>  (std::string("011111001000001010000010100010100100110000000000"));
    font['H'] = std::bitset<48>  (std::string("111111100001000000010000000100001111111000000000"));
    font['I'] = std::bitset<48>  (std::string("100000101000001011111110100000101000001000000000"));
    font['J'] = std::bitset<48>  (std::string("000011000000001000000010000000101111110000000000"));
    font['K'] = std::bitset<48>  (std::string("111111100001000000010000001010001100011000000000"));
    font['L'] = std::bitset<48>  (std::string("111111100000001000000010000000100000001000000000"));
    font['M'] = std::bitset<48>  (std::string("111111101000000001100000100000001111111000000000"));
    font['N'] = std::bitset<48>  (std::string("111111100100000000100000000100001111111000000000"));
    font['O'] = std::bitset<48>  (std::string("011111001000001010000010100000100111110000000000"));
    font['P'] = std::bitset<48>  (std::string("111111101001000010010000100100001111000000000000"));
    font['Q'] = std::bitset<48>  (std::string("011111001000001010001010100001000111101000000000"));
    font['R'] = std::bitset<48>  (std::string("111111101001000010010000100110001111011000000000"));
    font['S'] = std::bitset<48>  (std::string("011000101001001010010010100100101000110000000000"));
    font['T'] = std::bitset<48>  (std::string("100000001000000011111110100000001000000000000000"));
    font['U'] = std::bitset<48>  (std::string("111111000000001000000010000000101111110000000000"));
    font['V'] = std::bitset<48>  (std::string("111110000000010000000010000001001111100000000000"));
    font['W'] = std::bitset<48>  (std::string("111111100000001000001100000000101111111000000000"));
    font['X'] = std::bitset<48>  (std::string("110001100010100000010000001010001100011000000000"));
    font['Y'] = std::bitset<48>  (std::string("110000000010000000011110001000001100000000000000"));
    font['Z'] = std::bitset<48>  (std::string("100001101000101010010010101000101100001000000000"));
    font['['] = std::bitset<48>  (std::string("000000001111111010000010100000100000000000000000"));
    font['\''] = std::bitset<48>  (std::string("100000000110000000010000000011000000001000000000"));
    font[']'] = std::bitset<48>  (std::string("000000001000001010000010111111100000000000000000"));
    font['^'] = std::bitset<48>  (std::string("001000000100000010000000010000000010000000000000"));
    font['_'] = std::bitset<48>  (std::string("000000100000001000000010000000100000001000000000"));
    font['`'] = std::bitset<48>  (std::string("000000001000000001000000000000000000000000000000"));
    font['a'] = std::bitset<48>  (std::string("000001000010101000101010001010100001111000000000"));
    font['b'] = std::bitset<48>  (std::string("111111100001001000010010000100100000110000000000"));
    font['c'] = std::bitset<48>  (std::string("000111000010001000100010001000100001010000000000"));
    font['d'] = std::bitset<48>  (std::string("000011000001001000010010000100101111111000000000"));
    font['e'] = std::bitset<48>  (std::string("000111000010101000101010001010100001101000000000"));
    font['f'] = std::bitset<48>  (std::string("000100000111111010010000100100000000000000000000"));
    font['g'] = std::bitset<48>  (std::string("001100100100100101001001010010010011111000000000"));
    font['h'] = std::bitset<48>  (std::string("111111100001000000010000000100000000111000000000"));
    font['i'] = std::bitset<48>  (std::string("000000000000000001011110000000000000000000000000"));
    font['j'] = std::bitset<48>  (std::string("000000100000000100000001010111100000000000000000"));
    font['k'] = std::bitset<48>  (std::string("111111100000100000010100001000100000000000000000"));
    font['l'] = std::bitset<48>  (std::string("000000000000000011111110000000000000000000000000"));
    font['m'] = std::bitset<48>  (std::string("000111100001000000001000000100000001111000000000"));
    font['n'] = std::bitset<48>  (std::string("001111100001000000010000000100000001111000000000"));
    font['o'] = std::bitset<48>  (std::string("000111000010001000100010001000100001110000000000"));
    font['p'] = std::bitset<48>  (std::string("001111110010010000100100001001000001100000000000"));
    font['q'] = std::bitset<48>  (std::string("000110000010010000100100001001000011111100000000"));
    font['r'] = std::bitset<48>  (std::string("000000000011111000010000000100000000000000000000"));
    font['s'] = std::bitset<48>  (std::string("000000000001001000101010001010100010010000000000"));
    font['t'] = std::bitset<48>  (std::string("000000000010000011111110001000000000000000000000"));
    font['u'] = std::bitset<48>  (std::string("000111000000001000000010000000100001110000000000"));
    font['v'] = std::bitset<48>  (std::string("000110000000010000000010000001000001100000000000"));
    font['w'] = std::bitset<48>  (std::string("000111100000001000000100000000100001111000000000"));
    font['x'] = std::bitset<48>  (std::string("001000100001010000001000000101000010001000000000"));
    font['y'] = std::bitset<48>  (std::string("001100000000100000000111000010000011000000000000"));
    font['z'] = std::bitset<48>  (std::string("010001100100101001010010011000100000000000000000"));
    font['{'] = std::bitset<48>  (std::string("000000000000000001101100100100100000000000000000"));
    font['|'] = std::bitset<48>  (std::string("000000000000000011111110000000000000000000000000"));
    font['}'] = std::bitset<48>  (std::string("000000000000000010010010011011000000000000000000"));
    font['~'] = std::bitset<48>  (std::string("000100000010000000010000000010000001000000000000"));
}

main.cpp

#include "PPMDraw.h"
#include <iostream>

int main(){
    // ask for input
    std::string input;
    std::cout << "ENTER YOUR TEXT" << std::endl;
    getline(std::cin, input);
   // get size for image
  int width = input.size() * 6;
   PPMDraw image = PPMDraw(width, 8);
   image.fill(255, 255, 255);
   image.set_color(0, 0, 0);
   image.draw_string(0, 0, input);
   image.save("text.ppm");
}

Makefile

CC = g++
CFLAGS = -Wall -c -std=c++11
LFLAGS = -Wall
OBJS = main.o PPMDraw.o

list: $(OBJS)
    $(CC) $(LFLAGS) $(OBJS) -o text2ppm

main.o: PPMDraw.h
    $(CC) $(CFLAGS) main.cpp

PPMDraw.o: PPMDraw.h
    $(CC) $(CFLAGS) PPMDraw.cpp

clean:
    rm *.o main

Jeśli jesteś zainteresowany, pełna biblioteka PPMDraw jest tutaj :


1
Uważam, że twoje czcionki są bardzo przydatne!
Ludwik,

1

SmileBASIC, 231 bajtów

LINPUT C$?"P1
?8,LEN(C$)*8WHILE""<C$A=ASC(SHIFT(C$))D=ASC("*N.JZ`;O:²ÞøäüÄho"[A-65+12*(A<34)+47*(A<47)])FOR I=0TO 4B$=BIN$(VAL("7535712074617252"[D>>5<<1OR 1AND D>>I]),8)WHILE""<B$?POP(B$),
WEND?NEXT?"0 "*24WEND

wprowadź opis zdjęcia tutaj

Każda postać zawiera tylko 2 różne wzory wierszy, wybrane z „palety” 8 kombinacji. Dane dla każdego symbolu są przechowywane w 1 bajcie, a paleta jest przechowywana osobno.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.