html2canvas-pro 2.2.0 → 2.2.2

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.
@@ -64,7 +64,8 @@ const renderElement = async (element, opts, config) => {
64
64
  imageTimeout: opts.imageTimeout ?? 15000,
65
65
  proxy: opts.proxy,
66
66
  useCORS: opts.useCORS ?? false,
67
- customIsSameOrigin: opts.customIsSameOrigin
67
+ customIsSameOrigin: opts.customIsSameOrigin,
68
+ maxCacheSize: opts.maxCacheSize
68
69
  };
69
70
  const contextOptions = {
70
71
  logging: opts.logging ?? true,
@@ -310,10 +310,16 @@ const parse = (context, descriptor, style) => {
310
310
  valueCache = new Map();
311
311
  parseCache.set(descriptor, valueCache);
312
312
  }
313
- if (valueCache.size >= constants_1.PARSE_CACHE_MAX_PER_DESCRIPTOR) {
314
- const oldestKey = valueCache.keys().next().value;
315
- valueCache.delete(oldestKey);
313
+ // Skip caching for image descriptors — their parse() has the critical
314
+ // side effect of calling context.cache.addImage(url) which must run
315
+ // on every render pass (different cache instances per html2canvas call).
316
+ const skipCache = descriptor.type === 3 /* PropertyDescriptorParsingType.TYPE_VALUE */ && descriptor.format === 'image';
317
+ if (!skipCache) {
318
+ if (valueCache.size >= constants_1.PARSE_CACHE_MAX_PER_DESCRIPTOR) {
319
+ const oldestKey = valueCache.keys().next().value;
320
+ valueCache.delete(oldestKey);
321
+ }
322
+ valueCache.set(rawValue, result);
316
323
  }
317
- valueCache.set(rawValue, result);
318
324
  return result;
319
325
  };
@@ -67,7 +67,17 @@ class EffectsRenderer {
67
67
  this.ctx.globalCompositeOperation = effect.compositeOperation;
68
68
  }
69
69
  else if ((0, effects_1.isFilterEffect)(effect)) {
70
- this.ctx.filter = effect.filterString;
70
+ // Apply all filters except drop-shadow() via ctx.filter.
71
+ // drop-shadow() is rendered separately through ctx.shadow*
72
+ // because ctx.filter="drop-shadow(...)" taints the canvas
73
+ // even for same-origin content (Chrome, Firefox).
74
+ this.ctx.filter = effect.safeFilterString || 'none';
75
+ if (effect.shadow) {
76
+ this.ctx.shadowOffsetX = effect.shadow.offsetX;
77
+ this.ctx.shadowOffsetY = effect.shadow.offsetY;
78
+ this.ctx.shadowBlur = effect.shadow.blur;
79
+ this.ctx.shadowColor = effect.shadow.color;
80
+ }
71
81
  }
72
82
  this.activeEffects.push(effect);
73
83
  }
@@ -76,9 +76,23 @@ class BlendEffect {
76
76
  exports.BlendEffect = BlendEffect;
77
77
  class FilterEffect {
78
78
  constructor(filterString) {
79
- this.filterString = filterString;
80
79
  this.type = 5 /* EffectType.FILTER */;
81
80
  this.target = 2 /* EffectTarget.BACKGROUND_BORDERS */ | 4 /* EffectTarget.CONTENT */;
81
+ // Parse drop-shadow(...) out of the filter string so we can render it
82
+ // via ctx.shadow* instead of ctx.filter (which taints the canvas).
83
+ const dropShadowMatch = filterString.match(/drop-shadow\(\s*([\d.-]+)(px)?\s+([\d.-]+)(px)?\s+([\d.-]+)(px)?\s+(.+?)\s*\)/);
84
+ if (dropShadowMatch) {
85
+ this.shadow = {
86
+ offsetX: parseFloat(dropShadowMatch[1]),
87
+ offsetY: parseFloat(dropShadowMatch[3]),
88
+ blur: parseFloat(dropShadowMatch[5]),
89
+ color: dropShadowMatch[7].trim()
90
+ };
91
+ this.safeFilterString = filterString.replace(/drop-shadow\([^)]+\)\s*/g, '').trim();
92
+ }
93
+ else {
94
+ this.safeFilterString = filterString;
95
+ }
82
96
  }
83
97
  }
84
98
  exports.FilterEffect = FilterEffect;
@@ -57,9 +57,17 @@ export declare class BlendEffect implements IElementEffect {
57
57
  constructor(mixBlendMode: MixBlendMode);
58
58
  }
59
59
  export declare class FilterEffect implements IElementEffect {
60
- readonly filterString: string;
61
60
  readonly type: EffectType;
62
61
  readonly target: number;
62
+ /** CSS filter string with drop-shadow() stripped (safe for ctx.filter). */
63
+ readonly safeFilterString: string;
64
+ /** Shadow params for drop-shadow(), if present. */
65
+ readonly shadow?: {
66
+ offsetX: number;
67
+ offsetY: number;
68
+ blur: number;
69
+ color: string;
70
+ };
63
71
  constructor(filterString: string);
64
72
  }
65
73
  export declare const isTransformEffect: (effect: IElementEffect) => effect is TransformEffect;
package/package.json CHANGED
@@ -19,7 +19,7 @@
19
19
  "default": "./dist/html2canvas-pro.esm.js"
20
20
  }
21
21
  },
22
- "version": "2.2.0",
22
+ "version": "2.2.2",
23
23
  "author": {
24
24
  "name": "yorickshan",
25
25
  "email": "yorickshan@gmail.com",