Author Topic: Basic Text Condensing in QuarkXpress  (Read 2100 times)

0 Members and 1 Guest are viewing this topic.

Offline afig

  • Newbie
  • *
  • Posts: 7
  • Karma: 3
Basic Text Condensing in QuarkXpress
« on: June 22, 2007, 02:36:57 PM »
Although the subject line says "basic", the details could be a bit confusing so please bear with me. I will list the steps I take to condense a simple template.

We will start with a 3.5" x 2" document with one text box at the same dimensions. Because the basic unit of measurement is points, I convert my values to points though I typically keep the document measurements in inches. Whatever you're comfortable with is just fine.

For our font, we will use standard Helvetica. Depending on the font face, there are times where an AFM file is unavaiable and one must either be extracted or created using Fontographer or another font editing application which can generate one (using a variety of parameters). One major obstacle is the limitations within Xdata of variable lengths. I believe it's limited to 1024 characters. This becomes a hinderance when you are dealing with a font which has kerning pairs numbering in the thousands. Don't worry about that for now.

Back on track.

We have a text box that is 3.5" or 252 points. From my experience, I've found that padding your available space by 3-4 points and then opening your box a tiny bit is a good idea. This will avoid the occasional line break where your math didn't quite turn out the way you hoped. We can set our font size at 12 point which is relatively standard for most documents.

At this point, I already have a template shell constructed which cites fields, forces the Xdata preferences, sets my variables to zero, sets my itemdelimiters and word delimiters. It looks like this:

«fields word1, word2
«--Basic Business Card
«set picturefolders to ":images:"
«--
«set fieldseparator to tab
«--
«set fieldquote to ""
«--
«set itemdelimiter to " "
«--
«set worddelimiters to "|"
«--
«set autostart to true
«--
«set ignoremissingpictures to true
«--

I then set my variables for font size and box width.

«--
«put 1200 into Wsize
«--
«put 248 into maxbox
«--
«put 100 into scaler
«--
«put 0 into linewidth
«--
«put 0 into kernwidth
«--
«put "" into holder

Note that the font size is actually a multiple of 100. Xdata only handles whole numbers so keep that in mind later on where we have to do some tricky math to keep a whole number.

I was going to go into detail about how to extract the font metric data, but I will let you decide how you want to go about converting the font metric data from it's native format to a usable format. If you open an AFM file in a text editor (I use BBEdit), you will find the two entries where character metrics are listed and kerning pair metrics are listed. See below:

StartCharMetrics 228
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ;
C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ;
C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ;
.
.
.
C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ;
EndCharMetrics

The numbers beginning with 32 (in this case) represent the ascii value of the character and the value listed after the WX is the font metric value. These two numbers are what you are interested in. Ignore any line that begins with a C -1 because the ascii value is not listed. You can fiddle with this later if you want to get more advanced. The numbers will need to be reformatted so that you end up with something like this:

«--Helvetica
«put "32 259|33 274|34 331|..." into HelveticaSet

So basically, your variable is a pipe-delimited ascii value to metric value list.

Next you want to do something similar with the kerning pairs. They look like this in the AFM file:

StartKernPairs 250

KPX A y -40
KPX A w -40
KPX A v -40
.
.
.
KPX z e -15
EndKernPairs

How inconvenient. Now you will have to convert all the literal characters to their ascii equivalent so that you end up with a named variable like this:

«--Helvetica Kerning Pairs
«put "65 67 78|65 71 80|..." into HelveticaKernSet

The bad news for you is you'll have to do the legwork. I've written a script which extracts the font metric and kerning pair metrics then reformats them into the usuable format you see above. With a little creativity, you can do the same.

So now our working prototype looks something like this:

«fields word1, word2
«--Basic Business Card
«set picturefolders to ":images:"
«--
«set fieldseparator to tab
«--
«set fieldquote to ""
«--
«set itemdelimiter to " "
«--
«set worddelimiters to "|"
«--
«set autostart to true
«--
«set ignoremissingpictures to true
«--
«put 1200 into Wsize
«--
«put 248 into maxbox
«--
«put 100 into scaler
«--
«put 0 into linewidth
«--
«put 0 into kernwidth
«--
«put "" into holder
«--Helvetica
«put "32 259|33 274|34 331|..." into HelveticaSet
«--Helvetica Kerning Pairs
«put "65 67 78|65 71 80|..." into HelveticaKernSet

At this point, I do all my logic statements and preformatting. For demonstration purposes, let's just use our existing static variable "word1". The logic I have written below is so long winded and convoluted, it doesn't really pay for me to walk you through it line by line. Let's take a look at it.

«--
«if word1≠""
«put word1 into holder
«repeat while length(holder) ≥ 1
«put HelveticaSet into HelveticaSetA
«put HelveticaKernSet into HelveticaKernSetA
«repeat until char 1 of holder ≠ "<" or loopcounter = length(holder)
«put char offset(">",holder)+1 to length(holder) of holder into holder
«put loopcounter + 1 into loopcounter
«end repeat
«repeat until chartonum(char 1 of holder) = item 1 of word 1 of HelveticaSetA
«if word 2 of HelveticaSetA=""
«exit repeat
«endif
«put word 2 to length(HelveticaSetA) of HelveticaSetA into HelveticaSetA
«end repeat
«repeat until chartonum(char 1 of holder) = item 1 of word 1 of HelveticaKernSetA
«if word 2 of HelveticaKernSetA=""
«exit repeat
«endif
«put word 2 to length(HelveticaKernSetA) of HelveticaKernSetA into HelveticaKernSetA
«end repeat
«repeat until chartonum(char 2 of holder) = item 2 of word 1 of HelveticaKernSetA
«if word 2 of HelveticaKernSetA=""
«exit repeat
«endif
«put word 2 to length(HelveticaKernSetA) of HelveticaKernSetA into HelveticaKernSetA
«end repeat
«if item 1 of word 1 of HelveticaSetA = chartonum(char 1 of holder)
«put linewidth + item 2 of word 1 of HelveticaSetA into linewidth
«endif
«if item 1 of word 1 of HelveticaKernSetA = chartonum(char 1 of holder)
«if item 2 of word 1 of HelveticaKernSetA = chartonum(char 2 of holder)
«if char 1 of item 3 of word 1 of HelveticaKernSetA = "-"
«put kernwidth + offset("-",item 3 of word 1 of HelveticaKernSetA) into kernwidth
«else
«put kernwidth - item 3 of word 1 of FontKernSetA into kernwidth
«endif
«endif
«endif
«put char 2 to length(holder) of holder into holder
«end repeat
«put (maxbox*100)/((Wsize*(linewidth-kernwidth))/100000) into scaler
«put 0 into linewidth
«put 0 into kernwidth
«put 0 into loopcounter
«put "" into holder
«endif
«--

Note the bit where I deliberately jump over Xtags. I use them all the time and will typically use highly stylized variables. The longer version of the code actually uses a table of known special character tags and their metric values to give a more accurate measurement. The important part is the formula near the end where the actual calculation takes place. Keep in mind the desire to retain whole numbers. The reason we're dealing in multiples of 100X for the font and 100X for the box width is because we often get font sizes like 8.75 and Xdata will drop any remainders when it makes a calculation. Similar adjustments would have to be made when dealing with fonts measured in the thousandths.

One other observation and potential roadblock is the H&J settings in Quark. We've noticed that these settings can throw off the calculation by a small amount. Sometimes, it's enough to return a false measurement. Lastly, small caps are a large problem. I have yet to find a source of information that tells me how to accurately estimate small cap characters. Unless the font face is native small cap, Quark is doing to styling. Through testing, I've found that there is no consistent relationship between the cap character and the small cap character across different font faces/families. Try it for yourself and you will see. Some folks say 85% of the cap character, but I've found this to be less than accurate and different character groups return different percentages. Something to think about.

The final step is to convert the math into a horizontal scale tag which we will incorporate into our variable.

«--
«if word1≠""
«if scaler ≥ 100
«put 100 into scaler
«else
«put char 1 to 2 of scaler into scaler
«endif
«if scaler = 100
«put "<h100>" into Wscale
«else if scaler ≥ 95
«put "<h95>" into Wscale
«else if scaler ≥ 90
«put "<h90>" into Wscale
«else if scaler ≥ 85
«put "<h85>" into Wscale
«else if scaler ≥ 80
«put "<h80>" into Wscale
«else if scaler ≥ 75
«put "<h75>" into Wscale
«else if scaler ≥ 70
«put "<h70>" into Wscale
«else if scaler ≥ 65
«put "<h65>" into Wscale
«else if scaler ≥ 60
«put "<h60>" into Wscale
«else if scaler ≥ 55
«put "<h55>" into Wscale
«else
«put "<h50>" into Wscale
«endif
«put 100 into scaler
«endif
«--

In this example we are going to condense up to 50% at 5% intervals. We would go ahead and output like so:

«put styled Wscale & word1»

I hope this demonstation opens some doors to the real power that can be eeked out of QuarkXpress and Xdata when using a database driven workflow. If you have any questions or comments, please feel free to post them here.

Andrew

edit 6/28: Updated kern metric calculation to be accurate. The previous sample had the values always as negatives. Now the calculation should be accurate. I also added a statement for Xpresstag & Xtag jumping to escape possible infinite loops when a faulty tag is passed ("<xxxx" with no closing ">"). There are several ways to make logic statements so if you have a better way in mind, be sure to try it out.
« Last Edit: June 28, 2007, 10:07:57 AM by afig »

Offline Emma

  • Full Member
  • ***
  • Posts: 205
  • Karma: 9
Re: Basic Text Condensing in QuarkXpress
« Reply #1 on: June 25, 2007, 03:31:41 AM »
That's a lot to take on at first reading, but it's bookmarked for experimenting with as soon as I have a quiet morning! If nothing else, it's made me realise how my XData prototypes tend to be very unadventurous, in terms of manipulating variables etc, and that I could be doing a lot more! Thanks for the very detailed post.
------------
Quark 6.5
OS X 10.4.8
G4

Offline afig

  • Newbie
  • *
  • Posts: 7
  • Karma: 3
Re: Basic Text Condensing in QuarkXpress
« Reply #2 on: June 25, 2007, 09:34:40 AM »
If you ever want to experiment, I can send you a complete prototype either zipped or in text format to tinker with.