Jump to content

CopyFit Text & Leading


step

Recommended Posts

I have a tagged string that specifies the font size and the leading. That string is in a text frame with CopyFit applied to it:

var str = '<p br=false leading="360" quad=C><span font="Helvetica" color="Magenta" pointsize=30>string</span>';
return str;

 

As I understand it, CopyFit applies a magnification factor to a line of text to allow it to shrink or expand to fit a text frame. I have my OnCopyFit rule set up to copy fit "leading" and "text" but it doesn't appear to apply the same factor to both. It looks like it tries to copy fit the text first and then the leading (if necessary).

 

Is there a way to determine the magnification factor being applied for the "text" type and apply the same magnification factor to the "leading" type (as it works with auto-leading)? Theoretically:

 

OnCopyFit

if (!Copyfit(new MagnifyAttributes("text", 5, 400, 6, 672))) { 
   ReportWarning("Could not copyfit text in flow " + FusionPro.Composition.CurrentFlow.name);
}
else {
   try { 
       var factor = FusionPro.Composition.CurrentFlow.content.match(/factor="(\d*)"/)[1];
   }
   catch (e){
       var factor = 100;
   }
   FindTextFrame(FusionPro.Composition.CurrentFlow.name).content = '<magnify factor="' + factor + '" type="leading">' + 
       FindTextFrame(FusionPro.Composition.CurrentFlow.name).content + '</magnify>';
}

 

Is there a way to make use of the OnCopyFit Callback for this? Or will I need to write a function that uses TextMeasure?

Link to comment
Share on other sites

I don't understand why you don't just use auto-leading. You're specifying 30 point text on 36 point leading, which is the default auto-leading percentage of 120 percent. So if you just remove that leading="360" from your <p> tag, and use the default "text" mode of copyfitting, I think that will do what you want.

 

If you want to use a different auto-leading factor (than the default 120%), you can adjust this in the Paragraph Globals dialog for the job. Or, in FusionPro 9, you can set the auto-leading factor for an individual paragraph in the Paragraph Formatting dialog, or with the "linespacing" attribute of the <p> tag.

Link to comment
Share on other sites

You're right, Dan. In my example I am specifying 120% of the font size and not hard-coding that all together would certainly solve my problem, but I'm really just doing that for the sake of the example. What I'm actually doing is a little more complicated than that: I have three bodies of text (a headline in 150pt, a description in 30pt, and a disclaimer in 8pt) that stacked on top of each other in a single text frame.

 

I want the spacing between the three bodies of text to be equal (rather than a 150 pt break and a 30pt break) so I wrote a function to parse the tags and adjust the leading of the first character of the 2nd and 3rd paragraph so the spacing between them would be equal. Which works great until the text needs to be copyfitted. I'm sure there's a better way to do that.

 

While we're on the subject of leading tags, if they aren't tagged in the paragraph tag, do I need to specify a "leading" in TextMeasure? Or will TextMeasure assume auto-leading and determine the leading from the "pointsize" tag if the 'isTagged' property is set to 'true'?

Link to comment
Share on other sites

You're right, Dan. In my example I am specifying 120% of the font size and not hard-coding that all together would certainly solve my problem, but I'm really just doing that for the sake of the example. What I'm actually doing is a little more complicated than that: I have three bodies of text (a headline in 150pt, a description in 30pt, and a disclaimer in 8pt) that stacked on top of each other in a single text frame.

I see.

I want the spacing between the three bodies of text to be equal (rather than a 150 pt break and a 30pt break) so I wrote a function to parse the tags and adjust the leading of the first character of the 2nd and 3rd paragraph so the spacing between them would be equal. Which works great until the text needs to be copyfitted. I'm sure there's a better way to do that.

Yes, instead of using absolute/fixed leading, the "better" way to do it is to (upgrade to FusionPro 9 and) set the "linespacing" attribute of the <p> tag to whatever multiple number of lines you need (which can be non-integral) to accomplish the equivalent auto-leading for each paragraph. Or just set this in the Paragraph Formatting dialog. Or at least, that's the way to make it work with the default copyfitting. It's a bit of math, but less than what you would need to do with some kind of custom text measurement algorithm.

While we're on the subject of leading tags, if they aren't tagged in the paragraph tag, do I need to specify a "leading" in TextMeasure? Or will TextMeasure assume auto-leading and determine the leading from the "pointsize" tag if the 'isTagged' property is set to 'true'?

If you don't specify the leading in tags, then the FusionProTextMeasure object assumes auto-leading, regardless of the value of the "isTagged" property. If you want absolute/fixed leading, then you either need to specify it in tagging (which obviously requires "isTagged" to be set to true), or you need to set the "leading" property of the FusionProTextMeasure object.

Link to comment
Share on other sites

  • 3 months later...
I have my OnCopyFit rule set up to copy fit "leading" and "text" but it doesn't appear to apply the same factor to both. It looks like it tries to copy fit the text first and then the leading (if necessary).

Well, after further investigation and reading through the builtin.js file, I think I was "telling FP to copyfit leading and text" incorrectly. I (mistakenly) set up my OnCopyfit Callback rule to look like this:

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 72)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

if (!Copyfit(new MagnifyAttributes("leading", 25, 400, 60, 720)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

There are two things wrong with that (which have become obvious to me now):

  1. Calling the Copyfit function twice seems like it would lead to copyfitting the text first and then attempting to copyfit the leading.
  2. It seems like the MagnifyAttributes object interprets the min/max limit of leading as points rather than 10th's of a point.

 

While reading through the builtins.js file, I came across this block of code:

From function Copyfit

// handle an array as the first argument
   if (arguments.length == 1 && arguments[0] instanceof Array)
       args = arguments[0];
   else
   {
       args = Array();
       for (i = 0; i < arguments.length; i++)
           args.push(arguments[i]);
   }

So that means the Copyfit function will accept multiple arguments. Modifying my code to the following applied the same magnify factor to both the leading and the text of my tagged text:

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 72),new MagnifyAttributes("leading", 25, 400, 6, 72)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

The one thing to note, I guess, is that 'magnify' tag that gets applied to a frame's content, sets a magnify factor to increase/decrease your text/leading and it also sets a max and min point size for the text/leading. So for example, if I have two lines of text in a large frame set to "fill frame," the first line is larger (60pt) and the second line is smaller (10pt):

LINE1

Line 2

The 'magnify' tags may have a factor of "400" but since the header (60pt) is pretty close to the max pointsize (72pt) it will only be magnified by 120% while line 2 keeps increasing in size.

 

While I understand the reasoning behind that, some of our clients are very specific about keeping headlines 50% larger than the disclaimer, etc. They want the text to scale proportionally basically. With that being said, I came up with some code that will copyfit a text frame proportionally. Basically, I'm variably figuring out what the upper and lower bounds of the magnification factors should be based on the font sizes used. So, I read in the content, make an array of the font sizes, find the highest and lowest values, and then figure out the upper and lower bounds based on how much they could be magnified before they reach the min/max pointsize. Making my OnCopyfit rule look like this:

// default settings
var pointsize_min = 6;
var pointsize_max = 72;
var mag_min = 25;
var mag_max = 400;

var cf = FusionPro.Composition.CurrentFlow.content;
cf = cf.replace(/<variable name="([^"]*)">/g,function(a,b){return RuleOrField(b);});

var keys = ["pointsize", "z newsize"];
var find = '(' + keys.join("|") + ')\\s?=\\s?"?\\d*';
var pointsize = cf.match(new RegExp(find, 'gi')) || [];
// Remove dups
pointsize = pointsize.filter(function(item, pos) {return pointsize.indexOf(item) == pos;});
// Make them numeric values
pointsize = pointsize.map(function(s){s = s.replace(/[^\d]/g,''); return StringToNumber(s);});
// Sort in ascending order
pointsize = pointsize.sort(function(a,b){return (a > b) ? 1 : (a < b) ? -1 : 0;});

if (pointsize.length > 1) {
   var smallest = pointsize[0];
   var largest = pointsize[pointsize.length-1];
   mag_min = Round((pointsize_min/smallest)*100,0);
   mag_max = Round((pointsize_max/largest)*100,0);
}

// If the font's already larger than max, don't allow Copyfit it to increase it
mag_max = (largest > pointsize_max) ? 100 : mag_max;
// If the font's already smaller than the min, don't allow Copyfit it to shrink it
mag_min = (smallest < pointsize_min) ? 100 : mag_min;

if (!Copyfit(new MagnifyAttributes("text", mag_min, mag_max, pointsize_min, pointsize_max),new MagnifyAttributes("leading", mag_min, mag_max, pointsize_min, pointsize_max)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

So in my example, Copyfit would now see that the largest font size in the frame is 60pt. Knowing that the max-pointsize is 72, it will set the max-magnification factor to 120 to keep the second line proportional to the first.

 

I admit, I haven't tested this very much but it seems like it should work. Maybe someone will find this helpful. If this is documented somewhere and I missed it, I'll feel pretty stupid but I swear I don't remember reading how to pass Copyfit different attributes anywhere.

Link to comment
Share on other sites

So that means the Copyfit function will accept multiple arguments. Modifying my code to the following applied the same magnify factor to both the leading and the text of my tagged text:

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 72),new MagnifyAttributes("leading", 25, 400, 6, 72)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

Yes, that's the way to apply multiple types of copyfitting at the same time. But the way that it works is complicated. I'm not sure I can explain it fully here, but basically, it modifies the magnification factors for each MagnifyAttributes object proportionally, along the range from each one's minimum and maximum factors, until either everything fits, or minimums and maximums are reached.

The 'magnify' tags may have a factor of "400" but since the header (60pt) is pretty close to the max pointsize (72pt) it will only be magnified by 120% while line 2 keeps increasing in size.

 

While I understand the reasoning behind that, some of our clients are very specific about keeping headlines 50% larger than the disclaimer, etc. They want the text to scale proportionally basically. With that being said, I came up with some code that will copyfit a text frame proportionally.

Okay, but copyfitting does work proportionally, by default, unless it hits minimums or maximums. So you shouldn't need to write any specialized copyfitting code to accomplish what you describe. All you need to do, I think, is to set the maximum point size to be large enough that both parts of the text can grow proportionally without either hitting a maximum limit. It's hard for me to know exactly what will work best for you without the job files, but if you need a larger maximum than 72 (points), then you should specify a larger maximum, say, 200?

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 200),
               new MagnifyAttributes("leading", 25, 400, 6, 200)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

Or, you can simply set the maximum to zero so that no absolute maximum is applied:

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 0),
               new MagnifyAttributes("leading", 25, 400, 6, 0)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

You can do this with the minimum as well.

Link to comment
Share on other sites

Okay, but copyfitting does work proportionally, by default, unless it hits minimums or maximums. So you shouldn't need to write any specialized copyfitting code to accomplish what you describe. All you need to do, I think, is to set the maximum point size to be large enough that both parts of the text can grow proportionally without either hitting a maximum limit.

I understand that it copyfits proportionally until it hits mins and maxes. The additional code I wrote keeps it from scaling the text out of proportion. The issue that I'm encountering is: once it hits the min/max it's no longer proportional. Increasing the size would work and enlarging the max limit is certainly an option – I'm just giving an example. I'm hesitant to say that specifying the max/min of both the magnification factor and the pointsize seems like too many moving pieces because I'm sure that without the option, I'd want it, but right now, I can't understand why I wouldn't just specify the max/min pointsize and let the function determine the rest. I can't imagine a scenario where I'd say "okay, this can only get 25% smaller" as opposed to saying "okay, this font can't be smaller than 6pt." Anyway, I guess what I was trying to point out is: by default, you can't set the max and min pointsizes and expect the text to remain scaled proportionally should one of those limits be reached.

Or, you can simply set the maximum to zero so that no absolute maximum is applied:

if (!Copyfit(new MagnifyAttributes("text", 25, 400, 6, 0),
               new MagnifyAttributes("leading", 25, 400, 6, 0)))
   ReportWarning("Could not copyfit text in flow " + 
                 FusionPro.Composition.CurrentFlow.name);

You can do this with the minimum as well.

I'm not really sure that's accurate. This block of code suggests that it tries to "rationalize" the parameters so that if the min is larger than the max it switches them:

MagnifyAttributes.prototype.rationalize = function() {
   var i;

   if (this.min > this.max) {
       i = this.max;
       this.max = this.min;
       this.min = i;
   }

   if (this.factormin > this.factormax) {
       i = this.factormax;
       this.factormax = this.factormin;
       this.factormin = i;
   }
}

So in the code you posted, the text would never increase past 6pt font.

 

Ultimately, I guess copyfitting text in general is a hairy subject with a lot of "what if" scenarios and while I feel confident that the built in functionality is adequate in most situations, I just wanted to follow up on my original question and throw this make-shift solution out there in case someone else needed this functionality. If nothing else, you can look at this as an Evernote for Future-Ste. Because I know he's pretty forgetful.

Link to comment
Share on other sites

I can't understand why I wouldn't just specify the max/min pointsize and let the function determine the rest. I can't imagine a scenario where I'd say "okay, this can only get 25% smaller" as opposed to saying "okay, this font can't be smaller than 6pt."

This is actually a very common requirement, to be able to scale a bunch of text proportionally, but to also limit the absolute minimum size.

 

Also, we intentionally left the API as flexible as possible, because users, and their clients, often come up with requirements that even we can't always imagine or anticipate. (Although, such flexibility also creates a big challenge for QA testing, as the number of possible copyfitting scenarios and combinations of various magnification settings, with various kinds of text, is astronomical. And copyfitting is just one dusty little corner of the entirety of functionality in FusionPro and its seemingly endless number of features and combinations of interactions between them.)

Anyway, I guess what I was trying to point out is: by default, you can't set the max and min pointsizes and expect the text to remain scaled proportionally should one of those limits be reached.

 

I'm not really sure that's accurate. This block of code suggests that it tries to "rationalize" the parameters so that if the min is larger than the max it switches them:

MagnifyAttributes.prototype.rationalize = function() {
   var i;

   if (this.min > this.max) {
       i = this.max;
       this.max = this.min;
       this.min = i;
   }

   if (this.factormin > this.factormax) {
       i = this.factormax;
       this.factormax = this.factormin;
       this.factormin = i;
   }
}

So in the code you posted, the text would never increase past 6pt font.

Well, in the magnify tags that ultimately get generated by Copyfit, a min or max attribute of zero (or less than zero) means "no minimum/maximum." But you're right, the code there doesn't seem to account for that. However, you can always set the minimum to 1 and/or the maximum to say, 10,000, which is effectively the same thing as no min or max.

Ultimately, I guess copyfitting text in general is a hairy subject with a lot of "what if" scenarios and while I feel confident that the built in functionality is adequate in most situations, I just wanted to follow up on my original question and throw this make-shift solution out there in case someone else needed this functionality. If nothing else, you can look at this as an Evernote for Future-Ste. Because I know he's pretty forgetful.

Yes, there are practically an infinite number of possible scenarios. But I do appreciate you posting your solution. And I appreciate all the other contributions you've been making here on the forum. You've been killing it this week!

Link to comment
Share on other sites

Also, we intentionally left the API as flexible as possible, because users, and their clients, often come up with requirements that even we can't always imagine or anticipate.

Yeah I figured that was the case and while it seems like I'm griping about it now (I'm really not – I promise), the moment the mag options went missing I'd encounter a scenario that I'd need it.

 

Although, such flexibility also creates a big challenge for QA testing, as the number of possible copyfitting scenarios and combinations of various magnification settings, with various kinds of text, is astronomical. And copyfitting is just one dusty little corner of the entirety of functionality in FusionPro and its seemingly endless number of features and combinations of interactions between them.

That description is better than "hairy subject" but I can definitely empathize with you there.

 

Well, in the magnify tags that ultimately get generated by Copyfit, a min or max attribute of zero (or less than zero) means "no minimum/maximum."

Oh I see. That makes sense.

 

Yes, there are practically an infinite number of possible scenarios. But I do appreciate you posting your solution. And I appreciate all the other contributions you've been making here on the forum. You've been killing it this week!

Thanks! But in all honesty, I just like to post 20 lines of code to see your reply of how to do it in 5. Thanks for sharing your knowledge with the rest of the community!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...