% hacks.tex % % \begin{stealth} % \pspage{page_kludge.ps} % \setlength{\textwidth}{8.1 in} % \setlength{\oddsidemargin}{-.8 in} % \end{stealth} \chapter{Including Your Own PostScript Hacks} Let's face it. This manual is nice, but let's get into the nitty gritty of the examples presented here and maybe I can show you how to do some cool stuff with LameTeX. If you have questions, we can chat in person over mail. Here goes. \section{How to Use Include Files To Do Stuff} This manual can be formatted by running either LaTeX or LameTeX on the file {\tt lametex\_doc.tex}. There are a lot of other files, but {\tt lametex\_doc.tex} includes them using the LaTeX command $\backslash$include. While reading this section on examples, you will probably want to run LameTeX over just one chapter, not all of them. If you edit the file {\tt lametex\_doc.tex} you can ``comment out'' everything you don't want. For example, if you wanted to run LameTeX over the chapter on pages, you could edit the file so that it looked like: $\backslash$documentstyle[10pt]\{report\} \\ $\backslash$setlength\{$\backslash$textwidth\}\{6 in\} \\ $\backslash$setlength\{$\backslash$textheight\}\{9 in\} \\ $\backslash$setlength\{$\backslash$topmargin\}\{0 in\} \\ $\backslash$setlength\{$\backslash$oddsidemargin\}\{0.25 in\} \\ \% $\backslash$begin\{stealth\} $\backslash$includeps\{icons.ps\} $\backslash$end\{stealth\} \\ $\backslash$begin\{document\} \\ \% $\backslash$include\{titlepage\} \\ \% $\backslash$include\{introduction\} \\ \% $\backslash$include\{starting\} \\ \% $\backslash$include\{stealth\} \\ $\backslash$include\{pages\} \\ \% $\backslash$include\{normality\} \\ \% $\backslash$include\{hacks\} \\ \% $\backslash$include\{future\} \\ \% $\backslash$include\{errors\} \\ \% $\backslash$include\{commands\} \\ $\backslash$end\{document\} \\ Notice how all the chapters, except for pages.tex, have been placed in comments using the '\%' character. This means that both LaTeX and LameTeX will ignore them. \section{White Text Hack} Look in titlepage.tex, just before where it says ``Copyright 1992''. Here is a demonstration of changing the color of the text so that it is white instead of black. This is done using the special LameTeX stealth commands $\backslash$stealth and $\backslash$postscript. All the stealth commands are located inside comments so that the normal LaTeX won't see them. So I have to start a stealth environment, because without that none of the other commands I type inside the comments will be interpreted. Then I start a postscript environment. From that point on, everything in the file gets dumped directly to the postscript output. So ``1 setgray'' gets included directly in the PostScript output file. This is the PostScript command to paint things white, not black. Naturally after the one line has been painted white, I must put the default color back to black or else my whole document will be in white! The $\backslash$stealth and $\backslash$postscript environments are special because they don't as scope delimiters for internal changes. So if you did a boldface in a Huge environment you'd expect that when the Huge environment ended, that the boldface would go away. The ``scope'' of boldface was limited to the Huge environment. $\backslash$stealth and $\backslash$postscript don't limit scope like that. Here's a trick to try out. Try placing the words ``Copyright 1992'' before the ``1 setgray'' line and the words ``Jonathan Monsarrat'' afterwards. What happens? Does ``Copyright 1992'' come out in white or black? The answer is that is comes out in white, and if you refer to the Page chapter I can show you why. LameTeX is trying to center this line on the page. To do that it needs to know how long this line is. So instead of printing out the words one at a time, LameTeX stores the words in a big list, and then prints them at the end once the line has been completed. LameTeX always does this. So in the modified version I asked you to make, first a procedure to get the correct font is put on the word list. Then ``Copyright'' is added to the word list. Then ``1992'' is added. So far, nothing has been printed. Then the ``1 setgray'' gets executed. Then ``Jonathan'' and ``Monsarrat'' get added to the word list. Finally we reach the end of the line, and when the whole line prints out, all four words are in white because of the ``1 setgray'' command. The word list, as well as having words and commands on it, can also have numbers. A number on a word list means to move over an amount horizontaly. The $\backslash$hspace command and others add in horizontal whitespace in this way. \section{The Dagger Hack} LameTeX is written for PostScript version 1 because I wanted it to work on all PostScript printers. I love PostScript but it was very awkward to work with. For one thing, PostScript 1 doesn't have very good memory management tools. If you're not careful, even a simple hack like piping a thousand words through a small program and printing them will take up a lot of memory, because each word is stored in a string, and that string is never deleted, not even when the string is printed and cannot be accessed. Fortunately, there is a workaround. LameTeX uses the PostScript commands {\tt save} and {\tt restore} to do memory cleanup. If it didn't, it would use up so much memory that your document could not print out if it were long. The {\tt save} command takes a snapshot of the current state of computer (or printer) memory and the {\tt restore} command erases the current state and returns the computer (or printer) to exactly the state it was in whe the last {\tt save} command was executed. This happens at the beginning and end of each page, as mentioned in the chapter on Pages. Now here's an interesting question for you. I have this immense picture of a dagger that I want to include in my PostScript page. I want text to flow around the dagger. What should I do? Look in {\tt stealth.tex} and {\tt page\_dagger.ps} to find the answer. If I were to place the huge Dagger routine outside of a save-restore block, then it would hang around in memory forever, even if I didn't intend to use that particular picture any more in my document. This would be unclean. What I really want to do is to insert the Dagger picture, including the definition - because the definition takes up a lot of room too as well as variables - inside the StartPage routine. The StartPage routine gets called after the save and before the restore. So whatever garbage I throw into memory drawing the dagger will neatly get erased at the end of the page. Also there is the matter of the path defined in PageShape. The dagger itself is some 200 lines of curveto commands! This is way too much curviness and way too detailed for something as macroscopic as placing text. So I have drawn an irregular polygon around the dagger. The polygon works just as well for the simple blocky task of placing text around the dagger. Plus it is a lot simpler because it is made entirely of straight lines. You can view this path by uncommenting the line where it says ``Uncomment me'' in {\tt page\_dagger.ps}. Actually the description of the dagger itself gets thrown into the In-Between Page space that is not cleaned up, because the StartPage routine is defined along with the page itself in the In-Between Page space. One way to get around this I have implemented for {\tt page\_demon.ps}. That is to have the page description just contain a small bounding box, just like the description for the dagger. The actual drawing of the fancy demon I include in normality.tex, once on each of the three pages. Why would I include the file three times? Doesn't that make my PostScript file bigger? Yes, that is certainly true. But the demon hack is immense, some 25K of raw PostScript code. I really don't want to define a PostScript routine to draw all of that. If I use the include function, the routines that draw the get demon are executed without ever being saved. So it's OK to have a very big PostScript file as long as the file is a long stream of commands. You start getting into trouble when you define procedures with long streams of commands. Unfortunately, this does indeed mean that I have to ``guess'' where to place the $\backslash$include{demon.ps} command, once for each of the three pages. \section{The Titlebar Hack} The best thing about LameTeX is that if you want to do some pretty radical stuff, LameTeX says ``OK! Let's go for it!'', whereas TeX and LaTeX would probably say ``B-B-But, why would you want to do that? That wouldn't be... (trumpet flare) {\em professional!}'' Here's a great example. On the title page there are two big hacks, /Weird-Stuff and /Title. Both of these PostScript programs take a string off of the stack and display it in an unusual way. Using these two programs is as simple as starting a stealth environment, starting a postscript environment, and then just inserting the commands! NOTE: Notice how the LameTeX title has holes in it! An omen? A sign of portent about the program itself? Also note that of course I put all of the major graphics coding into the StartPage routine, including the definitions, so that when they are no longer needed these definitions will be erased. The definitions persist between the save and restore, and since all the printed text on the page comes between the save and restore, I can still call these routines from the LameTeX document as long as I do it before the restore command associated with the EndPage. \section{Page Number Hack} This hack is the logical opposite of the dagger hack. With the dagger hack, I wanted to stuff a lot of PostScript code into the /StartPage routine, get it to draw some stuff, and then destroy it. With the page number, I want the page number to be preserved across pages. It would be a crime if I changed page number 2 to 3, and then when the restore command came along it reverted back to 2! So instead of placing this code in /StartPage, it goes in /EndPage instead. The /EndPage routine gets called {\em after} the restore from the previous page and {\em before} the save from the next page. It's in-between pages, and any variables changed here, like pagenumber, will remain around. Also the InitPage routine gets called before the first save is done for the page, so it is in-between pages also. Here's another quirk to inbetween-pages. When you're on a page, a special dictionary is used called formatdict. A dictionary is just a place to store variables in PostScript. These variables are accessed directly like normal variables when you're on a page. But in-between, you need a special way to get at the variables. One exception: InitPage does have access to the variables directly, which is how it sets formatdict variables like BM and evenodd without using dictionaries. For example, if I want the bottommargin, I can't just say ``bottommargin'' to put the bottommargin onto the stack. I have to say ``formatdict /bottommargin get'', which does the same thing. If you are a PostScript expert, you'll know what I say when I note that I do this to keep plenty of room open in the generic user dictionary. \section{The Format Dictionary} The most important variables in the format dictionary are: \begin{description} \item[baselineskip] The number of lines to skip between lines. \item[bottommargin] The margin at the bottom of the page. The LaTeX words textheight and textwidth don't mean anything to LameTeX. They get translated into left, right, top, and bottom margins on the assumption that the textheight and textwidth commands apply to a normal-sized 8.5x11 inch paper. \item[bslot] The X coordinate of the left hand side of the current line. \item[coords] A very complex representation of the page path. \item[eslot] The X coordinate of the right hand side of the current line. \item[justify] An integer, can be 102 (or 'f') for full justify, 99 (or 'c') for centered, 114 (or 'r') for flush right, or 108 (or 'l') for flush left. \item[leftmargin] The margin at the left hand side of the page. There is no distinction between evensidemargin and oddsidemargin. \item[newfontcmd] The command of the ``currently used font'', which doesn't really have to be a font command at all. \item[para] Whether the end of this line will mark a new paragraph. \item[parindent] The amount of indentation for the first line of each paragraph. \item[parskip] The amount of vertical space to skip in-between paragraphs. \item[rightmargin] The margin at the right hand side of the page. The LaTeX words textheight and textwidth don't mean anything to LameTeX. They get translated into left, right, top, and bottom margins on the assumption that the textheight and textwidth commands apply to a normal-sized 8.5x11 inch paper. \item[savetype] The currently saved state, saved by the save command. \item[topmargin] The margin at the top of the page. \item[vspace] The amount of vertical space to skip for the next paragraph. \item[welem] The number of elements in the word list. \item[wlen] The total length of all the words in the word list, including a single space between each word. \item[wlist] The word list itself. Feel free to mess around with it. Please make sure to set ``welem'', ``wlen'', and ``woids'' to appropriate values or it'll break! The correct way to add stuff to wlist is put doing an indexed get and put into the array. The maximum length of wlist is 100 elements. It's defined at the top of format.ps if you want to change it. \item[woids] The number of elements in the word list that are actually words. \item[xpos] The current X position. \item[ypos] The current Y position of this line. \end{description} \section{The Icon Hack} Notice how each page description has a different definition for LeftMarginIcon. This is because each page is a little different and "where to put icons in the left margin" varies a little. So putting the little Wizard in the text is as simple as starting a stealth environment, starting a postscript environment, and called the /LeftMarginIcon routine to display the Wizard. Notice that the LeftMarginIcon uses one (or two) formatdict variables: ypos (and maybe bpos). Because the LeftMarginIcon routine is being called from inside the page, there is no need to do a fancy dictionary lookupt to get their values. \section{Doing it Yourself in PostScript} If you want to schlep a word onto the wordlist, say ``(elephantine) NW'' which is the PostScript command that puts the word ``elephantine'' onto the word list. A space will automatically be added for you. Do {\em not} put a space in your words. Instead use two PostScript calls. For example, do {\em not} say ``(ice cream) NW''. Instead say ``(ice) NW (cream) NW''. If you have a really long sentence, then you can just say ``(ice cream) Parse''. Parse is a PostScript routine that will break a string up by spacing into ``(ice) NW (cream) NW''. If you want to schlep some horizontal whitespace onto the wordlist, you can use the LaTeX $\backslash$hspace command. If you really want to do it in postscript, then ``54.0 HSpace'' is the PostScript command to add 54 points of horizontal space to the word list. There are 72 points in an inch. Also, naturally you can gronk the value of any of the variables in the fontdict directly. Grok-p? Keep in mind that if you change them in PostScript instead of in LameTeX, then LameTeX will ``lose track'' of them and may not reset them for you. You will have to put them back to their original values yourself. \section{Using $\backslash$pscmd to Do It When You Want It} the white-painting applied to the whole line, not just parts of it. You couldn't paint just part of a line white. Well, here's how. I'm going to tell you twice. This section is the easy slick way. The next section tells you the {\em same thing}, if you want to get your hands dirty, which I encourage. Anyway, for the easy way, take a look at {\tt example5.tex}. Here I define a command /Smiley that alternately either draws a picture without changing the currentpoint, or calls READJUST. Sometimes LameTeX will be building a line made out of 10 point type when suddenly the user wants to get 30 point type. Well, since the line started on this 10 point line, all the 30 point letters are too tall and will overwrite the previous line just above the current line! There is a PostScript command that LameTeX calls automatically when such oopses occur. That's /READJUST. It takes a vertical length to skip from the stack, in points. There are 72 points in an inch. I have some command ``in'' defined somewhere that just multiplies any number by 72 to convert it into points. You can call /READJUST yourself no problem. For example, I do it here in example5.tex to make the line tall enough to accept the smiley face. Don't forget! At the end of every page, everything gets wiped by the PostScript {\tt restore} routine. Here Smiley is defined On-Page in the middle of page 1. On page 2 it would be undefined. If you want your routine to hang around for page two, you either need to define it In-Between Pages (the bad wicked way) or define it in /StartPage (the good way of lightness and being). Notice that the $\backslash$pscmd command in placed inside braces. This delimits what is now the ``Smiley'' environment. For example, if Smiley had changed the font, the font change would have remained in effect until the end-brace delimiter. The way this is implemented is really for fonts, and being able to add your own PostScript functions is not something I had envisioned at first. I will fix this later, but for the time being realize that your function Smiley, if it not delimited, will be executed at the beginning of each new line. Also, any font changes like italics or boldface will kill your Smiley environment. Try taking out the braces around the $\backslash$pscmd and you will see what I mean. I hope you can see how you could use this to include really big pictures, not just small smiley faces. You get to have complete control over how big the picture is, by passing its width and height to READJUST. Alternately, you can modify the wlist array directly if you want something special. In later versions, the READJUST command will be able to handle non-rectangular boundaries just like pages do. There is no way to do this currently unless you modify the Page on the fly by defining the ``current page'' as something new (including the box around the Smiley'' and forcing a re-assessment of the dimensions of the page. Here are the rules for a routine that you use with $\backslash$pscmd: \begin{enumerate} \item When your routine is called, the currentpoint will be set to where the next word would normally be placed. Make sure that the currentpoint is defined when your routine is finished. You can accomplish this neatly by just doing a Postscript ``gsave'' at the beginning of your routine and a ``grestore'' afterwards. \item Don't forget that you have access to the entire word list and format dictionary. \item When your routine gets called, either false or true will be on the stack. The value will be ``false'' if LameTeX is building the word list and ``true'' if LameTeX is printing the word list. You gotta either use this or pop if off the stack by making the first command in your PostScript routine be ``pop''. \item When you split up a word, like by saying {\tt Will you be my SWEET$\backslash$pscmd{/drawheart}HEART?} LameTeX will make an attempt to put Sweet and Heart all in the same word. It won't try really hard though. There is no concept of ``glue'' in LameTeX. I gotta add this sometime soon. So if a pagebreak occurs, or a line break, LameTeX will gladly put SWEET at the end of one line and HEART at the beginning of another. Oops! \end{enumerate} \section{Behind the Scenes of $\backslash$pscmd} Remember the ``Word List''? You too can schlep things onto the word list. This is exactly what the $\backslash$pscmd does, but if for some reason it doesn't work or you want to try fiddling with the PostScript code directly, it's simple. Here's how. The most interesting part is schlepping a command onto the word list. Take a look at example3.tex. To schlep a command onto the word list, I have to first register the command by placing it onto the end of the {\bf fontnames} array. From now on I just refer to this command by its number which I store in the variable FUNKYnum. The actual syntax for schlepping a command onto the world list is to say ``[ FUNKYnum false ] NewFont'', where FUNKYnum is an index to my function in the {\bf fontnames} array, and the boolean is false if I want LameTeX to add a space after this NewFont command. If the boolean is false then LameTeX puts no space between a word before the NewFont command and a word afterwards. The line ``[ temp false ] NewFont'' is important. Once I have started playing God with the LameTeX PostScript code, I should remember to put the font back to the way it was. I hope it's obvious that the routine would't have to be a Font-changing routine at all. It could be any routine. Here are some things to keep in mind though. Remember the flow chart from the chapter on pages? The routine will be executed {\em twice}, once when the word list is being compiled, and once when the word list is being printed. \section{The Wigglies Hack: using SHOWIT} I have written a PostScript hack called {\tt format.ps} that does all the major formatting for LameTeX. The command that it uses to show words is the SHOWIT routine, which is defined as follows: ``/SHOWIT\{ show \} bind def''. Feel free to redefine this routine if you want to change the way the words look in any way. The routine will be called with the currentpoint set to the appropriate place and the string to be printed on the stack. I wrote a cool hack based on this. Try it out with example4.tex. And don't forget: {\bf When you play God with LameTeX's PostScript output, be sure to put things back!} When I have finished hacking up SHOWIT with my own definition, I put it back by saying ``/SHOWIT \{ show \} bind def''. You can't do this stuff with TeX macros! (Although you could argue I suppose that only a loony would try...) \section{Forcing Word Positions with NW} NW is defined as follows: ``/NW { NextWord } bind def''. NextWord is the routine that is called repeatedly, once for each word, to place the words in the word list. Feel free to modify this routine too if you want to perform some operation to the strings before they get included in the word list. \section{The Skew Page Hack} Look in the files {\tt starting.tex} and {\tt page\_skew.ps} for an example of diagonal text. LameTeX is not really capable of placing text in any way except horizontally (unless you redefine the SHOWIT and NW routines). So therefore, in order to get diagonal text, the page must be slanted. So although it looks to the user like the text is slanted and the page is an upright rectangle, to LameTeX it appears as if the page is a very wide page in the shape of a diamond on its end. And the text appears horizontally. \section{The Checkerboard Hack} Check out {\tt example6.tex}. Here is an example of two virtual pages being placed on a single physical 8.5x11 inch piece of paper, using a variable flip to determine which virtual page comes ``next''. I hope you can see that it wouldn't be hard to define several virtual pages on a single physical page (like for making index cards or mailing labels). \section{Bugs?} There are no bugs in LameTeX. % Replace the current small margins with the wider margins. % \begin{stealth} % \setlength{\textwidth}{6 in} % \setlength{\oddsidemargin}{0.25 in} % \end{stealth}