Генерация растровых файлов PBM из текста ASCII


19

Формат PBM (Portable BitMap) - это очень простой черно-белый растровый формат ASCII.

Вот пример для буквы «J» (скопировано из ссылки в википедии):

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. Ваша программа берет одну строку из стандартного ввода (например CODEGOLF.STACKEXCHANGE.COM!)
  2. Он генерирует файл PBM с растровым (читаемым) представлением строки.
  3. Каждый персонаж построен как сетка 8x8.
  4. Вы должны поддерживать символы [AZ] (все заглавные буквы), пробел, точку ('.') И восклицательный знак ('!').
  5. Не допускаются внешние библиотеки (конечно, нет связанных с PBM)!
  6. Используемый набор символов не должен быть просто внешним по отношению к вашей программе. Часть проблемы - эффективное хранение персонажей ...

Проверка на достоверность формата PBM может быть выполнена с помощью GIMP (или других). Продемонстрируйте пример ввода и вывода!

Самое короткое решение получит баллы за ответы 2012-01-31.

Удачи в гольф!

PS: я добавил награду (в процентном отношении огромную часть моей репутации Codegolf), чтобы (надеюсь) привлечь больше конкурентов.


Под «растровым представлением» вы подразумеваете символьное представление, близкое к чему-то похожему на буквы? Как близко? Будет ли разрешено что-то вроде растрового представления двоичного кода, азбуки Брайля или Морзе?
Говард

@Howard: идея состоит в том, чтобы сгенерировать изображение pbm, которое содержит исходный входной текст в «визуализированном» (растровом), но все еще читаемом человеком виде ( lettersдругими словами). Не похоже на пример, связанный с.
ChristopheD

Я добавил тэг колмогоров-сложности, потому что основная часть программы будет составлять 30 битовых карт.
Питер Тейлор

@ Питер Тейлор: Хорошо, спасибо!
ChristopheD

Я чувствую, что у нас будут долгие и мучительные дебаты о том, что представляет собой «внешнюю библиотеку».
JB

Ответы:


9

GolfScript, 133 байта

Это основано на моем 164-байтовом решении Perl и использует тот же самый шрифт размером 4 на 5 пикселей. Опять же, сначала я приведу читаемую версию:

{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, !, ., spaceв смешных выглядящие маленькие закорючки. Замена заглушек заготовками обойдется в 2 дополнительных символа; их полное удаление будет стоить 4.

Это моя первая программа на GolfScript, поэтому я не удивлюсь, если останется место для оптимизации. Вот как это работает:

  • {91,65>"!. "+?}%:sотображает допустимые символы ввода ( A- Z, !, ., space) к номерам 0 - 28 и присваивает результат s. Любые символы вне допустимого набора сопоставляются с -1, что и приводит к появлению загогулин при печати.

  • "P4"\,8*8толкает значения «P4», в 8 раз превышающие длину ввода, и 8 в стек. При печати в конце они сформируют заголовок PBM.

  • {16base}%[3]/берет предыдущую строку данных шрифта, разбивает каждый ее байт на два куска и разбивает результат на блоки, разделенные значением 3. {:p;{[p=0]0=}s%}%затем зацикливается на этих блоках, сначала присваивая каждый блок переменной, pа затем зацикливаясь на переназначенной входной строке s, заменяя каждый символ значением соответствующего смещения в p. Забавно выглядящая конструкция [p=0]0=делает то же самое p=, за исключением того, что она возвращает 0 для любых смещений после конца p; Мне это не очень нравится, но я не смог придумать более короткий способ справиться с этим.

  • Наконец, ]n*берет все в стеке (три значения заголовка и массив данных изображения) и соединяет их вместе с символами новой строки для печати.


Серьезно коротко (по любой метрике). Ницца!
ChristopheD

12

Perl, 164 байта, без сжатия zlib / gzip

Поспав о проблеме, мне удалось найти гораздо более короткое решение, чем первое. Хитрость заключается в том, чтобы использовать небольшую лазейку в правилах: символы должны соответствовать 8 на 8 пикселей каждый, но ничто не говорит о том, что они должны заполнить все это пространство. Поэтому я нарисовал свой собственный шрифт размером 4 на 5 пикселей, что позволило мне упаковать два символа в 5 байтов.

Вывод выглядит так:

"ПРИВЕТ, МИР!" (масштабируется х 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символ заменяется двоичной строкой, состоящей из восьми строк, разделенных пробелами (четыре 14-байтовые строки и одна 13-байтовая, плюс три одиночных нулевых байта для пустых строк). Я специально разработал свой шрифт таким образом, чтобы упакованные данные не содержали пробелов, одинарных кавычек или обратной косой черты, чтобы их можно было кодировать 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) считывает одну строку ввода, разбивает ее на массив символов (удобно , минуя какие - либо символ перевода строки) и отображает буквы , Aчтобы Zи символы , !и .для символьных кодов от 0 до 28, который обычно соответствуют непечатным управляющим символам в ASCII / Unicode. (Незначительным побочным эффектом этого является то, что любые вкладки на входе печатаются как Js.) Символ пробела остается не отображенным, поскольку цикл вывода в любом случае превращает любые коды выше 28 в пробелы.

  • Вторая строка просто печатает заголовок PBM. Он использует sayфункцию Perl 5.10 , поэтому вам нужно запустить этот скрипт, perl -M5.010чтобы он работал.

  • Цикл вывода берет разделенный пробелами список упакованных строк изображения и присваивает каждой из них $pпо очереди. (Я разработал шрифт так, чтобы упакованные данные не содержали никаких пробелов или 'символов.) Затем он зацикливается на вводимых символах @a, используя vecкоманду Perl, чтобы извлечь 4-битный фрагмент, соответствующий коду сопоставленного символа, из строки изображения, дополняет его до 8-битного байта и печатает его.


Старый ответ, 268 байт:

Это быстрая и грязная первая попытка. Я украл шрифт PleaseStand и сжал его вместе с исходным кодом. Поскольку полученный скрипт в основном непечатаемый, вот hexdump; используйте, 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 байт (122 байт с использованием BIOS)

Вот файл WinXP / MSDos .COM в кодировке Base64:

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

(Используйте что-то вроде этого ), чтобы декодировать текст и сохранить как «pbm.com». Затем в командной строке введите:

pbm текст для кодирования> outputfilename.pbm

Я проверил это на своей машине WinXP, используя как стандартную командную строку, так и DosBox V0.74.

ОБНОВИТЬ

Эта версия имеет размер 190 байт и использует крошечный шрифт Ильмари Каронена (здесь нет доступа к BIOS!): -

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

Чрезвычайно хорошее решение. На данный момент это претендент на награду, которая будет присуждена примерно через 20 часов. Отлично сработано!
ChristopheD

Можете ли вы опубликовать свой ассемблерный код для этого?
Sir_Lagsalot

1
После просмотра разборки и тестирования кода выясняется, что вы просто используете растровый шрифт, предоставленный BIOS. Это может быть подтверждено тем фактом, что ваша программа может выводить строчные буквы, символы и знаки препинания, которые не требуются при вызове. Таким образом, шрифт является внешним по отношению к вашей программе и не хранится в нем (по крайней мере, на мой взгляд).
Sir_Lagsalot

@Skizz: ты можешь это подтвердить? Это все еще делает чрезвычайно приятное решение, но это немного против спецификации.
ChristopheD

1
@ChristopheD: Ну, JB прокомментировал: «Я чувствую, что у нас будут долгие и мучительные дебаты о том, что представляет собой внешнюю библиотеку». - можно утверждать, что putsв Ruby есть внешняя библиотека. Да, он использует биос шрифты, доступ к которым осуществляется через разыменование указателя (нет loadоперации, чтобы получить шрифты в ОЗУ). Возможно, слишком далеко от правил. Мне бы это сошло с рук, если бы не было этих надоедливых детей ;-)
Skizz

6

Скрипт оболочки (код + данные = 295 символов)

Я надеюсь, что tail, gzip и dd не считаются «внешними библиотеками». Запустить как echo -n 'YOUR TEXT HERE' | ./text.sh > out.pbm. Я использовал шрифт Small Fonts size 7.5, хотя мне пришлось обрезать спусковое устройство от Q.

Пример вывода

БЫСТРО КОРИЧНЕВЫЕ ЛИСЫ Прыгают над ленивыми собаками.  ДЕЙСТВИТЕЛЬНО!

Код (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 в КУСЕ (), Ord (), .charCodeAt () и т.д.)
  • P4является магическим числом для файла PBM двоичного формата, который упаковывает восемь пикселей в каждый байт (по сравнению P1с файлом PBM формата ASCII). Вы увидите, как это окажется полезным.
  • Для каждой строки конечного вывода программа извлекает восьмипиксельный байт (соответствующий коду ASCII и номеру строки) из секции сжатых gzip данных в конце использования dd. ( tail -2 $0извлекает последние две строки скрипта; сжатые данные содержат один байт перевода строки 0x0a.) Так получилось, что восемь пикселей - это ширина одного символа. Нулевые байты, которые заполняют промежутки между поддерживаемыми символами, легко сжимаются, потому что они все одинаковы.
  • Все это записывается в файл с именем «8». Поскольку ровно восемь строк (а также восемь пикселей на байт), число байтов - это ширина вывода в пикселях. Высота вывода также включена в то, что wc -cпечатает имя входного файла «8» после подсчета байтов.
  • Теперь, когда заголовок заполнен, данные изображения печатаются. Bash только замечает, что две последние строки не являются допустимыми командами (последняя на самом деле недействительная UTF-8) после того, как он выполнил все, что было до этого.
  • Я использовал KZIP только для сжатия раздела данных, как это сделал Илмари Каронен для представления на конкурс «12 дней Рождества». Как описано здесь, по существу необходимо использовать шестнадцатеричный редактор, чтобы заменить формат заголовка ZIP на заголовок gzip. Включение CRC-32 и размера файла из оригинального ZIP-заголовка кажется ненужным.

2
Действительно хорошее (и короткое) решение! В сценариях оболочки использование dd, tail и gzip не следует рассматривать как внешние imho.
ChristopheD

1
Не могли бы вы добавить объяснение того, как это работает? Буду очень признателен.
Мистер Лама

2
Очень приятно, большое спасибо за объяснение. Однако использование версии «P4» не совсем то, что OP сказал «очень простой черно-белый растровый формат ASCII ».
Эрегон

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 строчные, а v может быть ошибочно принято за au, если его не увидеть в контексте.

Фактический размер:
фактический размер

Увеличенный x3:
увеличенный х3

Выход представляет собой PBM типа P1, как в примере в задаче. Это было забавное испытание.


4

Ruby 1,9, 346 байтов (122 кода + 224 байта данных)

Вот результат:

CODEGOLF

(Это хорошо, не правда ли?)

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.

Скрипт генерирует все строки и просто печатает их.

Вот hexdump (использование 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]}}*' '}

Что дает в общей сложности 268 при использовании 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:

Здесь другой подход. Я думаю, что '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. Я создаю метку с алфавитом и измеряю, где находится пиксель для каждой буквы.

В методе рисования, int py = (y < 3) ? y : y +1;и (8*a+x+17+x/4, py+81)это сложный способ, чтобы отрегулировать положение в шрифте. Huuuh! иначе потребуется 9 строк, и на каждую 4-ю букву добавляется дополнительный пиксель по горизонтали. Метод проб и ошибок привел меня к этому решению.

Затем в заголовок PBM записывается и каждая строка сообщения. Сообщение передается как заголовок фрейма.

Вот и все. Не самый короткий код, но ручная роспись шрифтов не требовалась.

Может быть, это может быть короче в BeanShell или Scala.

А теперь - как это выглядит?

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

Применено несколько масштабов: java.cafe детка PNG

Unzoomed: java.cafe детка JPG

Не то, чтобы число символов - это число символов в перетасованном решении Perl.

(немного больше в гольфе. Робот сделан статичным, что позволяет избежать одного объявления об исключении.)


Оригинальный подход, красиво сделано!
ChristopheD

1
+1 за оригинальность, но eww ... если вы собираетесь увеличить растровое изображение, используйте интерполяцию ближайшего соседа.
Илмари Каронен

Я использовал eog(Глаз Гнома) и скриншот. Я загружу немасштабированную jpgверсию; возможно, ваш браузер использует интерполяцию ближайшего соседа :).
пользователь неизвестен

1

С ++ СЛИШКОМ БОЛЬШОЙ, ЧТОБЫ ВЫИГРАТЬ

Я написал полнофункциональную программу рисования PPM на C ++ со своим собственным растровым шрифтом. Даже если убрать все ненужные функции, он все равно огромен по сравнению с ответами здесь из-за определения шрифта.

В любом случае, вот вывод для 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");
}

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

Если вам интересно, полная библиотека 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 байте, а палитра хранится отдельно.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.