freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Devel] pixel size, hinting and scaling


From: David Turner
Subject: Re: [Devel] pixel size, hinting and scaling
Date: Fri, 17 Jan 2003 12:35:12 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2a) Gecko/20020910

Hello Graham,

Graham Asher wrote:
David,

thanks for your interesting explanation of the transformations used by
FreeType, which mostly confirms what I thought. I was right, I think, in
saying that there was a defect, or perhaps what I could more kindly describe
as a small design flaw.

You say that the correct thing to do is use FT_Set_Pixel_Sizes to do all the
scaling, and FT_Set_Transform to do shearing and rotation, but no scaling.
This is what I'd already figured out. The design flaw is that
FT_Set_Transform doesn't enforce the condition that its transformation does
no scaling. It should either do this, or extract the scale factors, combine
them with the current scale, and reset the size by calling
FT_Set_Pixel_Sizes before applying the rotation and shear only. But this is
a minor problem if the facts are all understood: that is, if we know that
the transform should not do any scaling.

What I would really like - in an alternative FreeType in an alternative
universe, or possible in my much-deferred C++ interface to FT, which I
started writing a little while ago - is a *single* function to set the
transformation. This would set both pixel size and other transformations at
once. The identity matrix would give a size of 1 x 1 pixels, so { 12, 0, 0,
12, 0, 0 } would give a 12-pixel font instance. It would be the
responsibility of the driver to determine what components of the
trsnaformation were applicable to hinting.


Well, if you really think this would be useful, it's still possible to
provide a new API like FT_Set_Global_Transform that would automatically
perform the transformation decomposition for you, and would call
FT_Set_Char_Size and FT_Set_Transform automatically with the adequate
value. That shouldn't be too much work..

On the other hand, I'm pretty certain that we still need to separate the
transforms, and make the distinction to the end user when this makes
sense. I can give you two specific examples:


A. Displaying rotated text:

  Let's suppose that we want to display rotated text. For consistency
  reasons, it may be important to always use the same character pixel
  size, independent of the rotation angle: since hinting may alter
  glyph advances in a non-linear way, and you take the risk of
  generating random layout metrics variations, even small ones,
  when rotating your text.

  of course, this problem doesn't happen if you compute the position
  of each individual glyph before the rotation happens, but not all
  software is designed to do so.


B. Generating LCD-optimized glyph bitmaps:

  Generally speaking, this supposes that one hints the glyph outlines
  for the "reference" character size, then use an additionnal transform
  in order to multiply the width or height by a factor of 3.

  then, everything is rendered to a gray bitmap, filtered, and composited
  to the background image when needed...

  in this case, FT_Set_Transform is intentionally used to implement
  scaling after all hinting.


<<<<<<
decompose your transform into a two distinct ones: a scaling one, and
a shearing / rotating one. Equivalent to finding the matrix's eigenvalues


I have a way of doing this that is probably inefficient and doesn't use
eigenvalues. I'll look into eigenvalues, which I have heard of but I don't
know what they are. Thanks for the tip.

I stand corrected, this is not equivalent to finding the eigenvalues: it's
actually simple since we don't need reversability, just a decomposition.

Here's a proposed algorithm:

  let A be the matrix   | ax  bx  |
                        | ay  by  |

  then the scaling factors can be computed as:

     sx = sqrt( ax*ax + ay*ay )
     sy = ( ax*by - ay*bx ) / sx

  if sy > 0, we can write that A is equal to:

     | ax/sx  bx/sy  |  multiplied by | sx   0 |
     | ay/sx  by/sy  |                |  0  sy |

  if sy < 0, we can write that A is equal to:

     | ax/sx  -bx/sy  |  multiplied by | sx   0  |
     | ay/sx  -by/sy  |                |  0  -sy |

  (because we need both scaling factors > 0 !!)

in FreeType words:

  sx  = FT_Vector_Length( matrix.xx, matrix.yx );
  tmp = FT_MulFix( matrix.xx, matrix.yy ) - FT_MulFix( matrix.xy, matrix.yx );
  sy  = FT_DivFix( tmp, sx );

  matrix2.xx = FT_DivFix( matrix.xx, sx );
  matrix2.yx = FT_DivFix( matrix.yx, sx );

  if ( sy > 0 )
  {
    matrix2.xy = FT_DivFix( matrix.xy, sy );
    matrix2.yy = FT_DivFix( matrix.yy, sy );
  }
  else
  {
    matrix2.xy = - FT_DivFix( matrix.xy, sy );
    matrix2.yy = - FT_DivFix( matrix.yy, sy );
    sy         = - sy;
  }

  // delta is unchanged...

  FT_Set_Char_Size( face, sx, sy, 72*(65536/64), 72*(65536/64) );
  FT_Set_Transform( face, &matrix2, &delta );

though you would probably perform the computations with "double"s to avoid
numeric stability problems.

this algorithm has a strong bias along the X axis, it could probably
changed to select a different axis in certain circumstances though..

Hope this helps,

- David Turner
- The FreeType Project  (www.freetype.org)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]