Showcase and discover digital art at yex

Follow Design Stacks

Subscribe to our free newsletter to get all our latest tutorials and articles delivered directly to your inbox!

PageMaker Scripting FAQ – Moving to Advanced Scripting

A. What’s new with scripting in PageMaker 6.5?

PageMaker 6.5 has a completely new scripting engine that is world’s ahead of previous versions. Here are a few of the new features of 6.5’s scripting language:

  • queries (ask PageMaker questions)
  • variables (allow the temporary storage of information)
  • control loops (repeat until a condition is met)
  • conditionals (if a condition exists do something)
  • dialog boxes (facilitates user input)
  • subroutines (facilitates scripting by allowing the scripter to reuse sections of code)

These are the primary new features to the language, but there are others based upon PageMaker 6.5’s new capabilities (such as layers and frames).

Most important of the new features are queries. These allow to get information from PageMaker about its environment, the current document, the page, etc. Queries contain a query command followed by a pointer to a variable. For example:

GetFontList >> myFonts

This command would ask PageMaker for a list of all the installed fonts on the user’s computer and put the results into the variable “myFonts”. To actually see what’s inside the variable requires a bit more work. Because the format of the results of a query vary depending both upon the command and the kind of information being returned, it is imperative that the scriptwriter knows what to expect. In the above example the scriptwriter has no idea how many fonts are installed on the system. One, ten, 100, or a 1000 fonts may be installed. Therefore PageMaker stores the results of the query as part of a list.

A list is a series of data separated by a delimiter such as a comma or space. Since you know what delimiter is being used to separate the elements of a particular list, you can grab out the individual elements at will. For example the script:

GetFontList >> myFonts
message "The first font is " + myFonts(2)

would display a dialog box listing the name of the first font in the fontlist. This works because the GetFontList query returns information in the following order:

GetFontList >> nNumOfFonts, (sFontName, nFontID, 
bInstalled, bUsedInPub)

The first item in the list nNumOfFonts is the total number of fonts in the list. This is vital information if you want to search through the list of fonts–otherwise, how would you know when you’d finished the list?

You may notice that the second through fifth items in the response are grouped with a parenthesis. This is because these four items repeat for every font in the list. In other words, if there are 10 fonts installed on your computer, the list PageMaker returns would be 41 items long (4 times 10 fonts plus one for the number of fonts). If you wanted to grab particular font (say the sixth), you could say:

GetFontList >> myFonts
x = 6
message "Font " + x + " is " + myFonts(2+((x-1)*4))

This looks complicated, but the math is really simple. (Trust me: math is not my strong suit.) The formula works because if x=0, 0 times 4 plus 2 is 2, which is the position of the font name in the list. If x is 2, 2 times 4 plus 2 is ten, which again is the font name position. Look at the following chart. Items in the second column–beginning with “02”–are the index numbers to the font name.

01  02  03  04  05
06 07 08 09
10 11 12 13
14 15 16 17
18 19 20 21
22 23 24 25

The point of this is not to bore you with simple mathematics but to make sure you understand an important part of how PageMaker returns information to you. If you don’t understand how queries return information, you will be at a severe disadvantage scripting PageMaker.

Let’s look at that GetFontList query again:

GetFontList >> nNumOfFonts, (sFontName, nFontID,
bInstalled, bUsedInPub)

The form I’m using above follows Adobe’s conventions in that parameters are indicated by type–note the first letter of each name. The following table shows the types of data PageMaker can return (or expect to receive as part of a command):

(true/false or on/off)
Choice (list of unique choices) c
(fractional number)
Filename f
Number n
(series of characters)
(decimal number indicating vertical or horizontal position)
x (horizontal)
y (vertical)

Knowing the type of parameter PageMaker expects helps you remember which parameters do what. For example, knowing that “b” represents a boolean value should tell you that the “bInstalled” value shown above will be either a true or false value (or a 1 or 0 in computer binary thinking).

If you have programmed in another computer language such as BASIC, you may be familiar with control loops. If so you will be glad to know that PageMaker 6.5’s improved scripting language has all sorts of control loops.

Normally a computer program (or script) works in a linear fashion. That is, it starts on line 1 and proceeds through to the last line. This structure is useful for simple scripts, but more powerful programs need branches–that is, they need to make decisions and perform different functions depending upon the results of external factors. Control loops and conditionals work together to give your program a logical structure.

Let’s say you want to do something with that list of fonts we retrieved above. Perhaps you want to check to see if a particular font is installed. Logically, your program would have the following structure:

  1. Get a list of all the fonts.
  2. Start a loop from 1 to the total number of fonts.
  3. Does font match?
    If so, display message.
  4. If loop isn’t finished, increment it and go back to step 3.

What does this program look like? How about the following:

GetFontList >> totalFonts, myFonts 
loop x=1, totalFonts
if myFonts(x*4-3) = "Palatino"
message "Yes, " + myFonts(x*4-3) + " is installed!"

Wondering how the program works? Here’s what it does. The first line is somewhat familiar to us: we are storing the results of the font query into two variables. The first variable contains the total number of fonts, the second the balance of the font information. Separating the info into two variables makes it easier to extract the data we need.

The second line starts the loop which we set to count from 1 to the value of totalFonts. We create a variable called “x” which initially is set to 1 and each time through the loop it will increment by one. (Since we’ve told the loop to count up to totalFonts, we know it won’t go beyond that.)

The next line checks, one by one, to see if each font matches “Palatino” exactly. (Note that the math formula I’m using is different than the one I used earlier–can you see how it works?)

If the font matches, we put up a message saying that the font was found. If not, the script simply moves on, doing nothing special. When the script hits the last line, the “endloop” command, it does two things: it adds one to “x” and sends control of the script back to just after the “loop” command. We don’t need to explicitly check to see if x is greater than totalFonts because the loop command handles that for us.

Notice how I have indented various lines of the script? Indenting has no effect on how a script operates, but makes it much easier to read. See how everything between the outer loop commands is indented? The same is true for the stuff in between the “if” and “endif” commands. Indenting shows the control structure of your program. I highly recommend you indent your scripts–it makes finding problems much easier.

In these examples I’ve been using one of the new PageMaker features–the message dialog box. But PageMaker can create much more complicated dialog boxes containing elements like buttons, scrolling lists, radio buttons, checkboxes, and editable text fields. This makes interacting with the user much easier.

For example, you could ask the user a question and depending on the response, do something different.

dialogbegin -150, -50, 150, 50, "Choices"
pushbutton 220, 65, 280, 85, "Yes"

pushbutton 145, 65, 205, 85, "No"
static 15, 15, 285, 55, "Do you want to win the lottery?"
dialogend >> result

if result(1)="Yes"
message "Sorry, you didn't win."
message "Yeah, like I believe you."

The first part of the “dialogbegin” command is the size of dialog in pixels (screen dots) and the name of the dialog. The first two coordinates of the size indicate the upper-left corner of the box, the last two numbers the bottom-right corner. The other lines define the kind, position, and value of each element. PageMaker supports the following kinds of dialog elements:

(clickable button that closes dialog box)
pushbutton x1, y1, x2, y2, value
Text (any text you want to display, such as instructions or description) static x1, y1, x2, y2, value
Edit Text
(blank field where user can type in anything)
edit x1, y1, x2, y2, value
(a choice with an on/off value)
checkbox x1, y1, x2, y2, value, status
Radio Button (series of choices where only one is selectable at a time) radiobutton x1, y1, x2, y2, value, status
Scrolling List
(scrollable list of items–user can chose one)
listbox x1, y1, x2, y2, empty, value
(draws an empty box)
rect x1, y1, x2, y2, empty

In the above table, “value” represents the name of the elements, “status” whether the item is on or off, and “empty” stands for a null value that is reserved for future use by PageMaker’s developers. Whatever you put there is ignored. The “x1, y1, x2, y2” coordinates define both the position and size of the element by indicating the upper-left and bottom-right corners.

Once the user is finished with your dialog box, the results are put into a variable. If you have several items in the dialog, such as checkboxes, you can easily check the state of each one by parsing the list returned. The first item is always the name of the button clicked (in this case either “Yes” or “No”) and the rest follow in the order they were created. (The second item created is the third item in the list.)

One bad thing about dialog boxes is that because of display differences between the PC and the Mac, dialogs that work on one system may not look correct on the other. You should test your scripts on the other platform if you can. Ideally you would use PageMaker’s “getPlatform” query to see which computer the script is running on and create the dialog box appropriate for that system. (Sure, it means designing two dialog boxes, but that’s the price of compatibility.)

Currently creating dialog boxes isn’t much fun–the coordinates are confusing and there’s nothing visual until you run the script in PageMaker to see the result. Hopefully someone will create a tool to make the process easier.

B. What can’t I script with PageMaker 6.5?

While PageMaker 6.5’s language is much more powerful than previous version, it still isn’t perfect. There are a few limitations to scripting to keep in mind. Some of these you can overcome with external scripting.

Chief among PageMaker’s limitations is the lack of control over files and folders. It would be nice to be able to use scripting to do batch processing, for instance. Currently this is possible by “hardcoding” filenames into a script, but PageMaker does not make it easy to select a bunch of files. PageMaker also does not give you easy ways to create or open text documents–you have to use the “log” feature or export text from a PageMaker document. These are mostly minor inconveniences, however.

PageMaker scripting also does not let you control plug-ins (formerly Additions) and certain menu commands (like “Export to HTML”). (This is a bummer because if there ever was a command that needed help, it is the “Export to HTML” command.) Strangely, you cannot script indexing, something that seems ideal for scripting.

One thing I’d like to see in future versions of the PageMaker scripting language is the ability to save the contents of variables in between script launches. Both AppleScript and One Click have methods for storing values permanently–great for being able to reuse information gathered in a previous script run.

(For example, I’d like to write some PageMaker scripts that would function as “copy” and “paste” attributes commands. I can do this in One Click because it can remember the selected attributes permanently. In PageMaker I can write a script that can retrieve the attributes of the selected object, but I have no way to save that info for use by a “paste” script.)

There is a way of doing this by having the script write and read a log file that is in effect another script.

You can Include the script, which to start with would have just the word “return” in it and therefore do nothing.

Then the script will write the variables you need to keep into this file with the log commands.

Next time the script starts, it will Include the subsidiary script which now has the variables recorded from the previous time.

I use this method to set up default items such as file names or folders in a dialog box. When the user changes the items, these are written to the log file script to be read in next time, thus becoming the new default.

Most of the other limitations of scripting PageMaker have to do more with limitations of PageMaker itself. For example, you cannot have PageMaker create auto-updating character styles. You also can’t create an auto-updating time/date stamp (though potentially you could create one that would update whenever you run a particular script).

C. How about some real scripts?

Enough of the useless examples. Here are some real scripts that you might find useful. The first script is one called QuickCrops and it draws crop marks around whatever object or set of objects you have selected. It does this intelligently, too, saving your current line and color values and drawing the crops as “Registration” color and hairlines. It restores all changed settings back to your original values at the end of the script. The code is commented and demonstrates many features of PageMaker 6.5 scripting, including the use of subroutines.

IMPORTANT NOTE: Some of these lines were too long for proper display within this HTML document, so I’ve shorted and indented them. These lines are marked with an exclamation point (“!”). So a line written like this:

  gosub drawCorners selectItems(1),
!selectItems(2), selectItems(3),

really should be all on one line. Delete the “!” marks.

-- QuickCrops v1.0
-- Monday, March 31, 1997 10:02:15 AM
-- This PageMaker script draws crop
-- marks around your selection
-- Copyright 1997 by Marc Zeedar

-- With mucho thanks to
-- David Van Wagner for assistance
-- with the original AppleScript
-- version

-- Check for pubstate
-- (if wrong, forget script)
getPMState >> pmState

if pmState=4
-- change these values if you'd
-- like different size crops
theCropSize = .25
theOffset = .125

-- Setup PageMaker
getMeasureUnits >> oldMeasure
measureUnits inches,inches
getSelectList >> pageItems
getSelectInfo >> selectItems
redraw off
getfillandline >> oldLine
getcolor >> oldColor
linestyle 1,0
color "Registration"

gosub drawCorners selectItems(1), selectItems(2),
!selectItems(3), selectItems(4)

-- Reset PageMaker
fillandline oldLine
color oldColor
measureunits oldMeasure
redraw on

message "ERROR!"
message "You must have something "
message "selected for this script"
message "to draw crop marks around."

-- Subroutines

sub drawLine
getargs >> x1, y1, x2, y2
line x1, y1, x2, y2

sub horzTick
getargs >> xH, yH, hH
xT1 = (xH+hH*(theCropSize+theOffset))
xT2 = (xH+(hH*theOffset))
gosub drawLine xT1, yH, xT2, yH

sub vertTick
getargs >> xV, yV, vV
yT1 = (yV+vV*(theCropSize+theOffset))
yT2 = (yV+(vV*theOffset))
gosub drawLine xV, yT1, xV, yT2

sub cornerTick
getargs >> x, y, h, v
gosub horzTick x, y, h
gosub vertTick x, y, v

sub drawCorners
getargs >> aLeft, aTop, aRight, aBottom
gosub cornerTick aLeft, aTop, -1, -1
gosub cornerTick aLeft, aBottom, -1, 1
gosub cornerTick aRight, aBottom, 1, 1
gosub cornerTick aRight, aTop, 1, -1

--end of script

This next script shows you a dialog box with two scrolling text fields of all the colors defined in the document. You select the old color on the left and the replacement color from the right. When you click “OK” the script will go through the entire publication and replace old color with new color.

-- Replace Colors v1.0
-- Wednesday, July 16, 1997 9:46:19 AM
-- This PageMaker script finds and replaces
-- colors in the current publication

-- Check for pubstate (if wrong,forget script)
getPMState >> pmState

if (pmState=1)+(pmState=6)+(pmState=7)+(pmState=8)
message "ERROR!"
message "You must have a publication open"
message "or be in layout mode"
message "for this script to work."
getColorNames >> numColors,"...","...", colorList

dialogbegin -194,-115,194,115, Replace Colors
pushbutton 321,200,381,220,"OK"
pushbutton 250,200,310,220,"Cancel"
static 6,6,108,27,"Original Color"
static 200,6,337,28,"Replacement Color"
listbox 6,31,186,191,"...",colorList
listbox 200,31,380,191,"...",colorList
dialogend >> theButton,theResult

if theButton="OK"
oldColor = theResult(5)
newColor = theResult(6)
if (oldColor=newColor)+empty(oldColor)+empty(newColor)
-- do nothing
redraw off
suppressPalDraw colorpalette,true
suppressPalDraw controlpalette,true
getPages >> totalPages
getPageNumber >> originalPage,masterPage
loop z=1,totalPages
page z
getObjectList >> numObjects,objectList
loop obj=1,numObjects
select objectList(obj*6-5)
theObject = objectList(obj*6-4)
-- line,box,oval,or polygon
if (theObject=3)+(theObject=4)+(theObject=5)+(theObject=12)
gosub fillandlineColor
if (theObject=6)+(theObject=8)+(theObject=9)+(theObject=11)
gosub bitmapColor

loop z=1,totalPages
page z
getObjectList >> numObjects,objectList
loop obj=1,numObjects
select objectList(obj*6-5)
theObject = objectList(obj*6-4)

-- text block
if (theObject=1)
gosub textBlock
if (theObject=1)

page originalPage
redraw on
suppressPalDraw colorpalette,false
suppressPalDraw controlpalette,false
tool pointer


-- Subroutines

sub fillandlineColor
getFillAndLine >> a,fillColor,c,d,e,f,g,lineColor,h,i,j
if lineColor=oldColor
FillAndLine a,"dontcare",c,d,e,f,g,newColor,h,i,j
if fillColor=oldColor
FillAndLine a,newColor,c,d,e,f,g,"dontcare",h,i,j

sub bitmapColor
getColor >> theColor,tintValue
if theColor=oldColor
color newColor,tintValue

sub textBlock
findTypeAttr2 any,any,oldColor,any
changeTypeAttr2 any,any,newColor,any
try changeAll "","",allstories,0,0,useattributes
closestory discard
closestory discard
getPMState >> pmState
if (pmState=6)+(pmState=7)+(pmState=8)

--end of script

D. How do I link my database to PageMaker?

This is a common question and would be great to answer here, but I won’t. I can’t. There are too many variables involved. Everyone is using different database programs, different types of data, and has a different layout. I will discuss some of the problems involved with database publishing, and how you can go about creating your own automated publishing system.

There are two basic approaches to database publishing. One is to create scripts that bring the data into a PageMaker document and format it. The other is to export the data preformatted and ready to place manually using PageMaker’s tagged text import filter.

For a great description of this latter appraoch, see Olav Martin Kvern’s terrific article “Beyond the Phone Book” in the July/August 1996 issue of Adobe Magazine. He shows, step-by-step, how to do this with Claris’ FileMaker Pro database program. (The concept is simple: set up the database so that the exported data is framed with the appropriate PageMaker tags. This is similar to a database exporting info framed with HTML tags.)

The other approach, pure scripting, is so open as to give us a bewildering array of choices. There are two main problems we need to solve. One, exporting the data from the database in a format we can use, and two, figuring out how to explain to PageMaker where that data is located and how to position it in the layout.

Because PageMaker’s scripting language is limited in terms of its access to the file structure of a computer system, it is possible that external scripting must be used. Depending on the database, it may be able to control PageMaker.

If your project is highly repetitive, one possibility is to “hard code” the locations of your data. For example, let’s say you’ve got a 2-page flyer you produce regularly. It always follows the same format — a large cover photo and article, with 4 smaller pictures on the back (it could be a real estate flyer). You could write a script that would contain the location of the cover photo like this:

set cphoto = "Hard Drive:Flyer:Photo1.TIFF"

The script uses that information to tell PageMaker to import, place, and size the cover picture. The other pictures and text documents can be done the same way.

But since the location is stored as part of the script, if you move the photo or change it’s name, the script won’t work. The script is also inflexible as to the number of photos — it will only work with a single cover photo and 4 small pictures on the back. But you could write several scripts — one for each kind of flyer you make — and then flyers will build themselves!

A better approach, though more complicated, is to create your own “instruction document” for your generic script. Your script would read the instruction document and process the items listed. For example, let’s say you decide your instruction document will deal with two types of files: TIFF photos and text files. Your script needs to place these in the appropriate places. Your instruction document could resemble the following:

3 -- (number of items) 
PHOTO -- (a photo item is next)
"HD:Photos:photo10.tiff",10,85,3.5,2 -- (path, page, percent, x, y)
TEXT -- (a text item follows)
"HD:Text:long.text",5 -- (path, page)
PHOTO -- (a photo item is next)
"HD:Photos:photo11.tiff",11,110,7,4 -- (path, page, percent, x, y)

Your generic script would open and process the instruction file, reading it line by line. The first line would tell it the total number of items it needs to process. After reading the next line it would check the first word to see if it was “PHOTO” or “TEXT” and it would adjust how the next line is read to accommodate for the change in the number of parameters (photo items have 5 while text only have 2).

Depending on your task, you might not need all of the parameters I’ve included in my example. For instance, if you planned to always place your pictures at 100%, there’d be no need to include a percent parameter. On the other hand, you might need more parameters than I’ve outlined here — your script would have to be written to support those. Just remember that while more parameters give you more flexibility, they also make creating your “instruction document” more complex, and of course your script must process more information.

In the above example I’ve included x and y coordinate parameters for the photo item. Obviously, trying to decide in advance exactly where each photo should be placed is difficult. A better approach would be to position the photo onto the existing grid of your layout. Depending on your layout, you could tell the script to put the photo in a specific “quadrant”, or perhaps tell it to span a certain number of column guides. (The script would take care of making sure the photo was proportionally reduced or enlarged to fit.)

This would allow you to sketch out a rough design of your project, planning picture and text positions according to your grid. Your “instruction document” would specify the quadrant or layout position (such as “1” or “C”) and the script would make sure it was put into the correct place (see Figure 02 below).

faqfig02 picture

Obviously setting up such a structured publishing environment would not be easy. Writing and testing the script would be time consuming, and might even take more time than laying out the document by hand. A scripting solution also limits your design creativity, which some designers may find intolerable. (But remember, since scripting creates standard PageMaker documents, they are easy to change.)

On the other hand, if your project is large or repetitive, automation might save you a bundle of time.

The possibilities of automated database publishing are exciting. In the future, as deadline shorten and customers want information faster and faster, it is going to be the main method of generating layouts. PageMaker, with its flexible scripting language, provides a wonderful method of creating automated documents for both web and press.