Gerando arquivos de bitmap PBM a partir de texto ASCII


19

O formato PBM (Portable BitMap) é um formato de bitmap ASCII em preto e branco muito simples.

Aqui está um exemplo para a letra 'J' (copiada e colada no link da Wikipedia):

P1
# Este é um exemplo de bitmap da letra "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

Está na hora de criarmos uma pequena ferramenta para gerar arquivos nesse pequeno e bacana formato!

Seu objetivo é escrever o programa mais curto (em qualquer idioma) que esteja em conformidade com as seguintes regras:

  1. Seu programa usa uma string de stdin (por exemplo CODEGOLF.STACKEXCHANGE.COM!)
  2. Ele gera um arquivo PBM com uma representação de bitmap (legível) da sequência.
  3. Cada personagem é construído como uma grade 8x8.
  4. Você deve suportar os caracteres [AZ] (todos em maiúsculas), espaço, um ponto ('.') E um ponto de exclamação ('!').
  5. Nenhuma biblioteca externa permitida (certamente nenhuma relacionada ao PBM)!
  6. O conjunto de caracteres usado não deve ser simplesmente externo ao seu programa. Parte do desafio é armazenar os personagens com eficiência ...

O teste de validade do formato PBM pode ser feito com o GIMP (ou outros). Mostre a entrada e a saída da amostra!

A solução mais curta receberá os pontos de resposta em 31/01/2012.

Divirta-se jogando golfe!

PS: Eu adicionei uma recompensa (em porcentagem, uma grande parte da minha reputação de codegolf) para (espero) atrair mais concorrentes.


Por "sua representação de bitmap", você quer dizer uma representação de caractere próxima de algo que se parece com letras? Quão perto? Seria permitido algo como uma representação de bitmap de um código binário ou de código braille ou morse?
Howard Howard

@ Howard: a idéia é gerar uma imagem pbm que contenha o texto de entrada original em 'renderizado' (bitmap), mas ainda de forma legível por humanos (com lettersoutras palavras). Não muito diferente do exemplo vinculado a.
ChristopheD

Eu adicionei a tag kolmogorov-complexidade porque a maior parte do programa serão os 30 bitmaps.
22413 Peter Peter

@ Peter Taylor: Bom ponto, obrigado!
ChristopheD

Sinto que teremos um longo e doloroso debate sobre o que constitui uma "biblioteca externa".
JB

Respostas:


9

GolfScript, 133 bytes

Isso se baseia na minha solução Perl de 164 bytes e usa a mesma fonte de 4 por 5 pixels cheia de petiscos. Mais uma vez, darei a versão legível primeiro:

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

Aqui, FONT DATA HEREsignifica 71 bytes de dados de fontes binárias compactadas. A codificação é um pouco diferente da versão Perl: em vez de dividir a sequência compactada no espaço em branco, eu a expanda primeiro e depois a divido na mordidela 3(escolhida porque acontece que não ocorre em nenhum lugar na fonte).

Como os dados da fonte no script real contêm caracteres não imprimíveis, eu os dou como um hexadecimal abaixo. Use xxd -rpara transformar o despejo hexadecimal de volta no código executável do 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*

Ao contrário do script Perl, este código imprime quaisquer caracteres fora do conjunto A- Z, !, ., spacecomo rabiscos pequenos de aparência engraçada. Substituir os rabiscos por espaços em branco custaria 2 caracteres extras; removê-los inteiramente custaria 4.

Este é o meu primeiro programa GolfScript, portanto, não ficaria surpreso se sobrar espaço para otimização. Veja como funciona:

  • {91,65>"!. "+?}%:smapeia os caracteres de entrada válidos ( A- Z, !, ., space) para os números 0 - 28 e atribui o resultado a s. Quaisquer caracteres fora do conjunto válido são mapeados para -1, que é o que produz os rabiscos quando impressos.

  • "P4"\,8*8coloca os valores "P4", 8 vezes o comprimento da entrada e 8 na pilha. Quando impressos no final, eles formarão o cabeçalho PBM.

  • {16base}%[3]/pega a sequência anterior de dados da fonte, divide cada byte em duas mordidelas e divide o resultado em blocos delimitados pelo valor 3. {:p;{[p=0]0=}s%}%depois faz um loop sobre esses blocos, primeiro atribuindo cada bloco à variável pe, em seguida, fazendo um loop sobre a sequência de entrada remapeada s, substituindo cada caractere pelo valor no deslocamento correspondente em p. A construção de aparência engraçada [p=0]0=faz o mesmo que p=, exceto que retorna 0 para quaisquer compensações após o final de p; Eu realmente não gosto, mas não consegui descobrir uma maneira mais curta de lidar com isso.

  • Finalmente, ]n*pega tudo na pilha (os três valores do cabeçalho e a matriz de dados da imagem) e os une às novas linhas de impressão.


Seriamente curto (por qualquer métrica). Agradável!
ChristopheD

12

Perl, 164 bytes, sem compactação zlib / gzip

Depois de dormir no problema, consegui descobrir uma solução muito mais curta que a minha primeira. O truque é tirar proveito de uma brecha menor nas regras: os personagens precisam caber em 8 por 8 pixels cada, mas nada diz que eles precisam preencher todo esse espaço. Então, desenhei minha própria fonte de 4 por 5 pixels, permitindo que eu agrupasse dois caracteres em 5 bytes.

A saída é assim:

"OLÁ MUNDO!" (escalado x 4)

    "OH! UMA RAPOSA MARROM RÁPIDA PULA SOBRE O CÃO PREGUIÇOSO." (tamanho original)

Antes de fornecer o código real com os dados da fonte incorporada, deixe-me mostrar uma versão descodificada:

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

No código real, ele PACKED FONT DATAé substituído por uma cadeia binária que consiste em oito linhas delimitadas por espaço em branco (quatro linhas de 14 bytes e uma de 13 bytes, mais três bytes nulos únicos para as linhas em branco). Projetei deliberadamente minha fonte para que os dados compactados não contenham espaços em branco, aspas simples ou barras invertidas, para que pudessem ser codificados qw'...'.

Como a string da fonte compactada contém caracteres não imprimíveis, forneci o script real como um dump hexadecimal. Use xxd -rpara transformá-lo novamente em código Perl executável:

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}

Veja como funciona:

  • A primeira linha (na versão de-golfed) lê uma única linha de entrada, divide-a em uma matriz de caracteres (convenientemente omitindo quaisquer mudanças de linha de arrasto) e mapeia as letras Aa Ze os caracteres !e .para os códigos de caracteres de 0 a 28, que normalmente correspondem a caracteres de controle não imprimíveis em ASCII / Unicode. (Um efeito colateral menor disso é que todas as guias na entrada são impressas como Js.) O caractere de espaço é deixado sem mapeamento, pois o loop de saída transforma qualquer código acima de 28 em espaços em branco de qualquer maneira.

  • A segunda linha apenas imprime o cabeçalho PBM. Ele usa o sayrecurso Perl 5.10 , portanto, você precisa executar esse script perl -M5.010para que ele funcione.

  • O loop de saída pega uma lista delimitada por espaços em branco de linhas de imagem compactada e atribui cada uma delas $ppor vez. (Eu projetei a fonte para que os dados compactados não contivessem espaços em branco ou 'caracteres.) Em seguida, circula os caracteres de entrada @a, usando o veccomando Perl para extrair a mordidela de 4 bits correspondente ao código de caractere mapeado da linha da imagem, preenche-o em um byte de 8 bits e o imprime.


Resposta antiga, 268 bytes:

Esta é uma primeira tentativa rápida e suja. Eu roubei a fonte do PleaseStand e a comprimi junto com o meu código-fonte. Como o script resultante é praticamente imprimível, aqui está um hexdump; use xxd -rpara transformá-lo em código Perl executável:

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'

O código Perl descompactado consiste no seguinte preâmbulo:

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

seguido por oito repetições do seguinte código:

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

com BITMAP DATA HEREsubstituído com 29 bytes que codifica uma linha da fonte.


A solução mais recente é extremamente agradável. Nunca imaginei que isso pudesse ser feito em 165 caracteres.
ChristopheD

6

Código da máquina 8086

190 bytes (122 bytes usando o BIOS)

Aqui está o arquivo .COM do WinXP / MSDos codificado em Base64:

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

(Use algo parecido com isto ) para decodificar o texto e salve como "pbm.com". Em seguida, no prompt de comando, digite:

texto pbm a codificar> outputfilename.pbm

Eu testei isso na minha máquina WinXP usando o prompt de comando padrão e o DosBox V0.74.

ATUALIZAR

Esta versão tem 190 bytes e usa a fonte minúscula de Ilmari Karonen (sem acesso ao BIOS aqui!): -

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

Solução extremamente agradável. No momento, este é o candidato à recompensa, que será concedido em cerca de 20 horas. Bem feito!
ChristopheD

Você também pode postar seu código de montagem?
Sir_Lagsalot

11
Depois de analisar a desmontagem e testar o código, parece que você está apenas usando uma fonte de bitmap fornecida pela bios. Isso pode ser confirmado pelo fato de que seu programa pode gerar letras minúsculas, símbolos e pontuação não exigidos pelo desafio. Assim, a fonte é externa ao seu programa e não é armazenada por ele (pelo menos na minha opinião).
precisa saber é o seguinte

@ Skizz: você pode confirmar isso? Ainda é uma solução extremamente agradável, mas um pouco contra as especificações.
ChristopheD

11
@ChristopheD: Bem, JB comentou "Eu sinto que teremos um longo e doloroso debate sobre o que constitui uma biblioteca externa". - alguém poderia argumentar que putsem Ruby há uma biblioteca externa. Sim, ele usa as fontes da BIOS, acessadas por meio de uma referência de ponteiro (não há loadoperação para colocar as fontes na RAM). Talvez inclinar as regras longe demais. Eu teria fugido com ele se não tivesse sido para aqueles miúdos traquinas ;-)
Skizz

6

Script de shell (código + dados = 295 caracteres)

Espero que tail, gzip e dd não sejam contados como "bibliotecas externas". Executar como echo -n 'YOUR TEXT HERE' | ./text.sh > out.pbm. A fonte que eu usei é Small Fonts tamanho 7.5, embora eu tenha que cortar o descendente do Q.

Saída de exemplo

A RAPOSA MARROM RÁPIDA SALTA SOBRE CÃES PREGUIÇOSOS.  REALMENTE!

Código (137 caracteres)

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

Script completo

(use xxd -rpara recriar o arquivo original)

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                        .....>.

Explicação

  • odé o programa utilitário padrão "octal dump". A -tu1opção diz para produzir um despejo decimal de bytes individuais (uma solução suficiente para a falta de asc (), ord (), .charCodeAt () etc. do bash).
  • P4é o número mágico de um arquivo PBM de formato binário, que comporta oito pixels em cada byte (em comparação P1com o arquivo PBM de formato ASCII). Você verá como isso se mostra útil.
  • Por linha da saída final, o programa extrai um byte de oito pixels (correspondente ao código ASCII e ao número da linha) da seção de dados compactados com gzip no final dd. ( tail -2 $0extrai as duas últimas linhas do script; os dados compactados incluem um byte de alimentação de linha 0x0a.) Acontece que oito pixels têm a largura de um único caractere. Os bytes nulos que preenchem as lacunas entre os caracteres suportados são facilmente compactáveis ​​porque são todos iguais.
  • Tudo isso é gravado em um arquivo chamado "8". Como há exatamente oito linhas (e também oito pixels por byte), o número de bytes é a largura da saída em pixels. A altura da saída também está incluída, wc -cimprimindo o nome do arquivo de entrada "8" após a contagem de bytes.
  • Agora que o cabeçalho está completo, os dados da imagem são impressos. O Bash percebe apenas que as duas últimas linhas não são comandos válidos (a última é realmente UTF-8 inválida) depois de ter executado tudo o que era anterior.
  • Eu usei o KZIP apenas para compactar a seção de dados, como Ilmari Karonen fez para uma submissão completa ao desafio dos 12 dias de Natal. Conforme descrito aqui, é essencialmente necessário usar um editor hexadecimal para substituir o formato do cabeçalho ZIP por um cabeçalho gzip. Incluir o CRC-32 e o tamanho do arquivo do cabeçalho ZIP original parece desnecessário.

2
Solução realmente agradável (e curta)! Nos scripts de shell, o uso de dd, tail e gzip não deve ser considerado como imho externo.
ChristopheD

11
Se importa de adicionar uma explicação de como isso funciona? Seria muito apreciado.
Mr. Llama

2
Muito bom, muito obrigado pela explicação. No entanto, o uso da versão 'P4' não respeita o que o OP disse "um formato de bitmap ASCII em preto e branco muito simples ".
eregon

5

Python 2, 248 247 bytes

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)

Usa uma fonte 3x5, compactada em uma sequência imprimível, 3 bytes por caractere. A fonte é claramente legível, embora n esteja em minúsculas ev possa ser confundido com au se não for visto no contexto.

Tamanho atual:
tamanho atual

Zoom 3 x:
zoom x3

A saída é um PBM do tipo P1, conforme o exemplo no desafio. Foi um desafio divertido.


4

Ruby 1.9, 346 bytes (código 122 + dados de 224 bytes)

Aqui está o resultado:

CODEGOLF

(É bom, não é?)

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]}}*' '}

A fonte foi gerada por figlet -f banner -w 1000 $LETTERSe este script .

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

O script gera todas as linhas e simplesmente as imprime.

Aqui está um hexdump (use 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]}}*' '}

São necessários 93 bytes de código ao usar o goruby:

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]}}*' '}

O uso do ZLib reduz o tamanho dos dados para 142 bytes em vez de 224, mas adiciona 43 bytes no código, portanto 307 bytes:

#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]}}*' '}

O que dá um total de 268 ao usar o 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:

Aqui está uma abordagem diferente. Eu acho que 'awt' não conta como lib externa.

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

E não destruído:

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

Robô é a maneira mais curiosa de Java chamar getPixel. Eu crio um Label com o alfabeto e meço onde está um pixel para cada letra.

No método de pintura, int py = (y < 3) ? y : y +1;e(8*a+x+17+x/4, py+81) é a maneira mais complicada, de ajustar a posição na fonte. Huuuh! caso contrário, seria necessário 9 linhas e, a cada 4 letras, há um pixel adicional na horizontal. Tentativa e erro me levaram a esta solução.

Em seguida, o cabeçalho do PBM é gravado e cada linha da mensagem. A mensagem é passada como título do quadro.

É isso aí. Não é o código mais curto, mas não é necessário pintar a fonte manualmente.

Talvez possa ser mais curto no BeanShell ou Scala.

E agora - como é?

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

Vários zooms aplicados: java.café bebê PNG

Unzoomed: java.cafe bebê JPG

Não que o número de caracteres seja o número de caracteres da solução Perl embaralhados.

(jogou um pouco mais. Tornou o robô estático, o que evita uma declaração de exceção.)


Abordagem original, muito bem feita!
ChristopheD

11
+1 por originalidade, mas eww ... se você quiser ampliar um bitmap, use a interpolação do vizinho mais próximo.
Ilmari Karonen

Eu usei eog(Eye of Gnome) e uma captura de tela. Carregarei uma jpgversão sem escala ; talvez o seu navegador use uma interpolação de vizinhos mais próxima :).
usuário desconhecido

1

C ++ muito grande para ganhar

Eu escrevi um programa de desenho PPM completo em C ++, com minha própria fonte de bitmap. Mesmo eliminando todas as funções não necessárias, ainda é enorme comparado às respostas aqui por causa da definição da fonte.

De qualquer forma, aqui está a saída para HELLO WORLD: insira a descrição da imagem aqui

E o código:

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

Se você estiver interessado, a biblioteca completa do PPMDraw está aqui :


11
Achei suas fontes muito úteis!
Ludwik

1

SmileBASIC, 231 bytes

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

insira a descrição da imagem aqui

Cada caractere contém apenas 2 padrões de linha diferentes, escolhidos de uma "paleta" de 8 combinações. Os dados para cada símbolo são armazenados em 1 byte, com a paleta armazenada separadamente.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.