geekkoo - Окаменелости в LaTeX [entries|archive|friends|userinfo]
geekkoo

[ userinfo | ljr userinfo ]
[ archive | journal archive ]

Окаменелости в LaTeX [Nov. 25th, 2008|12:28 pm]
Previous Entry Add to Memories Tell A Friend Next Entry
У латеха (и вообще всех систем основанных на TeX-е) есть одна серьезная баго-фича, из-за которой его сложно использовать где-либо вне его ниши любительской полуавтоматической верстки. У него минимальный квант текста, с которым он оперирует - это параграф. Соответственно и вавод материала у него идет по-параграфам. Неясно, почему Кнут решил использовать именно такой алгоритм, может это как-то связано с аппаратурными ограничениями 80-х годов, но с тех пор об эту проблему спотыкаются все, кто пытается пропатчить output-routine. А таких уже набралось изрядное количество - Arthur Ogawa (автор revtex4 - лучшего класса для верстки научного текста), Nicola Talbott (автор flowfram - стилевого файла для постеров и брошюр) и авторов multicol (который совершенно дурацкий, поскольку там floats не работают).

Эта проблема возникает, когда нужно перейти со страницы (или колонки, врезки) одной ширины на другую с другой шириной. Дело в том, что латех сначала верстает параграф целиком, а потом только его печатает. Если при печати он натыкается на конец страницы, то действует он по-простому - отрезает лишнюю часть параграфа и просто переклеивает его на следующую. При этом, что другая страница имеет другую ширину его нисколько не заботит, эти изменения будут учтены только при вёрстке следующего параграфа.

И не нужно считать, что это важно только при вёрстке рекламных журнальчиков. На самом деле есть контрпример - Фейнмановские лекции по физике. Там каждая глава начиналась со страницы, где внешнее поле было более широким, чем на следующих, и туда вставлялось мини-оглавление с перечислением параграфов в этой главе. Как раз в латехе этот переход с первой странице на вторую автоматическом режиме проделать невозможно.

В качестве workaround можно пользоваться /parshape - высчитываете количество строк в последнем параграфе и перечисляете с какой строки нужно перейти на новую ширину. Понятно, что всё это делается вручную и при любой смене дизайна это придётся переделывать заново.

Если бы можно было переделать output-routine, чтобы вёрстка была многопроходной - один раз сверстал, вывел, наткнулся на конец страницы, откатился назад, вставил нужный /parshape и сверстал снова, и так пока весь параграф кончится. Но, по-моему, это как раз невозможно - 80-е годы, никуда не денешься.
LinkLeave a comment

Comments:
From:(Anonymous)
Date:November 25th, 2008 - 11:40 pm
(Link)
Привет из 80-х:

\danger \TeX\ breaks lists of lines into pages by computing badness ratings
and penalties, more or less as it does when breaking paragraphs into lines.
But pages are made up one at a time and removed from \TeX's memory; there is
no looking ahead to see how one page break will affect the next one.
In other words, \TeX\ uses a special method to find the optimum
breakpoints for the lines in an entire paragraph, but it doesn't attempt
to find the optimum breakpoints for the pages in an entire document. The
computer doesn't have enough high-speed memory capacity to remember the
contents of several pages, so \TeX\ simply chooses each page break as best
it can, by a process of ``local'' rather than ``global'' optimization.


Knuth The TexBook
[User Picture]
From:[info]geekkoo
Date:November 26th, 2008 - 08:35 am
(Link)
Да, про книжные страницы, не помещающиеся в память компьютера, сейчас читать смешно. Но проблема с отсутствием стека (списка) с отпечатанными страницами не должна (по идее) мешать обработке первого pagebreak-a. Т.е. первый разрыв откатить ещё можно, поскольку страница всё ещё сидит в памяти, и исправить parshape, а вот если на том же параграфе попадётся второй разрыв (страницы, колонки, flow-frame), то отработать его будет уже нельзя, поскольку начало параграфа к этому моменту будет уже выкинуто из памяти. Но этот случай покрывает от силы 10% случаев.

Ну, и потом. После того как Кнут заморозил свой TeX, появилось же много вариантов - etex, omega ... Неужели нигде это ограничение на "не больше одной страницы в памяти" не выбросили?
From:(Anonymous)
Date:November 26th, 2008 - 12:49 pm
(Link)
Не тупи.

Даже первый pagebreak ты не откатишь. TeX верстает сначала в horizontal, а потом в vertical моде. Когда он отрабатывает pagebreak он уже сидит в vertical моде, поэтому оптимизировать позицию этого брейка он может только варьируя количество vertical glue (расстоянием между параграфами и строками), а не изменением ширины пробела между словами в строке. То есть ты можешь послать output routine выставив ему неприемлемый penalty, что заставит его пересматривать vertical glue, но у тебя нет возможности послать его настолько далеко, чтобы он начал перекладывать весь параграф.

Глянь на lineno пакет. У них задача даже проще - выставить на полях номер строки начиная с верхней на странице. Для этого даже верстку пересматривать не надо, просто приписать сбоку циферки - и то им приходится срать в aux-файл инфой о том, на какой строке у них обрыв страницы случился.

А у тебя задача даже сложнее - для lineno двух проходов хватит, а тебя после отработки первого брейка со сменой ширины, нужно будет пересматривать верстку всех последующих страниц.

Так что, если рыть - то рыть в направлении внешнего скрипта с вызовами tex-а в цикле и grep-аньем aux-файла плюс патча на output, который бы плевал в auх номер строки в параграфе на разрыве странице, выставлением нужного parshape, чтобы это дело объехать, и прогоном latex-а столько раз сколько потребуется, до тех пор, пока он не перестанет плеваться.
From:(Anonymous)
Date:December 1st, 2008 - 03:25 pm
(Link)
При чём тут страницы? Насколько я помню, речь идёт о том, что, в отличие от абзаца, читать в память _всю_книгу_ и искать наилучшее в целом разбиение на страницы нереально!
Что жке касаемо откатов, то не берусь сказать совсем уж конкретно, но скопировать материал (он же, помнится, в каком-то боксе), отрезать страницу, проверить качество (вот тут главная проблема) и послать нафиг, восстановив вертикальный материал есть вполне описуемо. Да и двухпроходность, если уж очень приспичит -- запомнить токены, разобрать, посмотреть, что получилось -- тоже в принципе возможно...