Skip to content

Commit

Permalink
cff: Humanify user facing way "delta"s are handled
Browse files Browse the repository at this point in the history
[why]
At the moment the delta values are not de- or encoded. The delta format
is a packed format to have the smallest possible values in the array of
numbers (i.e. relative to the previous number).
But usually users do not face this but are shown absolute values; in
all other font specific applications.

For example
BlueValues [ 500, 550 ]      // User sees the BlueZone is from 500 to 550
Encoded as [ 500, 50 ]

opentype.js at the moment does not translate these deltas in any way and
users must know this and use the inconvenient 'packed' encoding format.

[how]
Convert the read relative delta values to absolute coordinates in the
blueValues (and other) properties, that users can interact with.

On font encoding time the absolute coordinates are converted back to
relative ones and encoded in the font file.

[note]
https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf

    The second and subsequent numbers in a delta are encoded as the
    difference between successive values. For example, an array a0,
    a1, ..., an would be encoded as: a0 (a1–a0) (a2–a1) ..., (an–a(n–1))

This is done because small numbers can be encoded with fewer bytes and
the total aim is to reduce the size.

Signed-off-by: Fini Jastrow <[email protected]>
  • Loading branch information
Finii authored and Connum committed Sep 9, 2024
1 parent 23c26de commit f33a89c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
26 changes: 26 additions & 0 deletions src/tables/cff.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@ function interpretDict(dict, meta, strings) {
if (m.type === 'SID') {
value = getCFFString(strings, value);
}
if (m.type === 'delta' && value !== null) {
if (!Array.isArray(value) || value.length % 2 != 0) {
throw new Error(`Read delta data invalid`);

Check failure on line 313 in src/tables/cff.mjs

View workflow job for this annotation

GitHub Actions / build

Strings must use singlequote
}
// Convert delta array to human readable version
let current = 0;
for(let i = 0; i < value.length; i++) {
value[i] = value[i] + current;
current = value[i]

Check failure on line 319 in src/tables/cff.mjs

View workflow job for this annotation

GitHub Actions / build

Missing semicolon
}
}
newDict[m.name] = value;
}
}
Expand Down Expand Up @@ -1416,6 +1427,21 @@ function makeDict(meta, attrs, strings) {
if (entry.type === 'SID') {
value = encodeString(value, strings);
}
if (entry.type === 'delta' && value !== null) {
if (!Array.isArray(value) || value.length % 2 != 0) {
throw new Error(`Provided delta data invalid`);

Check failure on line 1432 in src/tables/cff.mjs

View workflow job for this annotation

GitHub Actions / build

Strings must use singlequote
}
// Convert human readable delta array to DICT version
// See https://adobe-type-tools.github.io/font-tech-notes/pdfs/5176.CFF.pdf
// Private DICT data > Table 6 Operand Types > delta
let current = 0;
for(let i = 0; i < value.length; i++) {
let nextcurrent = value[i];
value[i] = value[i] - current;
current = nextcurrent;
}
console.log("OUTCOMING", value);

Check failure on line 1443 in src/tables/cff.mjs

View workflow job for this annotation

GitHub Actions / build

Strings must use singlequote
}

m[entry.op] = {name: entry.name, type: entry.type, value: value};
}
Expand Down
8 changes: 4 additions & 4 deletions test/tables/cff.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ describe('tables/cff.mjs', function () {
assert.equal(topDict.vstore, 16);
assert.equal(topDict.fdSelect, null);

assert.deepEqual(privateDict1.blueValues, [-20, 20, 472, 18, 35, 15, 105, 15, 10, 20, 40, 20]);
assert.deepEqual(privateDict1.otherBlues, [-250, 10]);
assert.deepEqual(privateDict1.familyBlues, [-20, 20, 473, 18, 34, 15, 104, 15, 10, 20, 40, 20]);
assert.deepEqual(privateDict1.familyOtherBlues, [ -249, 10 ]);
assert.deepEqual(privateDict1.blueValues, [-20, 0, 472, 490, 525, 540, 645, 660, 670, 690, 730, 750]);
assert.deepEqual(privateDict1.otherBlues, [-250, -240]);
assert.deepEqual(privateDict1.familyBlues, [-20, 0, 473, 491, 525, 540, 644, 659, 669, 689, 729, 749]);
assert.deepEqual(privateDict1.familyOtherBlues, [ -249, -239 ]);
assert.equal(privateDict1.blueScale, 0.0375);
assert.equal(privateDict1.blueShift, 7);
assert.equal(privateDict1.blueFuzz, 0);
Expand Down

0 comments on commit f33a89c

Please sign in to comment.