FreeType 1.31.1
This commit is contained in:
771
docs/bitmaps.txt
Normal file
771
docs/bitmaps.txt
Normal file
@@ -0,0 +1,771 @@
|
||||
|
||||
Bitmap and Pixmap generation with FreeType
|
||||
------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
|
||||
Introduction
|
||||
|
||||
I. The rasterizer component
|
||||
|
||||
II. Bitmap & pixmap descriptors
|
||||
|
||||
III. Rendering an outline
|
||||
|
||||
IV. Anti-aliasing palette and other concerns
|
||||
|
||||
Conclusion
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This document describes the steps that are needed to render a
|
||||
glyph outline into a bitmap or a pixmap with the FreeType library.
|
||||
It contains several important details needed to generate bitmaps
|
||||
correctly in all situations, including if an outline has been
|
||||
transformed or translated.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
I. The rasterizer component
|
||||
---------------------------
|
||||
|
||||
In FreeType, the component in charge of performing bitmap and
|
||||
pixmap rendering is called the `rasterizer'. Generation is
|
||||
performed through a traditional process called `scan-line
|
||||
conversion', but exhibits certain properties:
|
||||
|
||||
- The rasterizer doesn't allocate bitmaps:
|
||||
|
||||
In fact, it is only able to render an outline into an existing
|
||||
bitmap or pixmap, which is passed to one of its rendering
|
||||
functions. This means that the target bitmap/pixmap must be set
|
||||
up correctly by the caller to achieve desired results. Setting
|
||||
up bitmap and pixmap descriptors is explained in section II.
|
||||
|
||||
- It is able to render anti-aliased pixmaps directly:
|
||||
|
||||
This is unlike other graphics packages, which render to a
|
||||
`large' bitmap which is then filtered down. Putting the
|
||||
anti-aliasing logic within the rasterizer improves performance
|
||||
and reduces memory usage, as well as lets us use better
|
||||
algorithms which couldn't work in a `two-phase' process.
|
||||
|
||||
The rasterizer is located in the files `ttraster.h' and
|
||||
`ttraster.c' (or `ttraster.pas' for the Pascal version --
|
||||
unfortunately, this is severely out of date).
|
||||
|
||||
The format of outlines isn't important for most developers and
|
||||
won't be discussed here. However, a few conventions must be
|
||||
explained regarding the vector outlines:
|
||||
|
||||
|
||||
1. Units
|
||||
|
||||
All point coordinates within an outline are stored in 32-bit
|
||||
fractional pixel values, using the 26.6 fixed float format
|
||||
(which uses 26 bits for the integer part, and 6 bits for the
|
||||
fractional part). The following table gives some examples of
|
||||
real versus 26.6 coordinates:
|
||||
|
||||
-----------------------------------------
|
||||
real real coord 26.6 coord
|
||||
coord. * 2^6
|
||||
-----------------------------------------
|
||||
0 0*64 = 0.0 0
|
||||
2.4 2.4*64 = 153.6 154
|
||||
3 3*64 = 192.0 192
|
||||
-1.7 -1.7*64 = -108.8 -109
|
||||
|
||||
As you can see, conversion is relatively simple -- basically a
|
||||
multiplication by 64.
|
||||
|
||||
In order to differentiate coordinates expressed in real or 26.6
|
||||
systems, we'll use in the following lines brackets (`[' and `]')
|
||||
for real coordinates, and simple parentheses (`(' and `)') for
|
||||
fractional coordinates so that
|
||||
|
||||
[1.0,2.5] equals (64,160)
|
||||
|
||||
[0,0] equals (0,0)
|
||||
|
||||
[-2,3] equals (-128,192)
|
||||
|
||||
|
||||
2. Orientation
|
||||
|
||||
The rasterizer uses the traditional convention of an X axis
|
||||
oriented from left to right, and of a Y axis oriented from
|
||||
bottom to top.
|
||||
|
||||
^ Y
|
||||
|
|
||||
|
|
||||
|
|
||||
-*-----> X
|
||||
|
|
||||
|
||||
You've probably already used it at school when doing math :-)
|
||||
|
||||
Though the orientation of bitmap lines has the opposite
|
||||
direction on nearly all graphics systems, the former convention
|
||||
is the _right_ one when it comes to vector graphics. The reason
|
||||
is simply that for managing angles and vector cross-products
|
||||
resp. orientations in complex algorithms, a single convention,
|
||||
used in math as well as computing alike solves many headaches.
|
||||
|
||||
And due to education, most people expect a 45 degrees angle to
|
||||
be in the top right quadrant, at coordinate (1,1).
|
||||
|
||||
|
||||
3. Pixels and the grid
|
||||
|
||||
In a vector outline, a point is immaterial and has no size or
|
||||
width, just like in usual geometry. A `pixel' is an element of
|
||||
a computer image called a `map' (like a bitmap or a pixmap).
|
||||
|
||||
The FreeType rasterizer follows the convention defined by the
|
||||
TrueType specification regarding pixel placement:
|
||||
|
||||
- The map can be seen as a `grid' placed in the vector plane.
|
||||
The grid lines are set on integer real coordinates (i.e., on
|
||||
multiples of 64 in 26.6 fractional notation).
|
||||
|
||||
Each pixel is one `cell' of the grid, and can be `lit' with
|
||||
any color. Hence, each pixel has a width and a height of
|
||||
[1.0] units, (i.e., 64 fixed float units).
|
||||
|
||||
^ Y
|
||||
|
|
||||
| The pixel grid with two
|
||||
| points (not pixels!)
|
||||
+-----+-----+-----+-----+-----+ at coordinates [0,0]
|
||||
| | | | | | and [2,2].
|
||||
| | | | | |
|
||||
| | | | |[2,2]|
|
||||
+-----+-----+-----+-----@-----+ The pixels are the
|
||||
| | |11111|22222| | grid's cells, and this
|
||||
| | |11111|22222| | example show the four
|
||||
| | |11111|22222| | pixels enclosed within
|
||||
+-----+-----+-----+-----+-----+ the rectangle delimited
|
||||
| | |33333|44444| | by these two points.
|
||||
| | |33333|44444| |
|
||||
| | |33333|44444| |
|
||||
--+-----+-----@-----+-----+-----+----> X
|
||||
| | |[0,0]| | |
|
||||
| | | | | | Note that the numbering
|
||||
| | | | | | of pixels isn't
|
||||
+-----+-----+-----+-----+-----+ meaningful here, it's
|
||||
| | | | | | only used to distinguish
|
||||
| | | | | | them.
|
||||
| | | | | |
|
||||
+-----+-----+-----+-----+-----+
|
||||
|
|
||||
|
|
||||
|
||||
- The `center' of each pixel is always located on a
|
||||
`half-integer' coordinate, i.e., at -1.5, -0.5, 0.5, 1.5, etc.
|
||||
|
||||
- When drawing a shape, the rasterizer only `lits' a pixel when
|
||||
its center is placed _within_ the shape. This is important
|
||||
because an outline point may not be necessarily be on a grid
|
||||
line.
|
||||
|
||||
- When a pixel center falls on the shape, the pixel is lit too.
|
||||
|
||||
For example, the following graphics show the `lit' pixels
|
||||
corresponding to the rectangle enclosed by the points:
|
||||
|
||||
[-0.2, 0] and [2.4, 2.7]
|
||||
|
||||
|
||||
^ Y As one can see, the
|
||||
| newest pixels `1'
|
||||
| and `2' are now lit,
|
||||
| because its centers
|
||||
+-----+-----+-----+-----+--[2.4,2.7] are located at
|
||||
| | |11111|22222| @ | coordinates
|
||||
| . | . |11.11|22.22| . | [0.5,2.5] and
|
||||
| | |11111|22222| | [1.5,2.5],
|
||||
+-----+-----+-----+-----+-----+ respectively.
|
||||
| | |33333|44444| |
|
||||
| . | . |33.33|44.44| . | Note that pixel
|
||||
| | |33333|44444| | centers are
|
||||
+-----+-----+-----+-----+-----+ represented with a
|
||||
| | |55555|66666| | dot in the graphics.
|
||||
| . | . |55.55|66.66| . |
|
||||
| | |55555|66666| |
|
||||
--+-----+----@+-----+-----+-----+----> X
|
||||
| | [-0.2,0] | | |
|
||||
| . | . | . | . | . |
|
||||
| | | | | | Note also that pixel
|
||||
+-----+-----+-----+-----+-----+ numbering is still
|
||||
| | | | | | meaningless there.
|
||||
| . | . | . | . | . |
|
||||
| | | | | |
|
||||
+-----+-----+-----+-----+-----+
|
||||
|
|
||||
|
|
||||
|
||||
|
||||
4. Drop-out control
|
||||
|
||||
Sometimes, a stroke is too thin to even contain a single pixel
|
||||
center. This results in `lost continuity' in the resulting
|
||||
bitmap, i.e., some unpleasant `holes' or `breaks' in the
|
||||
rendered shape, which are called a `drop-out'.
|
||||
|
||||
Because a glyph representation uses curves (Bezier arcs), this
|
||||
case is not easily controllable during the `hinting' of glyph
|
||||
outlines by the font driver, which means that the rasterizer
|
||||
must be able to correct these `artefacts'.
|
||||
|
||||
This processing is called `drop-out control', and can be
|
||||
performed in several modes, defined by the TrueType
|
||||
specification, and which details do not belong to this document.
|
||||
However, the important idea is that, in _some_ cases, a pixel
|
||||
may be lit even if its center isn't part of the shape.
|
||||
|
||||
This case is relatively rare, but is mentioned because it has
|
||||
consequences of the rendering of maps. More precisely, in the
|
||||
way an outline's extent is computed (see below).
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
II. Bitmap and pixmap descriptors
|
||||
---------------------------------
|
||||
|
||||
The Freetype rasterizer only supports bitmaps and 8-bit pixmaps.
|
||||
In order to render an outline, a map descriptor must be sent to
|
||||
its rendering functions, along with a vectorial outline.
|
||||
|
||||
|
||||
1. Bitmap properties
|
||||
|
||||
This section explains how to set up a bitmap descriptor, and how
|
||||
vector coordinates in the outline plane relate to pixel
|
||||
positions within the bitmap buffer.
|
||||
|
||||
A bitmap's `raw data' is made of a simple bit buffer where each
|
||||
bit corresponds to a monochrome pixel. For the sake of
|
||||
simplicity, the FreeType rasterizer uses the following
|
||||
conventions to store bitmaps in a buffer:
|
||||
|
||||
- The value 0 is used for `unlit' pixels, usually the
|
||||
`background' when rendering text. Hence 1 is used for `lit'.
|
||||
|
||||
- Lines are padded to 8 bits, i.e. bytes. A bitmap row thus
|
||||
takes an integral number of bytes in its buffer. No further
|
||||
alignment is required.
|
||||
|
||||
(Some systems compress bitmaps by _not_ padding bit rows to
|
||||
byte boundaries. It is not possible to render into such a
|
||||
bitmap buffer with FreeType.)
|
||||
|
||||
- In a bitmap buffer byte, the left-most pixel is represented by
|
||||
the most significant bit (i.e., 0x80).
|
||||
|
||||
The opposite convention is not supported by the FreeType
|
||||
rasterizer, though it may possibly be implemented too if this
|
||||
ever comes useful (ask the developers -- for now, nobody did).
|
||||
|
||||
- Increasing offsets within a row correspond to right-most
|
||||
positions in the bitmap (i.e., byte 1 contains the
|
||||
8 bits/pixels that are located on the right of the
|
||||
8 bits/pixels of byte 0).
|
||||
|
||||
- A bitmap can be oriented in two ways:
|
||||
|
||||
o If increasing row addresses within the buffer correspond to
|
||||
lower vertical lines, the bitmap is said to go `down'. This
|
||||
is, for example, the case of nearly all video RAMs.
|
||||
|
||||
o If increasing row addresses within the buffer correspond to
|
||||
higher vertical lines, the bitmap is said to go `up'. This
|
||||
is the case, for example, for OS/2 bitmaps.
|
||||
|
||||
The `direction' of a bitmap is called `flow' to avoid any
|
||||
confusion. In both cases, the rasterizer ALWAYS matches the
|
||||
vector coordinate (0,0) with the lower-left corner of the
|
||||
*lower-left* pixel in the bitmap.
|
||||
|
||||
The following graphics illustrate these ideas:
|
||||
|
||||
|
||||
|
||||
Y ^
|
||||
| A `down-flow' bitmap.
|
||||
+--+--+--+--+--+--+--+--+ On the left is each
|
||||
| | | | | | | | | row's number and its
|
||||
0: 0 | | | | | | | | | offset in the bitmap
|
||||
+--+--+--+--+--+--+--+--+ buffer (where `w' is
|
||||
| | | | | | | | | the width, in bytes,
|
||||
1: w | | | | | | | | | of a single bitmap
|
||||
+--+--+--+--+--+--+--+--+ row). Note that the
|
||||
| | | | | | | | | origin is located at
|
||||
2: 2*w | | | | | | | | | the lower left, i.e.,
|
||||
+--+--+--+--+--+--+--+--+ near the leftmost bit
|
||||
| | | | | | | | | of the last bitmap
|
||||
3: 3*w | | | | | | | | | row.
|
||||
-@--+--+--+--+--+--+--+-----> X
|
||||
|[0,0]
|
||||
|
||||
|
||||
|
||||
Y ^
|
||||
| An `up-flow' bitmap.
|
||||
+--+--+--+--+--+--+--+--+ On the left is each
|
||||
| | | | | | | | | row's number and its
|
||||
3: 3*w | | | | | | | | | offset in the bitmap
|
||||
+--+--+--+--+--+--+--+--+ buffer (where `w' is
|
||||
| | | | | | | | | the width, in bytes,
|
||||
2: 2*w | | | | | | | | | of a single bitmap
|
||||
+--+--+--+--+--+--+--+--+ row). Note that the
|
||||
| | | | | | | | | origin is located at
|
||||
1: w | | | | | | | | | the lower left, i.e.,
|
||||
+--+--+--+--+--+--+--+--+ near the first bit in
|
||||
| | | | | | | | | the buffer.
|
||||
0: 0 | | | | | | | | | The first buffer bit
|
||||
-@--+--+--+--+--+--+--+-----> X corresponds to the
|
||||
|[0,0] rectangle [0,0]-[1,1]
|
||||
in the vector plane.
|
||||
|
||||
|
||||
2. Bitmap descriptors
|
||||
|
||||
Now that you understand all these details, a bitmap can be
|
||||
described to the rasterizer engine through a map, which
|
||||
structure must be set up by client application:
|
||||
|
||||
struct TT_Raster_Map_
|
||||
{
|
||||
int rows; /* number of rows */
|
||||
int cols; /* number of columns (bytes) per row */
|
||||
int width; /* number of pixels per line */
|
||||
int flow; /* bitmap orientation */
|
||||
|
||||
void* bitmap; /* bit/pixmap buffer */
|
||||
long size; /* bit/pixmap size in bytes */
|
||||
};
|
||||
typedef struct TT_Raster_Map_ TT_Raster_Map;
|
||||
|
||||
where the fields stand for:
|
||||
|
||||
rows:
|
||||
The number of rows within the bitmap buffer.
|
||||
|
||||
cols:
|
||||
The number of columns, i.e. bytes per row within the
|
||||
buffer. It corresponds to the `w' value used in the above
|
||||
graphics.
|
||||
|
||||
width:
|
||||
The number of pixels (i.e. bits) per row in the buffer. The
|
||||
rasterizer always clips its rendering to the bit width
|
||||
specified in this field, even if the `cols' fields
|
||||
corresponds to a larger width.
|
||||
|
||||
flow:
|
||||
The bitmap flow. Use the constants TT_Flow_Up and
|
||||
TT_Flow_Down exclusively for this field.
|
||||
|
||||
bitmap:
|
||||
A typeless pointer to the bit buffer.
|
||||
|
||||
size:
|
||||
The total size of the bit buffer in bytes. This is not used
|
||||
directly by the rasterizer, so applications can use it.
|
||||
|
||||
Note that the `cols' field should always be bigger than the
|
||||
value of `width' multiplied by 8. The rasterizer clips the
|
||||
generated bitmap to the `width' first bits in a row.
|
||||
|
||||
Note also that it is of course allowed to create, for example, a
|
||||
Windows or X11 bitmap through a normal system-specific API call,
|
||||
using a TT_Raster_Map that describes it to the rasterizer. It
|
||||
is thus possible to draw directly into such OS specific
|
||||
structures.
|
||||
|
||||
|
||||
IMPORTANT: *****************************************************
|
||||
|
||||
When rendering a bitmap, the rasterizer always OR-es the shape
|
||||
on the target bitmap. It is thus possible to draw several
|
||||
shapes into a single surface which successive calls to the
|
||||
render functions.
|
||||
|
||||
****************************************************************
|
||||
|
||||
|
||||
3. Pixmap properties
|
||||
|
||||
The rasterizer only supports 8-bit pixmaps, where one pixel is
|
||||
represented by a single byte. They must conform to the
|
||||
following rules:
|
||||
|
||||
- A 5-entries palette is used to generate an outline's pixmap in
|
||||
the buffer. They correspond to:
|
||||
|
||||
palette[0] -> background
|
||||
palette[1] -> `light'
|
||||
palette[2] -> `medium'
|
||||
palette[3] -> `dark'
|
||||
palette[4] -> foreground
|
||||
|
||||
where the terms `light', `medium', and `dark' correspond to
|
||||
intermediate values between the first (background) and last
|
||||
(foreground) entry.
|
||||
|
||||
The upcoming FreeType 2.0 will feature an additional
|
||||
anti-aliasing logic with a 17-entries palette.
|
||||
|
||||
- Lines are padded to 32 bits, i.e. 4 bytes. A pixmap row thus
|
||||
takes a multiple of 4 bytes in its buffer.
|
||||
|
||||
- Increasing offsets within a row correspond to right-most
|
||||
positions in the bitmap (i.e., byte/pixel 1 is to the right of
|
||||
byte/pixel 0).
|
||||
|
||||
- A pixmap can be oriented in two ways, following the same rules
|
||||
as a bitmap regarding its flow.
|
||||
|
||||
|
||||
IMPORTANT: *****************************************************
|
||||
|
||||
In order to improve performance when rendering large outlines
|
||||
with anti-aliasing, the rasterizer draws pixels in runs of
|
||||
4-bytes ONLY when at least one of their `colour' isn't 0
|
||||
(background).
|
||||
|
||||
This means that you should ALWAYS CLEAR the pixmap buffer before
|
||||
calling the rendering function, you may otherwise experience
|
||||
ugly artefacts, which are possibly left from a previous
|
||||
rendering!
|
||||
|
||||
In general, it is not possible to do colour compositing with the
|
||||
FreeType rasterizer (compositing is if you want to superpose a
|
||||
transparent coloured layer on top of an image). This is mainly
|
||||
due to the fact that:
|
||||
|
||||
- There are too many pixel formats to support.
|
||||
|
||||
- There is not a single portable way to do it anyway.
|
||||
|
||||
- It really is a graphics processing question, not one that
|
||||
should be solved by a text rendering engine.
|
||||
|
||||
****************************************************************
|
||||
|
||||
|
||||
4. Pixmap descriptors
|
||||
|
||||
Pixmaps use the same descriptor structure as bitmaps, with a few
|
||||
differences in interpretation:
|
||||
|
||||
- The `cols' field is used to indicate the number of _bytes_ in
|
||||
a pixmap row. It must thus be a multiple of 4!
|
||||
|
||||
- The rasterizer clips the outline to the first `width'
|
||||
pixels/width within each buffer row.
|
||||
|
||||
As usual, it should be possible to use a system-specific pixmap
|
||||
and render directly into it, as long as you set up a descriptor
|
||||
for it.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
|
||||
III. Rendering an outline
|
||||
-------------------------
|
||||
|
||||
Now that you understand how the rasterizer sees the target bitmaps
|
||||
and pixmaps it renders to, this section will explain how the
|
||||
rendering eventually happen.
|
||||
|
||||
|
||||
1. Outline coordinates and extents
|
||||
|
||||
Let's first consider the case where we're rendering text
|
||||
directly into a huge single bitmap. To do that, we simply
|
||||
translate each glyph outline before calling the rasterizer.
|
||||
Here the roadmap:
|
||||
|
||||
- Vectorial coordinates [0,0] are mapped to the lower left
|
||||
`corner' (in the grid) of the lower left pixel in the bitmap
|
||||
(whatever its flow is).
|
||||
|
||||
- When the glyph loader returns an outline, the latter is placed
|
||||
so that the coordinate [0,0] corresponds to the current cursor
|
||||
position.
|
||||
|
||||
This means that:
|
||||
|
||||
- If we use our own cursor (cx,cy) within the bitmap during text
|
||||
rendering, we must translate the outline to its position
|
||||
before rendering it, e.g. with
|
||||
|
||||
TT_Translate_Outline( outline, cx, cy )
|
||||
|
||||
(and the cursor position must be incremented after rendering
|
||||
each glyph).
|
||||
|
||||
- Before translation (i.e., when it is returned by the glyph
|
||||
loader), the glyph outline doesn't necessarily lie on any of
|
||||
the coordinate axes, nor is it limited to the first quadrant
|
||||
(i.e., x>0 and y>0 is not true in general).
|
||||
|
||||
Its extent can be computed with the function
|
||||
TT_Get_Outline_BBox(), which returns the minimum and maximum
|
||||
values of its X and Y point coordinates (in 26.6 format, of
|
||||
course).
|
||||
|
||||
|
||||
2. Computing an outline's dimensions in pixels
|
||||
|
||||
In many cases, however, it is much better to render individual
|
||||
glyph bitmaps, then cache them with appropriate metrics in order
|
||||
to render text much more quickly at a given point size.
|
||||
|
||||
To be able to render the smallest possible bitmap, the exact
|
||||
outline's extent dimensions in pixel are required. Again a
|
||||
roadmap:
|
||||
|
||||
- Get the outline's bounding box in vector coordinates:
|
||||
|
||||
Simply call the TT_Get_Outline_BBox() function which will
|
||||
return the values of xMin, yMin, xMax, and yMax in vector
|
||||
(i.e. fractional) coordinates.
|
||||
|
||||
- Grid-fit the bounding box:
|
||||
|
||||
Because of the way pixels are lit in the bitmaps relative to
|
||||
the position of their `centers' within the shape (see
|
||||
section I), it is necessary to align the values of xMin, xMax,
|
||||
yMin, and yMax to the pixel grid in order to compute the width
|
||||
and height of the resulting bitmap. This can be done with:
|
||||
|
||||
xMin = FLOOR ( xMin ); with FLOOR(x) == (x & -64)
|
||||
xMax = CEILING( xMax ); CEILING(x) == ((x+63) & -64)
|
||||
yMin = FLOOR ( yMin );
|
||||
yMax = CEILING( yMax );
|
||||
|
||||
The extents in pixels can then be simply computed as:
|
||||
|
||||
pixel_width = (xMax - xMin) / 64;
|
||||
pixel_height = (yMax - yMin) / 64;
|
||||
|
||||
Note that because of drop-out control, and because the
|
||||
bounding box computed currently includes all Bezier control
|
||||
points from the outline, the bitmap may be slightly larger
|
||||
than necessary in some cases.
|
||||
|
||||
Some improvements are planned for FreeType 2.0; for now, you
|
||||
should consider that finding the `exact' bitmap bounding box
|
||||
requires to scan all `borders' to detect null columns or rows.
|
||||
However, the values are right in most cases.
|
||||
|
||||
NOTE: It seems that in some *rare* cases, which relate to
|
||||
weird drop-out control situations, the above dimensions
|
||||
are not enough to store all bits from the outline (there
|
||||
are one or more bits `cut' on the edge).
|
||||
|
||||
This being hard to study (it only appears in very poorly
|
||||
hinted fonts), we leave this problem to FreeType 2.0.
|
||||
|
||||
- Create/setup a bitmap with the computed dimensions. DON'T
|
||||
FORGET TO CLEAR ITS BUFFER TOO!
|
||||
|
||||
- Translate the outline to stick within the bitmap space. This
|
||||
is done easily by translating it by (-xMin,-yMin), where you
|
||||
should ALWAYS USE THE GRID-FITTED VALUES computed above for
|
||||
xMin and yMin:
|
||||
|
||||
TT_Translate_Outline( outline, -xMin, -yMin );
|
||||
|
||||
|
||||
IMPORTANT: ***************************************************
|
||||
|
||||
For technical reasons, you should never translate a HINTED
|
||||
outline by a non-integer vector (i.e., a vector which
|
||||
coordinates aren't multiples of 64)! This would CERTAINLY
|
||||
completely RUIN the delicate HINTING of the glyph, and will
|
||||
result probably in pure GARBAGE at small point sizes.
|
||||
|
||||
Of course, if you're not interested in hinting, like when
|
||||
displaying rotated text, you can ignore this rule and
|
||||
translate to any position freely.
|
||||
|
||||
**************************************************************
|
||||
|
||||
- Render the bitmap (or pixmap).
|
||||
|
||||
DON'T FORGET TO STORE THE GRID-FITTED xMin and yMin WITH THE
|
||||
BITMAP! This will allow you later to place it correctly
|
||||
relative to your cursor position.
|
||||
|
||||
|
||||
Here's some example pseudo code:
|
||||
|
||||
{
|
||||
... load the glyph ...
|
||||
|
||||
TT_Outline outline;
|
||||
TT_BBox bbox;
|
||||
TT_Raster_Map bitmap;
|
||||
|
||||
|
||||
/* get the outline */
|
||||
TT_Get_Glyph_Outline( glyph, &outline );
|
||||
|
||||
/* compute its extent */
|
||||
TT_Get_Outline_BBox( &outline, &bbox );
|
||||
|
||||
/* Grid-fit it */
|
||||
bbox.xMin &= -64;
|
||||
bbox.xMax = ( bbox.xMax + 63 ) & -64;
|
||||
bbox.yMin &= -64;
|
||||
bbox.yMax = ( bbox.yMax + 63 ) & -64;
|
||||
|
||||
/* compute pixel dimensions */
|
||||
width = (bbox.xMax - bbox.xMin) / 64;
|
||||
height = (bbox.yMax - bbox.yMin) / 64;
|
||||
|
||||
/* set up bitmap */
|
||||
bitmap.rows = height;
|
||||
bitmap.width = width;
|
||||
bitmap.cols = (width + 7) / 8;
|
||||
bitmap.size = bitmap.rows * bitmap.cols;
|
||||
bitmap.bitmap = malloc( bitmap.size );
|
||||
if ( !bitmap.bitmap )
|
||||
return error_memory...
|
||||
|
||||
/* clear the bitmap buffer! */
|
||||
memset( bitmap.bitmap, 0, bitmap.size );
|
||||
|
||||
/* translate outline */
|
||||
TT_Translate_Outline( &outline, -bbox.xMin, -bbox.yMin );
|
||||
|
||||
/* render it within the bitmap */
|
||||
TT_Get_Outline_Bitmap( engine, &outline, &bitmap );
|
||||
|
||||
/* We're done; don't forget to save bbox.xMin and */
|
||||
/* bbox.yMin to adjust the bitmap position when */
|
||||
/* rendering text with it */
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
3. The case of transformed/rotated glyphs:
|
||||
|
||||
You may want to apply a transformation other than a translation
|
||||
to your glyph outlines before rendering them. For example, a
|
||||
simple slant to synthesize italics, or a slight rotation.
|
||||
|
||||
In all cases, it is possible to render individual glyph bitmaps.
|
||||
Just make sure to follow the same process AFTER you have
|
||||
transformed you outline!
|
||||
|
||||
DON'T FORGET THAT YOU NEED TO RE-COMPUTE THE BBOX TO GET THE
|
||||
CORRECT PIXEL DIMENSIONS AFTER A TRANSFORMATION.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
IV. Anti-aliasing palette and other concerns
|
||||
|
||||
When rendering pixmaps, using the TT_Get_Outline_Pixmap() or
|
||||
TT_Get_Glyph_Pixmap() functions, the rasterizer uses a 5-entries
|
||||
palette of 8-bit deep `colors'.
|
||||
|
||||
By default, this palette is set to ( 0, 1, 2, 3, 4 ), but one can
|
||||
change it to suit your needs with TT_Set_Raster_Palette().
|
||||
|
||||
While in bitmap mode, it simply OR-es the pixel values to the
|
||||
target bitmap that has been passed to TT_Get_Outline_Bitmap().
|
||||
|
||||
For pixmaps it simply writes directly the palette entries
|
||||
corresponding to the `color' of the `lit' pixels it has computed.
|
||||
This means that it is NOT POSSIBLE to render text in a single
|
||||
pixmap with multiple calls to TT_Get_Outline_Pixmaps() within the
|
||||
same target!
|
||||
|
||||
The reason is that `gray' pixels of two distinct outlines are not
|
||||
`added' when they overlap (the operation called 'compositing'), as
|
||||
it could be expected by applications.
|
||||
|
||||
The following graphic shows this effect when rendering two
|
||||
overlapping anti-aliased shapes:
|
||||
|
||||
|
||||
*** ***
|
||||
.** .**
|
||||
** **. **. **
|
||||
.*. .*.. .*..*.
|
||||
.*. + .*. = ---> ..*.
|
||||
.*. ** | .*. **
|
||||
** | **
|
||||
**. | **.
|
||||
*** | ***
|
||||
|
|
||||
|
||||
missing black pixel after second
|
||||
rendering...
|
||||
|
||||
|
||||
There is no simple way to perform a composition within the
|
||||
rasterizer. This would not be portable; moreover, it would be
|
||||
extremely slow if it is too general. This operation is thus left
|
||||
to client applications which can use their own system-specific API
|
||||
for transparently blitting the glyph pixmaps into a surface to
|
||||
form text.
|
||||
|
||||
NOTE:
|
||||
|
||||
If your system doesn't support transparent/alpha blits, you can
|
||||
still have a look at the source file `freetype/test/display.c'.
|
||||
It uses a large pixmap, with a special palette trick to render all
|
||||
text quickly, then convert everything to `real' colors for
|
||||
display.
|
||||
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
We've seen how the FreeType rasterizer sees bitmaps through
|
||||
descriptors, as well as the mapping which exists between the
|
||||
vector coordinate space and the pixel position space.
|
||||
|
||||
You should now be able to render outlines into bitmaps and pixmaps
|
||||
while applying transformations like translation, slanting, or
|
||||
rotation. Don't forget a few rules, however:
|
||||
|
||||
- Always clear the bitmap/pixmap buffer before rendering (unless
|
||||
you want to render several glyphs in a single _bitmap_; it won't
|
||||
work on a pixmap).
|
||||
|
||||
- A pixmap `cols' field, i.e. the size in bytes of each rows, must
|
||||
be a multiple of 4.
|
||||
|
||||
- Never translate a hinted outline by a non-integer vector if you
|
||||
want to preserve the hints (i.e., the vector's coordinates must
|
||||
be multiples of 64).
|
||||
|
||||
- Finally, don't expect the rasterizer to composite transparent
|
||||
`grays' for you in a single target pixmap through multiple
|
||||
calls.
|
||||
|
||||
|
||||
--- end of bitmaps.txt ---
|
||||
Reference in New Issue
Block a user