diff --git a/lib/icc_profile.js b/lib/icc_profile.js index cedbcf6..c48637e 100644 --- a/lib/icc_profile.js +++ b/lib/icc_profile.js @@ -1,12 +1,12 @@ class ICCProfile { - // store profiles as data and create spaces later? - constructor(label, data, channels, alternate) { + constructor(label, data, channels, alternate, type) { this.label = label; this.data = data; this.channels = channels; this.alternate = alternate; this.ref = null; this.streamRef = null; + this.type = type ?? (channels === 4 ? 'cmyk' : 'rgb'); } embed(document) { diff --git a/lib/mixins/color_space.js b/lib/mixins/color_space.js index 9f55931..7e00b1d 100644 --- a/lib/mixins/color_space.js +++ b/lib/mixins/color_space.js @@ -5,8 +5,8 @@ export default { this._colorProfiles = {}; }, - iccProfile(label, data, channels, alternate) { - const profile = new ICCProfile(label, data, channels, alternate); + iccProfile(label, data, channels, alternate, type) { + const profile = new ICCProfile(label, data, channels, alternate, type); profile.embed(this); this._colorProfiles[label] = profile; return this; diff --git a/lib/write_svg.js b/lib/write_svg.js index 99ad795..8fcffe7 100644 --- a/lib/write_svg.js +++ b/lib/write_svg.js @@ -689,9 +689,9 @@ export default function (doc, svg, x, y, options) { doc.page.xobjects[group.name] = group.xobj; doc.addContent('/' + group.name + ' Do'); } - function docApplyMask(group) { - let name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1); - let gstate = doc.ref({ + function docApplyAlphaMask(group) { + const name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1); + const gstate = doc.ref({ Type: 'ExtGState', CA: 1, ca: 1, @@ -706,6 +706,28 @@ export default function (doc, svg, x, y, options) { doc.page.ext_gstates[name] = gstate; doc.addContent('/' + name + ' gs'); } + function docApplyMask(group) { + const name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1); + // backdrop should be black + let bc = [0, 0, 0]; + if (doc._activeColorProfile && doc._activeColorProfile.type === 'cmyk') { + bc = [1, 1, 1, 1]; + } + const gstate = doc.ref({ + Type: 'ExtGState', + CA: 1, + ca: 1, + BM: 'Normal', + SMask: { + S: 'Luminosity', + G: group.xobj, + BC: bc, + }, + }); + gstate.end(); + doc.page.ext_gstates[name] = gstate; + doc.addContent('/' + name + ' gs'); + } function applyBlendMode(group, blendMode) { // map svg blendMode to pdf const key = String(blendMode || '').toLowerCase(); @@ -3297,7 +3319,7 @@ export default function (doc, svg, x, y, options) { this.drawChildren(true, false); doc.restore(); docEndGroup(group); - docApplyMask(group); + docApplyAlphaMask(group); }; }; @@ -3321,11 +3343,16 @@ export default function (doc, svg, x, y, options) { if (this.attr('maskContentUnits') === 'objectBoundingBox') { doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]); } + const maskType = this.attr('mask-type') ?? 'luminance'; this.clip(); this.drawChildren(false, true); doc.restore(); docEndGroup(group); - docApplyMask(group); + if (maskType === 'alpha') { + docApplyAlphaMask(group); + } else { + docApplyMask(group); + } }; }; diff --git a/package.json b/package.json index 5c0aaf7..46bd567 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "document", "vector" ], - "version": "0.17.56", + "version": "0.17.58", "homepage": "http://pdfkit.org/", "author": { "name": "Devon Govett", diff --git a/types/pdfkit.d.ts b/types/pdfkit.d.ts index e2a03a4..cbad330 100644 --- a/types/pdfkit.d.ts +++ b/types/pdfkit.d.ts @@ -40,6 +40,7 @@ shader(fn: () => any): any; data: Uint8Array | Buffer; channels: number; alternate: string | string[]; + type?: 'cmyk' | 'rgb' } } @@ -786,7 +787,7 @@ declare namespace PDFKit.Mixins { } interface PDFColorSpace { - iccProfile(label:string, data: Uint8Array | ArrayBuffer, channels: number, alternate: string|string[]): this; + iccProfile(label:string, data: Uint8Array | ArrayBuffer, channels: number, alternate: string|string[], type?: 'rgb'|'cmyk'): this; } interface PDFOutputIntent {