从ASCII文本生成PBM位图文件


19

PBM(便携式位图)格式是一个非常简单的ASCII黑白位图格式。

这是字母“ J”(从Wikipedia链接复制粘贴)的示例:

P1
#这是字母“ 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

是时候我们构建一个小的工具来生成这种漂亮的小格式的文件了!

您的目标是编写符合以下规则的最短程序(任何语言):

  1. 您的程序从stdin中获取一个字符串(例如CODEGOLF.STACKEXCHANGE.COM!
  2. 它生成带有字符串的位图(可读)表示的PBM文件。
  3. 每个字符都构造为8x8网格。
  4. 您必须支持字符[AZ](全部大写),空格,点('。')和感叹号('!')。
  5. 不允许使用外部库(肯定没有与PBM相关的库)!
  6. 所使用的字符集不能仅在程序外部。挑战的一部分是有效地存储角色。

可以使用GIMP(或其他工具)测试PBM格式的有效性。炫耀样本输入和输出!

最短的解决方案将于2012年1月31日获得解答。

打高尔夫球吧!

PS:我已经添加了赏金(从百分比上讲,这是我在代码高尔夫声誉中的很大一部分),以(希望)吸引更多的竞争对手。


“位图表示”是指接近像字母的字符表示吗?多近?是否可以使用二进制代码或盲文或莫尔斯电码的位图表示形式?
霍华德

@Howard:这个想法是生成一个pbm图像,其中包含原始的输入文本(呈“渲染”(位图)),但仍是人类可读的形式(letters换句话说就是)。与链接的示例没有什么不同。
ChristopheD

我添加了标签kolmogorov-complexity,因为该程序的大部分内容将是30个位图。
彼得·泰勒

@Peter Taylor:很好,谢谢!
ChristopheD

我觉得我们将对构成“外部库”的内容进行长时间而痛苦的辩论。
JB 2012年

Answers:


9

GolfScript,133个字节

这基于我的164字节Perl解决方案,并使用相同的四进位5×4像素字体。再次,我将首先提供可读版本:

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

在这里,FONT DATA HERE代表71个字节的二进制打包字体数据。编码与Perl版本中的编码略有不同:我不是先在空白处拆分打包的字符串,而是先对其进行扩展,然后在半字节中对其进行拆分3(之所以选择,是因为它恰好不在字体的任何位置出现)。

由于实际脚本中的字体数据包含不可打印的字符,因此我在下面将其作为十六进制转储给出。使用xxd -r打开十六进制转储回可执行代码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*

不同的是Perl脚本,该代码打印设置以外的任何字符A- ,Z,,! 因为看起来很有趣的一点潦草的字迹。用毛坯代替花粉将额外增加2个字符。完全删除它们将花费4。.space

这是我有史以来第一个GolfScript程序,因此如果还有一些优化余地,我也不会感到惊讶。运作方式如下:

  • {91,65>"!. "+?}%:s映射有效输入字符(A- ,Z!.),space以数字0 - 28,并将结果受让人s。有效集之外的任何字符都将映射到-1,这是在打印时产生花形的原因。

  • "P4"\,8*8将值“ P4”(输入长度​​的8倍)和8压入堆栈。在末尾打印时,这些将形成PBM标头。

  • {16base}%[3]/接受字体数据的前面的字符串,将其每个字节分成两个半字节,然后将结果分成由value分隔的块3{:p;{[p=0]0=}s%}%然后循环遍历这些块,首先将每个块分配给变量p,然后遍历重新映射的输入字符串s,用中对应偏移量的值替换每个字符p。看起来很有趣的构造[p=0]0=与构造相同p=,不同之处在于,对于超出末尾的任何偏移量,它都返回0 p。我不是很喜欢它,但是我还没有找到任何更短的方法来解决这个问题。

  • 最后,]n*获取堆栈上的所有内容(三个标头值和图像数据数组),并将它们与换行符连接在一起以进行打印。


严重短路(按任何度量标准)。真好!
ChristopheD

12

Perl,164字节,无zlib / gzip压缩

在沉迷于问题之后,我设法找到了比第一个解决方案短得多的解决方案。诀窍是利用规则中的一个小漏洞:每个字符需要以8 x 8像素填充,但是没有什么说它们必须填充所有空间。所以我画了自己的4 x 5像素字体,使我可以将两个字符打包成5个字节。

输出看起来像这样:

“你好,世界!” (比例x 4)

    “哦!那只敏捷的棕色狐狸在懒惰的狗上跳跃。” (原始尺寸)

在给出带有嵌入字体数据的实际代码之前,让我展示一个脱胶版本:

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

在实际的代码中,PACKED FONT DATA替换为由8个空格分隔的行(4个14字节的行和1个13字节的行,以及3个空白行的单个空字节)组成的二进制字符串。我特意设计了字体,以便打包的数据不包含空格,单引号或反斜杠,以便可以将其编码为qw'...'

由于打包的字体字符串包含不可打印的字符,因此我将实际脚本作为十六进制转储提供。用xxd -r把它放回可执行Perl代码:

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}

运作方式如下:

  • 第一行(在去golfed版本)读取输入的一行,它分为字符(方便省略任何尾随新行)的阵列,并且字母映射AZ与所述字符!.所述字符码0至28,其通常对应于ASCII / Unicode中不可打印的控制字符。(这样做的一个较小的副作用是输入中的所有制表符都将打印为Js。)由于输出循环始终将高于28的任何代码转换为空格,因此空格字符未映射。

  • 第二行仅显示PBM标头。它使用了Perl 5.10 say功能,因此您需要运行该脚本perl -M5.010才能正常工作。

  • 输出循环获取一个由空格分隔的打包图像行列表,并将每个行$p依次分配。(我设计了字体,以便打包的数据不包含任何空格或'字符。)然后@a使用Perl的vec命令在中循环输入中的字符,以从图像行中提取与映射的字符代码相对应的4位半字节,将其填充到8位字节并打印。


旧答案,268个字节:

这是一次快速而肮脏的尝试。我偷了PleaseStand的字体并将其与源代码一起压缩。由于生成的脚本大部分无法打印,因此这里是一个十六进制转储;用于xxd -r将其转换为可执行的Perl代码:

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'

解压缩后的Perl代码由以下前导组成:

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

然后是以下代码的八次重复:

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

BITMAP DATA HERE替换为29个字节编码的字体的一行。


较新的解决方案非常好。没想到这可以用165个字符完成。
ChristopheD

6

8086机器代码

190字节(使用BIOS时为122字节)

这是Base64编码的WinXP / MSDos .COM文件:

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

(使用一些东西 类似这样的)对文本进行解码并另存为“ pbm.com”。然后,在命令提示符下,键入:

要编码的pbm文本> outputfilename.pbm

我已经在WinXP计算机上使用标准命令提示符和DosBox V0.74对其进行了测试。

更新

此版本为190字节,并使用Ilmari Karonen的小字体(此处没有bios访问!):-

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

极好的解决方案。目前,这是赏金的竞争者,将在约20小时内颁发。做得好!
ChristopheD

您也可以为此发布您的汇编代码吗?
Sir_Lagsalot 2012年

1
在查看了反汇编并测试了代码之后,似乎您只是在使用bios提供的位图字体。您的程序可以输出挑战不需要的小写字母,符号和标点符号这一事实可以证实这一点。因此,字体在程序外部,而不是由程序存储(至少在我看来)。
Sir_Lagsalot 2012年

@Skizz:你能确认一下吗?它仍然是一个非常好的解决方案,但是有点违反规范。
ChristopheD

1
@ChristopheD:好吧,JB确实评论说:“我认为我们将就构成外部库的问题进行长期而痛苦的辩论。” -有人可能会说puts在Ruby中是一个外部库。是的,它确实使用通过指针引用访问的bios字体(没有load将字体导入RAM的操作)。违反规则可能太过分了。如果不是那些讨厌的孩子,我会放弃的;-)
Skizz 2012年

6

Shell脚本(代码+数据= 295个字符)

我希望tail,gzip和dd不要算作“外部库”。运行为echo -n 'YOUR TEXT HERE' | ./text.sh > out.pbm。我使用的字体是“ Small Fonts”(小字体),大小为7.5,尽管我确实必须将降序剪下来。

输出示例

快速的棕狐在懒惰的狗上跳跃。 真!

代码(137个字符)

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

完整的脚本

(用于xxd -r重新创建原始文件)

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

说明

  • od是标准的“八进制转储”实用程序。该-tu1选项告诉它生成单个字节的十进制转储(这是bash缺少asc(),ord()、. charCodeAt()等的充分解决方法)
  • P4 是二进制格式PBM文件的魔术数字,该文件将8个像素打包到每个字节中(相对于 P1 ASCII格式PBM文件则相反)。您将看到如何证明这一点有用。
  • 最终输出的每一行,程序最后使用,从gzip压缩的数据部分中提取一个八个像素的字节(对应于ASCII代码和行号)dd。(tail -2 $0提取脚本的最后两行;压缩的数据包括一个0x0a换行字节。)因此,单个字符的宽度为八个像素。填充支持字符之间空白的空字节很容易压缩,因为它们都是相同的。
  • 所有这些都被写入名为“ 8”的文件。因为正好有八行(每字节还有八个像素),所以字节数是输出的宽度(以像素为单位)。输出的高度也包括在其中,wc -c它的字节数后将打印输入文件名“ 8”。
  • 标题完成后,就可以打印图像数据了。Bash在执行了之前的所有内容之后,仅注意到最后两行不是有效命令(最后一个实际上是无效的UTF-8)。
  • 我仅使用KZIP来压缩数据部分,就像Ilmari Karonen所做的那样,是对“圣诞节12天”挑战的整个提交工作。如此处所述,本质上有必要使用十六进制编辑器以gzip标头替换ZIP标头格式。似乎不需要从原始ZIP标头中包含CRC-32和文件大小。

2
真的很好(又简短)的解决方案!在shell脚本中,不应将dd,tail和gzip的用法视为外部imho。
ChristopheD

1
介意添加有关其工作原理的说明?将不胜感激。
拉玛先生先生2012年

2
非常好,非常感谢您的解释。但是,使用“ P4”版本并没有真正尊重OP所说的“一种非常简单的ASCII黑白位图格式”。
俄勒冈州,2012年

5

Python 2中,248个 247字节

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)

使用3x5字体,打包成可打印的字符串,每个字符3个字节。字体清晰易读,尽管如果n在上下文中看不到,则n会是小写,而v可能会误认为au。

实际尺寸:
实际尺寸

放大x3:
放大x3

根据挑战中的示例,输出为P1型PBM。这是一个有趣的挑战。


4

Ruby 1.9,346字节(122码+ 224字节数据)

结果如下:

编码高尔夫

(很好,不是吗?)

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

字体由figlet -f banner -w 1000 $LETTERS此脚本生成

与运行 echo -n 'CODEGOLF.STACKEXCHANGE.COM!' | ruby script.rb > image.pbm

该脚本将生成所有行,然后简单地打印它们。

这是一个十六进制转储(使用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]}}*' '}

使用goruby时需要93个字节的代码:

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

使用ZLib将数据大小修剪为142个字节,而不是224个字节,但是在代码中添加了43个字节,因此为307个字节:

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

使用goruby时总计为268:

#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:

这是另一种方法。我认为“ awt”不算作外部库。

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

和无高尔夫球场:

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

机器人是Java调用getPixel的一种奇怪方式。我用字母创建一个Label,并测量每个字母的像素位置。

在paint方法,int py = (y < 3) ? y : y +1;(8*a+x+17+x/4, py+81)是复杂的方法,用于调整字体中的位置。u!否则将需要9行,并且每第4个字母在水平方向还有一个像素。反复试验使我想到了这个解决方案。

然后,将写入PBM的标题以及消息的每一行。该消息作为框架的标题传递。

而已。不是最短的代码,但是不需要手动绘制字体。

在BeanShell或Scala中,它可能更短。

现在-看起来如何?

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

应用了多个缩放: java.cafe宝贝PNG

未缩放: java.cafe宝贝JPG

字符数不是Perl解决方案中改组的字符数。

(使用了更多一点。使Robot静态化,避免了一个Exception声明。)


原始方法,做得很好!
ChristopheD

1
+1代表独创性,但请注意...如果要按比例放大位图,请使用最近邻插值。
Ilmari Karonen 2012年

我使用了eog(侏儒之眼)和一个屏幕截图。我将上传未缩放的jpg-version;也许您的浏览器使用最近邻插值:)。
用户未知

1

C ++太大赢了

我用自己的位图字体用C ++编写了功能齐全的PPM绘图程序。即使删除所有不必要的功能,由于字体的定义,与此处的答案相比,它仍然是巨大的。

无论如何,这是HELLO WORLD的输出: 在此处输入图片说明

和代码:

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

生成文件

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

如果您有兴趣,可以在这里查看完整的PPMDraw库:


1
我发现您的字体非常有用!
路德维克

1

SmileBASIC,231个字节

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

在此处输入图片说明

每个字符仅包含2种不同的行模式,这些模式是从8种组合的“调色板”中选择的。每个符号的数据存储在1个字节中,而调色板分别存储。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.