Skip to content

Commit 7704d8d

Browse files
authored
Merge pull request #715 from chearon/prefer-pango
Require Pango over "toy" Cairo font methods. Redo the custom font API
2 parents 6c0b64b + 50b7c12 commit 7704d8d

16 files changed

+575
-582
lines changed

Readme.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@
2727
$ npm install canvas
2828
```
2929

30-
Unless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/Automattic/node-canvas/wiki/_pages).
30+
Unless previously installed you'll _need_ __Cairo__ and __Pango__. For system-specific installation view the [Wiki](https://github.com/Automattic/node-canvas/wiki/_pages).
3131

3232
You can quickly install the dependencies by using the command for your OS:
3333

3434
OS | Command
3535
----- | -----
36-
OS X | `brew install pkg-config cairo libpng jpeg giflib`
36+
OS X | `brew install pkg-config cairo pango libpng jpeg giflib`
3737
Ubuntu | `sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++`
3838
Fedora | `sudo yum install cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel giflib-devel`
39-
Solaris | `pkgin install cairo pkg-config xproto renderproto kbproto xextproto`
39+
Solaris | `pkgin install cairo pango pkg-config xproto renderproto kbproto xextproto`
4040
Windows | [Instructions on our wiki](https://github.com/Automattic/node-canvas/wiki/Installation---Windows)
4141

4242
**El Capitan users:** If you have recently updated to El Capitan and are experiencing trouble when compiling, run the following command: `xcode-select --install`. Read more about the problem [on Stack Overflow](http://stackoverflow.com/a/32929012/148072).
@@ -190,6 +190,26 @@ canvas.toDataURL('image/jpeg', {opts...}, function(err, jpeg){ }); // see Canvas
190190
canvas.toDataURL('image/jpeg', quality, function(err, jpeg){ }); // spec-following; quality from 0 to 1
191191
```
192192

193+
### Canvas.registerFont for bundled fonts
194+
195+
It can be useful to use a custom font file if you are distributing code that uses node-canvas and a specific font. Or perhaps you are using it to do automated tests and you want the renderings to be the same across operating systems regardless of what fonts are installed.
196+
197+
To do that, you should use `Canvas.registerFont`.
198+
199+
**You need to call it before the Canvas is created**
200+
201+
```javascript
202+
Canvas.registerFont('comicsans.ttf', {family: 'Comic Sans'});
203+
204+
var canvas = new Canvas(500, 500),
205+
ctx = canvas.getContext('2d');
206+
207+
ctx.font = '12px "Comic Sans"';
208+
ctx.fillText(250, 10, 'Everyone hates this font :(');
209+
```
210+
211+
The second argument is an object with properties that resemble the CSS properties that are specified in `@font-face` rules. You must specify at least `family`. `weight`, and `style` are optional (and default to "normal").
212+
193213
### CanvasRenderingContext2D#patternQuality
194214

195215
Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.

binding.gyp

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,12 @@
44
'variables': {
55
'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle
66
'with_jpeg%': 'false',
7-
'with_gif%': 'false',
8-
'with_pango%': 'false',
9-
'with_freetype%': 'false'
7+
'with_gif%': 'false'
108
}
119
}, { # 'OS!="win"'
1210
'variables': {
1311
'with_jpeg%': '<!(./util/has_lib.sh jpeg)',
14-
'with_gif%': '<!(./util/has_lib.sh gif)',
15-
'with_pango%': '<!(./util/has_lib.sh pango)',
16-
'with_freetype%': '<!(./util/has_lib.sh freetype)'
12+
'with_gif%': '<!(./util/has_lib.sh gif)'
1713
}
1814
}]
1915
],
@@ -26,12 +22,21 @@
2622
'copies': [{
2723
'destination': '<(PRODUCT_DIR)',
2824
'files': [
25+
'<(GTK_Root)/bin/zlib1.dll',
26+
'<(GTK_Root)/bin/libintl-8.dll',
27+
'<(GTK_Root)/bin/libpng14-14.dll',
28+
'<(GTK_Root)/bin/libpangocairo-1.0-0.dll',
29+
'<(GTK_Root)/bin/libpango-1.0-0.dll',
30+
'<(GTK_Root)/bin/libpangoft2-1.0-0.dll',
31+
'<(GTK_Root)/bin/libpangowin32-1.0-0.dll',
2932
'<(GTK_Root)/bin/libcairo-2.dll',
30-
'<(GTK_Root)/bin/libexpat-1.dll',
3133
'<(GTK_Root)/bin/libfontconfig-1.dll',
3234
'<(GTK_Root)/bin/libfreetype-6.dll',
33-
'<(GTK_Root)/bin/libpng14-14.dll',
34-
'<(GTK_Root)/bin/zlib1.dll',
35+
'<(GTK_Root)/bin/libglib-2.0-0.dll',
36+
'<(GTK_Root)/bin/libgobject-2.0-0.dll',
37+
'<(GTK_Root)/bin/libgmodule-2.0-0.dll',
38+
'<(GTK_Root)/bin/libgthread-2.0-0.dll',
39+
'<(GTK_Root)/bin/libexpat-1.dll'
3540
]
3641
}]
3742
}]
@@ -48,17 +53,27 @@
4853
'src/color.cc',
4954
'src/Image.cc',
5055
'src/ImageData.cc',
56+
'src/register_font.cc',
5157
'src/init.cc'
5258
],
5359
'conditions': [
5460
['OS=="win"', {
5561
'libraries': [
5662
'-l<(GTK_Root)/lib/cairo.lib',
57-
'-l<(GTK_Root)/lib/libpng.lib'
63+
'-l<(GTK_Root)/lib/libpng.lib',
64+
'-l<(GTK_Root)/lib/pangocairo-1.0.lib',
65+
'-l<(GTK_Root)/lib/pango-1.0.lib',
66+
'-l<(GTK_Root)/lib/freetype.lib',
67+
'-l<(GTK_Root)/lib/glib-2.0.lib',
68+
'-l<(GTK_Root)/lib/gobject-2.0.lib'
5869
],
5970
'include_dirs': [
6071
'<(GTK_Root)/include',
6172
'<(GTK_Root)/include/cairo',
73+
'<(GTK_Root)/include/pango-1.0',
74+
'<(GTK_Root)/include/glib-2.0',
75+
'<(GTK_Root)/include/freetype2',
76+
'<(GTK_Root)/lib/glib-2.0/include'
6277
],
6378
'defines': [
6479
'_USE_MATH_DEFINES' # for M_PI
@@ -87,49 +102,15 @@
87102
'libraries': [
88103
'<!@(pkg-config pixman-1 --libs)',
89104
'<!@(pkg-config cairo --libs)',
90-
'<!@(pkg-config libpng --libs)'
105+
'<!@(pkg-config libpng --libs)',
106+
'<!@(pkg-config pangocairo --libs)',
107+
'<!@(pkg-config freetype2 --libs)'
91108
],
92109
'include_dirs': [
93110
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)',
94-
'<!@(pkg-config libpng --cflags-only-I | sed s/-I//g)'
95-
]
96-
}],
97-
['with_freetype=="true"', {
98-
'defines': [
99-
'HAVE_FREETYPE'
100-
],
101-
'sources': [
102-
'src/FontFace.cc'
103-
],
104-
'conditions': [
105-
['OS=="win"', {
106-
# No support for windows right now.
107-
}, { # 'OS!="win"'
108-
'include_dirs': [ # tried to pass through cflags but failed.
109-
# Need to include the header files of cairo AND freetype.
110-
# Looking up the includes of cairo does both.
111-
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)'
112-
]
113-
}]
114-
]
115-
}],
116-
['with_pango=="true"', {
117-
'defines': [
118-
'HAVE_PANGO'
119-
],
120-
'conditions': [
121-
['OS=="win"', {
122-
'libraries': [
123-
'-l<(GTK_Root)/lib/pangocairo.lib'
124-
]
125-
}, { # 'OS!="win"'
126-
'include_dirs': [ # tried to pass through cflags but failed
127-
'<!@(pkg-config pangocairo --cflags-only-I | sed s/-I//g)'
128-
],
129-
'libraries': [
130-
'<!@(pkg-config pangocairo --libs)'
131-
]
132-
}]
111+
'<!@(pkg-config libpng --cflags-only-I | sed s/-I//g)',
112+
'<!@(pkg-config pangocairo --cflags-only-I | sed s/-I//g)',
113+
'<!@(pkg-config freetype2 --cflags-only-I | sed s/-I//g)'
133114
]
134115
}],
135116
['with_jpeg=="true"', {

examples/font.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,22 @@ var fs = require('fs')
22
var path = require('path')
33
var Canvas = require('..')
44

5-
var Font = Canvas.Font
6-
7-
if (!Font) {
8-
throw new Error('Need to compile with font support')
9-
}
10-
115
function fontFile (name) {
126
return path.join(__dirname, '/pfennigFont/', name)
137
}
148

15-
var pfennigFont = new Font('pfennigFont', fontFile('Pfennig.ttf'))
16-
pfennigFont.addFace(fontFile('PfennigBold.ttf'), 'bold')
17-
pfennigFont.addFace(fontFile('PfennigItalic.ttf'), 'normal', 'italic')
18-
pfennigFont.addFace(fontFile('PfennigBoldItalic.ttf'), 'bold', 'italic')
9+
// Pass each font, including all of its individual variants if there are any, to
10+
// `registerFont`. When you set `ctx.font`, refer to the styles and the family
11+
// name as it is embedded in the TTF. If you aren't sure, open the font in
12+
// FontForge and visit Element -> Font Information and copy the Family Name
13+
Canvas.registerFont(fontFile('Pfennig.ttf'), {family: 'pfennigFont'})
14+
Canvas.registerFont(fontFile('PfennigBold.ttf'), {family: 'pfennigFont', weight: 'bold'})
15+
Canvas.registerFont(fontFile('PfennigItalic.ttf'), {family: 'pfennigFont', style: 'italic'})
16+
Canvas.registerFont(fontFile('PfennigBoldItalic.ttf'), {family: 'pfennigFont', weight: 'bold', style: 'italic'})
1917

2018
var canvas = new Canvas(320, 320)
2119
var ctx = canvas.getContext('2d')
2220

23-
// Tell the ctx to use the font.
24-
ctx.addFont(pfennigFont)
25-
2621
ctx.font = 'normal normal 50px Helvetica'
2722

2823
ctx.fillText('Quo Vaids?', 0, 70)

lib/canvas.js

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ var canvas = require('./bindings')
1818
, PNGStream = require('./pngstream')
1919
, PDFStream = require('./pdfstream')
2020
, JPEGStream = require('./jpegstream')
21-
, FontFace = canvas.FontFace
2221
, fs = require('fs')
2322
, packageJson = require("../package.json")
2423
, FORMATS = ['image/png', 'image/jpeg'];
@@ -76,28 +75,13 @@ exports.JPEGStream = JPEGStream;
7675
exports.Image = Image;
7776
exports.ImageData = canvas.ImageData;
7877

79-
if (FontFace) {
80-
var Font = function Font(name, path, idx) {
81-
this.name = name;
82-
this._faces = {};
83-
84-
this.addFace(path, 'normal', 'normal', idx);
85-
};
86-
87-
Font.prototype.addFace = function(path, weight, style, idx) {
88-
style = style || 'normal';
89-
weight = weight || 'normal';
90-
91-
var face = new FontFace(path, idx || 0);
92-
this._faces[weight + '-' + style] = face;
93-
};
94-
95-
Font.prototype.getFace = function(weightStyle) {
96-
return this._faces[weightStyle] || this._faces['normal-normal'];
97-
};
78+
/**
79+
* Resolve paths for registerFont
80+
*/
9881

99-
exports.Font = Font;
100-
}
82+
Canvas.registerFont = function(src, fontFace){
83+
return Canvas._registerFont(fs.realpathSync(src), fontFace);
84+
};
10185

10286
/**
10387
* Context2d implementation.

lib/context2d.js

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ var parseFont = exports.parseFont = function(str){
7777
font.style = captures[2] || 'normal';
7878
font.size = parseFloat(captures[3]);
7979
font.unit = captures[4];
80-
font.family = captures[5].replace(/["']/g, '').split(',')[0].trim();
80+
font.family = captures[5].replace(/["']/g, '').split(',').map(function (family) {
81+
return family.trim();
82+
}).join(',');
8183

8284
// TODO: dpi
8385
// TODO: remaining unit conversion
@@ -235,19 +237,6 @@ Context2d.prototype.__defineGetter__('strokeStyle', function(){
235237
return this.lastStrokeStyle || this.strokeColor;
236238
});
237239

238-
/**
239-
* Register `font` for usage.
240-
*
241-
* @param {Font} font
242-
* @api public
243-
*/
244-
245-
Context2d.prototype.addFont = function(font) {
246-
this._fonts = this._fonts || {};
247-
if (this._fonts[font.name]) return;
248-
this._fonts[font.name] = font;
249-
};
250-
251240
/**
252241
* Set font.
253242
*
@@ -261,22 +250,12 @@ Context2d.prototype.__defineSetter__('font', function(val){
261250
var font;
262251
if (font = parseFont(val)) {
263252
this.lastFontString = val;
264-
265-
var fonts = this._fonts;
266-
if (fonts && fonts[font.family]) {
267-
var fontObj = fonts[font.family];
268-
var type = font.weight + '-' + font.style;
269-
270-
var fontFace = fontObj.getFace(type);
271-
this._setFontFace(fontFace, font.size);
272-
} else {
273-
this._setFont(
274-
font.weight
275-
, font.style
276-
, font.size
277-
, font.unit
278-
, font.family);
279-
}
253+
this._setFont(
254+
font.weight
255+
, font.style
256+
, font.size
257+
, font.unit
258+
, font.family);
280259
}
281260
}
282261
});

0 commit comments

Comments
 (0)