pclkit
Version:
A PCL generation library for Node.js
497 lines (422 loc) • 16.7 kB
JavaScript
var fontkit = require('fontkit');
var font = function(document, id, fontBuffer, family) {
this.document = document;
this.id = id;
this._buffer = fontBuffer;
this.family = family;
this.size = 12;
this.font = fontkit.create(fontBuffer);
this.subset = this.font.createSubset();
this.unicode = [[0]];
this.widths = [this.font.getGlyph(0).advanceWidth];
this.name = this.font.postscriptName;
this.scale = 1000 / this.font.unitsPerEm;
this.ascender = this.font.ascent * this.scale;
this.descender = this.font.descent * this.scale;
this.xHeight = this.font.xHeight * this.scale;
this.capHeight = this.font.capHeight * this.scale;
this.lineGap = this.font.lineGap * this.scale;
this.bbox = this.font.bbox;
if (document.options.fontLayoutCache !== false) {
this.layoutCache = Object.create(null);
}
// Font Descriptor Size (Unsigned Integer 0 . . 65535)
// Specifies the number of bytes in the font descriptor
this.fontDescriptorSize = 0;
// Header Format (Unsigned Byte 0 . . 255)
// The Header Format byte identifies the font to format
// 0 PCL Bitmap
// 10 Intellifont Bound Scalable
// 11 Intellifont Unbound Scalable
// 15 TrueType Scalable (bound or unbound)
// 20 Resolution-Specified Bitmap
this.headerFormat = 0;
// Font Type (Unsigned Byte 0 . . 255)
// Font type describes the font’s relation to symbol sets
// 0 Bound font. Character codes 32 to 127 [decimal] are printable.
// 1 Bound font. Character codes 32 to 127 [decimal] and 160 to 255 [decimal] are printable.
// 2 Bound font. All character codes 0 to 255 are printable, except 0, 7 to 15, and 27 [decimal].
// 10 Unbound font. Character codes correspond to HP MSL numbers (for Intellifont unbound scalable fonts).
// 11 Unbound font. Character codes correspond to Unicode numbers (for TrueType unbound scalable fonts).
this.fontType = 0;
// Style (Unsigned Integer 0 . . 65535)
// Style Word = Posture + (4 x Width) + (32 x Structure)
this.style = {
// Posture:
// 0 Upright
// 1 Italic
// 2 Alternate Italic
// 3 Reserved
posture: 0,
// Appearance Width:
// 0 Normal
// 1 Condensed
// 2 Compressed or Extra Condensed
// 3 Extra Compressed
// 4 Ultra Compressed
// 5 Reserved
// 6 Extended or Expanded
// 7 Extra Extended or Extra Expanded
width: 0,
// Structure:
// 0 Solid
// 1 Outline
// 2 Inline
// 3 Contour, Distressed (edge effects)
// 4 Solid with Shadow
// 5 Outline with Shadow
// 6 Inline with Shadow
// 7 Contour with Shadow
// 8-11 Patterned (complex patterns, subject to type family)
// 12-15 Patterned with Shadow
// 16 Inverse
// 17 Inverse in Open Border
// 18-30 Reserved
// 31 Unknown Structure
structure: 0
};
// Baseline Position (Unsigned Integer 0 . . 65535)
// Bitmap Font - Specifies the distance from the top of the cell to the baseline(in font resolution dots).
// Intellifont Scalable - Specifies a Y-coordinate in the design window
// TrueType Scalable - Baseline Position must be set to zero.
this.baselinePosition = 0;
// Cell Width (Unsigned Integer 0 . . 65535)
// Specifies the width of the cell.
// The cell must be wide enough to accept the widest character.
// Bitmap Font - Specified in PCL coordinate system dots.
// Scalable Font - Specified in design units.
this.cellWidth = 0;
// Cell Height (Unsigned Integer 0 . . 65535)
// Specifies the height of the cell.
// The design cell for a font must be tall enough to accept the tallest character and greatest descender.
// Bitmap Font - Specified in PCL coordinate system dots.
// Scalable Font - Specified in design units.
this.cellHeight = 0;
// Orientation (Unsigned Byte 0 . . 255)
// Specifies the orientation of the font
// 0 portrait (0 degrees; the orientation of the raster scan of the printer)
// 1 landscape (90 degrees counterclockwise)
// 2 reverse portrait (180 degrees counterclockwise)
// 3 reverse landscape (270 degrees counterclockwise)
// Bitmap Font - Unsupported values invalidate font creation.
// Scalable Font - set to zero.
this.orientation = 0;
// Spacing (Boolean)
// Specifies the spacing of the font.
// 0 fixed spacing
// 1 proportional spacing
this.spacing = 0;
// Symbol Set (Unsigned Integer 0 . . 65535)
// Specifies the symbol set for the font.
// Symbol Set ID code = (# * 32) + (ID - 64)
// # represents the number portion of the ID selection value
// ID represents the ordinal(decimal) value of the ID character
// ex: Roman-8 8U => (8 * 32) + (85 - 64) = 277
// This field must have a value of 56 for a type 10 or 11 font (unbound Intellifont scalable) to be valid
this.symbolSet = 0;
// Pitch (Unsigned Integer 0 . . 65535)
// Pitch defines the default HMI for the font.
// Bitmap Font - Specifies the pitch of the font in quarter dots.
// Scalable Fonts - Contains the master design space width (escapement) of the font in design units.
this.pitch = 0;
// Height (Unsigned Integer 0 . . 65535)
// the height characteristic value of the font.
// Bitmap Font - Specifies the design height of the font in quarter-dots (radix dots).
// Intellifont Scalable - Specifies the master design height of the font in 1/8 points. A typical value for this field is 2000.
// TrueType Scalable - Set the Height field to zero.
this.height = 0;
// xHeight (Unsigned Integer 0 . . 65535)
// Bitmap Font - Specifies the height of the lower case “x” in quarter-dots (radix dots).
// Scalable Fonts - Specifies the distance from the baseline to the lower case “x” height in design units.
this.xHeight = 0;
// Width Type (Signed Byte -128 . . 127)
// Specifies the proportionate width of characters in the font.
// -5 Ultra Compressed
// -4 Extra Compressed
// -3 Compressed or Extra Condensed
// -2 Condensed
// 0 Normal
// 2 Expanded
// 3 Extra Expanded
// Additional width types may be added by HP.
this.widthType = 0;
// Stroke Weight (Signed Byte -128 . . 127)
// Specifies the thickness of the strokes used in designing the font.
// -7 Ultra Thin
// -6 Extra Thin
// -5 Thin
// -4 Extra Light
// -3 Light
// -2 Demi Light
// -1 Semi Light
// 0 Medium, Book, or Text
// 1 Semi Bold
// 2 Demi Bold
// 3 Bold
// 4 Extra Bold
// 5 Black
// 6 Extra Black
// 7 Ultra Black
this.strokeWeight = 0;
// Typeface (Unsigned Byte 0 . . 255)
// Typeface = Typeface Base Value + ( vendor Value * 4096)
this.typeface = {
// Vendor Number - Bits 15 - 12. This value is assigned by HP and is between decimal values 0 and 15.
// 0 Reserved
// 1 Agfa Division, Miles Inc.
// 2 Bitstream Inc.
// 3 Linotype Company
// 4 The Monotype Corporation plc
// 5 Adobe Systems Inc.
// 6-15 (Reserved)
vendor: 0,
// Typeface Family Number - Bits 11 - 0 This value is between 0 and 4095. See Appendix C in the PCL 5 Comparison Guide.
typefaceFamily: 0
};
// Serif Style (Unsigned Byte 0 . . 255)
// Specifies one of the following defined serif styles.
// for bitmap fonts:
// 0 Sans Serif Square
// 1 Sans Serif Round
// 2 Serif Line
// 3 Serif Triangle
// 4 Serif Swath
// 5 Serif Block
// 6 Serif Bracket
// 7 Rounded Bracket
// 8 Flair Serif, Modified Sans
// 9 Script Nonconnecting
// 10 Script Joining
// 11 Script Calligraphic
// 12 Script Broken Letter
// 13-63 Reserved
// for scalable fonts:
// 64 Sans Serif
// 128 Serif
// 192 Reserved
this.serifStyle = 0;
// Quality (Unsigned Byte 0 . . 255)
// This field specifies the quality of the font.
// 0 Data processing (draft)
// 1 Near Letter Quality
// 2 Letter Quality
this.quality = 0;
// Placement (Signed Byte -128 . . 127)
// Placement specifies the position of character patterns relative to the baseline.
// Scalable Font - Set the Placement field to zero.
// for bitmap fonts:
// 1 Superior
// 0 Normal
// -1 Inferior
this.placement = 0;
// Underline Position (Signed Byte -128 . . 127)
// Bitmap Font - Specifies the distance from the baseline to the top dot row of the underline in font design dots.
// Scalable Font - Set Underline Position to zero.
this.underlinePosition = 0;
// Underline Thickness (Unsigned Byte 0 . . 255)
// Specifies the thickness of the underline in font design dots for a bitmap font.
// Bitmap Font - A bitmap font prints three-dot thick underlines at 300 dpi (six-dot thick at 600 dpi).
// Scalable Font - Set Underline Thickness to zero.
this.underlineThickness = 0;
// Text Height (Unsigned Integer 0 . . 65535)
// Specifies the font’s optimum inter-line spacing. This value is typically equal to 120% of the height of the font.
// Bitmap Font - Specified in quarter-dots (radix dots).
// Scalable Fonts - Specified in design units.
this.textHeight = 0;
// Text Width (Unsigned Integer 0 . . 65535)
// Specifies the font’s average lowercase character width.
// Bitmap Font - Specified in quarter-dots (radix dots).
// Scalable Font - Specified in design units.
this.textWidth = 0;
// First Code (Unsigned Integer 0 . . 65535) / Last Code (Unsigned Integer 0 . . 65535)
// First Code specifies the character code of the first printable character in the font.
// Last Code Bound Font: Specifies the last code in the font.
// Last Code Unbound Font: specifies the maximum number of characters that can be downloaded into the font.
// Font Type First Code../..Last Code
// 0 32/127
// 1 32/127 - 160/255
// 2 0/255
// 10 Set to 0 (for unbound font)
// 11 Set to 0 (for unbound font)
this.firstCode = 0;
this.lastCode = 0;
// Pitch Extended (Unsigned Byte 0 . . 255)
// Bitmap Font - This is an addition to the Pitch field which extends the pitch an extra eight bits.
// Scalable Font - Set Pitch Extended field to zero.
this.pitchExtended = 0;
// Height Extended (Unsigned Byte 0 . . 255)
// Bitmap Font - This is an addition to the Height field which extends the height an extra eight bits.
// Scalable Font - Set The Height Extended field to zero.
this.heightExtended = 0;
// Cap Height (Unsigned Integer 0 . . 65535)
// Cap Height is a percentage of the Em of the font
// Scalable Font - Contains the cap height in design units.
this.capHeight = 0;
// Font Number (Unsigned Long Integer 0 . . 232-1)
this.fontNumber = {
nativeFormat: 0,
companyInitial: '',
vendorFontNumber: 0
};
// Font Name
// This is a 16 character ASCII field to which you may assign a font name.
this.fontName = '';
// X Resolution (Unsigned Integer 0 . . 65535)
// The X Resolution field is the pixel resolution in the X scan direction at
// which the font was designed.
this.xResolution = 0;
// Y Resolution (Unsigned Integer 0 . . 65535)
// The Y Resolution field is the pixel resolution in the Y scan direction at
// which the font was designed.
this.yResolution = 0;
// Scale Factor (Unsigned Integer 0 . . 65535)
// The Scale Factor field indicates the number of design units per Em.
this.scaleFactor = 0;
// Master Underline Position (Signed Integer -32768 . . 32767)
// The Master Underline Position is the top of the PCL floating underline
// with respect to the baseline in design units.
this.masterUnderlinePosition = 0;
// Master Underline Thickness (Unsigned Integer 0 . . 65535)
// thickness of the floating underline in design units.
this.masterUnderlineThickness = 0;
// Font Scaling Technology (Unsigned Byte 0 . . 255)
// For scalable fonts, this field species the technology to be used for font scaling.
// 0 Intellifont
// 1 TrueType
this.fontScalingTechnology = 0;
// Variety (Unsigned Byte 0 . . 255)
// For TrueType fonts, this field must be set to zero.
this.variety = 0;
// OR Threshold (Unsigned Integer 0 . . 65535)
// Formerly called the “LRE Threshold,” this is the pixel size in design
// units above which the missing pixel recovery process is switched on
// in Intellifont scaling and rasterization.
this.orThreshold = 0;
// Global Italic Angle (Signed Integer -32768 . . 32767)
// the tangent of the italic angle times 2^15 (relative to the vertical).
// Set this field to zero for upright fonts.
this.globalItalicAngle = 0;
// Global Intellifont Data Size (Unsigned Integer 0 . . 65535)
// The Global Intellifont Data Size identifies the size of the Global Intellifont data block.
this.globalIntellifontDataSize = 0;
// Global Intellifont Data
this.globalIntellifontData = 0;
// Character Complement (Array of Unsigned Byte)
this.characterComplement = [];
// Checksum
this.checksum = 0;
// Copyright
// This field contains ASCII data and is optional.
this.copyright = '';
// Segmented Font Data (Format 15)
this.segmentFontData = [];
};
font.prototype.computeStyle = function() {
var word = Buffer.alloc(2);
// Style Word = Posture + (4 x Width) + (32 x Structure)
word.writeUInt16LE(this.style.posture + this.style.width * 4 + this.style.structure * 32, 0);
return word;
};
font.prototype.computeTypeface = function() {
var word = Buffer.alloc(2);
// Typeface = Typeface Base Value + ( vendor Value * 4096)
word.writeUInt16LE(this.typeface.typefaceFamily + this.typeface.vendor * 4096, 0);
return word;
};
font.prototype.computeFontNumber = function() {
var buffer = Buffer.alloc(4);
var first = this.fontNumber.companyInitial.toUpperCase().charCodeAt(0) || 0;
if (this.fontNumber.nativeFormat) {
first += 128;
}
buffer.writeUInt8(first, 0);
var vendorFontNumberHex = this.fontNumber.vendorFontNumber.toString(16);
buffer.writeUInt8(parseInt(vendorFontNumberHex.slice(-6, -4), 16) || 0, 1);
buffer.writeUInt8(parseInt(vendorFontNumberHex.slice(-4, -2), 16) || 0, 2);
buffer.writeUInt8(parseInt(vendorFontNumberHex.slice(-2), 16) || 0, 3);
return buffer;
};
font.prototype.layoutRun = function(text, features) {
var run = this.font.layout(text, features);
// Normalize position values
for (var i = 0; i < run.positions.length; i++) {
var position = run.positions[i];
for (var key in position) {
position[key] *= this.scale;
}
position.advanceWidth = run.glyphs[i].advanceWidth * this.scale;
}
return run;
};
font.prototype.layoutCached = function(text) {
if (!this.layoutCache) {
return this.layoutRun(text);
}
var cached;
if ((cached = this.layoutCache[text])) {
return cached;
}
var run = this.layoutRun(text);
this.layoutCache[text] = run;
return run;
};
font.prototype.layout = function(text, features, onlyWidth) {
// Skip the cache if any user defined features are applied
if (features) {
return this.layoutRun(text, features);
}
var glyphs = onlyWidth ? null : [];
var positions = onlyWidth ? null : [];
var advanceWidth = 0;
// Split the string by words to increase cache efficiency.
// For this purpose, spaces and tabs are a good enough delimeter.
var last = 0;
var index = 0;
while (index <= text.length) {
var needle;
if (
(index === text.length && last < index) ||
((needle = text.charAt(index)), [' ', '\t'].includes(needle))
) {
var run = this.layoutCached(text.slice(last, ++index));
if (!onlyWidth) {
glyphs = glyphs.concat(run.glyphs);
positions = positions.concat(run.positions);
}
advanceWidth += run.advanceWidth;
last = index;
} else {
index++;
}
}
return { glyphs, positions, advanceWidth };
};
font.prototype.lineHeight = function(size, includeGap) {
if (includeGap == null) {
includeGap = false;
}
var gap = includeGap ? this.lineGap : 0;
return ((this.ascender + gap - this.descender) / 1000) * size;
};
font.prototype.encode = function(text, features) {
var { glyphs, positions } = this.layout(text, features);
var res = [];
for (var i = 0; i < glyphs.length; i++) {
var glyph = glyphs[i];
var gid = this.subset.includeGlyph(glyph.id);
res.push(text[i]);
if (this.widths[gid] == null) {
this.widths[gid] = glyph.advanceWidth * this.scale;
}
if (this.unicode[gid] == null) {
this.unicode[gid] = glyph.codePoints;
}
}
return [res, positions];
};
font.prototype.widthOfString = function(string, size, features) {
var width = this.layout(string, features, true).advanceWidth;
var scale = size / 1000;
return width * scale;
};
module.exports = font;