質問

I'm trying to wrap my head around the truetype specification. On this page, in the section 'cmap' format 4, the parameter idDelta is listed as an unsigned 16-bits integer (UInt16). Yet, further down, a few examples are given, and here idDelta is given the values -9, -18, -27 and 1. How is this possible?

役に立ちましたか?

解決 2

The definition and use of idDelta on that page is not consistent. In the struct subheader it is defined as an int16, while a little earlier the same subheader is listed as UInt16*4.

It's probably a bug in the spec.

If you look at actual implementations, like this one from perl Tk, you'll see that idDelta is usually given as signed:

typedef struct SUBHEADER {
    USHORT firstCode;       /* First valid low byte for subHeader. */
    USHORT entryCount;      /* Number valid low bytes for subHeader. */
    SHORT idDelta;      /* Constant adder to get base glyph index. */
    USHORT idRangeOffset;   /* Byte offset from here to appropriate
                 * glyphIndexArray. */
} SUBHEADER;

Or see the implementation from libpdfxx:

struct SubHeader
{
USHORT firstCode;
USHORT entryCount;
SHORT idDelta;
USHORT idRangeOffset;
};

他のヒント

This is not a bug in the spec. The reason they show negative numbers in the idDelta row for the examples is that All idDelta[i] arithmetic is modulo 65536. (quoted from the section just above). Here's how that works.

The formula to get the glyph index is

glyphIndex = idDelta[i] + c

where c is the character code. Since this expression must be modulo 65536, that's equivalent to the following expression if you were using integers larger than 2 bytes :

glyphIndex = (idDelta[i] + c) % 65536

idDelta is a u16, so let's say it had the max value 65535 (0xFFFF), then glyphIndex would be equal to c - 1 since:

0xFFFF + 2 = 0x10001 0x10001 % 0x10000 = 1

You can think of this as a 16 integer wrapping around to 0 when an overflow occurs.

Now remember that a modulo is repeated division, keeping the remainder. Well in this case, since idDelta is only 16 bits, the max amount of divisions a modulo will need to do is 1, since the max value you can get from adding two 16 bit integers is 0x1FFFE , which is smaller than 0x100000. That means that a shortcut is to subtract 65536 (0x10000) instead of performing the modulo.

glyphIndex = (idDelta[i] - 0x10000) + c

And this is what the example shows as the values in the table. Here's an actual example from a .ttf file I've decoded :enter image description here

I want the index for the character code 97 (lowercase 'a').

  1. 97 is greater than 32 and smaller than 126, so we use index 2 of the mappings.
  2. idDelta[2] == 65507
  3. glyphIndex = (65507 + 97) % 65536 === 68 which is the same as (65507 - 65536) + 97 === 68
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top