pdf-lib
Version:
Library for creating and modifying PDF files in JavaScript
62 lines (61 loc) • 3.19 kB
JavaScript
import first from 'lodash/first';
import last from 'lodash/last';
import zip from 'lodash/zip';
import { mapIntoContiguousGroups, toHexStringOfMinLength } from '../../../utils';
/** `glyphs` should be an array of unique glyphs sorted by their ID */
export var createCmap = function (glyphs) {
var delimiters = mapIntoContiguousGroups(glyphs, function (glyph) { return glyph.id; }, function (glyph) { return glyph.id; }).map(function (range) { return [
cmapHexFormat(cmapHexString(first(range))),
cmapHexFormat(cmapHexString(last(range))),
]; });
var mappings = mapIntoContiguousGroups(glyphs, function (glyph) { return glyph.id; }, function (glyph) { return cmapHexFormat.apply(void 0, glyph.codePoints.map(cmapCodePointFormat)); });
var bfRanges = zip(delimiters, mappings);
return fillCmapTemplate(bfRanges);
};
/* =============================== Templates ================================ */
// prettier-ignore
var fillBfrangeTemplate = function (_a) {
var _b = _a[0], start = _b[0], end = _b[1], mappings = _a[1];
return ("\n" + mappings.length + " beginbfrange\n" + start + " " + end + " [" + mappings.join(' ') + "]\nendbfrange\n").trim();
};
// prettier-ignore
var fillCmapTemplate = function (bfRanges) { return ("\n/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n /Registry (Adobe)\n /Ordering (UCS)\n /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000><ffff>\nendcodespacerange\n" + bfRanges.map(fillBfrangeTemplate).join('\n') + "\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend\n").trim(); };
/* =============================== Utilities ================================ */
var cmapHexFormat = function () {
var values = [];
for (var _i = 0; _i < arguments.length; _i++) {
values[_i] = arguments[_i];
}
return "<" + values.join('') + ">";
};
var cmapHexString = function (value) { return toHexStringOfMinLength(value, 4); };
var cmapCodePointFormat = function (codePoint) {
if (isUtf8CodePoint(codePoint))
return cmapHexString(codePoint);
if (isUtf16CodePoint(codePoint)) {
var hs = highSurrogate(codePoint);
var ls = lowSurrogate(codePoint);
return "" + cmapHexString(hs) + cmapHexString(ls);
}
var hex = codePoint.toString(16);
var msg = "0x" + hex + " is not a valid UTF-8 or UTF-16 codepoint.";
throw new Error(msg);
};
// From: https://en.wikipedia.org/wiki/UTF-16#Description
var isUtf8CodePoint = function (codePoint) {
return codePoint >= 0 && codePoint <= 0xffff;
};
// From: https://en.wikipedia.org/wiki/UTF-16#Description
var isUtf16CodePoint = function (codePoint) {
return codePoint >= 0x010000 && codePoint <= 0x10ffff;
};
// From Unicode 3.0 spec, section 3.7:
// http://unicode.org/versions/Unicode3.0.0/ch03.pdf
var highSurrogate = function (codePoint) {
return Math.floor((codePoint - 0x10000) / 0x400) + 0xd800;
};
// From Unicode 3.0 spec, section 3.7:
// http://unicode.org/versions/Unicode3.0.0/ch03.pdf
var lowSurrogate = function (codePoint) {
return ((codePoint - 0x10000) % 0x400) + 0xdc00;
};