Browse Source

implement Canvas::registerFont(ttf)

this is implemented differently depending on the operating system. for
MacOS, CTFontManagerRegisterFontsForURL is the call to add a temporary
font. for Linux we use FontConfig, and for Windows use
AddFontResourceEx. all have been tested successfully

updated README and examples/font.js
master
Caleb Hearon 9 years ago
parent
commit
84a252cdbd
  1. 18
      Readme.md
  2. 1
      binding.gyp
  3. 27
      examples/font.js
  4. 7
      lib/canvas.js
  5. 7
      src/Canvas.cc
  6. 4
      src/Canvas.h
  7. 26
      src/CanvasRenderingContext2d.cc
  8. 15
      src/init.cc
  9. 21
      src/register_font.cc
  10. 2
      src/register_font.h

18
Readme.md

@ -182,6 +182,24 @@ canvas.toDataURL('image/jpeg', {opts...}, function(err, jpeg){ }); // see Canvas
canvas.toDataURL('image/jpeg', quality, function(err, jpeg){ }); // spec-following; quality from 0 to 1
```
### Canvas#registerFont for bundled fonts
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 they have installed.
To do that, you should use `Canvas#registerFont`.
**You need to call it before the Canvas is created**
```javascript
Canvas.registerFont('comicsans.ttf');
var canvas = new Canvas(500, 500),
ctx = canvas.getContext('2d');
ctx.font = '12px "Comic Sans"';
ctx.fillText(250, 10, 'Everyone hates this font :(');
```
### CanvasRenderingContext2D#patternQuality
Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.

1
binding.gyp

@ -53,6 +53,7 @@
'src/color.cc',
'src/Image.cc',
'src/ImageData.cc',
'src/register_font.cc',
'src/init.cc'
],
'conditions': [

27
examples/font.js

@ -2,38 +2,33 @@ var fs = require('fs')
var path = require('path')
var Canvas = require('..')
var Font = Canvas.Font
if (!Font) {
throw new Error('Need to compile with font support')
}
function fontFile (name) {
return path.join(__dirname, '/pfennigFont/', name)
}
var pfennigFont = new Font('pfennigFont', fontFile('Pfennig.ttf'))
pfennigFont.addFace(fontFile('PfennigBold.ttf'), 'bold')
pfennigFont.addFace(fontFile('PfennigItalic.ttf'), 'normal', 'italic')
pfennigFont.addFace(fontFile('PfennigBoldItalic.ttf'), 'bold', 'italic')
// Pass each font, including all of its individual variants if there are any, to
// `registerFont`. When you set `ctx.font`, refer to the styles and the family
// name as it is embedded in the TTF. If you aren't sure, open the font in
// FontForge and visit Element -> Font Information and copy the Family Name
Canvas.registerFont(fontFile('Pfennig.ttf'))
Canvas.registerFont(fontFile('PfennigBold.ttf'))
Canvas.registerFont(fontFile('PfennigItalic.ttf'))
Canvas.registerFont(fontFile('PfennigBoldItalic.ttf'))
var canvas = new Canvas(320, 320)
var ctx = canvas.getContext('2d')
// Tell the ctx to use the font.
ctx.addFont(pfennigFont)
ctx.font = 'normal normal 50px Helvetica'
ctx.fillText('Quo Vaids?', 0, 70)
ctx.font = 'bold 50px pfennigFont'
ctx.font = 'bold 50px Pfennig'
ctx.fillText('Quo Vaids?', 0, 140)
ctx.font = 'italic 50px pfennigFont'
ctx.font = 'italic 50px Pfennig'
ctx.fillText('Quo Vaids?', 0, 210)
ctx.font = 'bold italic 50px pfennigFont'
ctx.font = 'bold italic 50px Pfennig'
ctx.fillText('Quo Vaids?', 0, 280)
canvas.createPNGStream().pipe(fs.createWriteStream(path.join(__dirname, 'font.png')))

7
lib/canvas.js

@ -14,6 +14,7 @@ var canvas = require('./bindings')
, Canvas = canvas.Canvas
, Image = canvas.Image
, cairoVersion = canvas.cairoVersion
, registerFont = canvas.registerFont
, Context2d = require('./context2d')
, PNGStream = require('./pngstream')
, PDFStream = require('./pdfstream')
@ -34,6 +35,12 @@ var Canvas = exports = module.exports = Canvas;
exports.version = packageJson.version;
/**
* Register custom font
*/
exports.registerFont = registerFont;
/**
* Cairo version.
*/

7
src/Canvas.cc

@ -4,9 +4,6 @@
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "Canvas.h"
#include "PNG.h"
#include "CanvasRenderingContext2d.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -14,6 +11,10 @@
#include <node_version.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>
#include "Canvas.h"
#include "PNG.h"
#include "CanvasRenderingContext2d.h"
#include "closure.h"
#ifdef HAVE_JPEG

4
src/Canvas.h

@ -8,16 +8,16 @@
#ifndef __NODE_CANVAS_H__
#define __NODE_CANVAS_H__
#include <v8.h>
#include <node.h>
#include <v8.h>
#include <node_object_wrap.h>
#include <node_version.h>
#include <pango/pangocairo.h>
#include <cairo.h>
#include <nan.h>
using namespace v8;
using namespace node;
using namespace v8;
/*
* Maxmimum states per context.

26
src/CanvasRenderingContext2d.cc

@ -6,11 +6,11 @@
//
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <limits>
#include <vector>
#include <algorithm>
#include "Canvas.h"
#include "Point.h"
#include "Image.h"
@ -32,6 +32,28 @@
Nan::Persistent<FunctionTemplate> Context2d::constructor;
/*
* Custom strndup since Windows doesn't have it
*/
static char*
_strndup(const char *s, size_t n) {
size_t i;
const char *p = s;
char *ret = NULL;
for (i = 0; i < n && *p; i++, p++)
;
ret = (char*)malloc(i + 1);
if (ret) {
memcpy(ret, s, i);
ret[i] = '\0';
}
return ret;
}
/*
* Rectangle arg assertions.
*/
@ -65,7 +87,7 @@ enum {
void state_assign_fontFamily(canvas_state_t *state, const char *str) {
free(state->fontFamily);
state->fontFamily = strndup(str, 100);
state->fontFamily = _strndup(str, 100);
}

15
src/init.cc

@ -12,12 +12,25 @@
#include "CanvasGradient.h"
#include "CanvasPattern.h"
#include "CanvasRenderingContext2d.h"
#include "register_font.h"
// Compatibility with Visual Studio versions prior to VS2015
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
NAN_METHOD(register_font_js) {
if (!info[0]->IsString()) {
return Nan::ThrowError("Wrong argument type");
}
String::Utf8Value filePath(info[0]);
if (!register_font((unsigned char*) *filePath)) {
Nan::ThrowError("Could not load font to the system's font host");
}
}
NAN_MODULE_INIT(init) {
Canvas::Initialize(target);
Image::Initialize(target);
@ -26,6 +39,8 @@ NAN_MODULE_INIT(init) {
Gradient::Initialize(target);
Pattern::Initialize(target);
Nan::SetMethod(target, "registerFont", register_font_js);
target->Set(Nan::New<String>("cairoVersion").ToLocalChecked(), Nan::New<String>(cairo_version_string()).ToLocalChecked());
#ifdef HAVE_JPEG

21
src/register_font.cc

@ -0,0 +1,21 @@
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <CoreText/CoreText.h>
#elif defined(_WIN32)
#include <windows.h>
#else
#include <fontconfig/fontconfig.h>
#endif
bool
register_font(unsigned char *filepath) {
#ifdef __APPLE__
CFURLRef filepathUrl = CFURLCreateFromFileSystemRepresentation(NULL, filepath, strlen((char*)filepath), false);
return CTFontManagerRegisterFontsForURL(filepathUrl, kCTFontManagerScopeProcess, NULL);
#elif defined(_WIN32)
return AddFontResourceEx((LPCSTR)filepath, FR_PRIVATE, 0) != 0;
#else
return FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(filepath));
#endif
}

2
src/register_font.h

@ -0,0 +1,2 @@
bool register_font(unsigned char *filepath);
Loading…
Cancel
Save