Support font with characters below 0x20 declared in format 1 cmap and be more general about the TrueType rewritting cases
This commit is contained in:
parent
910d807759
commit
10e9694135
95
fonts.js
95
fonts.js
@ -372,7 +372,7 @@ function getUnicodeRangeFor(value) {
|
|||||||
* var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
|
* var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
|
||||||
* type1Font.bind();
|
* type1Font.bind();
|
||||||
*/
|
*/
|
||||||
var Font = (function() {
|
var Font = (function Font() {
|
||||||
var constructor = function font_constructor(name, file, properties) {
|
var constructor = function font_constructor(name, file, properties) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.textMatrix = properties.textMatrix || IDENTITY_MATRIX;
|
this.textMatrix = properties.textMatrix || IDENTITY_MATRIX;
|
||||||
@ -531,6 +531,19 @@ var Font = (function() {
|
|||||||
}
|
}
|
||||||
ranges.push([start, end]);
|
ranges.push([start, end]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removes duplicate ranges
|
||||||
|
for (var i = ranges.length - 1; i > 0; i--) {
|
||||||
|
var range = [];
|
||||||
|
var range1 = ranges[i];
|
||||||
|
var range2 = ranges[i - 1];
|
||||||
|
if (range1[0] == range2[1]) {
|
||||||
|
range2[0] = range2[0] - 1;
|
||||||
|
range2[1] = range1[1];
|
||||||
|
ranges.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ranges;
|
return ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -790,21 +803,57 @@ var Font = (function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function replaceCMapTable(cmap, font, properties) {
|
function replaceCMapTable(cmap, font, properties) {
|
||||||
font.pos = (font.start ? font.start : 0) + cmap.length;
|
var start = (font.start ? font.start : 0) + cmap.length;
|
||||||
|
font.pos = start;
|
||||||
|
|
||||||
var version = int16(font.getBytes(2));
|
var version = int16(font.getBytes(2));
|
||||||
var numTables = int16(font.getBytes(2));
|
var numRecords = int16(font.getBytes(2));
|
||||||
|
|
||||||
|
var records = [];
|
||||||
|
for (var i = 0; i < numRecords; i++) {
|
||||||
|
records.push({
|
||||||
|
platformID: int16(font.getBytes(2)),
|
||||||
|
encodingID: int16(font.getBytes(2)),
|
||||||
|
offset: int32(font.getBytes(4))
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < numRecords; i++) {
|
||||||
|
var table = records[i];
|
||||||
|
font.pos = start + table.offset;
|
||||||
|
|
||||||
for (var i = 0; i < numTables; i++) {
|
|
||||||
var platformID = int16(font.getBytes(2));
|
|
||||||
var encodingID = int16(font.getBytes(2));
|
|
||||||
var offset = int32(font.getBytes(4));
|
|
||||||
var format = int16(font.getBytes(2));
|
var format = int16(font.getBytes(2));
|
||||||
var length = int16(font.getBytes(2));
|
var length = int16(font.getBytes(2));
|
||||||
var language = int16(font.getBytes(2));
|
var language = int16(font.getBytes(2));
|
||||||
|
|
||||||
if ((format == 0 && numTables == 1) ||
|
if (format == 0 && numRecords > 1) {
|
||||||
(format == 6 && numTables == 1 && !properties.encoding.empty)) {
|
// Characters below 0x20 are controls characters that are hardcoded
|
||||||
|
// into the platform so if some characters in the font are assigned
|
||||||
|
// under this limit they will not be displayed so let's rewrite the
|
||||||
|
// CMap.
|
||||||
|
var map = [];
|
||||||
|
var rewrite = false;
|
||||||
|
for (var j = 0; j < 256; j++) {
|
||||||
|
var index = font.getByte();
|
||||||
|
if (index != 0) {
|
||||||
|
map.push(index);
|
||||||
|
if (j < 0x20)
|
||||||
|
rewrite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rewrite) {
|
||||||
|
var glyphs = [];
|
||||||
|
for (var j = 0x20; j < 256; j++) {
|
||||||
|
// TODO do not hardcode WinAnsiEncoding
|
||||||
|
var unicode = GlyphsUnicode[Encodings["WinAnsiEncoding"][j]];
|
||||||
|
glyphs.push({ unicode: unicode });
|
||||||
|
}
|
||||||
|
cmap.data = createCMapTable(glyphs, true);
|
||||||
|
}
|
||||||
|
} else if ((format == 0 && numRecords == 1) ||
|
||||||
|
(format == 6 && numRecords == 1 && !properties.encoding.empty)) {
|
||||||
// Format 0 alone is not allowed by the sanitizer so let's rewrite
|
// Format 0 alone is not allowed by the sanitizer so let's rewrite
|
||||||
// that to a 3-1-4 Unicode BMP table
|
// that to a 3-1-4 Unicode BMP table
|
||||||
TODO('Use an other source of informations than ' +
|
TODO('Use an other source of informations than ' +
|
||||||
@ -818,7 +867,7 @@ var Font = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmap.data = createCMapTable(glyphs);
|
cmap.data = createCMapTable(glyphs);
|
||||||
} else if (format == 6 && numTables == 1) {
|
} else if (format == 6 && numRecords == 1) {
|
||||||
// Format 6 is a 2-bytes dense mapping, which means the font data
|
// Format 6 is a 2-bytes dense mapping, which means the font data
|
||||||
// lives glue together even if they are pretty far in the unicode
|
// lives glue together even if they are pretty far in the unicode
|
||||||
// table. (This looks weird, so I can have missed something), this
|
// table. (This looks weird, so I can have missed something), this
|
||||||
@ -871,10 +920,7 @@ var Font = (function() {
|
|||||||
var header = readOpenTypeHeader(font);
|
var header = readOpenTypeHeader(font);
|
||||||
var numTables = header.numTables;
|
var numTables = header.numTables;
|
||||||
|
|
||||||
// This keep a reference to the CMap and the post tables since they can
|
var cmap, maxp;
|
||||||
// be rewritted
|
|
||||||
var cmap, post, nameTable, maxp;
|
|
||||||
|
|
||||||
var tables = [];
|
var tables = [];
|
||||||
for (var i = 0; i < numTables; i++) {
|
for (var i = 0; i < numTables; i++) {
|
||||||
var table = readTableEntry(font);
|
var table = readTableEntry(font);
|
||||||
@ -882,10 +928,6 @@ var Font = (function() {
|
|||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
if (table.tag == 'cmap')
|
if (table.tag == 'cmap')
|
||||||
cmap = table;
|
cmap = table;
|
||||||
else if (table.tag == 'post')
|
|
||||||
post = table;
|
|
||||||
else if (table.tag == 'name')
|
|
||||||
nameTable = table;
|
|
||||||
else if (table.tag == 'maxp')
|
else if (table.tag == 'maxp')
|
||||||
maxp = table;
|
maxp = table;
|
||||||
|
|
||||||
@ -894,10 +936,6 @@ var Font = (function() {
|
|||||||
tables.push(table);
|
tables.push(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any tables are still in the array this means some required
|
|
||||||
// tables are missing, which means that we need to rebuild the
|
|
||||||
// font in order to pass the sanitizer.
|
|
||||||
if (requiredTables.length && requiredTables[0] == 'OS/2') {
|
|
||||||
// Create a new file to hold the new version of our truetype with a new
|
// Create a new file to hold the new version of our truetype with a new
|
||||||
// header and new offsets
|
// header and new offsets
|
||||||
var ttf = new Uint8Array(kMaxFontFileSize);
|
var ttf = new Uint8Array(kMaxFontFileSize);
|
||||||
@ -916,11 +954,12 @@ var Font = (function() {
|
|||||||
// of missing tables
|
// of missing tables
|
||||||
createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables);
|
createOpenTypeHeader('\x00\x01\x00\x00', ttf, offsets, numTables);
|
||||||
|
|
||||||
// Insert the missing table
|
if (requiredTables.indexOf('OS/2') != -1) {
|
||||||
tables.push({
|
tables.push({
|
||||||
tag: 'OS/2',
|
tag: 'OS/2',
|
||||||
data: stringToArray(createOS2Table(properties))
|
data: stringToArray(createOS2Table(properties))
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Replace the old CMAP table with a shiny new one
|
// Replace the old CMAP table with a shiny new one
|
||||||
if (properties.type == 'CIDFontType2') {
|
if (properties.type == 'CIDFontType2') {
|
||||||
@ -970,7 +1009,7 @@ var Font = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the 'post' table if needed
|
// Rewrite the 'post' table if needed
|
||||||
if (!post) {
|
if (requiredTables.indexOf('post') != -1) {
|
||||||
tables.push({
|
tables.push({
|
||||||
tag: 'post',
|
tag: 'post',
|
||||||
data: stringToArray(createPostTable(properties))
|
data: stringToArray(createPostTable(properties))
|
||||||
@ -978,7 +1017,7 @@ var Font = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the 'name' table if needed
|
// Rewrite the 'name' table if needed
|
||||||
if (!nameTable) {
|
if (requiredTables.indexOf('name') != -1) {
|
||||||
tables.push({
|
tables.push({
|
||||||
tag: 'name',
|
tag: 'name',
|
||||||
data: stringToArray(createNameTable(this.name))
|
data: stringToArray(createNameTable(this.name))
|
||||||
@ -1018,12 +1057,6 @@ var Font = (function() {
|
|||||||
fontData.push(ttf[i]);
|
fontData.push(ttf[i]);
|
||||||
|
|
||||||
return fontData;
|
return fontData;
|
||||||
} else if (requiredTables.length) {
|
|
||||||
error('Table ' + requiredTables[0] +
|
|
||||||
' is missing from the TrueType font');
|
|
||||||
}
|
|
||||||
|
|
||||||
return font.getBytes();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
convert: function font_convert(fontName, font, properties) {
|
convert: function font_convert(fontName, font, properties) {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<script type="text/javascript" src="viewer.js"></script>
|
<script type="text/javascript" src="viewer.js"></script>
|
||||||
<script type="text/javascript" src="../pdf.js"></script>
|
<script type="text/javascript" src="../pdf.js"></script>
|
||||||
<script type="text/javascript" src="../fonts.js"></script>
|
<script type="text/javascript" src="../fonts.js"></script>
|
||||||
|
<script type="text/javascript" src="../utils/fonts_utils.js"></script>
|
||||||
<script type="text/javascript" src="../crypto.js"></script>
|
<script type="text/javascript" src="../crypto.js"></script>
|
||||||
<script type="text/javascript" src="../glyphlist.js"></script>
|
<script type="text/javascript" src="../glyphlist.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user