Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for spot colors #1464

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Unreleased

- Add support for spot colors (#756, #1464)
- Add support for PDF/A-1b, PDF/A-1a, PDF/A-2b, PDF/A-2a, PDF/A-3b, PDF/A-3a

### [v0.13.0] - 2021-10-24
Expand Down
12 changes: 10 additions & 2 deletions docs/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ and some other properties. Here is a list of the available annotation methods:
* `fileAnnotation(x, y, width, height, file, options)`

Many of the annotations have a `color` option that you can specify. You can
use an array of RGB values, a hex color, or a named CSS color value for that
option.
use an array of RGB values, a hex color, a named CSS color value, or a named
spot color value for that option.



If you are adding an annotation to a piece of text, such as a link or
underline, you will need to know the width and height of the text in order to
Expand Down Expand Up @@ -58,6 +60,12 @@ Here is an example that uses a few of the annotation types.
.highlight(20, doc.y, doc.widthOfString('This text is highlighted!'), height)
.text('This text is highlighted!');

// Create text with a spot color
doc.addSpotColor('PANTONE185C', 0, 100, 78, 9)
doc.moveDown()
.fillColor('PANTONE185C')
.text('This text uses spot color!');

// Create the crossed out text
doc.moveDown()
.strike(20, doc.y, doc.widthOfString('STRIKE!'), height)
Expand Down
Binary file modified docs/guide.pdf
Binary file not shown.
21 changes: 21 additions & 0 deletions lib/mixins/SpotColor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default class SpotColor {
constructor(doc, name, C, M, Y, K) {
this.id = 'CS' + Object.keys(doc.spotColors).length;
this.name = name;
this.values = [C, M, Y, K];
this.ref = doc.ref([
'Separation',
this.name,
'DeviceCMYK',
{
Range: [0, 1, 0, 1, 0, 1, 0, 1],
C0: [0, 0, 0, 0],
C1: this.values.map(value => value / 100),
FunctionType: 2,
Domain: [0, 1],
N: 1
}
]);
this.ref.end();
}
}
19 changes: 17 additions & 2 deletions lib/mixins/color.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Gradient from '../gradient';
import pattern from '../pattern';
import SpotColor from './SpotColor';

const { PDFGradient, PDFLinearGradient, PDFRadialGradient } = Gradient;
const { PDFTilingPattern } = pattern;

export default {
initColor() {
this.spotColors = {};
// The opacity dictionaries
this._opacityRegistry = {};
this._opacityCount = 0;
Expand All @@ -26,6 +28,8 @@ export default {
color = [hex >> 16, (hex >> 8) & 0xff, hex & 0xff];
} else if (namedColors[color]) {
color = namedColors[color];
} else if (this.spotColors[color]) {
return this.spotColors[color];
}
}

Expand Down Expand Up @@ -66,8 +70,12 @@ export default {
const space = this._getColorSpace(color);
this._setColorSpace(space, stroke);

color = color.join(' ');
this.addContent(`${color} ${op}`);
if (color instanceof SpotColor) {
this.page.colorSpaces[color.id] = color.ref;
this.addContent(`1 ${op}`);
} else {
this.addContent(`${color.join(' ')} ${op}`);
}

return true;
},
Expand All @@ -78,6 +86,7 @@ export default {
},

_getColorSpace(color) {
if (color instanceof SpotColor) return color.id;
return color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
},

Expand Down Expand Up @@ -163,6 +172,12 @@ export default {

pattern(bbox, xStep, yStep, stream) {
return new PDFTilingPattern(this, bbox, xStep, yStep, stream);
},

addSpotColor: function(name, C, M, Y, K) {
const color = new SpotColor(this, name, C, M, Y, K);
this.spotColors[name] = color;
return this;
}
};

Expand Down
2 changes: 1 addition & 1 deletion lib/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class PDFObject {
static convert(object, encryptFn = null) {
// String literals are converted to the PDF name type
if (typeof object === 'string') {
return `/${object}`;
return /^[/[(\d].*/.test(object) ? object : `/${object}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add unit tests for this change?


// String objects are converted to PDF strings (UTF-16)
} else if (object instanceof String) {
Expand Down
4 changes: 4 additions & 0 deletions lib/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ class PDFPage {

end() {
this.dictionary.end();
this.resources.data.ColorSpace = this.resources.data.ColorSpace || {};
for (const color of Object.values(this.document.spotColors)) {
this.resources.data.ColorSpace[color.id] = `${color.ref.id} 0 R`;
}
this.resources.end();
return this.content.end();
}
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/color.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ describe('color', function() {
1
]);
});

test('normalize with spot color', function() {
const doc = new PDFDocument();
doc.addSpotColor('PANTONE 123 C', 0.1, 0.2, 0.3, 0.4);

const color = doc._normalizeColor('PANTONE 123 C');
expect(color.id).toEqual('CS0');
expect(color.values).toEqual([0.1, 0.2, 0.3, 0.4]);
});
});
2 changes: 1 addition & 1 deletion tests/unit/toContainChunk/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import diff from 'jest-diff';
import { diff } from 'jest-diff';
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly related to this PR, but as I was running the tests, my new test initially failed, and I had to change this to make the test error correctly.


const buildMessage = (utils, data, chunk, headIndex) => {
let message;
Expand Down
Loading