dompdf.js 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/README.md +168 -79
  3. package/dist/dom/element-container.d.ts +4 -2
  4. package/dist/dompdf.esm.js +614 -462
  5. package/dist/dompdf.esm.js.map +1 -1
  6. package/dist/dompdf.js +614 -462
  7. package/dist/dompdf.js.map +1 -1
  8. package/dist/index.d.ts +1 -3
  9. package/dist/lib/__tests__/index.js.map +1 -1
  10. package/dist/lib/css/property-descriptors/border-style.js.map +1 -1
  11. package/dist/lib/css/types/color.js.map +1 -1
  12. package/dist/lib/dom/element-container.js +3 -1
  13. package/dist/lib/dom/element-container.js.map +1 -1
  14. package/dist/lib/dom/node-parser.js +15 -7
  15. package/dist/lib/dom/node-parser.js.map +1 -1
  16. package/dist/lib/dom/replaced-elements/iframe-element-container.js.map +1 -1
  17. package/dist/lib/index.js +107 -42
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/render/canvas/foreignobject-renderer.js.map +1 -1
  20. package/dist/lib/render/canvas/pdf-renderer.js +276 -472
  21. package/dist/lib/render/canvas/pdf-renderer.js.map +1 -1
  22. package/dist/lib/render/page-format-map.js +54 -0
  23. package/dist/lib/render/page-format-map.js.map +1 -0
  24. package/dist/lib/render/paginate.js +172 -0
  25. package/dist/lib/render/paginate.js.map +1 -0
  26. package/dist/render/canvas/pdf-renderer.d.ts +41 -16
  27. package/dist/render/page-format-map.d.ts +4 -0
  28. package/dist/render/paginate.d.ts +3 -0
  29. package/dist/types/dom/element-container.d.ts +4 -2
  30. package/dist/types/index.d.ts +1 -3
  31. package/dist/types/render/canvas/pdf-renderer.d.ts +41 -16
  32. package/dist/types/render/page-format-map.d.ts +4 -0
  33. package/dist/types/render/paginate.d.ts +3 -0
  34. package/package.json +135 -134
  35. package/dist/lib/render/canvas/canvas-renderer2.js +0 -1415
  36. package/dist/lib/render/canvas/canvas-renderer2.js.map +0 -1
  37. package/dist/render/canvas/canvas-renderer2.d.ts +0 -81
  38. package/dist/types/render/canvas/canvas-renderer2.d.ts +0 -81
@@ -1,1415 +0,0 @@
1
- "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
- return new (P || (P = Promise))(function (resolve, reject) {
20
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
- step((generator = generator.apply(thisArg, _arguments || [])).next());
24
- });
25
- };
26
- var __generator = (this && this.__generator) || function (thisArg, body) {
27
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
- function verb(n) { return function (v) { return step([n, v]); }; }
30
- function step(op) {
31
- if (f) throw new TypeError("Generator is already executing.");
32
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
- if (y = 0, t) op = [op[0] & 2, t.value];
35
- switch (op[0]) {
36
- case 0: case 1: t = op; break;
37
- case 4: _.label++; return { value: op[1], done: false };
38
- case 5: _.label++; y = op[1]; op = [0]; continue;
39
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
- default:
41
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
- if (t[2]) _.ops.pop();
46
- _.trys.pop(); continue;
47
- }
48
- op = body.call(thisArg, _);
49
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
- }
52
- };
53
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
54
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
55
- if (ar || !(i in from)) {
56
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
57
- ar[i] = from[i];
58
- }
59
- }
60
- return to.concat(ar || Array.prototype.slice.call(from));
61
- };
62
- Object.defineProperty(exports, "__esModule", { value: true });
63
- exports.CanvasRenderer = void 0;
64
- var jspdf_1 = require("jspdf"); // 用于生成PDF文档
65
- // import "../../SourceHanSansSC-Normal-Min-normal"; // 导入思源黑体
66
- // import "../../SourceHanSansCN-Medium-normal"; // 导入阿里巴巴普惠体字体
67
- var bitwise_1 = require("../../core/bitwise"); // 位运算工具函数
68
- var bounds_1 = require("../../css/layout/bounds"); // 边界计算
69
- var text_1 = require("../../css/layout/text"); // 文本分段和边界
70
- var line_height_1 = require("../../css/property-descriptors/line-height"); // 行高计算
71
- var parser_1 = require("../../css/syntax/parser"); // 维度标记判断
72
- var color_1 = require("../../css/types/color"); // 颜色相关工具
73
- var gradient_1 = require("../../css/types/functions/gradient"); // 渐变计算
74
- var image_1 = require("../../css/types/image"); // 图片类型
75
- var length_percentage_1 = require("../../css/types/length-percentage"); // 长度百分比
76
- var select_element_container_1 = require("../../dom/elements/select-element-container"); // Select元素容器
77
- var textarea_element_container_1 = require("../../dom/elements/textarea-element-container"); // Textarea元素容器
78
- var canvas_element_container_1 = require("../../dom/replaced-elements/canvas-element-container"); // Canvas元素容器
79
- var iframe_element_container_1 = require("../../dom/replaced-elements/iframe-element-container"); // IFrame元素容器
80
- var image_element_container_1 = require("../../dom/replaced-elements/image-element-container"); // Image元素容器
81
- var input_element_container_1 = require("../../dom/replaced-elements/input-element-container"); // Input元素容器
82
- var svg_element_container_1 = require("../../dom/replaced-elements/svg-element-container"); // SVG元素容器
83
- var background_1 = require("../background"); // 背景渲染计算
84
- var bezier_curve_1 = require("../bezier-curve"); // 贝塞尔曲线
85
- var border_1 = require("../border"); // 边框路径解析
86
- var bound_curves_1 = require("../bound-curves"); // 边界曲线计算
87
- var box_sizing_1 = require("../box-sizing"); // 内容盒模型
88
- var effects_1 = require("../effects"); // 效果相关
89
- var font_metrics_1 = require("../font-metrics"); // 字体度量
90
- var path_1 = require("../path"); // 路径变换
91
- var renderer_1 = require("../renderer"); // 渲染器基类
92
- var stacking_context_1 = require("../stacking-context"); // 堆叠上下文
93
- var vector_1 = require("../vector"); // 向量
94
- // 遮罩偏移常量
95
- var MASK_OFFSET = 10000;
96
- var leftMargin = 0;
97
- var topMargin = 0;
98
- // Canvas渲染器类,继承自Renderer
99
- var CanvasRenderer = /** @class */ (function (_super) {
100
- __extends(CanvasRenderer, _super);
101
- // 构造函数
102
- function CanvasRenderer(context, options) {
103
- var _this =
104
- // console.log('options参数',options,context)
105
- _super.call(this, context, options) || this;
106
- _this._activeEffects = []; // 活动效果数组
107
- _this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
108
- _this.ctx = _this.canvas.getContext('2d');
109
- // 计算页面尺寸并转换为 pt 单位 (1pt = 1/72 inch, 1px = 1/96 inch)
110
- var pxToPt = function (px) { return px * (72 / 96); };
111
- //
112
- var pageWidth = pxToPt(options.width);
113
- var pageHeight = pxToPt(options.height);
114
- console.log('pageWidth', pageWidth);
115
- console.log('pageHeight', pageHeight);
116
- // 初始化 jsPDF
117
- _this.jspdfCtx = new jspdf_1.jsPDF({
118
- orientation: pageWidth > pageHeight ? 'landscape' : 'portrait',
119
- unit: 'pt',
120
- format: [pageWidth, pageHeight],
121
- hotfixes: ["px_scaling"]
122
- });
123
- // 确保字体已加载并注册到 jsPDF
124
- if (options.fontConfig) {
125
- try {
126
- _this.loadFont();
127
- }
128
- catch (error) {
129
- console.warn('Failed to set font:', error);
130
- // 如果设置失败,使用默认字体
131
- _this.jspdfCtx.setFont('Helvetica');
132
- }
133
- }
134
- // this.jspdfCtx.setFont('SourceHanSansSC-Normal-Min');
135
- // 将 pxToPt 保存为实例属性,以便其他方法使用
136
- _this.pxToPt = pxToPt;
137
- if (!options.canvas) {
138
- _this.canvas.width = Math.floor(options.width * options.scale);
139
- _this.canvas.height = Math.floor(options.height * options.scale);
140
- _this.canvas.style.width = "".concat(options.width, "px");
141
- _this.canvas.style.height = "".concat(options.height, "px");
142
- }
143
- _this.fontMetrics = new font_metrics_1.FontMetrics(document);
144
- _this.ctx.scale(_this.options.scale, _this.options.scale);
145
- _this.ctx.translate(-options.x, -options.y);
146
- _this.ctx.textBaseline = 'bottom';
147
- _this._activeEffects = [];
148
- _this.context.logger.debug("Canvas renderer initialized (".concat(options.width, "x").concat(options.height, ") with scale ").concat(options.scale));
149
- return _this;
150
- }
151
- CanvasRenderer.prototype.loadFont = function () {
152
- return __awaiter(this, void 0, void 0, function () {
153
- var fontData;
154
- return __generator(this, function (_a) {
155
- switch (_a.label) {
156
- case 0:
157
- if (!this.options.fontConfig.fontBase64) return [3 /*break*/, 1];
158
- // 直接使用 Base64 编码
159
- fontData = this.options.fontConfig.fontBase64;
160
- return [3 /*break*/, 3];
161
- case 1:
162
- if (!this.options.fontConfig.fontUrl) return [3 /*break*/, 3];
163
- return [4 /*yield*/, this.loadFontFromURL(this.options.fontConfig.fontUrl)];
164
- case 2:
165
- fontData = _a.sent();
166
- _a.label = 3;
167
- case 3:
168
- // console.log('fontData',fontData)
169
- // 将字体添加到 jsPDF
170
- this.addFontToJsPDF(fontData);
171
- return [2 /*return*/];
172
- }
173
- });
174
- });
175
- };
176
- CanvasRenderer.prototype.loadFontFromURL = function (url) {
177
- return __awaiter(this, void 0, void 0, function () {
178
- var response, blob;
179
- return __generator(this, function (_a) {
180
- switch (_a.label) {
181
- case 0: return [4 /*yield*/, fetch(url, {
182
- mode: 'no-cors',
183
- headers: {
184
- 'Content-Type': 'font/ttf'
185
- }
186
- })];
187
- case 1:
188
- response = _a.sent();
189
- return [4 /*yield*/, response.blob()];
190
- case 2:
191
- blob = _a.sent();
192
- // const fontUrl = URL.createObjectURL(blob);
193
- // console.log('response', blob, fontUrl)
194
- // 注意:no-cors 模式下无法读取响应内容!
195
- // const blob = await response.blob();
196
- return [2 /*return*/, new Promise(function (resolve, reject) {
197
- var reader = new FileReader();
198
- reader.onload = function () { return resolve(reader.result.split(',')[1]); }; // 提取 Base64 数据
199
- reader.onerror = function () { return reject(new Error('字体文件读取失败')); };
200
- reader.readAsDataURL(blob);
201
- })];
202
- }
203
- });
204
- });
205
- };
206
- CanvasRenderer.prototype.addFontToJsPDF = function (fontData) {
207
- var _a = this.options.fontConfig, fontFamily = _a.fontFamily, fontWeight = _a.fontWeight, fontStyle = _a.fontStyle;
208
- this.jspdfCtx.addFileToVFS("".concat(fontFamily, ".ttf"), fontData); // 将字体添加到虚拟文件系统
209
- this.jspdfCtx.addFont("".concat(fontFamily, ".ttf"), fontFamily, fontStyle, fontWeight); // 注册字体
210
- this.jspdfCtx.setFont(fontFamily); // 设置当前字体
211
- };
212
- // 应用效果数组
213
- CanvasRenderer.prototype.applyEffects = function (effects) {
214
- var _this = this;
215
- while (this._activeEffects.length) {
216
- this.popEffect();
217
- }
218
- effects.forEach(function (effect) { return _this.applyEffect(effect); });
219
- };
220
- CanvasRenderer.prototype.pxToMm = function (px) {
221
- var mmPerInch = 25.4;
222
- var pxPerInch = 96;
223
- return (px * mmPerInch) / pxPerInch;
224
- };
225
- // 应用单个效果
226
- CanvasRenderer.prototype.applyEffect = function (effect) {
227
- this.ctx.save();
228
- if ((0, effects_1.isOpacityEffect)(effect)) {
229
- this.ctx.globalAlpha = effect.opacity;
230
- }
231
- if ((0, effects_1.isTransformEffect)(effect)) {
232
- this.ctx.translate(effect.offsetX, effect.offsetY);
233
- this.ctx.transform(effect.matrix[0], effect.matrix[1], effect.matrix[2], effect.matrix[3], effect.matrix[4], effect.matrix[5]);
234
- this.ctx.translate(-effect.offsetX, -effect.offsetY);
235
- }
236
- if ((0, effects_1.isClipEffect)(effect)) {
237
- this.path(effect.path);
238
- this.ctx.clip();
239
- }
240
- this._activeEffects.push(effect);
241
- };
242
- // 移除最后应用的效果
243
- CanvasRenderer.prototype.popEffect = function () {
244
- this._activeEffects.pop();
245
- this.ctx.restore();
246
- };
247
- // 渲染堆叠上下文
248
- CanvasRenderer.prototype.renderStack = function (stack) {
249
- return __awaiter(this, void 0, void 0, function () {
250
- var styles;
251
- return __generator(this, function (_a) {
252
- switch (_a.label) {
253
- case 0:
254
- styles = stack.element.container.styles;
255
- if (!styles.isVisible()) return [3 /*break*/, 2];
256
- return [4 /*yield*/, this.renderStackContent(stack)];
257
- case 1:
258
- _a.sent();
259
- return [3 /*break*/, 3];
260
- case 2:
261
- console.log('不渲染', styles.isVisible());
262
- _a.label = 3;
263
- case 3: return [2 /*return*/];
264
- }
265
- });
266
- });
267
- };
268
- // 渲染节点
269
- CanvasRenderer.prototype.renderNode = function (paint) {
270
- return __awaiter(this, void 0, void 0, function () {
271
- return __generator(this, function (_a) {
272
- switch (_a.label) {
273
- case 0:
274
- if ((0, bitwise_1.contains)(paint.container.flags, 16 /* FLAGS.DEBUG_RENDER */)) {
275
- debugger;
276
- }
277
- if (!paint.container.styles.isVisible()) return [3 /*break*/, 3];
278
- return [4 /*yield*/, this.renderNodeBackgroundAndBorders(paint)];
279
- case 1:
280
- _a.sent();
281
- return [4 /*yield*/, this.renderNodeContent(paint)];
282
- case 2:
283
- _a.sent();
284
- _a.label = 3;
285
- case 3: return [2 /*return*/];
286
- }
287
- });
288
- });
289
- };
290
- // 渲染带有字母间距的文本
291
- CanvasRenderer.prototype.renderTextWithLetterSpacing = function (text, letterSpacing, baseline) {
292
- var _this = this;
293
- if (letterSpacing === 0) {
294
- var extraPadding = text.text.startsWith('•') ? -15 : 0;
295
- var extraPaddingPt = text.text.startsWith('•') ? (text.bounds.height + 2) / 2 : 0;
296
- this.ctx.fillText(text.text, text.bounds.left + extraPadding, text.bounds.top + baseline);
297
- // 转换坐标为 pt 单位
298
- var leftPt = this.pxToPt(text.bounds.left + extraPadding - leftMargin);
299
- var topPt = this.pxToPt(text.bounds.top + baseline + extraPaddingPt - topMargin);
300
- // console.log('绘制文字',extraPadding,leftPt,text.bounds.left + extraPadding,topPt,text.bounds.top + baseline + extraPaddingPt,text)
301
- // 设置PDF文字颜色
302
- this.jspdfCtx.text(text.text, leftPt, topPt);
303
- }
304
- else {
305
- var letters = (0, text_1.segmentGraphemes)(text.text);
306
- var startX = text.bounds.left;
307
- if (letters[0] === '•') {
308
- startX -= 8;
309
- }
310
- letters.reduce(function (left, letter) {
311
- _this.ctx.fillText(letter, left, text.bounds.top + baseline);
312
- _this.jspdfCtx.text(letter, _this.pxToPt(left - leftMargin), _this.pxToPt(text.bounds.top + baseline - topMargin));
313
- // console.log('绘制文字2',left,text.bounds.top + baseline)
314
- return _this.pxToPt(left + _this.ctx.measureText(letter).width);
315
- }, startX);
316
- }
317
- };
318
- // 创建字体样式
319
- CanvasRenderer.prototype.createFontStyle = function (styles) {
320
- var fontVariant = styles.fontVariant
321
- .filter(function (variant) { return variant === 'normal' || variant === 'small-caps'; })
322
- .join('');
323
- var fontFamily = fixIOSSystemFonts(styles.fontFamily).join(', ');
324
- var fontSize = (0, parser_1.isDimensionToken)(styles.fontSize)
325
- ? "".concat(styles.fontSize.number).concat(styles.fontSize.unit)
326
- : "".concat(styles.fontSize.number, "px");
327
- return [
328
- [styles.fontStyle, fontVariant, styles.fontWeight, fontSize, fontFamily].join(' '),
329
- fontFamily,
330
- fontSize
331
- ];
332
- };
333
- // 添加一个新的颜色转换函数
334
- CanvasRenderer.prototype.convertColor = function (color) {
335
- // 如果是透明色,返回白色
336
- if ((0, color_1.isTransparent)(color)) {
337
- return '#FFFFFF';
338
- }
339
- // 将 rgba 转换为 rgb
340
- // 从32位整数中提取RGB分量
341
- var r = 0xff & (color >> 24);
342
- var g = 0xff & (color >> 16);
343
- var b = 0xff & (color >> 8);
344
- return "#".concat(r.toString(16).padStart(2, '0')).concat(g.toString(16).padStart(2, '0')).concat(b.toString(16).padStart(2, '0'));
345
- // 其他颜色格式直接使用 asString
346
- return (0, color_1.asString)(color);
347
- };
348
- // 渲染文本节点
349
- CanvasRenderer.prototype.renderTextNode = function (text, styles) {
350
- return __awaiter(this, void 0, void 0, function () {
351
- var _a, font, fontFamily, fontSize, fontSizePt, _b, baseline, middle, paintOrder, newTextBounds;
352
- var _this = this;
353
- return __generator(this, function (_c) {
354
- _a = this.createFontStyle(styles), font = _a[0], fontFamily = _a[1], fontSize = _a[2];
355
- this.ctx.font = font;
356
- fontSizePt = this.pxToPt(styles.fontSize.number);
357
- this.jspdfCtx.setFontSize(fontSizePt);
358
- this.ctx.direction = styles.direction === 1 /* DIRECTION.RTL */ ? 'rtl' : 'ltr';
359
- this.ctx.textAlign = 'left';
360
- this.ctx.textBaseline = 'alphabetic';
361
- _b = this.fontMetrics.getMetrics(fontFamily, fontSize), baseline = _b.baseline, middle = _b.middle;
362
- paintOrder = styles.paintOrder;
363
- newTextBounds = [];
364
- text.textBounds.forEach(function (text) {
365
- var hasText = newTextBounds.filter(function (el) { return el.bounds.top == text.bounds.top; });
366
- if (hasText.length > 0) {
367
- hasText[0].text += text.text;
368
- }
369
- else {
370
- newTextBounds = __spreadArray(__spreadArray([], newTextBounds, true), [text], false);
371
- }
372
- });
373
- text.textBounds = newTextBounds;
374
- // console.log(newTextBounds)
375
- text.textBounds.forEach(function (text) {
376
- paintOrder.forEach(function (paintOrderLayer) {
377
- switch (paintOrderLayer) {
378
- case 0 /* PAINT_ORDER_LAYER.FILL */:
379
- // console.log('PAINT_ORDER_LAYER.FILL',paintOrderLayer,PAINT_ORDER_LAYER.FILL)
380
- // console.log('text.text颜色',styles.color,asString(styles.color))
381
- _this.ctx.fillStyle = _this.convertColor(styles.color);
382
- _this.jspdfCtx.setTextColor(_this.convertColor(styles.color)); // 设置颜色
383
- _this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline);
384
- var textShadows = styles.textShadow;
385
- if (textShadows.length && text.text.trim().length) {
386
- textShadows
387
- .slice(0)
388
- .reverse()
389
- .forEach(function (textShadow) {
390
- _this.ctx.shadowColor = _this.convertColor(textShadow.color);
391
- _this.ctx.shadowOffsetX = textShadow.offsetX.number * _this.options.scale;
392
- _this.ctx.shadowOffsetY = textShadow.offsetY.number;
393
- _this.ctx.shadowBlur = textShadow.blur.number;
394
- _this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline);
395
- _this.jspdfCtx.setTextColor(_this.convertColor(textShadow.color)); // 设置颜色
396
- });
397
- _this.ctx.shadowColor = '';
398
- _this.ctx.shadowOffsetX = 0;
399
- _this.ctx.shadowOffsetY = 0;
400
- _this.ctx.shadowBlur = 0;
401
- }
402
- if (styles.textDecorationLine.length) {
403
- _this.ctx.fillStyle = _this.convertColor(styles.textDecorationColor || styles.color);
404
- styles.textDecorationLine.forEach(function (textDecorationLine) {
405
- switch (textDecorationLine) {
406
- case 1 /* TEXT_DECORATION_LINE.UNDERLINE */:
407
- // Draws a line at the baseline of the font
408
- // TODO As some browsers display the line as more than 1px if the font-size is big,
409
- // need to take that into account both in position and size
410
- _this.ctx.fillRect(text.bounds.left, Math.round(text.bounds.top + baseline), text.bounds.width, 1);
411
- break;
412
- case 2 /* TEXT_DECORATION_LINE.OVERLINE */:
413
- _this.ctx.fillRect(text.bounds.left, Math.round(text.bounds.top), text.bounds.width, 1);
414
- break;
415
- case 3 /* TEXT_DECORATION_LINE.LINE_THROUGH */:
416
- // TODO try and find exact position for line-through
417
- _this.ctx.fillRect(text.bounds.left, Math.ceil(text.bounds.top + middle), text.bounds.width, 1);
418
- break;
419
- }
420
- });
421
- }
422
- break;
423
- case 1 /* PAINT_ORDER_LAYER.STROKE */:
424
- // console.log('PAINT_ORDER_LAYER.STROKE',paintOrderLayer,PAINT_ORDER_LAYER.STROKE)
425
- if (styles.webkitTextStrokeWidth && text.text.trim().length) {
426
- _this.ctx.strokeStyle = _this.convertColor(styles.webkitTextStrokeColor);
427
- _this.ctx.lineWidth = styles.webkitTextStrokeWidth;
428
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
429
- _this.ctx.lineJoin = !!window.chrome ? 'miter' : 'round';
430
- _this.ctx.strokeText(text.text, text.bounds.left, text.bounds.top + baseline);
431
- }
432
- _this.ctx.strokeStyle = '';
433
- _this.ctx.lineWidth = 0;
434
- _this.ctx.lineJoin = 'miter';
435
- break;
436
- }
437
- });
438
- });
439
- return [2 /*return*/];
440
- });
441
- });
442
- };
443
- // 渲染替换元素(如图片、canvas等)
444
- // 渲染替换元素(如图片、canvas等)的方法
445
- CanvasRenderer.prototype.renderReplacedElement = function (container, curves, image, type) {
446
- if (!image || container.intrinsicWidth <= 0 || container.intrinsicHeight <= 0) {
447
- return;
448
- }
449
- var box = (0, box_sizing_1.contentBox)(container);
450
- var path = (0, bound_curves_1.calculatePaddingBoxPath)(curves);
451
- this.path(path);
452
- this.ctx.save();
453
- this.ctx.clip();
454
- // 计算图片在PDF中的位置和尺寸
455
- var x = this.pxToPt(box.left - leftMargin);
456
- var y = this.pxToPt(box.top - topMargin);
457
- var width = this.pxToPt(box.width);
458
- var height = this.pxToPt(box.height);
459
- try {
460
- // Canvas 处理
461
- if (type === 'canvas') {
462
- var canvas = image;
463
- var imageData = canvas.toDataURL('image/jpeg', 0.95);
464
- try {
465
- this.jspdfCtx.addImage({
466
- imageData: imageData,
467
- format: 'JPEG',
468
- x: x,
469
- y: y,
470
- w: width,
471
- h: height
472
- });
473
- }
474
- catch (error) {
475
- console.error('Failed to add canvas image:', error);
476
- }
477
- }
478
- // SVG 和普通图片处理
479
- else {
480
- var imageData = void 0;
481
- if (type === 'svg') {
482
- // 对于 SVG,需要特殊处理
483
- var svgElement = container;
484
- imageData = svgElement.svg;
485
- try {
486
- this.jspdfCtx.addImage({
487
- imageData: imageData,
488
- format: 'SVG',
489
- x: x,
490
- y: y,
491
- w: width,
492
- h: height
493
- });
494
- }
495
- catch (error) {
496
- console.error('Failed to add SVG image:', error);
497
- }
498
- }
499
- else {
500
- // 创建临时 canvas 来处理图片
501
- var tempCanvas = document.createElement('canvas');
502
- tempCanvas.width = container.intrinsicWidth;
503
- tempCanvas.height = container.intrinsicHeight;
504
- var tempCtx = tempCanvas.getContext('2d');
505
- if (tempCtx) {
506
- tempCtx.drawImage(image, 0, 0);
507
- imageData = tempCanvas.toDataURL('image/jpeg', 0.95);
508
- try {
509
- this.jspdfCtx.addImage({
510
- imageData: imageData,
511
- format: 'JPEG',
512
- x: x,
513
- y: y,
514
- w: width,
515
- h: height
516
- });
517
- }
518
- catch (error) {
519
- console.error('Failed to add image:', error);
520
- }
521
- }
522
- else {
523
- throw new Error('Failed to get canvas context');
524
- }
525
- }
526
- }
527
- }
528
- catch (error) {
529
- console.error("Error rendering ".concat(type, ":"), error);
530
- }
531
- this.ctx.restore();
532
- };
533
- // 渲染节点内容
534
- // 渲染节点内容的异步方法
535
- CanvasRenderer.prototype.renderNodeContent = function (paint) {
536
- return __awaiter(this, void 0, void 0, function () {
537
- var container, curves, styles, _i, _a, child, image, e_1, image, e_2, iframeRenderer, canvas, size, _b, fontFamily, fontSize, baseline, bounds, x, textBounds, img, image, url, e_3, fontFamily, bounds;
538
- return __generator(this, function (_c) {
539
- switch (_c.label) {
540
- case 0:
541
- // 应用内容效果
542
- this.applyEffects(paint.getEffects(4 /* EffectTarget.CONTENT */));
543
- container = paint.container;
544
- curves = paint.curves;
545
- styles = container.styles;
546
- // console.log('stylescontainer',styles,container)
547
- if (!leftMargin) {
548
- leftMargin = container.bounds.left;
549
- }
550
- if (!topMargin) {
551
- topMargin = container.bounds.top;
552
- }
553
- _i = 0, _a = container.textNodes;
554
- _c.label = 1;
555
- case 1:
556
- if (!(_i < _a.length)) return [3 /*break*/, 4];
557
- child = _a[_i];
558
- return [4 /*yield*/, this.renderTextNode(child, styles)];
559
- case 2:
560
- _c.sent();
561
- _c.label = 3;
562
- case 3:
563
- _i++;
564
- return [3 /*break*/, 1];
565
- case 4:
566
- if (!(container instanceof image_element_container_1.ImageElementContainer)) return [3 /*break*/, 8];
567
- _c.label = 5;
568
- case 5:
569
- _c.trys.push([5, 7, , 8]);
570
- return [4 /*yield*/, this.context.cache.match(container.src)];
571
- case 6:
572
- image = _c.sent();
573
- this.renderReplacedElement(container, curves, image, 'image');
574
- return [3 /*break*/, 8];
575
- case 7:
576
- e_1 = _c.sent();
577
- this.context.logger.error("Error loading image ".concat(container.src));
578
- return [3 /*break*/, 8];
579
- case 8:
580
- // 处理Canvas元素
581
- if (container instanceof canvas_element_container_1.CanvasElementContainer) {
582
- this.renderReplacedElement(container, curves, container.canvas, 'canvas');
583
- }
584
- if (!(container instanceof svg_element_container_1.SVGElementContainer)) return [3 /*break*/, 12];
585
- _c.label = 9;
586
- case 9:
587
- _c.trys.push([9, 11, , 12]);
588
- return [4 /*yield*/, this.context.cache.match(container.svg)];
589
- case 10:
590
- image = _c.sent();
591
- this.renderReplacedElement(container, curves, image, 'svg');
592
- return [3 /*break*/, 12];
593
- case 11:
594
- e_2 = _c.sent();
595
- this.context.logger.error("Error loading svg ".concat(container.svg.substring(0, 255)));
596
- return [3 /*break*/, 12];
597
- case 12:
598
- if (!(container instanceof iframe_element_container_1.IFrameElementContainer && container.tree)) return [3 /*break*/, 14];
599
- iframeRenderer = new CanvasRenderer(this.context, {
600
- scale: this.options.scale,
601
- fontConfig: this.options.fontConfig,
602
- backgroundColor: container.backgroundColor,
603
- x: 0,
604
- y: 0,
605
- width: container.width,
606
- height: container.height
607
- });
608
- return [4 /*yield*/, iframeRenderer.render(container.tree)];
609
- case 13:
610
- canvas = _c.sent();
611
- if (container.width && container.height) {
612
- this.ctx.drawImage(canvas, 0, 0, container.width, container.height, container.bounds.left, container.bounds.top, container.bounds.width, container.bounds.height);
613
- }
614
- _c.label = 14;
615
- case 14:
616
- // 处理Input元素
617
- if (container instanceof input_element_container_1.InputElementContainer) {
618
- size = Math.min(container.bounds.width, container.bounds.height);
619
- // 渲染复选框
620
- if (container.type === input_element_container_1.CHECKBOX) {
621
- if (container.checked) {
622
- this.ctx.save();
623
- this.path([
624
- new vector_1.Vector(container.bounds.left + size * 0.39363, container.bounds.top + size * 0.79),
625
- new vector_1.Vector(container.bounds.left + size * 0.16, container.bounds.top + size * 0.5549),
626
- new vector_1.Vector(container.bounds.left + size * 0.27347, container.bounds.top + size * 0.44071),
627
- new vector_1.Vector(container.bounds.left + size * 0.39694, container.bounds.top + size * 0.5649),
628
- new vector_1.Vector(container.bounds.left + size * 0.72983, container.bounds.top + size * 0.23),
629
- new vector_1.Vector(container.bounds.left + size * 0.84, container.bounds.top + size * 0.34085),
630
- new vector_1.Vector(container.bounds.left + size * 0.39363, container.bounds.top + size * 0.79)
631
- ]);
632
- this.ctx.fillStyle = this.convertColor(input_element_container_1.INPUT_COLOR);
633
- this.ctx.fill();
634
- this.ctx.restore();
635
- }
636
- }
637
- // 渲染单选框
638
- else if (container.type === input_element_container_1.RADIO) {
639
- if (container.checked) {
640
- this.ctx.save();
641
- this.ctx.beginPath();
642
- this.ctx.arc(container.bounds.left + size / 2, container.bounds.top + size / 2, size / 4, 0, Math.PI * 2, true);
643
- this.ctx.fillStyle = this.convertColor(input_element_container_1.INPUT_COLOR);
644
- this.ctx.fill();
645
- this.ctx.restore();
646
- }
647
- }
648
- }
649
- // 处理文本输入元素
650
- if (isTextInputElement(container) && container.value.length) {
651
- _b = this.createFontStyle(styles), fontFamily = _b[0], fontSize = _b[1];
652
- baseline = this.fontMetrics.getMetrics(fontFamily, fontSize).baseline;
653
- this.ctx.font = fontFamily;
654
- this.ctx.fillStyle = this.convertColor(styles.color);
655
- this.ctx.textBaseline = 'alphabetic';
656
- this.ctx.textAlign = canvasTextAlign(container.styles.textAlign);
657
- bounds = (0, box_sizing_1.contentBox)(container);
658
- x = 0;
659
- // 根据文本对齐方式调整x坐标
660
- switch (container.styles.textAlign) {
661
- case 1 /* TEXT_ALIGN.CENTER */:
662
- x += bounds.width / 2;
663
- break;
664
- case 2 /* TEXT_ALIGN.RIGHT */:
665
- x += bounds.width;
666
- break;
667
- }
668
- textBounds = bounds.add(x, 0, 0, -bounds.height / 2 + 1);
669
- this.ctx.save();
670
- this.path([
671
- new vector_1.Vector(bounds.left, bounds.top),
672
- new vector_1.Vector(bounds.left + bounds.width, bounds.top),
673
- new vector_1.Vector(bounds.left + bounds.width, bounds.top + bounds.height),
674
- new vector_1.Vector(bounds.left, bounds.top + bounds.height)
675
- ]);
676
- this.ctx.clip();
677
- this.renderTextWithLetterSpacing(new text_1.TextBounds(container.value, textBounds), styles.letterSpacing, baseline);
678
- this.ctx.restore();
679
- this.ctx.textBaseline = 'alphabetic';
680
- this.ctx.textAlign = 'left';
681
- }
682
- if (!(0, bitwise_1.contains)(container.styles.display, 2048 /* DISPLAY.LIST_ITEM */)) return [3 /*break*/, 20];
683
- if (!(container.styles.listStyleImage !== null)) return [3 /*break*/, 19];
684
- img = container.styles.listStyleImage;
685
- if (!(img.type === 0 /* CSSImageType.URL */)) return [3 /*break*/, 18];
686
- image = void 0;
687
- url = img.url;
688
- _c.label = 15;
689
- case 15:
690
- _c.trys.push([15, 17, , 18]);
691
- return [4 /*yield*/, this.context.cache.match(url)];
692
- case 16:
693
- image = _c.sent();
694
- this.ctx.drawImage(image, container.bounds.left - (image.width + 10), container.bounds.top);
695
- return [3 /*break*/, 18];
696
- case 17:
697
- e_3 = _c.sent();
698
- this.context.logger.error("Error loading list-style-image ".concat(url));
699
- return [3 /*break*/, 18];
700
- case 18: return [3 /*break*/, 20];
701
- case 19:
702
- if (paint.listValue && container.styles.listStyleType !== -1 /* LIST_STYLE_TYPE.NONE */) {
703
- fontFamily = this.createFontStyle(styles)[0];
704
- this.ctx.font = fontFamily;
705
- this.ctx.fillStyle = this.convertColor(styles.color);
706
- this.ctx.textBaseline = 'middle';
707
- this.ctx.textAlign = 'right';
708
- bounds = new bounds_1.Bounds(container.bounds.left, container.bounds.top + (0, length_percentage_1.getAbsoluteValue)(container.styles.paddingTop, container.bounds.width), container.bounds.width, (0, line_height_1.computeLineHeight)(styles.lineHeight, styles.fontSize.number) / 2 + 1);
709
- this.renderTextWithLetterSpacing(new text_1.TextBounds(paint.listValue, bounds), styles.letterSpacing, (0, line_height_1.computeLineHeight)(styles.lineHeight, styles.fontSize.number) / 2 + 2);
710
- this.ctx.textBaseline = 'bottom';
711
- this.ctx.textAlign = 'left';
712
- }
713
- _c.label = 20;
714
- case 20: return [2 /*return*/];
715
- }
716
- });
717
- });
718
- };
719
- // 渲染堆叠上下文内容
720
- CanvasRenderer.prototype.renderStackContent = function (stack) {
721
- return __awaiter(this, void 0, void 0, function () {
722
- var _i, _a, child, _b, _c, child, _d, _e, child, _f, _g, child, _h, _j, child, _k, _l, child, _m, _o, child;
723
- return __generator(this, function (_p) {
724
- switch (_p.label) {
725
- case 0:
726
- if ((0, bitwise_1.contains)(stack.element.container.flags, 16 /* FLAGS.DEBUG_RENDER */)) {
727
- debugger;
728
- }
729
- // https://www.w3.org/TR/css-position-3/#painting-order
730
- // 1. the background and borders of the element forming the stacking context.
731
- return [4 /*yield*/, this.renderNodeBackgroundAndBorders(stack.element)];
732
- case 1:
733
- // https://www.w3.org/TR/css-position-3/#painting-order
734
- // 1. the background and borders of the element forming the stacking context.
735
- _p.sent();
736
- _i = 0, _a = stack.negativeZIndex;
737
- _p.label = 2;
738
- case 2:
739
- if (!(_i < _a.length)) return [3 /*break*/, 5];
740
- child = _a[_i];
741
- return [4 /*yield*/, this.renderStack(child)];
742
- case 3:
743
- _p.sent();
744
- _p.label = 4;
745
- case 4:
746
- _i++;
747
- return [3 /*break*/, 2];
748
- case 5:
749
- // 3. For all its in-flow, non-positioned, block-level descendants in tree order:
750
- return [4 /*yield*/, this.renderNodeContent(stack.element)];
751
- case 6:
752
- // 3. For all its in-flow, non-positioned, block-level descendants in tree order:
753
- _p.sent();
754
- _b = 0, _c = stack.nonInlineLevel;
755
- _p.label = 7;
756
- case 7:
757
- if (!(_b < _c.length)) return [3 /*break*/, 10];
758
- child = _c[_b];
759
- return [4 /*yield*/, this.renderNode(child)];
760
- case 8:
761
- _p.sent();
762
- _p.label = 9;
763
- case 9:
764
- _b++;
765
- return [3 /*break*/, 7];
766
- case 10:
767
- _d = 0, _e = stack.nonPositionedFloats;
768
- _p.label = 11;
769
- case 11:
770
- if (!(_d < _e.length)) return [3 /*break*/, 14];
771
- child = _e[_d];
772
- return [4 /*yield*/, this.renderStack(child)];
773
- case 12:
774
- _p.sent();
775
- _p.label = 13;
776
- case 13:
777
- _d++;
778
- return [3 /*break*/, 11];
779
- case 14:
780
- _f = 0, _g = stack.nonPositionedInlineLevel;
781
- _p.label = 15;
782
- case 15:
783
- if (!(_f < _g.length)) return [3 /*break*/, 18];
784
- child = _g[_f];
785
- return [4 /*yield*/, this.renderStack(child)];
786
- case 16:
787
- _p.sent();
788
- _p.label = 17;
789
- case 17:
790
- _f++;
791
- return [3 /*break*/, 15];
792
- case 18:
793
- _h = 0, _j = stack.inlineLevel;
794
- _p.label = 19;
795
- case 19:
796
- if (!(_h < _j.length)) return [3 /*break*/, 22];
797
- child = _j[_h];
798
- return [4 /*yield*/, this.renderNode(child)];
799
- case 20:
800
- _p.sent();
801
- _p.label = 21;
802
- case 21:
803
- _h++;
804
- return [3 /*break*/, 19];
805
- case 22:
806
- _k = 0, _l = stack.zeroOrAutoZIndexOrTransformedOrOpacity;
807
- _p.label = 23;
808
- case 23:
809
- if (!(_k < _l.length)) return [3 /*break*/, 26];
810
- child = _l[_k];
811
- return [4 /*yield*/, this.renderStack(child)];
812
- case 24:
813
- _p.sent();
814
- _p.label = 25;
815
- case 25:
816
- _k++;
817
- return [3 /*break*/, 23];
818
- case 26:
819
- _m = 0, _o = stack.positiveZIndex;
820
- _p.label = 27;
821
- case 27:
822
- if (!(_m < _o.length)) return [3 /*break*/, 30];
823
- child = _o[_m];
824
- return [4 /*yield*/, this.renderStack(child)];
825
- case 28:
826
- _p.sent();
827
- _p.label = 29;
828
- case 29:
829
- _m++;
830
- return [3 /*break*/, 27];
831
- case 30: return [2 /*return*/];
832
- }
833
- });
834
- });
835
- };
836
- // 创建遮罩
837
- CanvasRenderer.prototype.mask = function (paths) {
838
- this.ctx.beginPath();
839
- this.ctx.moveTo(0, 0);
840
- this.ctx.lineTo(this.canvas.width, 0);
841
- this.ctx.lineTo(this.canvas.width, this.canvas.height);
842
- this.ctx.lineTo(0, this.canvas.height);
843
- this.ctx.lineTo(0, 0);
844
- this.formatPath(paths.slice(0).reverse());
845
- this.ctx.closePath();
846
- };
847
- // 创建路径
848
- CanvasRenderer.prototype.path = function (paths) {
849
- this.ctx.beginPath();
850
- this.formatPath(paths);
851
- this.ctx.closePath();
852
- };
853
- // 格式化路径
854
- CanvasRenderer.prototype.formatPath = function (paths) {
855
- var _this = this;
856
- paths.forEach(function (point, index) {
857
- var start = (0, bezier_curve_1.isBezierCurve)(point) ? point.start : point;
858
- if (index === 0) {
859
- _this.ctx.moveTo(start.x, start.y);
860
- }
861
- else {
862
- _this.ctx.lineTo(start.x, start.y);
863
- }
864
- if ((0, bezier_curve_1.isBezierCurve)(point)) {
865
- _this.ctx.bezierCurveTo(point.startControl.x, point.startControl.y, point.endControl.x, point.endControl.y, point.end.x, point.end.y);
866
- }
867
- });
868
- };
869
- // 渲染重复图案
870
- CanvasRenderer.prototype.renderRepeat = function (path, pattern, offsetX, offsetY) {
871
- this.path(path);
872
- this.ctx.fillStyle = pattern;
873
- this.ctx.translate(offsetX, offsetY);
874
- this.ctx.fill();
875
- this.ctx.translate(-offsetX, -offsetY);
876
- };
877
- // 调整图片大小
878
- CanvasRenderer.prototype.resizeImage = function (image, width, height) {
879
- var _a;
880
- if (image.width === width && image.height === height) {
881
- return image;
882
- }
883
- var ownerDocument = (_a = this.canvas.ownerDocument) !== null && _a !== void 0 ? _a : document;
884
- var canvas = ownerDocument.createElement('canvas');
885
- canvas.width = Math.max(1, width);
886
- canvas.height = Math.max(1, height);
887
- var ctx = canvas.getContext('2d');
888
- ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
889
- return canvas;
890
- };
891
- // 渲染背景图片
892
- CanvasRenderer.prototype.renderBackgroundImage = function (container) {
893
- return __awaiter(this, void 0, void 0, function () {
894
- var index, _loop_1, this_1, _i, _a, backgroundImage;
895
- var _this = this;
896
- return __generator(this, function (_b) {
897
- switch (_b.label) {
898
- case 0:
899
- index = container.styles.backgroundImage.length - 1;
900
- _loop_1 = function (backgroundImage) {
901
- var image, url, e_4, _c, path, x, y, width, height, pattern, xPt, yPt, widthPt, heightPt, _d, path, x, y, width, height, _e, lineLength, x0, x1, y0, y1, canvas, ctx, gradient_2, pattern, _f, path, left, top_1, width, height, position, x, y, _g, rx, ry, radialGradient_1, midX, midY, f, invF;
902
- return __generator(this, function (_h) {
903
- switch (_h.label) {
904
- case 0:
905
- if (!(backgroundImage.type === 0 /* CSSImageType.URL */)) return [3 /*break*/, 5];
906
- image = void 0;
907
- url = backgroundImage.url;
908
- _h.label = 1;
909
- case 1:
910
- _h.trys.push([1, 3, , 4]);
911
- return [4 /*yield*/, this_1.context.cache.match(url)];
912
- case 2:
913
- image = _h.sent();
914
- return [3 /*break*/, 4];
915
- case 3:
916
- e_4 = _h.sent();
917
- this_1.context.logger.error("Error loading background-image ".concat(url));
918
- return [3 /*break*/, 4];
919
- case 4:
920
- if (image) {
921
- _c = (0, background_1.calculateBackgroundRendering)(container, index, [
922
- image.width,
923
- image.height,
924
- image.width / image.height
925
- ]), path = _c[0], x = _c[1], y = _c[2], width = _c[3], height = _c[4];
926
- pattern = this_1.ctx.createPattern(this_1.resizeImage(image, width, height), 'repeat');
927
- this_1.renderRepeat(path, pattern, x, y);
928
- xPt = this_1.pxToPt(x - leftMargin);
929
- yPt = this_1.pxToPt(y - topMargin);
930
- widthPt = this_1.pxToPt(width);
931
- heightPt = this_1.pxToPt(height);
932
- this_1.jspdfCtx.addImage(image, 'JPEG', xPt, yPt, widthPt, heightPt);
933
- }
934
- return [3 /*break*/, 6];
935
- case 5:
936
- if ((0, image_1.isLinearGradient)(backgroundImage)) {
937
- _d = (0, background_1.calculateBackgroundRendering)(container, index, [null, null, null]), path = _d[0], x = _d[1], y = _d[2], width = _d[3], height = _d[4];
938
- _e = (0, gradient_1.calculateGradientDirection)(backgroundImage.angle, width, height), lineLength = _e[0], x0 = _e[1], x1 = _e[2], y0 = _e[3], y1 = _e[4];
939
- canvas = document.createElement('canvas');
940
- canvas.width = width;
941
- canvas.height = height;
942
- ctx = canvas.getContext('2d');
943
- gradient_2 = ctx.createLinearGradient(x0, y0, x1, y1);
944
- (0, gradient_1.processColorStops)(backgroundImage.stops, lineLength).forEach(function (colorStop) {
945
- return gradient_2.addColorStop(colorStop.stop, _this.convertColor(colorStop.color));
946
- });
947
- ctx.fillStyle = gradient_2;
948
- ctx.fillRect(0, 0, width, height);
949
- if (width > 0 && height > 0) {
950
- pattern = this_1.ctx.createPattern(canvas, 'repeat');
951
- this_1.renderRepeat(path, pattern, x, y);
952
- }
953
- }
954
- else if ((0, image_1.isRadialGradient)(backgroundImage)) {
955
- _f = (0, background_1.calculateBackgroundRendering)(container, index, [
956
- null,
957
- null,
958
- null
959
- ]), path = _f[0], left = _f[1], top_1 = _f[2], width = _f[3], height = _f[4];
960
- position = backgroundImage.position.length === 0 ? [length_percentage_1.FIFTY_PERCENT] : backgroundImage.position;
961
- x = (0, length_percentage_1.getAbsoluteValue)(position[0], width);
962
- y = (0, length_percentage_1.getAbsoluteValue)(position[position.length - 1], height);
963
- _g = (0, gradient_1.calculateRadius)(backgroundImage, x, y, width, height), rx = _g[0], ry = _g[1];
964
- if (rx > 0 && ry > 0) {
965
- radialGradient_1 = this_1.ctx.createRadialGradient(left + x, top_1 + y, 0, left + x, top_1 + y, rx);
966
- (0, gradient_1.processColorStops)(backgroundImage.stops, rx * 2).forEach(function (colorStop) {
967
- return radialGradient_1.addColorStop(colorStop.stop, _this.convertColor(colorStop.color));
968
- });
969
- this_1.path(path);
970
- this_1.ctx.fillStyle = radialGradient_1;
971
- if (rx !== ry) {
972
- midX = container.bounds.left + 0.5 * container.bounds.width;
973
- midY = container.bounds.top + 0.5 * container.bounds.height;
974
- f = ry / rx;
975
- invF = 1 / f;
976
- this_1.ctx.save();
977
- this_1.ctx.translate(midX, midY);
978
- this_1.ctx.transform(1, 0, 0, f, 0, 0);
979
- this_1.ctx.translate(-midX, -midY);
980
- this_1.ctx.fillRect(left, invF * (top_1 - midY) + midY, width, height * invF);
981
- this_1.ctx.restore();
982
- }
983
- else {
984
- this_1.ctx.fill();
985
- }
986
- }
987
- }
988
- _h.label = 6;
989
- case 6:
990
- index--;
991
- return [2 /*return*/];
992
- }
993
- });
994
- };
995
- this_1 = this;
996
- _i = 0, _a = container.styles.backgroundImage.slice(0).reverse();
997
- _b.label = 1;
998
- case 1:
999
- if (!(_i < _a.length)) return [3 /*break*/, 4];
1000
- backgroundImage = _a[_i];
1001
- return [5 /*yield**/, _loop_1(backgroundImage)];
1002
- case 2:
1003
- _b.sent();
1004
- _b.label = 3;
1005
- case 3:
1006
- _i++;
1007
- return [3 /*break*/, 1];
1008
- case 4: return [2 /*return*/];
1009
- }
1010
- });
1011
- });
1012
- };
1013
- /**
1014
- * 渲染实线边框
1015
- * @param color - 边框颜色
1016
- * @param side - 边的位置(0-3,分别代表上右下左)
1017
- * @param curvePoints - 边框曲线点
1018
- */
1019
- CanvasRenderer.prototype.renderSolidBorder = function (color, side, curvePoints) {
1020
- return __awaiter(this, void 0, void 0, function () {
1021
- return __generator(this, function (_a) {
1022
- // console.log('renderSolidBorder实线边框信息', color, side, curvePoints, parsePathForBorder(curvePoints, side))
1023
- // 设置PDF边框颜色
1024
- // const [r, g, b] = color;
1025
- // this.jspdfCtx.setDrawColor('#dd2526');
1026
- // 解析边框路径
1027
- this.path((0, border_1.parsePathForBorder)(curvePoints, side));
1028
- // 设置填充颜色
1029
- this.ctx.fillStyle = this.convertColor(color);
1030
- // 填充路径
1031
- this.ctx.fill();
1032
- this.jspdfCtx.fill();
1033
- return [2 /*return*/];
1034
- });
1035
- });
1036
- };
1037
- // 渲染双线边框
1038
- CanvasRenderer.prototype.renderDoubleBorder = function (color, width, side, curvePoints) {
1039
- return __awaiter(this, void 0, void 0, function () {
1040
- var outerPaths, innerPaths;
1041
- return __generator(this, function (_a) {
1042
- switch (_a.label) {
1043
- case 0:
1044
- if (!(width < 3)) return [3 /*break*/, 2];
1045
- return [4 /*yield*/, this.renderSolidBorder(color, side, curvePoints)];
1046
- case 1:
1047
- _a.sent();
1048
- return [2 /*return*/];
1049
- case 2:
1050
- outerPaths = (0, border_1.parsePathForBorderDoubleOuter)(curvePoints, side);
1051
- this.path(outerPaths);
1052
- this.ctx.fillStyle = this.convertColor(color);
1053
- this.ctx.fill();
1054
- innerPaths = (0, border_1.parsePathForBorderDoubleInner)(curvePoints, side);
1055
- this.path(innerPaths);
1056
- this.ctx.fill();
1057
- return [2 /*return*/];
1058
- }
1059
- });
1060
- });
1061
- };
1062
- // 渲染节点的背景和边框
1063
- CanvasRenderer.prototype.renderNodeBackgroundAndBorders = function (paint) {
1064
- return __awaiter(this, void 0, void 0, function () {
1065
- var styles, hasBackground, borders, backgroundPaintingArea, startPoint, endPoint, x, y, width, height, side, _i, borders_1, border;
1066
- var _this = this;
1067
- return __generator(this, function (_a) {
1068
- switch (_a.label) {
1069
- case 0:
1070
- // 应用背景和边框的效果
1071
- this.applyEffects(paint.getEffects(2 /* EffectTarget.BACKGROUND_BORDERS */));
1072
- styles = paint.container.styles;
1073
- hasBackground = !(0, color_1.isTransparent)(styles.backgroundColor) || styles.backgroundImage.length;
1074
- borders = [
1075
- { style: styles.borderTopStyle, color: styles.borderTopColor, width: styles.borderTopWidth },
1076
- { style: styles.borderRightStyle, color: styles.borderRightColor, width: styles.borderRightWidth },
1077
- { style: styles.borderBottomStyle, color: styles.borderBottomColor, width: styles.borderBottomWidth },
1078
- { style: styles.borderLeftStyle, color: styles.borderLeftColor, width: styles.borderLeftWidth }
1079
- ];
1080
- backgroundPaintingArea = calculateBackgroundCurvedPaintingArea((0, background_1.getBackgroundValueForIndex)(styles.backgroundClip, 0), paint.curves);
1081
- if (!(hasBackground || styles.boxShadow.length)) return [3 /*break*/, 2];
1082
- this.ctx.save();
1083
- this.path(backgroundPaintingArea);
1084
- this.ctx.clip();
1085
- // 绘制背景色
1086
- if (!(0, color_1.isTransparent)(styles.backgroundColor)) {
1087
- this.ctx.fillStyle = this.convertColor(styles.backgroundColor);
1088
- this.ctx.fill();
1089
- startPoint = backgroundPaintingArea[0];
1090
- endPoint = backgroundPaintingArea[2];
1091
- x = Number(this.pxToPt(startPoint.x - leftMargin));
1092
- y = Number(this.pxToPt(startPoint.y - topMargin));
1093
- width = Number(this.pxToPt(endPoint.x - startPoint.x));
1094
- height = Number(this.pxToPt(endPoint.y - startPoint.y));
1095
- // 在PDF中渲染背景色
1096
- this.jspdfCtx.setFillColor(this.convertColor(styles.backgroundColor));
1097
- try {
1098
- // 确保所有参数都是有效的数字
1099
- if (!isNaN(x) && !isNaN(y) && !isNaN(width) && !isNaN(height)) {
1100
- console.log('背景shadow:', { x: x, y: y, width: width, height: height });
1101
- this.jspdfCtx.rect(x, y, width, height, 'F');
1102
- }
1103
- else {
1104
- console.warn('无效的矩形参数:', { x: x, y: y, width: width, height: height });
1105
- }
1106
- }
1107
- catch (e) {
1108
- console.error('绘制背景颜色失败:', e);
1109
- }
1110
- }
1111
- // 渲染背景图片
1112
- return [4 /*yield*/, this.renderBackgroundImage(paint.container)];
1113
- case 1:
1114
- // 渲染背景图片
1115
- _a.sent();
1116
- this.ctx.restore();
1117
- styles.boxShadow
1118
- .slice(0)
1119
- .reverse()
1120
- .forEach(function (shadow) {
1121
- _this.ctx.save();
1122
- var borderBoxArea = (0, bound_curves_1.calculateBorderBoxPath)(paint.curves);
1123
- var maskOffset = shadow.inset ? 0 : MASK_OFFSET;
1124
- var shadowPaintingArea = (0, path_1.transformPath)(borderBoxArea, -maskOffset + (shadow.inset ? 1 : -1) * shadow.spread.number, (shadow.inset ? 1 : -1) * shadow.spread.number, shadow.spread.number * (shadow.inset ? -2 : 2), shadow.spread.number * (shadow.inset ? -2 : 2));
1125
- if (shadow.inset) {
1126
- _this.path(borderBoxArea);
1127
- _this.ctx.clip();
1128
- _this.mask(shadowPaintingArea);
1129
- }
1130
- else {
1131
- _this.mask(borderBoxArea);
1132
- _this.ctx.clip();
1133
- _this.path(shadowPaintingArea);
1134
- }
1135
- _this.ctx.shadowOffsetX = shadow.offsetX.number + maskOffset;
1136
- _this.ctx.shadowOffsetY = shadow.offsetY.number;
1137
- _this.ctx.shadowColor = _this.convertColor(shadow.color);
1138
- _this.ctx.shadowBlur = shadow.blur.number;
1139
- _this.ctx.fillStyle = shadow.inset ? _this.convertColor(shadow.color) : 'rgba(0,0,0,1)';
1140
- _this.ctx.fill();
1141
- _this.ctx.restore();
1142
- });
1143
- _a.label = 2;
1144
- case 2:
1145
- side = 0;
1146
- _i = 0, borders_1 = borders;
1147
- _a.label = 3;
1148
- case 3:
1149
- if (!(_i < borders_1.length)) return [3 /*break*/, 13];
1150
- border = borders_1[_i];
1151
- if (!(border.style !== 0 /* BORDER_STYLE.NONE */ && !(0, color_1.isTransparent)(border.color) && border.width > 0)) return [3 /*break*/, 11];
1152
- if (!(border.style === 2 /* BORDER_STYLE.DASHED */)) return [3 /*break*/, 5];
1153
- return [4 /*yield*/, this.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 2 /* BORDER_STYLE.DASHED */)];
1154
- case 4:
1155
- _a.sent();
1156
- return [3 /*break*/, 11];
1157
- case 5:
1158
- if (!(border.style === 3 /* BORDER_STYLE.DOTTED */)) return [3 /*break*/, 7];
1159
- return [4 /*yield*/, this.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 3 /* BORDER_STYLE.DOTTED */)];
1160
- case 6:
1161
- _a.sent();
1162
- return [3 /*break*/, 11];
1163
- case 7:
1164
- if (!(border.style === 4 /* BORDER_STYLE.DOUBLE */)) return [3 /*break*/, 9];
1165
- return [4 /*yield*/, this.renderDoubleBorder(border.color, border.width, side, paint.curves)];
1166
- case 8:
1167
- _a.sent();
1168
- return [3 /*break*/, 11];
1169
- case 9: return [4 /*yield*/, this.renderSolidBorder(border.color, side, paint.curves)];
1170
- case 10:
1171
- _a.sent();
1172
- _a.label = 11;
1173
- case 11:
1174
- side++;
1175
- _a.label = 12;
1176
- case 12:
1177
- _i++;
1178
- return [3 /*break*/, 3];
1179
- case 13: return [2 /*return*/];
1180
- }
1181
- });
1182
- });
1183
- };
1184
- CanvasRenderer.prototype.drawBoxWithGradientShadow = function (x, y, width, height, color) {
1185
- // 创建更细腻的阴影效果
1186
- var shadowSteps = 20; // 增加阴影层数
1187
- var shadowSpread = 6; // 调整阴影扩散
1188
- var maxOpacity = 0.12; // 降低最大不透明度
1189
- var blur = 2; // 添加模糊效果
1190
- // 转换坐标为 pt
1191
- var xPt = this.pxToPt(x - leftMargin);
1192
- var yPt = this.pxToPt(y - topMargin);
1193
- var widthPt = this.pxToPt(width);
1194
- var heightPt = this.pxToPt(height);
1195
- // 绘制阴影层
1196
- for (var i = 0; i < shadowSteps; i++) {
1197
- var opacity = maxOpacity * Math.pow(1 - i / shadowSteps, 1.5);
1198
- this.jspdfCtx.setFillColor(this.convertColor(color));
1199
- this.jspdfCtx.setGState(new this.jspdfCtx.GState({ opacity: opacity }));
1200
- var spread = (i * shadowSpread) / shadowSteps;
1201
- var blurOffset = blur * (1 - i / shadowSteps);
1202
- // 绘制多个略微偏移的矩形来模拟模糊效果
1203
- for (var j = 0; j < 4; j++) {
1204
- var offset = blurOffset * (j / 3 - 0.5);
1205
- this.jspdfCtx.rect(xPt - spread + offset, yPt - spread + offset, widthPt + (spread * 2), heightPt + (spread * 2), 'F');
1206
- }
1207
- }
1208
- // 绘制主要内容
1209
- this.jspdfCtx.setFillColor(this.convertColor(color));
1210
- this.jspdfCtx.setGState(new this.jspdfCtx.GState({ opacity: 1 }));
1211
- this.jspdfCtx.rect(xPt, yPt, widthPt, heightPt, 'F');
1212
- };
1213
- // 这个方法用于渲染虚线和点线边框
1214
- CanvasRenderer.prototype.renderDashedDottedBorder = function (color, // 边框颜色
1215
- width, // 边框宽度
1216
- side, // 边的位置(0-3,分别代表上右下左)
1217
- curvePoints, // 边框曲线点
1218
- style // 边框样式(DASHED或DOTTED)
1219
- ) {
1220
- return __awaiter(this, void 0, void 0, function () {
1221
- var strokePaths, boxPaths, startX, startY, endX, endY, length, dashLength, spaceLength, useLineDash, multiplier, numberOfDashes, minSpace, maxSpace, path1, path2, x1, y1, x2, y2, path1, path2;
1222
- return __generator(this, function (_a) {
1223
- this.ctx.save(); // 保存当前画布状态
1224
- this.jspdfCtx.saveGraphicsState(); // 保存PDF绘图状态
1225
- strokePaths = (0, border_1.parsePathForBorderStroke)(curvePoints, side);
1226
- boxPaths = (0, border_1.parsePathForBorder)(curvePoints, side);
1227
- // 如果是虚线边框,需要先裁剪路径
1228
- if (style === 2 /* BORDER_STYLE.DASHED */) {
1229
- this.path(boxPaths);
1230
- this.ctx.clip();
1231
- // PDF裁剪路径
1232
- this.jspdfCtx.clip();
1233
- }
1234
- if ((0, bezier_curve_1.isBezierCurve)(boxPaths[0])) {
1235
- startX = boxPaths[0].start.x;
1236
- startY = boxPaths[0].start.y;
1237
- }
1238
- else {
1239
- startX = boxPaths[0].x;
1240
- startY = boxPaths[0].y;
1241
- }
1242
- if ((0, bezier_curve_1.isBezierCurve)(boxPaths[1])) {
1243
- endX = boxPaths[1].end.x;
1244
- endY = boxPaths[1].end.y;
1245
- }
1246
- else {
1247
- endX = boxPaths[1].x;
1248
- endY = boxPaths[1].y;
1249
- }
1250
- if (side === 0 || side === 2) {
1251
- length = Math.abs(startX - endX);
1252
- }
1253
- else {
1254
- length = Math.abs(startY - endY);
1255
- }
1256
- // 开始绘制路径
1257
- this.ctx.beginPath();
1258
- this.jspdfCtx.setDrawColor(this.convertColor(color)); // 设置PDF绘制颜色
1259
- if (style === 3 /* BORDER_STYLE.DOTTED */) {
1260
- this.formatPath(strokePaths);
1261
- }
1262
- else {
1263
- this.formatPath(boxPaths.slice(0, 2));
1264
- }
1265
- dashLength = width < 3 ? width * 3 : width * 2;
1266
- spaceLength = width < 3 ? width * 2 : width;
1267
- if (style === 3 /* BORDER_STYLE.DOTTED */) {
1268
- dashLength = width;
1269
- spaceLength = width;
1270
- }
1271
- useLineDash = true;
1272
- if (length <= dashLength * 2) {
1273
- useLineDash = false;
1274
- }
1275
- else if (length <= dashLength * 2 + spaceLength) {
1276
- multiplier = length / (2 * dashLength + spaceLength);
1277
- dashLength *= multiplier;
1278
- spaceLength *= multiplier;
1279
- }
1280
- else {
1281
- numberOfDashes = Math.floor((length + spaceLength) / (dashLength + spaceLength));
1282
- minSpace = (length - numberOfDashes * dashLength) / (numberOfDashes - 1);
1283
- maxSpace = (length - (numberOfDashes + 1) * dashLength) / numberOfDashes;
1284
- spaceLength =
1285
- maxSpace <= 0 || Math.abs(spaceLength - minSpace) < Math.abs(spaceLength - maxSpace)
1286
- ? minSpace
1287
- : maxSpace;
1288
- }
1289
- // 设置虚线样式
1290
- if (useLineDash) {
1291
- if (style === 3 /* BORDER_STYLE.DOTTED */) {
1292
- this.ctx.setLineDash([0, dashLength + spaceLength]);
1293
- this.jspdfCtx.setLineDashPattern([0, dashLength + spaceLength], 0); // PDF虚线样式
1294
- }
1295
- else {
1296
- this.ctx.setLineDash([dashLength, spaceLength]);
1297
- this.jspdfCtx.setLineDashPattern([dashLength, spaceLength], 0); // PDF虚线样式
1298
- }
1299
- }
1300
- // 设置线条样式并绘制
1301
- if (style === 3 /* BORDER_STYLE.DOTTED */) {
1302
- this.ctx.lineCap = 'round';
1303
- this.ctx.lineWidth = width;
1304
- this.jspdfCtx.setLineCap('round'); // PDF线帽样式
1305
- this.jspdfCtx.setLineWidth(width);
1306
- }
1307
- else {
1308
- this.ctx.lineWidth = width * 2 + 1.1;
1309
- this.jspdfCtx.setLineWidth(width * 2 + 1.1);
1310
- }
1311
- this.ctx.strokeStyle = this.convertColor(color);
1312
- this.ctx.stroke();
1313
- this.jspdfCtx.stroke(); // PDF绘制线条
1314
- this.ctx.setLineDash([]);
1315
- this.jspdfCtx.setLineDashPattern([], 0); // 重置PDF虚线样式
1316
- // 处理虚线边框的圆角连接处
1317
- if (style === 2 /* BORDER_STYLE.DASHED */) {
1318
- if ((0, bezier_curve_1.isBezierCurve)(boxPaths[0])) {
1319
- path1 = boxPaths[3];
1320
- path2 = boxPaths[0];
1321
- x1 = this.pxToPt(path1.end.x);
1322
- y1 = this.pxToPt(path1.end.y);
1323
- x2 = this.pxToPt(path2.start.x);
1324
- y2 = this.pxToPt(path2.start.y);
1325
- try {
1326
- this.jspdfCtx.line(x1, y1, x2, y2);
1327
- this.jspdfCtx.stroke();
1328
- }
1329
- catch (error) {
1330
- console.warn('Failed to draw dashed border:', error);
1331
- }
1332
- }
1333
- if ((0, bezier_curve_1.isBezierCurve)(boxPaths[1])) {
1334
- path1 = boxPaths[1];
1335
- path2 = boxPaths[2];
1336
- this.ctx.beginPath();
1337
- this.formatPath([new vector_1.Vector(path1.end.x, path1.end.y), new vector_1.Vector(path2.start.x, path2.start.y)]);
1338
- this.ctx.stroke();
1339
- this.jspdfCtx.lines([[path1.end.x, path1.end.y, path2.start.x, path2.start.y]], path1.end.x, path1.end.y); // PDF绘制连接线
1340
- this.jspdfCtx.stroke();
1341
- }
1342
- }
1343
- this.ctx.restore(); // 恢复画布状态
1344
- this.jspdfCtx.restoreGraphicsState(); // 恢复PDF绘图状态
1345
- return [2 /*return*/];
1346
- });
1347
- });
1348
- };
1349
- CanvasRenderer.prototype.render = function (element) {
1350
- return __awaiter(this, void 0, void 0, function () {
1351
- var stack, fileName;
1352
- return __generator(this, function (_a) {
1353
- switch (_a.label) {
1354
- case 0:
1355
- if (this.options.backgroundColor) {
1356
- this.ctx.fillStyle = this.convertColor(this.options.backgroundColor);
1357
- this.ctx.fillRect(this.options.x, this.options.y, this.options.width, this.options.height);
1358
- }
1359
- stack = (0, stacking_context_1.parseStackingContexts)(element);
1360
- return [4 /*yield*/, this.renderStack(stack)];
1361
- case 1:
1362
- _a.sent();
1363
- this.applyEffects([]);
1364
- fileName = this.options.pdfFileName || 'output.pdf';
1365
- this.jspdfCtx.save(fileName);
1366
- return [2 /*return*/, this.canvas];
1367
- }
1368
- });
1369
- });
1370
- };
1371
- return CanvasRenderer;
1372
- }(renderer_1.Renderer));
1373
- exports.CanvasRenderer = CanvasRenderer;
1374
- var isTextInputElement = function (container) {
1375
- if (container instanceof textarea_element_container_1.TextareaElementContainer) {
1376
- return true;
1377
- }
1378
- else if (container instanceof select_element_container_1.SelectElementContainer) {
1379
- return true;
1380
- }
1381
- else if (container instanceof input_element_container_1.InputElementContainer && container.type !== input_element_container_1.RADIO && container.type !== input_element_container_1.CHECKBOX) {
1382
- return true;
1383
- }
1384
- return false;
1385
- };
1386
- var calculateBackgroundCurvedPaintingArea = function (clip, curves) {
1387
- switch (clip) {
1388
- case 0 /* BACKGROUND_CLIP.BORDER_BOX */:
1389
- return (0, bound_curves_1.calculateBorderBoxPath)(curves);
1390
- case 2 /* BACKGROUND_CLIP.CONTENT_BOX */:
1391
- return (0, bound_curves_1.calculateContentBoxPath)(curves);
1392
- case 1 /* BACKGROUND_CLIP.PADDING_BOX */:
1393
- default:
1394
- return (0, bound_curves_1.calculatePaddingBoxPath)(curves);
1395
- }
1396
- };
1397
- var canvasTextAlign = function (textAlign) {
1398
- switch (textAlign) {
1399
- case 1 /* TEXT_ALIGN.CENTER */:
1400
- return 'center';
1401
- case 2 /* TEXT_ALIGN.RIGHT */:
1402
- return 'right';
1403
- case 0 /* TEXT_ALIGN.LEFT */:
1404
- default:
1405
- return 'left';
1406
- }
1407
- };
1408
- // see https://github.com/niklasvh/html2canvas/pull/2645
1409
- var iOSBrokenFonts = ['-apple-system', 'system-ui'];
1410
- var fixIOSSystemFonts = function (fontFamilies) {
1411
- return /iPhone OS 15_(0|1)/.test(window.navigator.userAgent)
1412
- ? fontFamilies.filter(function (fontFamily) { return iOSBrokenFonts.indexOf(fontFamily) === -1; })
1413
- : fontFamilies;
1414
- };
1415
- //# sourceMappingURL=canvas-renderer2.js.map