UNPKG

@aeolun/muhammara

Version:

Create, read and modify PDF files and streams. A drop in replacement for hummusjs PDF library

274 lines (230 loc) 7.13 kB
const { xObjectForm } = require("./xObjectForm"); exports._getPathOptions = function _getPathOptions( options = {}, originX, originY ) { this.current = this.current || {}; const colorspace = options.colorspace || this.options.colorspace; const colorName = options.colorName; const pathOptions = { originX, originY, font: this._getFont(options), size: options.size || this.current.defaultFontSize, charSpace: options.charSpace || 0, underline: false, strikeOut: false, color: this._transformColor(options.color, { colorspace: colorspace, colorName: options.colorName, }), colorspace, colorName, colorArray: [], lineCap: this._lineCap(), lineJoin: this._lineJoin(), miterLimit: 1.414, width: 2, align: options.align, }; if (options.opacity == void 0 || isNaN(options.opacity)) { options.opacity = 1; } else { options.opacity = options.opacity < 0 ? 0 : options.opacity > 1 ? 1 : options.opacity; } pathOptions.opacity = options.opacity; const extGStates = this._createExtGStates(options.opacity); pathOptions.strokeGsId = extGStates.stroke; pathOptions.fillGsId = extGStates.fill; if (options.size || options.fontSize) { const size = options.size || options.fontSize; if (!isNaN(size)) { pathOptions.size = size <= 0 ? 1 : size; } } if (options.width || options.lineWidth) { const width = options.width || options.lineWidth; if (!isNaN(width)) { pathOptions.width = width <= 0 ? 1 : width; } } const colorOpts = { colorspace: colorspace, wantColorModel: true, colorName: options.colorName, }; if (options.stroke) { pathOptions.strokeModel = this._transformColor(options.stroke, colorOpts); pathOptions.stroke = pathOptions.strokeModel.color; } if (options.fill) { pathOptions.fillModel = this._transformColor(options.fill, colorOpts); pathOptions.fill = pathOptions.fillModel.color; } pathOptions.colorModel = this._transformColor( options.color || options.colour, colorOpts ); pathOptions.color = pathOptions.colorModel.color; pathOptions.colorspace = pathOptions.colorModel.colorspace; // rotation if (options.rotation !== void 0) { const rotation = parseFloat(options.rotation); pathOptions.rotation = rotation; pathOptions.rotationOrigin = options.rotationOrigin || null; } // skew if (options.skewX !== void 0) { pathOptions.skewX = options.skewX; } if (options.skewY != void 0) { pathOptions.skewY = options.skewY; } // Page 127 of PDF 1.7 specification pathOptions.dash = Array.isArray(options.dash) ? options.dash : []; pathOptions.dashPhase = !isNaN(options.dashPhase) ? options.dashPhase : 0; if (pathOptions.dash[0] == 0 && pathOptions.dash[1] == 0) { pathOptions.dash = []; // no dash, solid unbroken line pathOptions.dashPhase = 0; } // Page 125-126 of PDF 1.7 specification if (options.lineJoin !== void 0) { pathOptions.lineJoin = this._lineJoin(options.lineJoin); } if (options.lineCap !== void 0) { pathOptions.lineCap = this._lineCap(options.lineCap); } if (options.miterLimit !== void 0) { if (!isNaN(options.miterLimit)) { pathOptions.miterLimit = options.miterLimit; } } return pathOptions; }; exports._getDistance = function _getDistance(coordA, coordB) { const disX = Math.abs(coordB[0] - coordA[0]); const disY = Math.abs(coordB[1] - coordB[1]); const distance = Math.sqrt(disX * disX + disY * disY); return distance; }; exports._getTransformParams = getTransformParams; function getTransformParams(inAngle, x, y, offsetX, offsetY) { const theta = toRadians(inAngle); const cosTheta = Math.cos(theta); const sinTheta = Math.sin(theta); const nx = cosTheta * -offsetX + sinTheta * -offsetY; const ny = cosTheta * -offsetY - sinTheta * -offsetX; return [cosTheta, -sinTheta, sinTheta, cosTheta, x - nx, y - ny]; } exports._setRotationContext = function _setRotationTransform( context, x, y, options ) { const deltaY = options.deltaY ? options.deltaY : 0; if (options.rotation === undefined || options.rotation === 0) { context.cm(1, 0, 0, 1, x, y - deltaY); // no rotation } else { let rotationOrigin; if (!hasRotation(options)) { rotationOrigin = [options.originX, options.originY]; // supply default } else { if (options.useGivenCoords) { rotationOrigin = options.rotationOrigin; } else { const orig = this._calibrateCoordinate( options.rotationOrigin[0], options.rotationOrigin[1] ); rotationOrigin = [orig.nx, orig.ny]; } } const rm = getTransformParams( // rotation matrix options.rotation, rotationOrigin[0], rotationOrigin[1], x - rotationOrigin[0], y - rotationOrigin[1] - deltaY ); context.cm(rm[0], rm[1], rm[2], rm[3], rm[4], rm[5]); } }; function hasRotation(options) { return ( options.rotationOrigin && Array.isArray(options.rotationOrigin) && options.rotationOrigin.length === 2 ); } function toRadians(angle) { return 2 * Math.PI * ((angle % 360) / 360); } function getSkewTransform(skewXAngle = 0, skewYAngle = 0) { const alpha = toRadians(skewXAngle); const beta = toRadians(skewYAngle); const tanAlpha = Math.tan(alpha); const tanBeta = Math.tan(beta); return [1, tanAlpha, tanBeta, 1, 0, 0]; } exports._setSkewContext = function _setSkewTransform(context, options) { if (options.skewX || options.skewY) { const sm = getSkewTransform(options.skewX, options.skewY); context.cm(sm[0], sm[1], sm[2], sm[3], sm[4], sm[5]); } }; exports._setScalingTransform = function _setScalingTransform(context, options) { if (options.ratio) { context.cm(options.ratio[0], 0, 0, options.ratio[1], 0, 0); } }; exports._drawObject = function _drawObject( self, x, y, width, height, options, callback ) { let xObject = options.xObject; // allows caller to supply existing form object if (!xObject) { self.pauseContext(); xObject = new xObjectForm(self.writer, width, height); const xObjectCtx = xObject.getContentContext(); xObjectCtx.q(); callback(xObjectCtx, xObject); xObjectCtx.Q(); xObject.end(); self.resumeContext(); } const context = self.pageContext; context.q(); self._setRotationContext(context, x, y, options); self._setSkewContext(context, options); self._setScalingTransform(context, options); context.doXObject(xObject).Q(); }; exports._lineCap = function _lineCap(type) { const round = 1; let cap = round; if (type) { const capStyle = ["butt", "round", "square"]; const capType = capStyle.indexOf(type); cap = capType !== -1 ? capType : round; } return cap; }; exports._lineJoin = function _lineJoin(type) { const round = 1; let join = round; if (type) { const joinStyle = ["miter", "round", "bevel"]; const joinType = joinStyle.indexOf(type); join = joinType !== -1 ? joinType : round; } return join; };