Initial commit

This commit is contained in:
WatermelonModders
2022-05-31 12:35:46 -04:00
commit fc5cb0c32c
4097 changed files with 447075 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
<!----------------------------------- STOP! ----------------------------------->
<!---
Having trouble installing node-canvas? Please make sure you have read
the installation instructions located here before asking for help:
https://github.com/Automattic/node-canvas#installation
Still having problems, found a bug or want a feature? Fill out the form below.
-->
<!--- Provide a general summary of the issue in the Title above -->
## Issue or Feature
<!--- Provide info about the bug or feature. -->
## Steps to Reproduce
<!--- For bugs, provide a short, complete code example to reproduce the issue. -->
```js
var Canvas = require('canvas');
var canvas = new Canvas(200, 200);
var ctx = canvas.getContext('2d');
// etc.
```
## Your Environment
* Version of node-canvas (e.g. 1.4.0):
* Environment (e.g. node 4.2.0 on Mac OS X 10.8):
+6
View File
@@ -0,0 +1,6 @@
testing
build
benchmarks
examples
support
test
+23
View File
@@ -0,0 +1,23 @@
language: node_js
node_js:
- '6'
- '4'
- '0.12'
- '0.10'
- '0.8'
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libcairo2-dev
- libjpeg8-dev
- libpango1.0-dev
- libgif-dev
- g++-4.9
env:
- CXX=g++-4.9
before_install:
- if [[ $TRAVIS_NODE_VERSION == 0.8 ]]; then npm install -g npm@1.4.28; fi
- npm explore npm -g -- npm install node-gyp@latest
sudo: false
+644
View File
@@ -0,0 +1,644 @@
1.6.2 / 2016-10-30
==================
* Fix deprecation warnings (#835)
1.6.1 / 2016-10-23
==================
* Convert has_lib.sh to sh so it also works on BSD OSes (#820)
1.6.0 / 2016-10-16
==================
* Support canvas.getBuffer('raw') (#819)
1.5.0 / 2016-09-11
==================
* Crude PDF stream implementation (#781)
* Update CI settings (#797)
* Reduce some of the install warnings (#794)
* Fix lineDash browser tests never finishing (#793)
* Add issue template (#791)
1.4.0 / 2016-06-03
==================
* Add support for evenodd fill rule (#762)
1.3.17 / 2016-06-03
===================
* Removing redundant duplicate calls (#769)
* Cleanup examples (#776)
* Fix CanvasRenderingContext2D class name (#777)
1.3.16 / 2016-05-29
===================
* Fix leak of data when streaming JPEG (#774)
1.3.15 / 2016-05-09
===================
* Fix segfault in putImageData (#750)
1.3.14 / 2016-05-05
===================
* Clamp JPEG buffer size (#739)
1.3.13 / 2016-05-01
===================
* Bumb NAN version (#759)
1.3.12 / 2016-03-01
===================
* Expose freetype version (#718)
* Require new in constructor (#717)
1.3.11 / 2016-03-01
===================
* Properly clamp quality in toDataURL (#728)
* Strict mode (#719)
1.3.10 / 2016-02-07
===================
* Fix segfault on node 0.10.x (#712)
1.3.9 / 2016-01-27
==================
* Allow to unbind onload/onerror callback handlers (#706)
1.3.8 / 2016-01-22
==================
* Cleanup build scripts and fix pangocairo detection (#701)
1.3.7 / 2016-01-13
==================
* Don't unbind onload/onerror callbacks after invoking them (#615)
1.3.6 / 2016-01-06
==================
* Allow optional arguments in `toDataURL` to be `undefined` and improve `toDataURL`'s spec compliance (#690)
1.3.5 / 2015-12-07
==================
* Add image/jpeg support to `toDataUrl` (#685)
1.3.4 / 2015-11-21
==================
* Upgrade nan to 2.1.0 (#671)
1.3.3 / 2015-11-21
==================
* Fix compilation on Visual Studio 2015 (#670)
1.3.2 / 2015-11-18
==================
* Fix incorrect Y offset and scaling for shadows (#669)
1.3.1 / 2015-11-09
==================
* Wrap std::min calls in paranthesis to prevent macro expansion on windows (#660)
1.3.0 / 2015-10-26
==================
* Expose ImageData constructor and make it more spec-compliant (#569)
1.2.11 / 2015-10-20
===================
* Implement blur on images (#648)
1.2.10 / 2015-10-12
===================
* Fix segfault in Canvas#jpegStream (#629)
1.2.9 / 2015-09-14
==================
* Upgrade to Nan 2.x with support for iojs 3.x and Node.js 4.x (#622)
1.2.8 / 2015-08-30
==================
* Clean up the tests (#612)
* Replace CanvasPixelArray with Uint8ClampedArray to be API-compliant (#604)
* Specify travis iojs versions (#611)
1.2.7 / 2015-07-29
==================
* Avoid future reserved keyword (#592)
1.2.6 / 2015-07-29
==================
* Fix the build on windows (#589)
1.2.5 / 2015-07-28
==================
* Another npm release, since 1.2.4 was botched (see #596)
1.2.4 / 2015-07-23
==================
* Point `homepage` and `repository` links to [`github.com/Automattic/node-canvas`][repo]
* Fix Travis builds and Cairo include paths (thanks, Linus Unnebäck!)
1.2.3 / 2015-05-21
==================
* Update TJ Holowaychuk's username in the readme
* Fix segmentation fault in `Image::loadFromBuffer` when buffer is empty
* Optimize getImageData()
* package: add "license" attribute
* package: update "nan" to v1.8.4
* package: append `.git` to "repository" URL
1.2.2 / 2015-04-18
==================
* Now works on io.js
* Fix 'drawImage' scaling (the dimensions of the region that gets clipped also needs to be scaled).
* Fix bug in StreamPNGSync
1.2.1 / 2015-02-10
==================
* Use non-cairo 1.12 API for shadow blur
1.2.0 / 2015-01-31
==================
* travis: drop support for node v0.6
* Merge pull request #507 from salzhrani/iojs
* io.js compatibility
* Merge pull request #505 from woodcoder/shadow-blur
* Fix issue with line width not being correct in stroked shadows.
* Add another shadow/transform test.
* Refactor setSourceRGBA to allow the context to be supplied.
* Simple image shadow (no blurring or handling current transforms) based on image's alpha channel.
* Test showing issue #133, that images don't have shadows.
* The +1 on the offset seems to match the browser's output better, but I can't work out why it would be needed (unless it's pixel alignment related).
* Make the shadow radius more accurately match the browser's, making use of sigma scale as used in SKIA: https://github.com/google/skia/blob/master/src/effects/SkBlurMask.cpp#L26.
* Create a new image surface to render blurred shadows to, this means that vector formats like PDF will now render blurs.
* Add recommended calls to flush and dirty buffer, as per http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-image-surface-get-data.
* Add PDF button to test page to easily generate PDF version of the test image.
* Fix to ensure shadowOffset is unaffected by the current transform.
* New test illustrating that canvas implementation doesn't translate the shadowOffset.
* Merge pull request #490 from AllYearbooks/master
* Merge pull request #501 from motiz88/hsl-color
* Code style + attribution. Also removed parseClipped() and commented out wrapInt (now wrap_int).
* Added visual tests for hsl() and hsla() color parsing.
* Fixed <number> handling in hsl/hsla color parser. parseNumber() was erroring out on numbers with long fractional parts.
* hsl/hsla color parsing + rebeccapurple hsl() and hsla() color values are now supported, with corresponding unit tests. Also added rebeccapurple (from CSS Color Level 4) to the named color list.
* float rather than int for drawImage arguments
* with_pango to true and use fontconfig to load fonts
* Merge pull request #399 from nulltask/fix/lighten
* Merge pull request #465 from espadrine/master
* Merge pull request #470 from tonylukasavage/patch-1
* Add one-liner MacPorts install to docs
* Offer SVG output.
* Readme update: node-gyp.
* Readme: fix subheading size
* Readme: remove Gemnasium badge, use SVG for npm badge
* Readme: add Travis-CI badge
* change operator lighter to lighten
1.1.6 / 2014-08-01
==================
* export canvas.CanvasPixelArray instead of canvas.PixelArray which is undefined
* Glib version test into giflib exists test
* Giflib 5.1
* install: use an even older version of giflib (v4.1.6)
* install: use an older version of giflib (v4.2.3)
* install: install `giflib`
* install: use more compatible sh syntax
* travis: attempt to run the ./install script before testintg
* travis: test node v0.6, v0.8, v0.10, and v0.11
* Distinguish between 'add' and 'lighter'
1.1.5 / 2014-06-26
==================
* Readme: remove Contributors section
* Readme: update copyright
* On Windows, copy required DLLs next to ".node" file (#442 @pandell)
* Duplicate "msvc_settings" for "Debug" configuration
* Remove unneeded #include <nan.h>
* Use float constants to prevent double->float conversion warning
* Ignore Visual C++ 2013 warnings (#441 @pandell)
* Add algorithm include to CanvasRenderingContext2d.cc for std::min (#435 @kkoopa)
* Updated NAN to 1.2.0 (#434 @kkoopa)
1.1.4 / 2014-06-08
==================
* Fix compile error with Visual C++
* Add support for the lineDash API
* Update NAN
* New V8 compatibility
* Correctly limit bounds in PutImageData to prevent segment fault
* Fix segfault when onload and onerror are not function
* Add support for Node 0.11.9
1.1.3 / 2014-01-08
==================
* Add CAIRO_FORMAT_INVALID
* Readjust the amount of allocated memory
* Fix argument index for filter parameter
* Make has_lib.sh work properly on Debian 64bit
1.1.2 / 2013-10-31
==================
* NAN dep upgrade, full node@<=0.11.8 compatibility
* Use node::MakeCallback() instead of v8::Function::Call()
* Improve nan location discovery
* Fix enabling gif/jpeg options on Ubuntu 13.04
1.1.1 / 2013-10-09
==================
* add better support for outdated versions of Cairo
1.1.0 / 2013-08-01
==================
* add png compression options
* add jpeg stream progressive mode option
* fix resource leaks on read errors
1.0.4 / 2013-07-23
==================
* 0.11.4+ compatibility using NAN
* fix typo in context2d for imageSmoothingEnabled
1.0.3 / 2013-06-04
==================
* add "nearest" and "bilinear" to patternQuality
* fix fread() retval check (items not bytes)
* removed unneeded private fields
1.0.2 / 2013-03-22
==================
* add Context2d#imageSmoothingEnabled=
1.0.1 / 2013-02-25
==================
* travis: test modern node versions
* change the node-gyp build to use pkg-config
1.0.0 / 2013-01-16
==================
* add conditional pango font support [Julian Viereck]
* add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods
* add support for grayscale JPEGs
* fix: explicitly cast the after work callback function to "uv_after_work_cb"
* fix test server for express 3.x
* fix: call cairo_surface_finish in ~Canvas when pdf
* remove old 0.4.x binding support. Closes #197
0.13.1 / 2012-08-20
==================
* fix cases where GIF_LIB_VERSION is not defined
* fix auto-detection of optional libraries for OS X
* fix Context2d::SetFont for pango when setting normal weight/style
0.13.0 / 2012-08-12
==================
* add pango support [c-spencer]
* add pango / png / jpeg gyp auto-detection [c-spencer]
* add `.gifVersion` [tootallnate]
* add `.jpegVersion` [tootallnate]
* add moar gyp stuff [tootallnate]
* remove wscript
* fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()`
0.12.1 / 2012-06-29
==================
* fix jpeg malloc Image issue. Closes #160 [c-spencer]
* Improve Image mode API
* Add clearData method to handle reassignment of src, and clean up mime data memory handling.
* Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional.
* Add optional mime-data tracking to Image.
* Refactor JPEG decoding into decodeJPEGIntoSurface
0.12.0 / 2012-05-02
==================
* Added `textDrawingMode` context property [c-spencer]
* Added additional TextMetrics properties [c-spencer]
0.11.3 / 2012-04-25
==================
* Fixed `Image` memory leak. Closes #150
* Fixed Context2d::hasShadow()
0.11.2 / 2012-04-12
==================
* Fixed: pdf memory leak, free closure and surface in ~Canvas
0.11.1 / 2012-04-10
==================
* Changed: renamed .nextPage() to .addPage()
0.11.0 / 2012-04-10
==================
* Added quick PDF support
* Added `Canvas#type` getter
* Added ./examples/pdf-images.js
* Added ./examples/multiple-page-pdf.js
* Added ./examples/small-pdf.js
0.10.3 / 2012-02-27
==================
* Fixed quadratic curve starting point for undefined path. Closes #155
0.10.2 / 2012-02-06
==================
* Fixed: Context2d setters with invalid values ignored
* Changed: replaced seek with `fstat()`
0.10.1 / 2012-01-31
==================
* Added _/opt/local/lib_ to wscript [obarthel]
* Added bounds checking to `rgba_to_string()` [obarthel]
* Fixed cleanup in JPEG Image loading [obarthel]
* Fixed missing CSS color table values [obarthel]
0.10.0 / 2012-01-18
==================
* Added `ctx.createPattern()` [slaskis]
0.9.0 / 2012-01-13
==================
* Added `createJPEGStream()` [Elijah Hamovitz]
0.8.3 / 2012-01-04
==================
* Added support for libjpeg62-dev or libjpeg8-dev [wwlinx]
0.8.2 / 2011-12-14
==================
* Fixed two memory leaks in context2d [Tharit]
* Fixed `make test-server`
0.8.1 / 2011-10-31
==================
* Added 0.5.x support [TooTallNate]
* Fixed `measureText().width`. Closes #126
0.8.0 / 2011-10-28
==================
* Added data uri support. Closes #49
0.7.3 / 2011-09-14
==================
* Added better lineTo() / moveTo() exception messages
0.7.2 / 2011-08-30
==================
* Changed: prefix some private methods with _
0.7.1 / 2011-08-25
==================
* Added better image format detection
* Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD
0.7.0 / 2011-07-12
==================
* Added GIF support [Brian McKinney]
0.6.0 / 2011-06-04
==================
* Added `Image#src=Buffer` support. Closes #91
* Added `devDependencies`
* Added `source-atop` test
* Added _image-src.js_ example
* Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()`
* Fixed v8 memory hint when resizing canvas [atomizer]
0.5.4 / 2011-04-20
==================
* Added; special case of zero-width rectangle [atomizer]
* Fixed; do not clamp arguments to integer values [atomizer]
* Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer]
* Fixed; `restorePath()`: clear current path before appending [atomizer]
0.5.3 / 2011-04-11
==================
* Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte]
0.5.2 / 2011-04-09
==================
* Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte]
0.5.1 / 2011-03-16
==================
* Fixed (kinda) `img.src=` error handling
* Fixed; move closure.h down for malloc ref. Closes #80
0.5.0 / 2011-03-14
==================
* Added several more operators (color-dodge, color-burn, difference, etc)
* Performance; no longer re-allocating `closure->data` for each png write
* Fixed freeing of `Context2d` states
* Fixed text alignment / baseline [Olaf]
* Fixed HandleScopes [Olaf]
* Fixed small misc memory leaks
* Fixed `Buffer` usage for node 0.4.x
0.4.3 / 2011-01-11
==================
* Fixed font family dereferencing. Closes #72
* Fixed; stripping of quotes from font-family before applying
* Fixed duplicate textAlign getter
* Removed sans-serif default of _Arial_
0.4.2 / 2010-12-28
==================
* Fixed font size growing issue after successive calls. Closes #70
0.4.1 / 2010-12-18
==================
* Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68
0.4.0 / 2010-12-12
==================
* Added `drawImage()` with `Canvas` instance support. Closes #67
0.3.3 / 2010-11-30
==================
* Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_
* Fixed; pre-multiply `putImageData()` components
* Fixed; `PixelArray` data is not premultiplied
0.3.2 / 2010-11-26
==================
* Added --profile option to config
* Fixed `eio_custom` segfault(s). Closes #46
* Fixed two named colors. Closes #62 [thanks noonat]
* Fixed a few warnings
* Fixed; freeing data in `Image::loadJPEG()` on failure
* Fixed; include _jpeglib_ only when __HAVE_JPEG__
* Fixed; using `strstr()` instead of `strnstr()`
0.3.1 / 2010-11-24
==================
* Fixed; `Image` loading is sync until race-condition is resolved
* Fixed; `Image::loadJPEG()` return status based on errno
0.3.0 / 2010-11-24
==================
* Added arcTo(). Closes #11
* Added c color parser, _./examples/ray.js_ is now twice as fast
* Fixed `putImageData()` bug messing up rgba channels
0.2.1 / 2010-11-19
==================
* Added image _resize_ example
* Fixed canvas resizing via `{width,height}=`. Closes #57
* Fixed `Canvas#getContext()`, caching the CanvasRenderingContext
* Fixed async image loading (test server still messed)
0.2.0 / 2010-11-18
==================
* Added jpeg `Image` support (when libjpeg is available)
* Added _hsl_ / _hsla_ color support. [Tom Carden]
0.1.0 / 2010-11-17
==================
* Added `Image`
* Added `ImageData`
* Added `PixelArray`
* Added `CanvasRenderingContext2d#drawImage()`
* Added `CanvasRenderingContext2d#getImageData()`
* Added `CanvasRenderingContext2d#createImageData()`
* Added kraken blur benchmark example
* Added several new tests
* Fixed instanceof checks for many c++ methods
* Fixed test runner in firefox [Don Park]
0.0.8 / 2010-11-12
==================
* Added `CanvasRenderingContext2d#drawImage()`
* Fixed `free()` call missing stdlib
* Fixed Image#{width,height} initialization to 0
* Fixed; load image on non-LOADING state
0.0.7 / 2010-11-12
==================
* Fixed _lighter_ for older versions of cairo
0.0.6 / 2010-11-12
==================
* Added `Image`
* Added conditional support for cairo 1.10.0 operators
0.0.5 / 2010-11-10
==================
* Added custom port support to _test/server.js_
* Added more global composite operator support
* Added `Context2d#antialias=`
* Added _voronoi_ example
* Added -D__NDEBUG__ to default build
* Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park]
* Fixed getter bug preventing patterns from being returned via `fillStyle` etc
* Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc()
* Fixed; free `Canvas::ToBuffer()` closure data
0.0.4 / 2010-11-09
==================
* Bump to fix npm engine cache bug...
0.0.3 / 2010-11-09
==================
* Added async `toDataURL()` support
* Added async `toBuffer()` support
* Removed buffer utils
0.0.2 / 2010-11-08
==================
* Added shadow support (faster/better gaussian blur to come)
* Added node v0.3 support [Don Park]
* Added -O3 to build
* Removed `Canvas#savePNG()` use `Canvas#createPNGStream()`
0.0.1 / 2010-11-04
==================
* Initial release
[repo]: https://github.com/Automattic/node-canvas
+348
View File
@@ -0,0 +1,348 @@
node-canvas
===========
### Canvas graphics API backed by Cairo
[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas)
[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas)
node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org).
## Authors
- TJ Holowaychuk ([tj](http://github.com/tj))
- Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate))
- Rod Vagg ([rvagg](http://github.com/rvagg))
- Juriy Zaytsev ([kangax](http://github.com/kangax))
## Installation
```bash
$ npm install canvas
```
Unless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/Automattic/node-canvas/wiki/_pages).
You can quickly install the dependencies by using the command for your OS:
OS | Command
----- | -----
OS X | `brew install pkg-config cairo libpng jpeg giflib`
Ubuntu | `sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++`
Fedora | `sudo yum install cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel giflib-devel`
Solaris | `pkgin install cairo pkg-config xproto renderproto kbproto xextproto`
Windows | [Instructions on our wiki](https://github.com/Automattic/node-canvas/wiki/Installation---Windows)
**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).
## Screencasts
- [Introduction](http://screenr.com/CTk)
## Example
```javascript
var Canvas = require('canvas')
, Image = Canvas.Image
, canvas = new Canvas(200, 200)
, ctx = canvas.getContext('2d');
ctx.font = '30px Impact';
ctx.rotate(.1);
ctx.fillText("Awesome!", 50, 100);
var te = ctx.measureText('Awesome!');
ctx.strokeStyle = 'rgba(0,0,0,0.5)';
ctx.beginPath();
ctx.lineTo(50, 102);
ctx.lineTo(50 + te.width, 102);
ctx.stroke();
console.log('<img src="' + canvas.toDataURL() + '" />');
```
## Non-Standard API
node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers.
### Image#src=Buffer
node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O.
```javascript
fs.readFile(__dirname + '/images/squid.png', function(err, squid){
if (err) throw err;
img = new Image;
img.src = squid;
ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4);
});
```
Below is an example of a canvas drawing it-self as the source several time:
```javascript
var img = new Image;
img.src = canvas.toBuffer();
ctx.drawImage(img, 0, 0, 50, 50);
ctx.drawImage(img, 50, 0, 50, 50);
ctx.drawImage(img, 100, 0, 50, 50);
```
### Image#dataMode
node-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs).
When mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering.
```javascript
var img = new Image;
img.dataMode = Image.MODE_IMAGE; // Only image data tracked
img.dataMode = Image.MODE_MIME; // Only mime data tracked
img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked
```
If image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.
### Canvas#pngStream()
To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted.
```javascript
var fs = require('fs')
, out = fs.createWriteStream(__dirname + '/text.png')
, stream = canvas.pngStream();
stream.on('data', function(chunk){
out.write(chunk);
});
stream.on('end', function(){
console.log('saved png');
});
```
Currently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`.
### Canvas#jpegStream() and Canvas#syncJPEGStream()
You can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with
some optional parameters; functionality is otherwise identical to
`pngStream()`. See `examples/crop.js` for an example.
_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both
are synchronous_
```javascript
var stream = canvas.jpegStream({
bufsize: 4096 // output buffer size in bytes, default: 4096
, quality: 75 // JPEG quality (0-100) default: 75
, progressive: false // true for progressive compression, default: false
});
```
### Canvas#toBuffer()
A call to `Canvas#toBuffer()` will return a node `Buffer` instance containing image data.
```javascript
// PNG Buffer, default settings
var buf = canvas.toBuffer();
// PNG Buffer, zlib compression level 3 (from 0-9), faster but bigger
var buf2 = canvas.toBuffer(undefined, 3, canvas.PNG_FILTER_NONE);
// ARGB32 Buffer, native-endian
var buf3 = canvas.toBuffer('raw');
var stride = canvas.stride;
// In memory, this is `canvas.height * canvas.stride` bytes long.
// The top row of pixels, in ARGB order, left-to-right, is:
var topPixelsARGBLeftToRight = buf3.slice(0, canvas.width * 4);
var row3 = buf3.slice(2 * canvas.stride, 2 * canvas.stride + canvas.width * 4);
```
### Canvas#toBuffer() async
Optionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`.
```javascript
canvas.toBuffer(function(err, buf){
});
```
### Canvas#toDataURL() sync and async
The following syntax patterns are supported:
```javascript
var dataUrl = canvas.toDataURL(); // defaults to PNG
var dataUrl = canvas.toDataURL('image/png');
canvas.toDataURL(function(err, png){ }); // defaults to PNG
canvas.toDataURL('image/png', function(err, png){ });
canvas.toDataURL('image/jpeg', function(err, jpeg){ }); // sync JPEG is not supported
canvas.toDataURL('image/jpeg', {opts...}, function(err, jpeg){ }); // see Canvas#jpegStream for valid options
canvas.toDataURL('image/jpeg', quality, function(err, jpeg){ }); // spec-following; quality from 0 to 1
```
### CanvasRenderingContext2D#patternQuality
Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.
- fast
- good
- best
- nearest
- bilinear
### CanvasRenderingContext2D#textDrawingMode
Can be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill.
Defaults to _path_.
This property is tracked as part of the canvas state in save/restore.
### CanvasRenderingContext2D#filter
Like `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_.
- fast
- good
- best
- nearest
- bilinear
### Global Composite Operations
In addition to those specified and commonly implemented by browsers, the following have been added:
- multiply
- screen
- overlay
- hard-light
- soft-light
- hsl-hue
- hsl-saturation
- hsl-color
- hsl-luminosity
## Anti-Aliasing
Set anti-aliasing mode
- default
- none
- gray
- subpixel
For example:
```javascript
ctx.antialias = 'none';
```
## PDF Support
Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating
a PDF on initialization, using the "pdf" string:
```js
var canvas = new Canvas(200, 500, 'pdf');
```
An additional method `.addPage()` is then available to create
multiple page PDFs:
```js
ctx.font = '22px Helvetica';
ctx.fillText('Hello World', 50, 80);
ctx.addPage();
ctx.font = '22px Helvetica';
ctx.fillText('Hello World 2', 50, 80);
ctx.addPage();
ctx.font = '22px Helvetica';
ctx.fillText('Hello World 3', 50, 80);
ctx.addPage();
```
## SVG support
Just like PDF support, make sure to install cairo with `--enable-svg=yes`.
You also need to tell node-canvas that it is working on SVG upon its initialization:
```js
var canvas = new Canvas(200, 500, 'svg');
// Use the normal primitives.
fs.writeFile('out.svg', canvas.toBuffer());
```
## Benchmarks
Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself.
## Contribute
Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/Automattic/node-canvas/issues) for existing issues.
## Examples
Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser.
## Testing
If you have not previously, init git submodules:
$ git submodule update --init
Install the node modules:
$ npm install
Build node-canvas:
$ node-gyp rebuild
Unit tests:
$ make test
Visual tests:
$ make test-server
## Versions
Tested with and designed for:
- node 0.4.2
- cairo 1.8.6
For node 0.2.x `node-canvas` <= 0.4.3 may be used,
0.5.0 and above are designed for node 0.4.x only.
## License
(The MIT License)
Copyright (c) 2010 LearnBoost, and contributors &lt;dev@learnboost.com&gt;
Copyright (c) 2014 Automattic, Inc and contributors &lt;dev@automattic.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+170
View File
@@ -0,0 +1,170 @@
{
'conditions': [
['OS=="win"', {
'variables': {
'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle
'with_jpeg%': 'false',
'with_gif%': 'false',
'with_pango%': 'false',
'with_freetype%': 'false'
}
}, { # 'OS!="win"'
'variables': {
'with_jpeg%': '<!(./util/has_lib.sh jpeg)',
'with_gif%': '<!(./util/has_lib.sh gif)',
'with_pango%': '<!(./util/has_lib.sh pango)',
'with_freetype%': '<!(./util/has_lib.sh freetype)'
}
}]
],
'targets': [
{
'target_name': 'canvas-postbuild',
'dependencies': ['canvas'],
'conditions': [
['OS=="win"', {
'copies': [{
'destination': '<(PRODUCT_DIR)',
'files': [
'<(GTK_Root)/bin/libcairo-2.dll',
'<(GTK_Root)/bin/libexpat-1.dll',
'<(GTK_Root)/bin/libfontconfig-1.dll',
'<(GTK_Root)/bin/libfreetype-6.dll',
'<(GTK_Root)/bin/libpng14-14.dll',
'<(GTK_Root)/bin/zlib1.dll',
]
}]
}]
]
},
{
'target_name': 'canvas',
'include_dirs': ["<!(node -e \"require('nan')\")"],
'sources': [
'src/Canvas.cc',
'src/CanvasGradient.cc',
'src/CanvasPattern.cc',
'src/CanvasRenderingContext2d.cc',
'src/color.cc',
'src/Image.cc',
'src/ImageData.cc',
'src/init.cc'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/cairo.lib',
'-l<(GTK_Root)/lib/libpng.lib'
],
'include_dirs': [
'<(GTK_Root)/include',
'<(GTK_Root)/include/cairo',
],
'defines': [
'_USE_MATH_DEFINES' # for M_PI
],
'configurations': {
'Debug': {
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': 4,
'ExceptionHandling': 1,
'DisableSpecificWarnings': [4100, 4127, 4201, 4244, 4267, 4506, 4611, 4714, 4512]
}
}
},
'Release': {
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': 4,
'ExceptionHandling': 1,
'DisableSpecificWarnings': [4100, 4127, 4201, 4244, 4267, 4506, 4611, 4714, 4512]
}
}
}
}
}, { # 'OS!="win"'
'libraries': [
'<!@(pkg-config pixman-1 --libs)',
'<!@(pkg-config cairo --libs)',
'<!@(pkg-config libpng --libs)'
],
'include_dirs': [
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)',
'<!@(pkg-config libpng --cflags-only-I | sed s/-I//g)'
]
}],
['with_freetype=="true"', {
'defines': [
'HAVE_FREETYPE'
],
'sources': [
'src/FontFace.cc'
],
'conditions': [
['OS=="win"', {
# No support for windows right now.
}, { # 'OS!="win"'
'include_dirs': [ # tried to pass through cflags but failed.
# Need to include the header files of cairo AND freetype.
# Looking up the includes of cairo does both.
'<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)'
]
}]
]
}],
['with_pango=="true"', {
'defines': [
'HAVE_PANGO'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/pangocairo.lib'
]
}, { # 'OS!="win"'
'include_dirs': [ # tried to pass through cflags but failed
'<!@(pkg-config pangocairo --cflags-only-I | sed s/-I//g)'
],
'libraries': [
'<!@(pkg-config pangocairo --libs)'
]
}]
]
}],
['with_jpeg=="true"', {
'defines': [
'HAVE_JPEG'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/jpeg.lib'
]
}, {
'libraries': [
'-ljpeg'
]
}]
]
}],
['with_gif=="true"', {
'defines': [
'HAVE_GIF'
],
'conditions': [
['OS=="win"', {
'libraries': [
'-l<(GTK_Root)/lib/gif.lib'
]
}, {
'libraries': [
'-lgif'
]
}]
]
}]
]
}
]
}
+329
View File
@@ -0,0 +1,329 @@
# We borrow heavily from the kernel build setup, though we are simpler since
# we don't have Kconfig tweaking settings on us.
# The implicit make rules have it looking for RCS files, among other things.
# We instead explicitly write all the rules we care about.
# It's even quicker (saves ~200ms) to pass -r on the command line.
MAKEFLAGS=-r
# The source directory tree.
srcdir := ..
abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= .
# The V=1 flag on command line makes us verbosely print command lines.
ifdef V
quiet=
else
quiet=quiet_
endif
# Specify BUILDTYPE=Release on the command line for a release build.
BUILDTYPE ?= Release
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
# as they reach into the src/ directory for data with relative paths.
builddir ?= $(builddir_name)/$(BUILDTYPE)
abs_builddir := $(abspath $(builddir))
depsdir := $(builddir)/.deps
# Object output directory.
obj := $(builddir)/obj
abs_obj := $(abspath $(obj))
# We build up a list of every single one of the targets so we can slurp in the
# generated dependency rule Makefiles in one pass.
all_deps :=
CC.target ?= $(CC)
CFLAGS.target ?= $(CFLAGS)
CXX.target ?= $(CXX)
CXXFLAGS.target ?= $(CXXFLAGS) $(CPPFLAGS)
LINK.target ?= $(LINK)
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
# C++ apps need to be linked with g++.
LINK ?= $(CXX.target)
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= gcc
CFLAGS.host ?=
CXX.host ?= g++
CXXFLAGS.host ?=
LINK.host ?= $(CXX.host)
LDFLAGS.host ?=
AR.host ?= ar
# Define a dir function that can handle spaces.
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
# "leading spaces cannot appear in the text of the first argument as written.
# These characters can be put into the argument value by variable substitution."
empty :=
space := $(empty) $(empty)
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
replace_spaces = $(subst $(space),?,$1)
unreplace_spaces = $(subst ?,$(space),$1)
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
# Flags to make gcc output dependency info. Note that you need to be
# careful here to use the flags that ccache and distcc can understand.
# We write to a dep file on the side first and then rename at the end
# so we can't end up with a broken dep file.
depfile = $(depsdir)/$(call replace_spaces,$@).d
DEPFLAGS = -MMD -MF $(depfile).raw
# We have to fixup the deps output in a few ways.
# (1) the file output should mention the proper .o file.
# ccache or distcc lose the path to the target, so we convert a rule of
# the form:
# foobar.o: DEP1 DEP2
# into
# path/to/foobar.o: DEP1 DEP2
# (2) we want missing files not to cause us to fail to build.
# We want to rewrite
# foobar.o: DEP1 DEP2 \
# DEP3
# to
# DEP1:
# DEP2:
# DEP3:
# so if the files are missing, they're just considered phony rules.
# We have to do some pretty insane escaping to get those backslashes
# and dollar signs past make, the shell, and sed at the same time.
# Doesn't work with spaces, but that's fine: .d files have spaces in
# their names replaced with other characters.
define fixup_dep
# The depfile may not exist if the input file didn't have any #includes.
touch $(depfile).raw
# Fixup path as in (1).
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
# Add extra rules as in (2).
# We remove slashes and replace spaces with new lines;
# remove blank lines;
# delete the first line and append a colon to the remaining lines.
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
grep -v '^$$' |\
sed -e 1d -e 's|$$|:|' \
>> $(depfile)
rm $(depfile).raw
endef
# Command definitions:
# - cmd_foo is the actual command to run;
# - quiet_cmd_foo is the brief-output summary of the command.
quiet_cmd_cc = CC($(TOOLSET)) $@
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_cxx = CXX($(TOOLSET)) $@
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
quiet_cmd_copy = COPY $@
# send stderr to /dev/null to ignore messages when linking directories.
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
quiet_cmd_alink = AR($(TOOLSET)) $@
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
# Due to circular dependencies between libraries :(, we wrap the
# special "figure out circular dependencies" flags around the entire
# input list during linking.
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
# We support two kinds of shared objects (.so):
# 1) shared_library, which is just bundling together many dependent libraries
# into a link line.
# 2) loadable_module, which is generating a module intended for dlopen().
#
# They differ only slightly:
# In the former case, we want to package all dependent code into the .so.
# In the latter case, we want to package just the API exposed by the
# outermost module.
# This means shared_library uses --whole-archive, while loadable_module doesn't.
# (Note that --whole-archive is incompatible with the --start-group used in
# normal linking.)
# Other shared-object link notes:
# - Set SONAME to the library filename so our binaries don't reference
# the local, absolute paths used on the link command-line.
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
# Define an escape_quotes function to escape single quotes.
# This allows us to handle quotes properly as long as we always use
# use single quotes and escape_quotes.
escape_quotes = $(subst ','\'',$(1))
# This comment is here just to include a ' to unconfuse syntax highlighting.
# Define an escape_vars function to escape '$' variable syntax.
# This allows us to read/write command lines with shell variables (e.g.
# $LD_LIBRARY_PATH), without triggering make substitution.
escape_vars = $(subst $$,$$$$,$(1))
# Helper that expands to a shell command to echo a string exactly as it is in
# make. This uses printf instead of echo because printf's behaviour with respect
# to escape sequences is more portable than echo's across different shells
# (e.g., dash, bash).
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
# Helper to compare the command we're about to run against the command
# we logged the last time we ran the command. Produces an empty
# string (false) when the commands match.
# Tricky point: Make has no string-equality test function.
# The kernel uses the following, but it seems like it would have false
# positives, where one string reordered its arguments.
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
# $(filter-out $(cmd_$@), $(cmd_$(1))))
# We instead substitute each for the empty string into the other, and
# say they're equal if both substitutions produce the empty string.
# .d files contain ? instead of spaces, take that into account.
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
# Helper that is non-empty when a prerequisite changes.
# Normally make does this implicitly, but we force rules to always run
# so we can check their command lines.
# $? -- new prerequisites
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
# Helper that executes all postbuilds until one fails.
define do_postbuilds
@E=0;\
for p in $(POSTBUILDS); do\
eval $$p;\
E=$$?;\
if [ $$E -ne 0 ]; then\
break;\
fi;\
done;\
if [ $$E -ne 0 ]; then\
rm -rf "$@";\
exit $$E;\
fi
endef
# do_cmd: run a command via the above cmd_foo names, if necessary.
# Should always run for a given target to handle command-line changes.
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
# Third argument, if non-zero, makes it do POSTBUILDS processing.
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
# spaces already and dirx strips the ? characters.
define do_cmd
$(if $(or $(command_changed),$(prereq_changed)),
@$(call exact_echo, $($(quiet)cmd_$(1)))
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
$(if $(findstring flock,$(word 1,$(cmd_$1))),
@$(cmd_$(1))
@echo " $(quiet_cmd_$(1)): Finished",
@$(cmd_$(1))
)
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
@$(if $(2),$(fixup_dep))
$(if $(and $(3), $(POSTBUILDS)),
$(call do_postbuilds)
)
)
endef
# Declare the "all" target first so it is the default,
# even though we don't have the deps yet.
.PHONY: all
all:
# make looks for ways to re-generate included makefiles, but in our case, we
# don't have a direct way. Explicitly telling make that it has nothing to do
# for them makes it go faster.
%.d: ;
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
# do_cmd.
.PHONY: FORCE_DO_CMD
FORCE_DO_CMD:
TOOLSET := target
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
$(findstring $(join ^,$(prefix)),\
$(join ^,canvas-postbuild.target.mk)))),)
include canvas-postbuild.target.mk
endif
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
$(findstring $(join ^,$(prefix)),\
$(join ^,canvas.target.mk)))),)
include canvas.target.mk
endif
quiet_cmd_regen_makefile = ACTION Regenerating $@
cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/home/xor/shared_vm/git/node-sunwell/node_modules/canvas/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dnode_gyp_dir=/usr/share/node-gyp" "-Dnode_lib_file=node.lib" "-Dmodule_root_dir=/home/xor/shared_vm/git/node-sunwell/node_modules/canvas" binding.gyp
Makefile: $(srcdir)/../../../../../../../usr/share/node-gyp/addon.gypi $(srcdir)/../../../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp
$(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
# sub-makefiles. This is just here to clarify.
all:
# Add in dependency-tracking rules. $(all_deps) is the list of every single
# target in our tree. Only consider the ones with .d (dependency) info:
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
ifneq ($(d_files),)
include $(d_files)
endif
@@ -0,0 +1 @@
cmd_Release/canvas-postbuild.node := ln -f "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node" 2>/dev/null || (rm -rf "Release/canvas-postbuild.node" && cp -af "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node")
@@ -0,0 +1 @@
cmd_Release/canvas.node := ln -f "Release/obj.target/canvas.node" "Release/canvas.node" 2>/dev/null || (rm -rf "Release/canvas.node" && cp -af "Release/obj.target/canvas.node" "Release/canvas.node")
@@ -0,0 +1 @@
cmd_Release/obj.target/canvas-postbuild.node := g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas-postbuild.node -o Release/obj.target/canvas-postbuild.node -Wl,--start-group -Wl,--end-group
@@ -0,0 +1 @@
cmd_Release/obj.target/canvas.node := g++ -shared -pthread -rdynamic -m64 -Wl,-soname=canvas.node -o Release/obj.target/canvas.node -Wl,--start-group Release/obj.target/canvas/src/Canvas.o Release/obj.target/canvas/src/CanvasGradient.o Release/obj.target/canvas/src/CanvasPattern.o Release/obj.target/canvas/src/CanvasRenderingContext2d.o Release/obj.target/canvas/src/color.o Release/obj.target/canvas/src/Image.o Release/obj.target/canvas/src/ImageData.o Release/obj.target/canvas/src/init.o Release/obj.target/canvas/src/FontFace.o -Wl,--end-group -lpixman-1 -lcairo -lpng12 -ljpeg -lgif
@@ -0,0 +1,95 @@
cmd_Release/obj.target/canvas/src/Canvas.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Canvas.o.d.raw -c -o Release/obj.target/canvas/src/Canvas.o ../src/Canvas.cc
Release/obj.target/canvas/src/Canvas.o: ../src/Canvas.cc ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/PNG.h \
/usr/include/libpng12/png.h /usr/include/libpng12/pngconf.h \
/usr/include/libpng12/pngconf.h ../src/closure.h \
../src/CanvasRenderingContext2d.h ../src/color.h ../src/CanvasGradient.h \
/usr/include/freetype2/ft2build.h \
/usr/include/freetype2/freetype/config/ftheader.h \
/usr/include/cairo/cairo-ft.h /usr/include/cairo/cairo.h \
/usr/include/freetype2/freetype/freetype.h \
/usr/include/freetype2/freetype/config/ftconfig.h \
/usr/include/freetype2/freetype/fttypes.h \
/usr/include/freetype2/freetype/ftsystem.h \
/usr/include/freetype2/freetype/ftimage.h \
/usr/include/freetype2/freetype/fterrors.h \
/usr/include/freetype2/freetype/ftmoderr.h \
/usr/include/freetype2/freetype/fterrdef.h \
/usr/include/cairo/cairo-pdf.h /usr/include/cairo/cairo-svg.h \
../src/JPEGStream.h
../src/Canvas.cc:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/PNG.h:
/usr/include/libpng12/png.h:
/usr/include/libpng12/pngconf.h:
/usr/include/libpng12/pngconf.h:
../src/closure.h:
../src/CanvasRenderingContext2d.h:
../src/color.h:
../src/CanvasGradient.h:
/usr/include/freetype2/ft2build.h:
/usr/include/freetype2/freetype/config/ftheader.h:
/usr/include/cairo/cairo-ft.h:
/usr/include/cairo/cairo.h:
/usr/include/freetype2/freetype/freetype.h:
/usr/include/freetype2/freetype/config/ftconfig.h:
/usr/include/freetype2/freetype/fttypes.h:
/usr/include/freetype2/freetype/ftsystem.h:
/usr/include/freetype2/freetype/ftimage.h:
/usr/include/freetype2/freetype/fterrors.h:
/usr/include/freetype2/freetype/ftmoderr.h:
/usr/include/freetype2/freetype/fterrdef.h:
/usr/include/cairo/cairo-pdf.h:
/usr/include/cairo/cairo-svg.h:
../src/JPEGStream.h:
@@ -0,0 +1,58 @@
cmd_Release/obj.target/canvas/src/CanvasGradient.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d.raw -c -o Release/obj.target/canvas/src/CanvasGradient.o ../src/CanvasGradient.cc
Release/obj.target/canvas/src/CanvasGradient.o: ../src/CanvasGradient.cc \
../src/color.h ../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/CanvasGradient.h
../src/CanvasGradient.cc:
../src/color.h:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/CanvasGradient.h:
@@ -0,0 +1,59 @@
cmd_Release/obj.target/canvas/src/CanvasPattern.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d.raw -c -o Release/obj.target/canvas/src/CanvasPattern.o ../src/CanvasPattern.cc
Release/obj.target/canvas/src/CanvasPattern.o: ../src/CanvasPattern.cc \
../src/Canvas.h /usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/Image.h \
../src/CanvasPattern.h
../src/CanvasPattern.cc:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/Image.h:
../src/CanvasPattern.h:
@@ -0,0 +1,90 @@
cmd_Release/obj.target/canvas/src/CanvasRenderingContext2d.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d.raw -c -o Release/obj.target/canvas/src/CanvasRenderingContext2d.o ../src/CanvasRenderingContext2d.cc
Release/obj.target/canvas/src/CanvasRenderingContext2d.o: \
../src/CanvasRenderingContext2d.cc ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/Point.h ../src/Image.h \
../src/ImageData.h ../src/CanvasRenderingContext2d.h ../src/color.h \
../src/CanvasGradient.h /usr/include/freetype2/ft2build.h \
/usr/include/freetype2/freetype/config/ftheader.h \
/usr/include/cairo/cairo-ft.h /usr/include/cairo/cairo.h \
/usr/include/freetype2/freetype/freetype.h \
/usr/include/freetype2/freetype/config/ftconfig.h \
/usr/include/freetype2/freetype/fttypes.h \
/usr/include/freetype2/freetype/ftsystem.h \
/usr/include/freetype2/freetype/ftimage.h \
/usr/include/freetype2/freetype/fterrors.h \
/usr/include/freetype2/freetype/ftmoderr.h \
/usr/include/freetype2/freetype/fterrdef.h ../src/CanvasPattern.h \
../src/FontFace.h
../src/CanvasRenderingContext2d.cc:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/Point.h:
../src/Image.h:
../src/ImageData.h:
../src/CanvasRenderingContext2d.h:
../src/color.h:
../src/CanvasGradient.h:
/usr/include/freetype2/ft2build.h:
/usr/include/freetype2/freetype/config/ftheader.h:
/usr/include/cairo/cairo-ft.h:
/usr/include/cairo/cairo.h:
/usr/include/freetype2/freetype/freetype.h:
/usr/include/freetype2/freetype/config/ftconfig.h:
/usr/include/freetype2/freetype/fttypes.h:
/usr/include/freetype2/freetype/ftsystem.h:
/usr/include/freetype2/freetype/ftimage.h:
/usr/include/freetype2/freetype/fterrors.h:
/usr/include/freetype2/freetype/ftmoderr.h:
/usr/include/freetype2/freetype/fterrdef.h:
../src/CanvasPattern.h:
../src/FontFace.h:
@@ -0,0 +1,80 @@
cmd_Release/obj.target/canvas/src/FontFace.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/FontFace.o.d.raw -c -o Release/obj.target/canvas/src/FontFace.o ../src/FontFace.cc
Release/obj.target/canvas/src/FontFace.o: ../src/FontFace.cc \
../src/FontFace.h ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h /usr/include/freetype2/ft2build.h \
/usr/include/freetype2/freetype/config/ftheader.h \
/usr/include/cairo/cairo-ft.h /usr/include/cairo/cairo.h \
/usr/include/freetype2/freetype/freetype.h \
/usr/include/freetype2/freetype/config/ftconfig.h \
/usr/include/freetype2/freetype/fttypes.h \
/usr/include/freetype2/freetype/ftsystem.h \
/usr/include/freetype2/freetype/ftimage.h \
/usr/include/freetype2/freetype/fterrors.h \
/usr/include/freetype2/freetype/ftmoderr.h \
/usr/include/freetype2/freetype/fterrdef.h
../src/FontFace.cc:
../src/FontFace.h:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
/usr/include/freetype2/ft2build.h:
/usr/include/freetype2/freetype/config/ftheader.h:
/usr/include/cairo/cairo-ft.h:
/usr/include/cairo/cairo.h:
/usr/include/freetype2/freetype/freetype.h:
/usr/include/freetype2/freetype/config/ftconfig.h:
/usr/include/freetype2/freetype/fttypes.h:
/usr/include/freetype2/freetype/ftsystem.h:
/usr/include/freetype2/freetype/ftimage.h:
/usr/include/freetype2/freetype/fterrors.h:
/usr/include/freetype2/freetype/ftmoderr.h:
/usr/include/freetype2/freetype/fterrdef.h:
@@ -0,0 +1,57 @@
cmd_Release/obj.target/canvas/src/Image.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/Image.o.d.raw -c -o Release/obj.target/canvas/src/Image.o ../src/Image.cc
Release/obj.target/canvas/src/Image.o: ../src/Image.cc ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/Image.h
../src/Image.cc:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/Image.h:
@@ -0,0 +1,58 @@
cmd_Release/obj.target/canvas/src/ImageData.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/ImageData.o.d.raw -c -o Release/obj.target/canvas/src/ImageData.o ../src/ImageData.cc
Release/obj.target/canvas/src/ImageData.o: ../src/ImageData.cc \
../src/ImageData.h ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h
../src/ImageData.cc:
../src/ImageData.h:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
@@ -0,0 +1,4 @@
cmd_Release/obj.target/canvas/src/color.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/color.o.d.raw -c -o Release/obj.target/canvas/src/color.o ../src/color.cc
Release/obj.target/canvas/src/color.o: ../src/color.cc ../src/color.h
../src/color.cc:
../src/color.h:
@@ -0,0 +1,88 @@
cmd_Release/obj.target/canvas/src/init.o := g++ '-DNODE_GYP_MODULE_NAME=canvas' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DHAVE_FREETYPE' '-DHAVE_JPEG' '-DHAVE_GIF' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../../nan -I/usr/include/cairo -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -ffunction-sections -fdata-sections -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/canvas/src/init.o.d.raw -c -o Release/obj.target/canvas/src/init.o ../src/init.cc
Release/obj.target/canvas/src/init.o: ../src/init.cc ../src/Canvas.h \
/usr/include/nodejs/deps/v8/include/v8.h \
/usr/include/nodejs/deps/v8/include/v8-version.h \
/usr/include/nodejs/deps/v8/include/v8config.h \
/usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
/usr/include/nodejs/src/node_object_wrap.h \
/usr/include/nodejs/src/node_version.h /usr/include/cairo/cairo.h \
/usr/include/cairo/cairo-version.h /usr/include/cairo/cairo-features.h \
/usr/include/cairo/cairo-deprecated.h ../../nan/nan.h \
/usr/include/nodejs/deps/uv/include/uv.h \
/usr/include/nodejs/deps/uv/include/uv-errno.h \
/usr/include/nodejs/deps/uv/include/uv-version.h \
/usr/include/nodejs/deps/uv/include/uv-unix.h \
/usr/include/nodejs/deps/uv/include/uv-threadpool.h \
/usr/include/nodejs/deps/uv/include/uv-linux.h \
/usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
../../nan/nan_callbacks.h ../../nan/nan_callbacks_12_inl.h \
../../nan/nan_maybe_43_inl.h ../../nan/nan_converters.h \
../../nan/nan_converters_43_inl.h ../../nan/nan_new.h \
../../nan/nan_implementation_12_inl.h ../../nan/nan_persistent_12_inl.h \
../../nan/nan_weak.h ../../nan/nan_object_wrap.h \
../../nan/nan_typedarray_contents.h ../src/Image.h ../src/ImageData.h \
../src/CanvasGradient.h ../src/CanvasPattern.h \
../src/CanvasRenderingContext2d.h ../src/color.h \
/usr/include/freetype2/ft2build.h \
/usr/include/freetype2/freetype/config/ftheader.h \
/usr/include/cairo/cairo-ft.h /usr/include/cairo/cairo.h \
/usr/include/freetype2/freetype/freetype.h \
/usr/include/freetype2/freetype/config/ftconfig.h \
/usr/include/freetype2/freetype/fttypes.h \
/usr/include/freetype2/freetype/ftsystem.h \
/usr/include/freetype2/freetype/ftimage.h \
/usr/include/freetype2/freetype/fterrors.h \
/usr/include/freetype2/freetype/ftmoderr.h \
/usr/include/freetype2/freetype/fterrdef.h ../src/FontFace.h
../src/init.cc:
../src/Canvas.h:
/usr/include/nodejs/deps/v8/include/v8.h:
/usr/include/nodejs/deps/v8/include/v8-version.h:
/usr/include/nodejs/deps/v8/include/v8config.h:
/usr/include/nodejs/src/node.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/nodejs/src/node_object_wrap.h:
/usr/include/nodejs/src/node_version.h:
/usr/include/cairo/cairo.h:
/usr/include/cairo/cairo-version.h:
/usr/include/cairo/cairo-features.h:
/usr/include/cairo/cairo-deprecated.h:
../../nan/nan.h:
/usr/include/nodejs/deps/uv/include/uv.h:
/usr/include/nodejs/deps/uv/include/uv-errno.h:
/usr/include/nodejs/deps/uv/include/uv-version.h:
/usr/include/nodejs/deps/uv/include/uv-unix.h:
/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
/usr/include/nodejs/deps/uv/include/uv-linux.h:
/usr/include/nodejs/src/node_buffer.h:
/usr/include/nodejs/src/node.h:
../../nan/nan_callbacks.h:
../../nan/nan_callbacks_12_inl.h:
../../nan/nan_maybe_43_inl.h:
../../nan/nan_converters.h:
../../nan/nan_converters_43_inl.h:
../../nan/nan_new.h:
../../nan/nan_implementation_12_inl.h:
../../nan/nan_persistent_12_inl.h:
../../nan/nan_weak.h:
../../nan/nan_object_wrap.h:
../../nan/nan_typedarray_contents.h:
../src/Image.h:
../src/ImageData.h:
../src/CanvasGradient.h:
../src/CanvasPattern.h:
../src/CanvasRenderingContext2d.h:
../src/color.h:
/usr/include/freetype2/ft2build.h:
/usr/include/freetype2/freetype/config/ftheader.h:
/usr/include/cairo/cairo-ft.h:
/usr/include/cairo/cairo.h:
/usr/include/freetype2/freetype/freetype.h:
/usr/include/freetype2/freetype/config/ftconfig.h:
/usr/include/freetype2/freetype/fttypes.h:
/usr/include/freetype2/freetype/ftsystem.h:
/usr/include/freetype2/freetype/ftimage.h:
/usr/include/freetype2/freetype/fterrors.h:
/usr/include/freetype2/freetype/ftmoderr.h:
/usr/include/freetype2/freetype/fterrdef.h:
../src/FontFace.h:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
# This file is generated by gyp; do not edit.
export builddir_name ?= ./build/.
.PHONY: all
all:
$(MAKE) canvas canvas-postbuild
+42
View File
@@ -0,0 +1,42 @@
# This file is generated by gyp; do not edit.
TOOLSET := target
TARGET := canvas-postbuild
### Rules for final target.
LDFLAGS_Debug := \
-pthread \
-rdynamic \
-m64
LDFLAGS_Release := \
-pthread \
-rdynamic \
-m64
LIBS :=
$(obj).target/canvas-postbuild.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(obj).target/canvas-postbuild.node: LIBS := $(LIBS)
$(obj).target/canvas-postbuild.node: TOOLSET := $(TOOLSET)
$(obj).target/canvas-postbuild.node: FORCE_DO_CMD
$(call do_cmd,solink_module)
all_deps += $(obj).target/canvas-postbuild.node
# Add target alias
.PHONY: canvas-postbuild
canvas-postbuild: $(builddir)/canvas-postbuild.node
# Copy this to the executable output path.
$(builddir)/canvas-postbuild.node: TOOLSET := $(TOOLSET)
$(builddir)/canvas-postbuild.node: $(obj).target/canvas-postbuild.node FORCE_DO_CMD
$(call do_cmd,copy)
all_deps += $(builddir)/canvas-postbuild.node
# Short alias for building this executable.
.PHONY: canvas-postbuild.node
canvas-postbuild.node: $(obj).target/canvas-postbuild.node $(builddir)/canvas-postbuild.node
# Add executable to "all" target.
.PHONY: all
all: $(builddir)/canvas-postbuild.node
+169
View File
@@ -0,0 +1,169 @@
# This file is generated by gyp; do not edit.
TOOLSET := target
TARGET := canvas
DEFS_Debug := \
'-DNODE_GYP_MODULE_NAME=canvas' \
'-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-DHAVE_FREETYPE' \
'-DHAVE_JPEG' \
'-DHAVE_GIF' \
'-DBUILDING_NODE_EXTENSION' \
'-DDEBUG' \
'-D_DEBUG'
# Flags passed to all source files.
CFLAGS_Debug := \
-fPIC \
-pthread \
-Wall \
-Wextra \
-Wno-unused-parameter \
-m64 \
-g \
-O0
# Flags passed to only C files.
CFLAGS_C_Debug :=
# Flags passed to only C++ files.
CFLAGS_CC_Debug := \
-fno-rtti \
-fno-exceptions \
-std=gnu++0x
INCS_Debug := \
-I/usr/include/nodejs/include/node \
-I/usr/include/nodejs/src \
-I/usr/include/nodejs/deps/uv/include \
-I/usr/include/nodejs/deps/v8/include \
-I$(srcdir)/../nan \
-I/usr/include/cairo \
-I/usr/include/glib-2.0 \
-I/usr/lib/x86_64-linux-gnu/glib-2.0/include \
-I/usr/include/pixman-1 \
-I/usr/include/freetype2 \
-I/usr/include/libpng12
DEFS_Release := \
'-DNODE_GYP_MODULE_NAME=canvas' \
'-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-DHAVE_FREETYPE' \
'-DHAVE_JPEG' \
'-DHAVE_GIF' \
'-DBUILDING_NODE_EXTENSION'
# Flags passed to all source files.
CFLAGS_Release := \
-fPIC \
-pthread \
-Wall \
-Wextra \
-Wno-unused-parameter \
-m64 \
-O3 \
-ffunction-sections \
-fdata-sections \
-fno-omit-frame-pointer
# Flags passed to only C files.
CFLAGS_C_Release :=
# Flags passed to only C++ files.
CFLAGS_CC_Release := \
-fno-rtti \
-fno-exceptions \
-std=gnu++0x
INCS_Release := \
-I/usr/include/nodejs/include/node \
-I/usr/include/nodejs/src \
-I/usr/include/nodejs/deps/uv/include \
-I/usr/include/nodejs/deps/v8/include \
-I$(srcdir)/../nan \
-I/usr/include/cairo \
-I/usr/include/glib-2.0 \
-I/usr/lib/x86_64-linux-gnu/glib-2.0/include \
-I/usr/include/pixman-1 \
-I/usr/include/freetype2 \
-I/usr/include/libpng12
OBJS := \
$(obj).target/$(TARGET)/src/Canvas.o \
$(obj).target/$(TARGET)/src/CanvasGradient.o \
$(obj).target/$(TARGET)/src/CanvasPattern.o \
$(obj).target/$(TARGET)/src/CanvasRenderingContext2d.o \
$(obj).target/$(TARGET)/src/color.o \
$(obj).target/$(TARGET)/src/Image.o \
$(obj).target/$(TARGET)/src/ImageData.o \
$(obj).target/$(TARGET)/src/init.o \
$(obj).target/$(TARGET)/src/FontFace.o
# Add to the list of files we specially track dependencies for.
all_deps += $(OBJS)
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
# End of this set of suffix rules
### Rules for final target.
LDFLAGS_Debug := \
-pthread \
-rdynamic \
-m64
LDFLAGS_Release := \
-pthread \
-rdynamic \
-m64
LIBS := \
-lpixman-1 \
-lcairo \
-lpng12 \
-ljpeg \
-lgif
$(obj).target/canvas.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(obj).target/canvas.node: LIBS := $(LIBS)
$(obj).target/canvas.node: TOOLSET := $(TOOLSET)
$(obj).target/canvas.node: $(OBJS) FORCE_DO_CMD
$(call do_cmd,solink_module)
all_deps += $(obj).target/canvas.node
# Add target alias
.PHONY: canvas
canvas: $(builddir)/canvas.node
# Copy this to the executable output path.
$(builddir)/canvas.node: TOOLSET := $(TOOLSET)
$(builddir)/canvas.node: $(obj).target/canvas.node FORCE_DO_CMD
$(call do_cmd,copy)
all_deps += $(builddir)/canvas.node
# Short alias for building this executable.
.PHONY: canvas.node
canvas.node: $(obj).target/canvas.node $(builddir)/canvas.node
# Add executable to "all" target.
.PHONY: all
all: $(builddir)/canvas.node
+136
View File
@@ -0,0 +1,136 @@
# Do not edit. File was generated by node-gyp's "configure" step
{
"target_defaults": {
"cflags": [],
"default_configuration": "Release",
"defines": [],
"include_dirs": [],
"libraries": []
},
"variables": {
"asan": 0,
"host_arch": "x64",
"icu_gyp_path": "tools/icu/icu-system.gyp",
"icu_small": "false",
"node_byteorder": "little",
"node_install_npm": "false",
"node_prefix": "/usr",
"node_release_urlbase": "",
"node_shared_http_parser": "false",
"node_shared_libuv": "true",
"node_shared_openssl": "true",
"node_shared_zlib": "true",
"node_tag": "",
"node_use_dtrace": "false",
"node_use_etw": "false",
"node_use_lttng": "false",
"node_use_openssl": "true",
"node_use_perfctr": "false",
"openssl_fips": "",
"openssl_no_asm": 0,
"python": "/usr/bin/python",
"target_arch": "x64",
"uv_parent_path": "/deps/uv/",
"uv_use_dtrace": "false",
"v8_enable_gdbjit": 0,
"v8_enable_i18n_support": 1,
"v8_no_strict_aliasing": 1,
"v8_optimized_debug": 0,
"v8_random_seed": 0,
"v8_use_snapshot": "true",
"want_separate_host_toolset": 0,
"nodedir": "/usr/include/nodejs",
"copy_dev_lib": "true",
"standalone_static_library": 1,
"cache_lock_stale": "60000",
"legacy_bundling": "",
"sign_git_tag": "",
"user_agent": "npm/3.5.2 node/v4.2.6 linux x64",
"always_auth": "",
"bin_links": "true",
"key": "",
"description": "true",
"fetch_retries": "2",
"heading": "npm",
"if_present": "",
"init_version": "1.0.0",
"user": "",
"force": "",
"only": "",
"cache_min": "10",
"init_license": "ISC",
"editor": "vi",
"rollback": "true",
"tag_version_prefix": "v",
"cache_max": "Infinity",
"userconfig": "/home/xor/.npmrc",
"engine_strict": "",
"init_author_name": "",
"init_author_url": "",
"tmp": "/tmp",
"depth": "Infinity",
"save_dev": "",
"usage": "",
"cafile": "",
"progress": "true",
"https_proxy": "",
"onload_script": "",
"rebuild_bundle": "true",
"save_bundle": "",
"shell": "/bin/bash",
"prefix": "/usr/local",
"dry_run": "",
"browser": "",
"cache_lock_wait": "10000",
"registry": "https://registry.npmjs.org/",
"save_optional": "",
"scope": "",
"searchopts": "",
"versions": "",
"cache": "/home/xor/.npm",
"global_style": "",
"ignore_scripts": "",
"searchsort": "name",
"version": "",
"local_address": "",
"viewer": "man",
"color": "true",
"fetch_retry_mintimeout": "10000",
"umask": "0002",
"fetch_retry_maxtimeout": "60000",
"message": "%s",
"ca": "",
"cert": "",
"global": "",
"link": "",
"access": "",
"also": "",
"save": "",
"unicode": "true",
"long": "",
"production": "",
"unsafe_perm": "true",
"node_version": "4.2.6",
"tag": "latest",
"git_tag_version": "true",
"shrinkwrap": "true",
"fetch_retry_factor": "10",
"npat": "",
"proprietary_attribs": "true",
"save_exact": "",
"strict_ssl": "true",
"globalconfig": "/etc/npmrc",
"dev": "",
"init_module": "/home/xor/.npm-init.js",
"parseable": "",
"globalignorefile": "/etc/npmignore",
"cache_lock_retries": "10",
"save_prefix": "^",
"group": "1000",
"init_author_email": "",
"searchexclude": "",
"git": "git",
"optional": "true",
"json": ""
}
}
+1
View File
@@ -0,0 +1 @@
module.exports = require('./lib/canvas');
+3
View File
@@ -0,0 +1,3 @@
'use strict';
module.exports = require('../build/Release/canvas');
+312
View File
@@ -0,0 +1,312 @@
'use strict';
/*!
* Canvas
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var canvas = require('./bindings')
, Canvas = canvas.Canvas
, Image = canvas.Image
, cairoVersion = canvas.cairoVersion
, Context2d = require('./context2d')
, PNGStream = require('./pngstream')
, PDFStream = require('./pdfstream')
, JPEGStream = require('./jpegstream')
, FontFace = canvas.FontFace
, fs = require('fs')
, packageJson = require("../package.json")
, FORMATS = ['image/png', 'image/jpeg'];
/**
* Export `Canvas` as the module.
*/
var Canvas = exports = module.exports = Canvas;
/**
* Library version.
*/
exports.version = packageJson.version;
/**
* Cairo version.
*/
exports.cairoVersion = cairoVersion;
/**
* jpeglib version.
*/
if (canvas.jpegVersion) {
exports.jpegVersion = canvas.jpegVersion;
}
/**
* gif_lib version.
*/
if (canvas.gifVersion) {
exports.gifVersion = canvas.gifVersion.replace(/[^.\d]/g, '');
}
/**
* freetype version.
*/
if (canvas.freetypeVersion) {
exports.freetypeVersion = canvas.freetypeVersion;
}
/**
* Expose constructors.
*/
exports.Context2d = Context2d;
exports.PNGStream = PNGStream;
exports.PDFStream = PDFStream;
exports.JPEGStream = JPEGStream;
exports.Image = Image;
exports.ImageData = canvas.ImageData;
if (FontFace) {
var Font = function Font(name, path, idx) {
this.name = name;
this._faces = {};
this.addFace(path, 'normal', 'normal', idx);
};
Font.prototype.addFace = function(path, weight, style, idx) {
style = style || 'normal';
weight = weight || 'normal';
var face = new FontFace(path, idx || 0);
this._faces[weight + '-' + style] = face;
};
Font.prototype.getFace = function(weightStyle) {
return this._faces[weightStyle] || this._faces['normal-normal'];
};
exports.Font = Font;
}
/**
* Context2d implementation.
*/
require('./context2d');
/**
* Image implementation.
*/
require('./image');
/**
* Inspect canvas.
*
* @return {String}
* @api public
*/
Canvas.prototype.inspect = function(){
return '[Canvas ' + this.width + 'x' + this.height + ']';
};
/**
* Get a context object.
*
* @param {String} contextId
* @return {Context2d}
* @api public
*/
Canvas.prototype.getContext = function(contextId){
if ('2d' == contextId) {
var ctx = this._context2d || (this._context2d = new Context2d(this));
this.context = ctx;
ctx.canvas = this;
return ctx;
}
};
/**
* Create a `PNGStream` for `this` canvas.
*
* @return {PNGStream}
* @api public
*/
Canvas.prototype.pngStream =
Canvas.prototype.createPNGStream = function(){
return new PNGStream(this);
};
/**
* Create a synchronous `PNGStream` for `this` canvas.
*
* @return {PNGStream}
* @api public
*/
Canvas.prototype.syncPNGStream =
Canvas.prototype.createSyncPNGStream = function(){
return new PNGStream(this, true);
};
/**
* Create a `PDFStream` for `this` canvas.
*
* @return {PDFStream}
* @api public
*/
Canvas.prototype.pdfStream =
Canvas.prototype.createPDFStream = function(){
return new PDFStream(this);
};
/**
* Create a synchronous `PDFStream` for `this` canvas.
*
* @return {PDFStream}
* @api public
*/
Canvas.prototype.syncPDFStream =
Canvas.prototype.createSyncPDFStream = function(){
return new PDFStream(this, true);
};
/**
* Create a `JPEGStream` for `this` canvas.
*
* @param {Object} options
* @return {JPEGStream}
* @api public
*/
Canvas.prototype.jpegStream =
Canvas.prototype.createJPEGStream = function(options){
return this.createSyncJPEGStream(options);
};
/**
* Create a synchronous `JPEGStream` for `this` canvas.
*
* @param {Object} options
* @return {JPEGStream}
* @api public
*/
Canvas.prototype.syncJPEGStream =
Canvas.prototype.createSyncJPEGStream = function(options){
options = options || {};
// Don't allow the buffer size to exceed the size of the canvas (#674)
var maxBufSize = this.width * this.height * 4;
var clampedBufSize = Math.min(options.bufsize || 4096, maxBufSize);
return new JPEGStream(this, {
bufsize: clampedBufSize
, quality: options.quality || 75
, progressive: options.progressive || false
});
};
/**
* Return a data url. Pass a function for async support (required for "image/jpeg").
*
* @param {String} type, optional, one of "image/png" or "image/jpeg", defaults to "image/png"
* @param {Object|Number} encoderOptions, optional, options for jpeg compression (see documentation for Canvas#jpegStream) or the JPEG encoding quality from 0 to 1.
* @param {Function} fn, optional, callback for asynchronous operation. Required for type "image/jpeg".
* @return {String} data URL if synchronous (callback omitted)
* @api public
*/
Canvas.prototype.toDataURL = function(a1, a2, a3){
// valid arg patterns (args -> [type, opts, fn]):
// [] -> ['image/png', null, null]
// [qual] -> ['image/png', null, null]
// [undefined] -> ['image/png', null, null]
// ['image/png'] -> ['image/png', null, null]
// ['image/png', qual] -> ['image/png', null, null]
// [fn] -> ['image/png', null, fn]
// [type, fn] -> [type, null, fn]
// [undefined, fn] -> ['image/png', null, fn]
// ['image/png', qual, fn] -> ['image/png', null, fn]
// ['image/jpeg', fn] -> ['image/jpeg', null, fn]
// ['image/jpeg', opts, fn] -> ['image/jpeg', opts, fn]
// ['image/jpeg', qual, fn] -> ['image/jpeg', {quality: qual}, fn]
// ['image/jpeg', undefined, fn] -> ['image/jpeg', null, fn]
if (this.width === 0 || this.height === 0) {
// Per spec, if the bitmap has no pixels, return this string:
return "data:,";
}
var type = 'image/png';
var opts = {};
var fn;
if ('function' === typeof a1) {
fn = a1;
} else {
if ('string' === typeof a1 && FORMATS.indexOf(a1.toLowerCase()) !== -1) {
type = a1.toLowerCase();
}
if ('function' === typeof a2) {
fn = a2;
} else {
if ('object' === typeof a2) {
opts = a2;
} else if ('number' === typeof a2) {
opts = {quality: Math.max(0, Math.min(1, a2)) * 100};
}
if ('function' === typeof a3) {
fn = a3;
} else if (undefined !== a3) {
throw new TypeError(typeof a3 + ' is not a function');
}
}
}
if ('image/png' === type) {
if (fn) {
this.toBuffer(function(err, buf){
if (err) return fn(err);
fn(null, 'data:image/png;base64,' + buf.toString('base64'));
});
} else {
return 'data:image/png;base64,' + this.toBuffer().toString('base64');
}
} else if ('image/jpeg' === type) {
if (undefined === fn) {
throw new Error('Missing required callback function for format "image/jpeg"');
}
var stream = this.jpegStream(opts);
// note that jpegStream is synchronous
var buffers = [];
stream.on('data', function (chunk) {
buffers.push(chunk);
});
stream.on('error', function (err) {
fn(err);
});
stream.on('end', function() {
var result = 'data:image/jpeg;base64,' + Buffer.concat(buffers).toString('base64');
fn(null, result);
});
}
};
+371
View File
@@ -0,0 +1,371 @@
'use strict';
/*!
* Canvas - Context2d
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var canvas = require('./bindings')
, Context2d = canvas.CanvasRenderingContext2d
, CanvasGradient = canvas.CanvasGradient
, CanvasPattern = canvas.CanvasPattern
, ImageData = canvas.ImageData;
/**
* Export `Context2d` as the module.
*/
var Context2d = exports = module.exports = Context2d;
/**
* Cache color string RGBA values.
*/
var cache = {};
/**
* Text baselines.
*/
var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging'];
/**
* Font RegExp helpers.
*/
var weights = 'normal|bold|bolder|lighter|[1-9]00'
, styles = 'normal|italic|oblique'
, units = 'px|pt|pc|in|cm|mm|%'
, string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+';
/**
* Font parser RegExp;
*/
var fontre = new RegExp('^ *'
+ '(?:(' + weights + ') *)?'
+ '(?:(' + styles + ') *)?'
+ '([\\d\\.]+)(' + units + ') *'
+ '((?:' + string + ')( *, *(?:' + string + '))*)'
);
/**
* Parse font `str`.
*
* @param {String} str
* @return {Object}
* @api private
*/
var parseFont = exports.parseFont = function(str){
var font = {}
, captures = fontre.exec(str);
// Invalid
if (!captures) return;
// Cached
if (cache[str]) return cache[str];
// Populate font object
font.weight = captures[1] || 'normal';
font.style = captures[2] || 'normal';
font.size = parseFloat(captures[3]);
font.unit = captures[4];
font.family = captures[5].replace(/["']/g, '').split(',')[0].trim();
// TODO: dpi
// TODO: remaining unit conversion
switch (font.unit) {
case 'pt':
font.size /= .75;
break;
case 'in':
font.size *= 96;
break;
case 'mm':
font.size *= 96.0 / 25.4;
break;
case 'cm':
font.size *= 96.0 / 2.54;
break;
}
return cache[str] = font;
};
/**
* Enable or disable image smoothing.
*
* @api public
*/
Context2d.prototype.__defineSetter__('imageSmoothingEnabled', function(val){
this._imageSmoothing = !! val;
this.patternQuality = val ? 'best' : 'fast';
});
/**
* Get image smoothing value.
*
* @api public
*/
Context2d.prototype.__defineGetter__('imageSmoothingEnabled', function(val){
return !! this._imageSmoothing;
});
/**
* Create a pattern from `Image` or `Canvas`.
*
* @param {Image|Canvas} image
* @param {String} repetition
* @return {CanvasPattern}
* @api public
*/
Context2d.prototype.createPattern = function(image, repetition){
// TODO Use repetition (currently always 'repeat')
return new CanvasPattern(image);
};
/**
* Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`.
*
* @param {Number} x0
* @param {Number} y0
* @param {Number} x1
* @param {Number} y1
* @return {CanvasGradient}
* @api public
*/
Context2d.prototype.createLinearGradient = function(x0, y0, x1, y1){
return new CanvasGradient(x0, y0, x1, y1);
};
/**
* Create a radial gradient at the given point `(x0, y0)` and `(x1, y1)`
* and radius `r0` and `r1`.
*
* @param {Number} x0
* @param {Number} y0
* @param {Number} r0
* @param {Number} x1
* @param {Number} y1
* @param {Number} r1
* @return {CanvasGradient}
* @api public
*/
Context2d.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){
return new CanvasGradient(x0, y0, r0, x1, y1, r1);
};
/**
* Reset transform matrix to identity, then apply the given args.
*
* @param {...}
* @api public
*/
Context2d.prototype.setTransform = function(){
this.resetTransform();
this.transform.apply(this, arguments);
};
/**
* Set the fill style with the given css color string.
*
* @api public
*/
Context2d.prototype.__defineSetter__('fillStyle', function(val){
if (!val) return;
if ('CanvasGradient' == val.constructor.name
|| 'CanvasPattern' == val.constructor.name) {
this.lastFillStyle = val;
this._setFillPattern(val);
} else if ('string' == typeof val) {
this._setFillColor(val);
}
});
/**
* Get previous fill style.
*
* @return {CanvasGradient|String}
* @api public
*/
Context2d.prototype.__defineGetter__('fillStyle', function(){
return this.lastFillStyle || this.fillColor;
});
/**
* Set the stroke style with the given css color string.
*
* @api public
*/
Context2d.prototype.__defineSetter__('strokeStyle', function(val){
if (!val) return;
if ('CanvasGradient' == val.constructor.name
|| 'CanvasPattern' == val.constructor.name) {
this.lastStrokeStyle = val;
this._setStrokePattern(val);
} else if ('string' == typeof val) {
this._setStrokeColor(val);
}
});
/**
* Get previous stroke style.
*
* @return {CanvasGradient|String}
* @api public
*/
Context2d.prototype.__defineGetter__('strokeStyle', function(){
return this.lastStrokeStyle || this.strokeColor;
});
/**
* Register `font` for usage.
*
* @param {Font} font
* @api public
*/
Context2d.prototype.addFont = function(font) {
this._fonts = this._fonts || {};
if (this._fonts[font.name]) return;
this._fonts[font.name] = font;
};
/**
* Set font.
*
* @see exports.parseFont()
* @api public
*/
Context2d.prototype.__defineSetter__('font', function(val){
if (!val) return;
if ('string' == typeof val) {
var font;
if (font = parseFont(val)) {
this.lastFontString = val;
var fonts = this._fonts;
if (fonts && fonts[font.family]) {
var fontObj = fonts[font.family];
var type = font.weight + '-' + font.style;
var fontFace = fontObj.getFace(type);
this._setFontFace(fontFace, font.size);
} else {
this._setFont(
font.weight
, font.style
, font.size
, font.unit
, font.family);
}
}
}
});
/**
* Get the current font.
*
* @api public
*/
Context2d.prototype.__defineGetter__('font', function(){
return this.lastFontString || '10px sans-serif';
});
/**
* Set text baseline.
*
* @api public
*/
Context2d.prototype.__defineSetter__('textBaseline', function(val){
if (!val) return;
var n = baselines.indexOf(val);
if (~n) {
this.lastBaseline = val;
this._setTextBaseline(n);
}
});
/**
* Get the current baseline setting.
*
* @api public
*/
Context2d.prototype.__defineGetter__('textBaseline', function(){
return this.lastBaseline || 'alphabetic';
});
/**
* Set text alignment.
*
* @api public
*/
Context2d.prototype.__defineSetter__('textAlign', function(val){
switch (val) {
case 'center':
this._setTextAlignment(0);
this.lastTextAlignment = val;
break;
case 'left':
case 'start':
this._setTextAlignment(-1);
this.lastTextAlignment = val;
break;
case 'right':
case 'end':
this._setTextAlignment(1);
this.lastTextAlignment = val;
break;
}
});
/**
* Get the current font.
*
* @see exports.parseFont()
* @api public
*/
Context2d.prototype.__defineGetter__('textAlign', function(){
return this.lastTextAlignment || 'start';
});
/**
* Create `ImageData` with the given dimensions or
* `ImageData` instance for dimensions.
*
* @param {Number|ImageData} width
* @param {Number} height
* @return {ImageData}
* @api public
*/
Context2d.prototype.createImageData = function(width, height){
if ('ImageData' == width.constructor.name) {
height = width.height;
width = width.width;
}
return new ImageData(new Uint8ClampedArray(width * height * 4), width, height);
};
+61
View File
@@ -0,0 +1,61 @@
'use strict';
/*!
* Canvas - Image
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Canvas = require('./bindings')
, Image = Canvas.Image;
/**
* Src setter.
*
* - convert data uri to `Buffer`
*
* @param {String|Buffer} val filename, buffer, data uri
* @api public
*/
Image.prototype.__defineSetter__('src', function(val){
if ('string' == typeof val && 0 == val.indexOf('data:')) {
val = val.slice(val.indexOf(',') + 1);
this.source = new Buffer(val, 'base64');
} else {
this.source = val;
}
});
/**
* Src getter.
*
* TODO: return buffer
*
* @api public
*/
Image.prototype.__defineGetter__('src', function(){
return this.source;
});
/**
* Inspect image.
*
* TODO: indicate that the .src was a buffer, data uri etc
*
* @return {String}
* @api public
*/
Image.prototype.inspect = function(){
return '[Image'
+ (this.complete ? ':' + this.width + 'x' + this.height : '')
+ (this.src ? ' ' + this.src : '')
+ (this.complete ? ' complete' : '')
+ ']';
};
+62
View File
@@ -0,0 +1,62 @@
'use strict';
/*!
* Canvas - JPEGStream
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Stream = require('stream').Stream;
/**
* Initialize a `JPEGStream` with the given `canvas`.
*
* "data" events are emitted with `Buffer` chunks, once complete the
* "end" event is emitted. The following example will stream to a file
* named "./my.jpeg".
*
* var out = fs.createWriteStream(__dirname + '/my.jpeg')
* , stream = canvas.createJPEGStream();
*
* stream.pipe(out);
*
* @param {Canvas} canvas
* @param {Boolean} sync
* @api public
*/
var JPEGStream = module.exports = function JPEGStream(canvas, options, sync) {
var self = this
, method = sync
? 'streamJPEGSync'
: 'streamJPEG';
this.options = options;
this.sync = sync;
this.canvas = canvas;
this.readable = true;
// TODO: implement async
if ('streamJPEG' == method) method = 'streamJPEGSync';
process.nextTick(function(){
canvas[method](options.bufsize, options.quality, options.progressive, function(err, chunk){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (chunk) {
self.emit('data', chunk);
} else {
self.emit('end');
self.readable = false;
}
});
});
};
/**
* Inherit from `EventEmitter`.
*/
JPEGStream.prototype.__proto__ = Stream.prototype;
+59
View File
@@ -0,0 +1,59 @@
'use strict';
/*!
* Canvas - PDFStream
*/
/**
* Module dependencies.
*/
var Stream = require('stream').Stream;
/**
* Initialize a `PDFStream` with the given `canvas`.
*
* "data" events are emitted with `Buffer` chunks, once complete the
* "end" event is emitted. The following example will stream to a file
* named "./my.pdf".
*
* var out = fs.createWriteStream(__dirname + '/my.pdf')
* , stream = canvas.createPDFStream();
*
* stream.pipe(out);
*
* @param {Canvas} canvas
* @param {Boolean} sync
* @api public
*/
var PDFStream = module.exports = function PDFStream(canvas, sync) {
var self = this
, method = sync
? 'streamPDFSync'
: 'streamPDF';
this.sync = sync;
this.canvas = canvas;
this.readable = true;
// TODO: implement async
if ('streamPDF' == method) method = 'streamPDFSync';
process.nextTick(function(){
canvas[method](function(err, chunk, len){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (len) {
self.emit('data', chunk, len);
} else {
self.emit('end');
self.readable = false;
}
});
});
};
/**
* Inherit from `EventEmitter`.
*/
PDFStream.prototype.__proto__ = Stream.prototype;
+61
View File
@@ -0,0 +1,61 @@
'use strict';
/*!
* Canvas - PNGStream
* Copyright (c) 2010 LearnBoost <tj@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Stream = require('stream').Stream;
/**
* Initialize a `PNGStream` with the given `canvas`.
*
* "data" events are emitted with `Buffer` chunks, once complete the
* "end" event is emitted. The following example will stream to a file
* named "./my.png".
*
* var out = fs.createWriteStream(__dirname + '/my.png')
* , stream = canvas.createPNGStream();
*
* stream.pipe(out);
*
* @param {Canvas} canvas
* @param {Boolean} sync
* @api public
*/
var PNGStream = module.exports = function PNGStream(canvas, sync) {
var self = this
, method = sync
? 'streamPNGSync'
: 'streamPNG';
this.sync = sync;
this.canvas = canvas;
this.readable = true;
// TODO: implement async
if ('streamPNG' == method) method = 'streamPNGSync';
process.nextTick(function(){
canvas[method](function(err, chunk, len){
if (err) {
self.emit('error', err);
self.readable = false;
} else if (len) {
self.emit('data', chunk, len);
} else {
self.emit('end');
self.readable = false;
}
});
});
};
/**
* Inherit from `EventEmitter`.
*/
PNGStream.prototype.__proto__ = Stream.prototype;
+138
View File
@@ -0,0 +1,138 @@
{
"_args": [
[
"canvas@^1.3.13",
"/home/xor/shared_vm/git/node-sunwell"
]
],
"_from": "canvas@>=1.3.13 <2.0.0",
"_id": "canvas@1.6.2",
"_inCache": true,
"_installable": true,
"_location": "/canvas",
"_nodeVersion": "6.7.0",
"_npmOperationalInternal": {
"host": "packages-18-east.internal.npmjs.com",
"tmp": "tmp/canvas-1.6.2.tgz_1477855890935_0.3815066539682448"
},
"_npmUser": {
"email": "linus@folkdatorn.se",
"name": "linusu"
},
"_npmVersion": "3.10.7",
"_phantomChildren": {},
"_requested": {
"name": "canvas",
"raw": "canvas@^1.3.13",
"rawSpec": "^1.3.13",
"scope": null,
"spec": ">=1.3.13 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/canvas/-/canvas-1.6.2.tgz",
"_shasum": "12b56e3f00e7880aa45e3aae59fe75237720aaa4",
"_shrinkwrap": null,
"_spec": "canvas@^1.3.13",
"_where": "/home/xor/shared_vm/git/node-sunwell",
"author": {
"email": "tj@learnboost.com",
"name": "TJ Holowaychuk"
},
"bugs": {
"url": "https://github.com/Automattic/node-canvas/issues"
},
"contributors": [
{
"name": "Nathan Rajlich",
"email": "nathan@tootallnate.net"
},
{
"name": "Rod Vagg",
"email": "r@va.gg"
},
{
"name": "Juriy Zaytsev",
"email": "kangax@gmail.com"
}
],
"dependencies": {
"nan": "^2.4.0"
},
"description": "Canvas graphics API backed by Cairo",
"devDependencies": {
"body-parser": "^1.13.3",
"express": "^4.13.2",
"mocha": "*",
"pug": "^2.0.0-beta3",
"standard": "^7.1.1"
},
"directories": {},
"dist": {
"shasum": "12b56e3f00e7880aa45e3aae59fe75237720aaa4",
"tarball": "https://registry.npmjs.org/canvas/-/canvas-1.6.2.tgz"
},
"engines": {
"node": ">=0.8.0"
},
"gitHead": "bdc72016423b796c8203fed5f3bbda53536d31c2",
"gypfile": true,
"homepage": "https://github.com/Automattic/node-canvas",
"keywords": [
"cairo",
"canvas",
"graphic",
"graphics",
"image",
"images",
"pdf",
"pixman"
],
"license": "MIT",
"main": "./lib/canvas.js",
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "kangax",
"email": "kangax@gmail.com"
},
{
"name": "tootallnate",
"email": "nathan@tootallnate.net"
},
{
"name": "rauchg",
"email": "rauchg@gmail.com"
},
{
"name": "domenic",
"email": "d@domenic.me"
},
{
"name": "linusu",
"email": "linus@folkdatorn.se"
}
],
"name": "canvas",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/Automattic/node-canvas.git"
},
"scripts": {
"benchmark": "node benchmarks/run.js",
"install": "node-gyp rebuild",
"prebenchmark": "node-gyp build",
"pretest": "node-gyp build",
"pretest-server": "node-gyp build",
"test": "standard examples/*.js && mocha test/*.test.js",
"test-server": "node test/server.js"
},
"version": "1.6.2"
}
+673
View File
@@ -0,0 +1,673 @@
//
// Canvas.cc
//
// 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>
#include <node_buffer.h>
#include <node_version.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>
#include "closure.h"
#ifdef HAVE_JPEG
#include "JPEGStream.h"
#endif
Nan::Persistent<FunctionTemplate> Canvas::constructor;
/*
* Initialize Canvas.
*/
void
Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Canvas::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("Canvas").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
Nan::SetPrototypeMethod(ctor, "toBuffer", ToBuffer);
Nan::SetPrototypeMethod(ctor, "streamPNGSync", StreamPNGSync);
Nan::SetPrototypeMethod(ctor, "streamPDFSync", StreamPDFSync);
#ifdef HAVE_JPEG
Nan::SetPrototypeMethod(ctor, "streamJPEGSync", StreamJPEGSync);
#endif
Nan::SetAccessor(proto, Nan::New("type").ToLocalChecked(), GetType);
Nan::SetAccessor(proto, Nan::New("stride").ToLocalChecked(), GetStride);
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight);
Nan::SetTemplate(proto, "PNG_NO_FILTERS", Nan::New<Uint32>(PNG_NO_FILTERS));
Nan::SetTemplate(proto, "PNG_FILTER_NONE", Nan::New<Uint32>(PNG_FILTER_NONE));
Nan::SetTemplate(proto, "PNG_FILTER_SUB", Nan::New<Uint32>(PNG_FILTER_SUB));
Nan::SetTemplate(proto, "PNG_FILTER_UP", Nan::New<Uint32>(PNG_FILTER_UP));
Nan::SetTemplate(proto, "PNG_FILTER_AVG", Nan::New<Uint32>(PNG_FILTER_AVG));
Nan::SetTemplate(proto, "PNG_FILTER_PAETH", Nan::New<Uint32>(PNG_FILTER_PAETH));
Nan::SetTemplate(proto, "PNG_ALL_FILTERS", Nan::New<Uint32>(PNG_ALL_FILTERS));
Nan::Set(target, Nan::New("Canvas").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a Canvas with the given width and height.
*/
NAN_METHOD(Canvas::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
int width = 0, height = 0;
canvas_type_t type = CANVAS_TYPE_IMAGE;
if (info[0]->IsNumber()) width = info[0]->Uint32Value();
if (info[1]->IsNumber()) height = info[1]->Uint32Value();
if (info[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(info[2]))
? CANVAS_TYPE_PDF
: !strcmp("svg", *String::Utf8Value(info[2]))
? CANVAS_TYPE_SVG
: CANVAS_TYPE_IMAGE;
Canvas *canvas = new Canvas(width, height, type);
canvas->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
/*
* Get type string.
*/
NAN_GETTER(Canvas::GetType) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<String>(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image").ToLocalChecked());
}
/*
* Get stride.
*/
NAN_GETTER(Canvas::GetStride) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(canvas->stride()));
}
/*
* Get width.
*/
NAN_GETTER(Canvas::GetWidth) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(canvas->width));
}
/*
* Set width.
*/
NAN_SETTER(Canvas::SetWidth) {
if (value->IsNumber()) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
canvas->width = value->Uint32Value();
canvas->resurface(info.This());
}
}
/*
* Get height.
*/
NAN_GETTER(Canvas::GetHeight) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(canvas->height));
}
/*
* Set height.
*/
NAN_SETTER(Canvas::SetHeight) {
if (value->IsNumber()) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
canvas->height = value->Uint32Value();
canvas->resurface(info.This());
}
}
/*
* Canvas::ToBuffer callback.
*/
static cairo_status_t
toBuffer(void *c, const uint8_t *data, unsigned len) {
closure_t *closure = (closure_t *) c;
if (closure->len + len > closure->max_len) {
uint8_t *data;
unsigned max = closure->max_len;
do {
max *= 2;
} while (closure->len + len > max);
data = (uint8_t *) realloc(closure->data, max);
if (!data) return CAIRO_STATUS_NO_MEMORY;
closure->data = data;
closure->max_len = max;
}
memcpy(closure->data + closure->len, data, len);
closure->len += len;
return CAIRO_STATUS_SUCCESS;
}
/*
* EIO toBuffer callback.
*/
#if NODE_VERSION_AT_LEAST(0, 6, 0)
void
Canvas::ToBufferAsync(uv_work_t *req) {
#elif NODE_VERSION_AT_LEAST(0, 5, 4)
void
Canvas::EIO_ToBuffer(eio_req *req) {
#else
int
Canvas::EIO_ToBuffer(eio_req *req) {
#endif
closure_t *closure = (closure_t *) req->data;
closure->status = canvas_write_to_png_stream(
closure->canvas->surface()
, toBuffer
, closure);
#if !NODE_VERSION_AT_LEAST(0, 5, 4)
return 0;
#endif
}
/*
* EIO after toBuffer callback.
*/
#if NODE_VERSION_AT_LEAST(0, 6, 0)
void
Canvas::ToBufferAsyncAfter(uv_work_t *req) {
#else
int
Canvas::EIO_AfterToBuffer(eio_req *req) {
#endif
Nan::HandleScope scope;
closure_t *closure = (closure_t *) req->data;
#if NODE_VERSION_AT_LEAST(0, 6, 0)
delete req;
#else
ev_unref(EV_DEFAULT_UC);
#endif
if (closure->status) {
Local<Value> argv[1] = { Canvas::Error(closure->status) };
closure->pfn->Call(1, argv);
} else {
Local<Object> buf = Nan::CopyBuffer((char*)closure->data, closure->len).ToLocalChecked();
memcpy(Buffer::Data(buf), closure->data, closure->len);
Local<Value> argv[2] = { Nan::Null(), buf };
closure->pfn->Call(2, argv);
}
closure->canvas->Unref();
delete closure->pfn;
closure_destroy(closure);
free(closure);
#if !NODE_VERSION_AT_LEAST(0, 6, 0)
return 0;
#endif
}
/*
* Convert PNG data to a node::Buffer, async when a
* callback function is passed.
*/
NAN_METHOD(Canvas::ToBuffer) {
cairo_status_t status;
uint32_t compression_level = 6;
uint32_t filter = PNG_ALL_FILTERS;
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
// TODO: async / move this out
if (canvas->isPDF() || canvas->isSVG()) {
cairo_surface_finish(canvas->surface());
closure_t *closure = (closure_t *) canvas->closure();
Local<Object> buf = Nan::CopyBuffer((char*) closure->data, closure->len).ToLocalChecked();
info.GetReturnValue().Set(buf);
return;
}
if (info.Length() >= 1 && info[0]->StrictEquals(Nan::New<String>("raw").ToLocalChecked())) {
// Return raw ARGB data -- just a memcpy()
cairo_surface_t *surface = canvas->surface();
cairo_surface_flush(surface);
const unsigned char *data = cairo_image_surface_get_data(surface);
Local<Object> buf = Nan::CopyBuffer(reinterpret_cast<const char*>(data), canvas->nBytes()).ToLocalChecked();
info.GetReturnValue().Set(buf);
return;
}
if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
if (!info[1]->IsUndefined()) {
bool good = true;
if (info[1]->IsNumber()) {
compression_level = info[1]->Uint32Value();
} else if (info[1]->IsString()) {
if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
compression_level = 0;
} else {
uint32_t tmp = info[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
compression_level = tmp;
}
}
} else {
good = false;
}
if (good) {
if (compression_level > 9) {
return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return Nan::ThrowTypeError("Compression level must be a number.");
}
}
if (!info[2]->IsUndefined()) {
if (info[2]->IsUint32()) {
filter = info[2]->Uint32Value();
} else {
return Nan::ThrowTypeError("Invalid filter value.");
}
}
}
// Async
if (info[0]->IsFunction()) {
closure_t *closure = (closure_t *) malloc(sizeof(closure_t));
status = closure_init(closure, canvas, compression_level, filter);
// ensure closure is ok
if (status) {
closure_destroy(closure);
free(closure);
return Nan::ThrowError(Canvas::Error(status));
}
// TODO: only one callback fn in closure
canvas->Ref();
closure->pfn = new Nan::Callback(info[0].As<Function>());
#if NODE_VERSION_AT_LEAST(0, 6, 0)
uv_work_t* req = new uv_work_t;
req->data = closure;
uv_queue_work(uv_default_loop(), req, ToBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter);
#else
eio_custom(EIO_ToBuffer, EIO_PRI_DEFAULT, EIO_AfterToBuffer, closure);
ev_ref(EV_DEFAULT_UC);
#endif
return;
// Sync
} else {
closure_t closure;
status = closure_init(&closure, canvas, compression_level, filter);
// ensure closure is ok
if (status) {
closure_destroy(&closure);
return Nan::ThrowError(Canvas::Error(status));
}
Nan::TryCatch try_catch;
status = canvas_write_to_png_stream(canvas->surface(), toBuffer, &closure);
if (try_catch.HasCaught()) {
closure_destroy(&closure);
try_catch.ReThrow();
return;
} else if (status) {
closure_destroy(&closure);
return Nan::ThrowError(Canvas::Error(status));
} else {
Local<Object> buf = Nan::CopyBuffer((char *)closure.data, closure.len).ToLocalChecked();
closure_destroy(&closure);
info.GetReturnValue().Set(buf);
return;
}
}
}
/*
* Canvas::StreamPNG callback.
*/
static cairo_status_t
streamPNG(void *c, const uint8_t *data, unsigned len) {
Nan::HandleScope scope;
closure_t *closure = (closure_t *) c;
Local<Object> buf = Nan::CopyBuffer((char *)data, len).ToLocalChecked();
Local<Value> argv[3] = {
Nan::Null()
, buf
, Nan::New<Number>(len) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure->fn, 3, argv);
return CAIRO_STATUS_SUCCESS;
}
/*
* Stream PNG data synchronously.
*/
NAN_METHOD(Canvas::StreamPNGSync) {
uint32_t compression_level = 6;
uint32_t filter = PNG_ALL_FILTERS;
// TODO: async as well
if (!info[0]->IsFunction())
return Nan::ThrowTypeError("callback function required");
if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
if (!info[1]->IsUndefined()) {
bool good = true;
if (info[1]->IsNumber()) {
compression_level = info[1]->Uint32Value();
} else if (info[1]->IsString()) {
if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
compression_level = 0;
} else {
uint32_t tmp = info[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
compression_level = tmp;
}
}
} else {
good = false;
}
if (good) {
if (compression_level > 9) {
return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return Nan::ThrowTypeError("Compression level must be a number.");
}
}
if (!info[2]->IsUndefined()) {
if (info[2]->IsUint32()) {
filter = info[2]->Uint32Value();
} else {
return Nan::ThrowTypeError("Invalid filter value.");
}
}
}
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
closure_t closure;
closure.fn = Local<Function>::Cast(info[0]);
closure.compression_level = compression_level;
closure.filter = filter;
Nan::TryCatch try_catch;
cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return;
} else if (status) {
Local<Value> argv[1] = { Canvas::Error(status) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
} else {
Local<Value> argv[3] = {
Nan::Null()
, Nan::Null()
, Nan::New<Uint32>(0) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
}
return;
}
/*
* Canvas::StreamPDF FreeCallback
*/
void stream_pdf_free(char *, void *) {}
/*
* Canvas::StreamPDF callback.
*/
static cairo_status_t
streamPDF(void *c, const uint8_t *data, unsigned len) {
Nan::HandleScope scope;
closure_t *closure = static_cast<closure_t *>(c);
Local<Object> buf = Nan::NewBuffer(const_cast<char *>(reinterpret_cast<const char *>(data)), len, stream_pdf_free, 0).ToLocalChecked();
Local<Value> argv[3] = {
Nan::Null()
, buf
, Nan::New<Number>(len) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), closure->fn, 3, argv);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t canvas_write_to_pdf_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) {
closure_t *pdf_closure = static_cast<closure_t *>(closure);
size_t whole_chunks = pdf_closure->len / PAGE_SIZE;
size_t remainder = pdf_closure->len - whole_chunks * PAGE_SIZE;
for (size_t i = 0; i < whole_chunks; ++i) {
write_func(pdf_closure, &pdf_closure->data[i * PAGE_SIZE], PAGE_SIZE);
}
if (remainder) {
write_func(pdf_closure, &pdf_closure->data[whole_chunks * PAGE_SIZE], remainder);
}
return CAIRO_STATUS_SUCCESS;
}
/*
* Stream PDF data synchronously.
*/
NAN_METHOD(Canvas::StreamPDFSync) {
if (!info[0]->IsFunction())
return Nan::ThrowTypeError("callback function required");
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.Holder());
if (!canvas->isPDF())
return Nan::ThrowTypeError("wrong canvas type");
cairo_surface_finish(canvas->surface());
closure_t closure;
closure.data = static_cast<closure_t *>(canvas->closure())->data;
closure.len = static_cast<closure_t *>(canvas->closure())->len;
closure.fn = info[0].As<Function>();
Nan::TryCatch try_catch;
cairo_status_t status = canvas_write_to_pdf_stream(canvas->surface(), streamPDF, &closure);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
} else if (status) {
Local<Value> error = Canvas::Error(status);
Nan::Call(closure.fn, Nan::GetCurrentContext()->Global(), 1, &error);
} else {
Local<Value> argv[3] = {
Nan::Null()
, Nan::Null()
, Nan::New<Uint32>(0) };
Nan::Call(closure.fn, Nan::GetCurrentContext()->Global(), 3, argv);
}
}
/*
* Stream JPEG data synchronously.
*/
#ifdef HAVE_JPEG
NAN_METHOD(Canvas::StreamJPEGSync) {
// TODO: async as well
if (!info[0]->IsNumber())
return Nan::ThrowTypeError("buffer size required");
if (!info[1]->IsNumber())
return Nan::ThrowTypeError("quality setting required");
if (!info[2]->IsBoolean())
return Nan::ThrowTypeError("progressive setting required");
if (!info[3]->IsFunction())
return Nan::ThrowTypeError("callback function required");
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
closure_t closure;
closure.fn = Local<Function>::Cast(info[3]);
Nan::TryCatch try_catch;
write_to_jpeg_stream(canvas->surface(), info[0]->NumberValue(), info[1]->NumberValue(), info[2]->BooleanValue(), &closure);
if (try_catch.HasCaught()) {
try_catch.ReThrow();
}
return;
}
#endif
/*
* Initialize cairo surface.
*/
Canvas::Canvas(int w, int h, canvas_type_t t): Nan::ObjectWrap() {
type = t;
width = w;
height = h;
_surface = NULL;
_closure = NULL;
if (CANVAS_TYPE_PDF == t) {
_closure = malloc(sizeof(closure_t));
assert(_closure);
cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
assert(status == CAIRO_STATUS_SUCCESS);
_surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h);
} else if (CANVAS_TYPE_SVG == t) {
_closure = malloc(sizeof(closure_t));
assert(_closure);
cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
assert(status == CAIRO_STATUS_SUCCESS);
_surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h);
} else {
_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
assert(_surface);
Nan::AdjustExternalMemory(nBytes());
}
}
/*
* Destroy cairo surface.
*/
Canvas::~Canvas() {
switch (type) {
case CANVAS_TYPE_PDF:
case CANVAS_TYPE_SVG:
cairo_surface_finish(_surface);
closure_destroy((closure_t *) _closure);
free(_closure);
cairo_surface_destroy(_surface);
break;
case CANVAS_TYPE_IMAGE:
int oldNBytes = nBytes();
cairo_surface_destroy(_surface);
Nan::AdjustExternalMemory(-oldNBytes);
break;
}
}
/*
* Re-alloc the surface, destroying the previous.
*/
void
Canvas::resurface(Local<Object> canvas) {
Nan::HandleScope scope;
Local<Value> context;
switch (type) {
case CANVAS_TYPE_PDF:
cairo_pdf_surface_set_size(_surface, width, height);
break;
case CANVAS_TYPE_SVG:
// Re-surface
cairo_surface_finish(_surface);
closure_destroy((closure_t *) _closure);
cairo_surface_destroy(_surface);
closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
_surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height);
// Reset context
context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
if (!context->IsUndefined()) {
Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
cairo_t *prev = context2d->context();
context2d->setContext(cairo_create(surface()));
cairo_destroy(prev);
}
break;
case CANVAS_TYPE_IMAGE:
// Re-surface
size_t oldNBytes = nBytes();
cairo_surface_destroy(_surface);
_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
Nan::AdjustExternalMemory(nBytes() - oldNBytes);
// Reset context
context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
if (!context->IsUndefined()) {
Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
cairo_t *prev = context2d->context();
context2d->setContext(cairo_create(surface()));
cairo_destroy(prev);
}
break;
}
}
/*
* Construct an Error from the given cairo status.
*/
Local<Value>
Canvas::Error(cairo_status_t status) {
return Exception::Error(Nan::New<String>(cairo_status_to_string(status)).ToLocalChecked());
}
+99
View File
@@ -0,0 +1,99 @@
//
// Canvas.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_CANVAS_H__
#define __NODE_CANVAS_H__
#include <v8.h>
#include <node.h>
#include <node_object_wrap.h>
#include <node_version.h>
#if HAVE_PANGO
#include <pango/pangocairo.h>
#else
#include <cairo.h>
#endif
#include <nan.h>
using namespace v8;
using namespace node;
/*
* Maxmimum states per context.
* TODO: remove/resize
*/
#ifndef CANVAS_MAX_STATES
#define CANVAS_MAX_STATES 64
#endif
/*
* Canvas types.
*/
typedef enum {
CANVAS_TYPE_IMAGE,
CANVAS_TYPE_PDF,
CANVAS_TYPE_SVG
} canvas_type_t;
/*
* Canvas.
*/
class Canvas: public Nan::ObjectWrap {
public:
int width;
int height;
canvas_type_t type;
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(ToBuffer);
static NAN_GETTER(GetType);
static NAN_GETTER(GetStride);
static NAN_GETTER(GetWidth);
static NAN_GETTER(GetHeight);
static NAN_SETTER(SetWidth);
static NAN_SETTER(SetHeight);
static NAN_METHOD(StreamPNGSync);
static NAN_METHOD(StreamPDFSync);
static NAN_METHOD(StreamJPEGSync);
static Local<Value> Error(cairo_status_t status);
#if NODE_VERSION_AT_LEAST(0, 6, 0)
static void ToBufferAsync(uv_work_t *req);
static void ToBufferAsyncAfter(uv_work_t *req);
#else
static
#if NODE_VERSION_AT_LEAST(0, 5, 4)
void
#else
int
#endif
EIO_ToBuffer(eio_req *req);
static int EIO_AfterToBuffer(eio_req *req);
#endif
inline bool isPDF(){ return CANVAS_TYPE_PDF == type; }
inline bool isSVG(){ return CANVAS_TYPE_SVG == type; }
inline cairo_surface_t *surface(){ return _surface; }
inline void *closure(){ return _closure; }
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
inline int nBytes(){ return height * stride(); }
Canvas(int width, int height, canvas_type_t type);
void resurface(Local<Object> canvas);
private:
~Canvas();
cairo_surface_t *_surface;
void *_closure;
};
#endif
+122
View File
@@ -0,0 +1,122 @@
//
// Gradient.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "color.h"
#include "Canvas.h"
#include "CanvasGradient.h"
Nan::Persistent<FunctionTemplate> Gradient::constructor;
/*
* Initialize CanvasGradient.
*/
void
Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Gradient::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked());
// Prototype
Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop);
Nan::Set(target, Nan::New("CanvasGradient").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a new CanvasGradient.
*/
NAN_METHOD(Gradient::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
// Linear
if (4 == info.Length()) {
Gradient *grad = new Gradient(
info[0]->NumberValue()
, info[1]->NumberValue()
, info[2]->NumberValue()
, info[3]->NumberValue());
grad->Wrap(info.This());
info.GetReturnValue().Set(info.This());
return;
}
// Radial
if (6 == info.Length()) {
Gradient *grad = new Gradient(
info[0]->NumberValue()
, info[1]->NumberValue()
, info[2]->NumberValue()
, info[3]->NumberValue()
, info[4]->NumberValue()
, info[5]->NumberValue());
grad->Wrap(info.This());
info.GetReturnValue().Set(info.This());
return;
}
return Nan::ThrowTypeError("invalid arguments");
}
/*
* Add color stop.
*/
NAN_METHOD(Gradient::AddColorStop) {
if (!info[0]->IsNumber())
return Nan::ThrowTypeError("offset required");
if (!info[1]->IsString())
return Nan::ThrowTypeError("color string required");
Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(info.This());
short ok;
String::Utf8Value str(info[1]);
uint32_t rgba = rgba_from_string(*str, &ok);
if (ok) {
rgba_t color = rgba_create(rgba);
cairo_pattern_add_color_stop_rgba(
grad->pattern()
, info[0]->NumberValue()
, color.r
, color.g
, color.b
, color.a);
} else {
return Nan::ThrowTypeError("parse color failed");
}
}
/*
* Initialize linear gradient.
*/
Gradient::Gradient(double x0, double y0, double x1, double y1) {
_pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
}
/*
* Initialize radial gradient.
*/
Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) {
_pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
}
/*
* Destroy the pattern.
*/
Gradient::~Gradient() {
cairo_pattern_destroy(_pattern);
}
+28
View File
@@ -0,0 +1,28 @@
//
// CanvasGradient.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_GRADIENT_H__
#define __NODE_GRADIENT_H__
#include "Canvas.h"
class Gradient: public Nan::ObjectWrap {
public:
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(AddColorStop);
Gradient(double x0, double y0, double x1, double y1);
Gradient(double x0, double y0, double r0, double x1, double y1, double r1);
inline cairo_pattern_t *pattern(){ return _pattern; }
private:
~Gradient();
cairo_pattern_t *_pattern;
};
#endif
+86
View File
@@ -0,0 +1,86 @@
//
// Pattern.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "Canvas.h"
#include "Image.h"
#include "CanvasPattern.h"
Nan::Persistent<FunctionTemplate> Pattern::constructor;
/*
* Initialize CanvasPattern.
*/
void
Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Pattern::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
// Prototype
Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a new CanvasPattern.
*/
NAN_METHOD(Pattern::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
cairo_surface_t *surface;
Local<Object> obj = info[0]->ToObject();
// Image
if (Nan::New(Image::constructor)->HasInstance(obj)) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
if (!img->isComplete()) {
return Nan::ThrowError("Image given has not completed loading");
}
surface = img->surface();
// Canvas
} else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
surface = canvas->surface();
// Invalid
} else {
return Nan::ThrowTypeError("Image or Canvas expected");
}
Pattern *pattern = new Pattern(surface);
pattern->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
/*
* Initialize linear gradient.
*/
Pattern::Pattern(cairo_surface_t *surface) {
_pattern = cairo_pattern_create_for_surface(surface);
}
/*
* Destroy the pattern.
*/
Pattern::~Pattern() {
cairo_pattern_destroy(_pattern);
}
+27
View File
@@ -0,0 +1,27 @@
//
// CanvasPattern.h
//
// Copyright (c) 2011 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_PATTERN_H__
#define __NODE_PATTERN_H__
#include "Canvas.h"
class Pattern: public Nan::ObjectWrap {
public:
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
Pattern(cairo_surface_t *surface);
inline cairo_pattern_t *pattern(){ return _pattern; }
private:
~Pattern();
// TODO REPEAT/REPEAT_X/REPEAT_Y
cairo_pattern_t *_pattern;
};
#endif
File diff suppressed because it is too large Load Diff
+185
View File
@@ -0,0 +1,185 @@
//
// CanvasRenderingContext2d.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_CONTEXT2D_H__
#define __NODE_CONTEXT2D_H__
#include "color.h"
#include "Canvas.h"
#include "CanvasGradient.h"
#ifdef HAVE_FREETYPE
#include <ft2build.h>
#include <cairo-ft.h>
#include FT_FREETYPE_H
#endif
#include <vector>
using namespace std;
typedef enum {
TEXT_DRAW_PATHS,
TEXT_DRAW_GLYPHS
} canvas_draw_mode_t;
/*
* State struct.
*
* Used in conjunction with Save() / Restore() since
* cairo's gstate maintains only a single source pattern at a time.
*/
typedef struct {
rgba_t fill;
rgba_t stroke;
cairo_filter_t patternQuality;
cairo_pattern_t *fillPattern;
cairo_pattern_t *strokePattern;
cairo_pattern_t *fillGradient;
cairo_pattern_t *strokeGradient;
float globalAlpha;
short textAlignment;
short textBaseline;
rgba_t shadow;
int shadowBlur;
double shadowOffsetX;
double shadowOffsetY;
canvas_draw_mode_t textDrawingMode;
#if HAVE_PANGO
PangoWeight fontWeight;
PangoStyle fontStyle;
double fontSize;
char *fontFamily;
#endif
} canvas_state_t;
#if HAVE_PANGO
void state_assign_fontFamily(canvas_state_t *state, const char *str);
#endif
class Context2d: public Nan::ObjectWrap {
public:
short stateno;
canvas_state_t *states[CANVAS_MAX_STATES];
canvas_state_t *state;
Context2d(Canvas *canvas);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(DrawImage);
static NAN_METHOD(PutImageData);
static NAN_METHOD(Save);
static NAN_METHOD(Restore);
static NAN_METHOD(Rotate);
static NAN_METHOD(Translate);
static NAN_METHOD(Scale);
static NAN_METHOD(Transform);
static NAN_METHOD(ResetTransform);
static NAN_METHOD(IsPointInPath);
static NAN_METHOD(BeginPath);
static NAN_METHOD(ClosePath);
static NAN_METHOD(AddPage);
static NAN_METHOD(Clip);
static NAN_METHOD(Fill);
static NAN_METHOD(Stroke);
static NAN_METHOD(FillText);
static NAN_METHOD(StrokeText);
static NAN_METHOD(SetFont);
#ifdef HAVE_FREETYPE
static NAN_METHOD(SetFontFace);
#endif
static NAN_METHOD(SetFillColor);
static NAN_METHOD(SetStrokeColor);
static NAN_METHOD(SetFillPattern);
static NAN_METHOD(SetStrokePattern);
static NAN_METHOD(SetTextBaseline);
static NAN_METHOD(SetTextAlignment);
static NAN_METHOD(SetLineDash);
static NAN_METHOD(GetLineDash);
static NAN_METHOD(MeasureText);
static NAN_METHOD(BezierCurveTo);
static NAN_METHOD(QuadraticCurveTo);
static NAN_METHOD(LineTo);
static NAN_METHOD(MoveTo);
static NAN_METHOD(FillRect);
static NAN_METHOD(StrokeRect);
static NAN_METHOD(ClearRect);
static NAN_METHOD(Rect);
static NAN_METHOD(Arc);
static NAN_METHOD(ArcTo);
static NAN_METHOD(GetImageData);
static NAN_GETTER(GetPatternQuality);
static NAN_GETTER(GetGlobalCompositeOperation);
static NAN_GETTER(GetGlobalAlpha);
static NAN_GETTER(GetShadowColor);
static NAN_GETTER(GetFillColor);
static NAN_GETTER(GetStrokeColor);
static NAN_GETTER(GetMiterLimit);
static NAN_GETTER(GetLineCap);
static NAN_GETTER(GetLineJoin);
static NAN_GETTER(GetLineWidth);
static NAN_GETTER(GetLineDashOffset);
static NAN_GETTER(GetShadowOffsetX);
static NAN_GETTER(GetShadowOffsetY);
static NAN_GETTER(GetShadowBlur);
static NAN_GETTER(GetAntiAlias);
static NAN_GETTER(GetTextDrawingMode);
static NAN_GETTER(GetFilter);
static NAN_SETTER(SetPatternQuality);
static NAN_SETTER(SetGlobalCompositeOperation);
static NAN_SETTER(SetGlobalAlpha);
static NAN_SETTER(SetShadowColor);
static NAN_SETTER(SetMiterLimit);
static NAN_SETTER(SetLineCap);
static NAN_SETTER(SetLineJoin);
static NAN_SETTER(SetLineWidth);
static NAN_SETTER(SetLineDashOffset);
static NAN_SETTER(SetShadowOffsetX);
static NAN_SETTER(SetShadowOffsetY);
static NAN_SETTER(SetShadowBlur);
static NAN_SETTER(SetAntiAlias);
static NAN_SETTER(SetTextDrawingMode);
static NAN_SETTER(SetFilter);
inline void setContext(cairo_t *ctx) { _context = ctx; }
inline cairo_t *context(){ return _context; }
inline Canvas *canvas(){ return _canvas; }
inline bool hasShadow();
void inline setSourceRGBA(rgba_t color);
void inline setSourceRGBA(cairo_t *ctx, rgba_t color);
void setTextPath(const char *str, double x, double y);
void blur(cairo_surface_t *surface, int radius);
void shadow(void (fn)(cairo_t *cr));
void shadowStart();
void shadowApply();
void savePath();
void restorePath();
void saveState();
void restoreState();
void inline setFillRule(v8::Local<v8::Value> value);
void fill(bool preserve = false);
void stroke(bool preserve = false);
void save();
void restore();
#if HAVE_PANGO
void setFontFromState();
inline PangoLayout *layout(){ return _layout; }
#endif
private:
~Context2d();
Canvas *_canvas;
cairo_t *_context;
cairo_path_t *_path;
#if HAVE_PANGO
PangoLayout *_layout;
#endif
};
#endif
+113
View File
@@ -0,0 +1,113 @@
//
// FontFace.cc
//
// Copyright (c) 2012 Julian Viereck <julian.viereck@gmail.com>
//
#include "FontFace.h"
#include <fontconfig/fontconfig.h>
Nan::Persistent<FunctionTemplate> FontFace::constructor;
/*
* Destroy ft_face.
*/
FontFace::~FontFace() {
// Decrement extra reference count added in ::New(...).
// Once there is no reference left to crFace, cairo will release the
// free type font face as well.
cairo_font_face_destroy(_crFace);
}
/*
* Initialize FontFace.
*/
void
FontFace::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(FontFace::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("FontFace").ToLocalChecked());
// Prototype
Nan::Set(target, Nan::New("FontFace").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a new FontFace object.
*/
FT_Library library; /* handle to library */
bool FontFace::_initLibrary = true;
static cairo_user_data_key_t key;
/*
* Initialize a new FontFace.
*/
NAN_METHOD(FontFace::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
if (!info[0]->IsString()
|| !info[1]->IsNumber()) {
return Nan::ThrowError("Wrong argument types passed to FontFace constructor");
}
String::Utf8Value filePath(info[0]);
int faceIdx = int(info[1]->NumberValue());
FT_Face ftFace;
FT_Error ftError;
cairo_font_face_t *crFace;
if (_initLibrary) {
_initLibrary = false;
ftError = FT_Init_FreeType(&library);
if (ftError) {
return Nan::ThrowError("Could not load library");
}
}
// Create new freetype font face.
ftError = FT_New_Face(library, *filePath, faceIdx, &ftFace);
if (ftError) {
return Nan::ThrowError("Could not load font file");
}
#if HAVE_PANGO
// Load the font file in fontconfig
FcBool ok = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(*filePath));
if (!ok) {
return Nan::ThrowError("Could not load font in FontConfig");
}
#endif
// Create new cairo font face.
crFace = cairo_ft_font_face_create_for_ft_face(ftFace, 0);
// If the cairo font face is released, release the FreeType font face as well.
int status = cairo_font_face_set_user_data (crFace, &key,
ftFace, (cairo_destroy_func_t) FT_Done_Face);
if (status) {
cairo_font_face_destroy (crFace);
FT_Done_Face (ftFace);
return Nan::ThrowError("Failed to setup cairo font face user data");
}
// Explicit reference count the cairo font face. Otherwise the font face might
// get released by cairo although the JS font face object is still alive.
cairo_font_face_reference(crFace);
FontFace *face = new FontFace(crFace);
face->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
+32
View File
@@ -0,0 +1,32 @@
//
// FontFace.h
//
// Copyright (c) 2012 Julian Viereck <julian.viereck@gmail.com>
//
#ifndef __NODE_TRUE_TYPE_FONT_FACE_H__
#define __NODE_TRUE_TYPE_FONT_FACE_H__
#include "Canvas.h"
#include <ft2build.h>
#include <cairo-ft.h>
#include FT_FREETYPE_H
class FontFace: public Nan::ObjectWrap {
public:
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
FontFace(cairo_font_face_t *crFace)
:_crFace(crFace) {}
inline cairo_font_face_t *cairoFace(){ return _crFace; }
private:
~FontFace();
cairo_font_face_t *_crFace;
static bool _initLibrary;
};
#endif
+974
View File
@@ -0,0 +1,974 @@
//
// Image.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "Canvas.h"
#include "Image.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <node_buffer.h>
#ifdef HAVE_GIF
typedef struct {
uint8_t *buf;
unsigned len;
unsigned pos;
} gif_data_t;
#endif
/*
* Read closure used by loadFromBuffer.
*/
typedef struct {
unsigned len;
uint8_t *buf;
} read_closure_t;
Nan::Persistent<FunctionTemplate> Image::constructor;
/*
* Initialize Image.
*/
void
Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Image::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("Image").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
Nan::SetAccessor(proto, Nan::New("source").ToLocalChecked(), GetSource, SetSource);
Nan::SetAccessor(proto, Nan::New("complete").ToLocalChecked(), GetComplete);
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
Nan::SetAccessor(proto, Nan::New("onload").ToLocalChecked(), GetOnload, SetOnload);
Nan::SetAccessor(proto, Nan::New("onerror").ToLocalChecked(), GetOnerror, SetOnerror);
#if CAIRO_VERSION_MINOR >= 10
Nan::SetAccessor(proto, Nan::New("dataMode").ToLocalChecked(), GetDataMode, SetDataMode);
ctor->Set(Nan::New("MODE_IMAGE").ToLocalChecked(), Nan::New<Number>(DATA_IMAGE));
ctor->Set(Nan::New("MODE_MIME").ToLocalChecked(), Nan::New<Number>(DATA_MIME));
#endif
Nan::Set(target, Nan::New("Image").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a new Image.
*/
NAN_METHOD(Image::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
Image *img = new Image;
img->data_mode = DATA_IMAGE;
img->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
/*
* Get complete boolean.
*/
NAN_GETTER(Image::GetComplete) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Boolean>(Image::COMPLETE == img->state));
}
#if CAIRO_VERSION_MINOR >= 10
/*
* Get dataMode.
*/
NAN_GETTER(Image::GetDataMode) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->data_mode));
}
/*
* Set dataMode.
*/
NAN_SETTER(Image::SetDataMode) {
if (value->IsNumber()) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
int mode = value->Uint32Value();
img->data_mode = (data_mode_t) mode;
}
}
#endif
/*
* Get width.
*/
NAN_GETTER(Image::GetWidth) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->width));
}
/*
* Get height.
*/
NAN_GETTER(Image::GetHeight) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->height));
}
/*
* Get src path.
*/
NAN_GETTER(Image::GetSource) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<String>(img->filename ? img->filename : "").ToLocalChecked());
}
/*
* Clean up assets and variables.
*/
void
Image::clearData() {
if (_surface) {
cairo_surface_destroy(_surface);
Nan::AdjustExternalMemory(-_data_len);
_data_len = 0;
_surface = NULL;
}
free(_data);
_data = NULL;
free(filename);
filename = NULL;
width = height = 0;
state = DEFAULT;
}
/*
* Set src path.
*/
NAN_SETTER(Image::SetSource) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
cairo_status_t status = CAIRO_STATUS_READ_ERROR;
img->clearData();
// url string
if (value->IsString()) {
String::Utf8Value src(value);
if (img->filename) free(img->filename);
img->filename = strdup(*src);
status = img->load();
// Buffer
} else if (Buffer::HasInstance(value)) {
uint8_t *buf = (uint8_t *) Buffer::Data(value->ToObject());
unsigned len = Buffer::Length(value->ToObject());
status = img->loadFromBuffer(buf, len);
}
// check status
if (status) {
img->error(Canvas::Error(status));
} else {
img->loaded();
}
}
/*
* Load image data from `buf` by sniffing
* the bytes to determine format.
*/
cairo_status_t
Image::loadFromBuffer(uint8_t *buf, unsigned len) {
uint8_t data[4] = {0};
memcpy(data, buf, (len < 4 ? len : 4) * sizeof(uint8_t));
if (isPNG(data)) return loadPNGFromBuffer(buf);
#ifdef HAVE_GIF
if (isGIF(data)) return loadGIFFromBuffer(buf, len);
#endif
#ifdef HAVE_JPEG
#if CAIRO_VERSION_MINOR < 10
if (isJPEG(data)) return loadJPEGFromBuffer(buf, len);
#else
if (isJPEG(data)) {
if (DATA_IMAGE == data_mode) return loadJPEGFromBuffer(buf, len);
if (DATA_MIME == data_mode) return decodeJPEGBufferIntoMimeSurface(buf, len);
if ((DATA_IMAGE | DATA_MIME) == data_mode) {
cairo_status_t status;
status = loadJPEGFromBuffer(buf, len);
if (status) return status;
return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
}
}
#endif
#endif
return CAIRO_STATUS_READ_ERROR;
}
/*
* Load PNG data from `buf`.
*/
cairo_status_t
Image::loadPNGFromBuffer(uint8_t *buf) {
read_closure_t closure;
closure.len = 0;
closure.buf = buf;
_surface = cairo_image_surface_create_from_png_stream(readPNG, &closure);
cairo_status_t status = cairo_surface_status(_surface);
if (status) return status;
return CAIRO_STATUS_SUCCESS;
}
/*
* Read PNG data.
*/
cairo_status_t
Image::readPNG(void *c, uint8_t *data, unsigned int len) {
read_closure_t *closure = (read_closure_t *) c;
memcpy(data, closure->buf + closure->len, len);
closure->len += len;
return CAIRO_STATUS_SUCCESS;
}
/*
* Get onload callback.
*/
NAN_GETTER(Image::GetOnload) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onload) {
info.GetReturnValue().Set(img->onload->GetFunction());
} else {
info.GetReturnValue().SetNull();
}
}
/*
* Set onload callback.
*/
NAN_SETTER(Image::SetOnload) {
if (value->IsFunction()) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
img->onload = new Nan::Callback(value.As<Function>());
} else if (value->IsNull()) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onload) {
delete img->onload;
}
img->onload = NULL;
}
}
/*
* Get onerror callback.
*/
NAN_GETTER(Image::GetOnerror) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onerror) {
info.GetReturnValue().Set(img->onerror->GetFunction());
} else {
info.GetReturnValue().SetNull();
}
}
/*
* Set onerror callback.
*/
NAN_SETTER(Image::SetOnerror) {
if (value->IsFunction()) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
img->onerror = new Nan::Callback(value.As<Function>());
} else if (value->IsNull()) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onerror) {
delete img->onerror;
}
img->onerror = NULL;
}
}
/*
* Initialize a new Image.
*/
Image::Image() {
filename = NULL;
_data = NULL;
_data_len = 0;
_surface = NULL;
width = height = 0;
state = DEFAULT;
onload = NULL;
onerror = NULL;
}
/*
* Destroy image and associated surface.
*/
Image::~Image() {
clearData();
if (onerror) {
delete onerror;
onerror = NULL;
}
if (onload) {
delete onload;
onload = NULL;
}
}
/*
* Initiate image loading.
*/
cairo_status_t
Image::load() {
if (LOADING != state) {
state = LOADING;
return loadSurface();
}
return CAIRO_STATUS_READ_ERROR;
}
/*
* Invoke onload (when assigned) and assign dimensions.
*/
void
Image::loaded() {
Nan::HandleScope scope;
state = COMPLETE;
width = cairo_image_surface_get_width(_surface);
height = cairo_image_surface_get_height(_surface);
_data_len = height * cairo_image_surface_get_stride(_surface);
Nan::AdjustExternalMemory(_data_len);
if (onload != NULL) {
onload->Call(0, NULL);
}
}
/*
* Invoke onerror (when assigned) with the given err.
*/
void
Image::error(Local<Value> err) {
Nan::HandleScope scope;
if (onerror != NULL) {
Local<Value> argv[1] = { err };
onerror->Call(1, argv);
}
}
/*
* Load cairo surface from the image src.
*
* TODO: support more formats
* TODO: use node IO or at least thread pool
*/
cairo_status_t
Image::loadSurface() {
FILE *stream = fopen(filename, "rb");
if (!stream) return CAIRO_STATUS_READ_ERROR;
uint8_t buf[5];
if (1 != fread(&buf, 5, 1, stream)) {
fclose(stream);
return CAIRO_STATUS_READ_ERROR;
}
fseek(stream, 0, SEEK_SET);
// png
if (isPNG(buf)) {
fclose(stream);
return loadPNG();
}
// gif
#ifdef HAVE_GIF
if (isGIF(buf)) return loadGIF(stream);
#endif
// jpeg
#ifdef HAVE_JPEG
if (isJPEG(buf)) return loadJPEG(stream);
#endif
fclose(stream);
return CAIRO_STATUS_READ_ERROR;
}
/*
* Load PNG.
*/
cairo_status_t
Image::loadPNG() {
_surface = cairo_image_surface_create_from_png(filename);
return cairo_surface_status(_surface);
}
// GIF support
#ifdef HAVE_GIF
/*
* Return the alpha color for `gif` at `frame`, or -1.
*/
int
get_gif_transparent_color(GifFileType *gif, int frame) {
ExtensionBlock *ext = gif->SavedImages[frame].ExtensionBlocks;
int len = gif->SavedImages[frame].ExtensionBlockCount;
for (int x = 0; x < len; ++x, ++ext) {
if ((ext->Function == GRAPHICS_EXT_FUNC_CODE) && (ext->Bytes[0] & 1)) {
return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3];
}
}
return -1;
}
/*
* Memory GIF reader callback.
*/
int
read_gif_from_memory(GifFileType *gif, GifByteType *buf, int len) {
gif_data_t *data = (gif_data_t *) gif->UserData;
if ((data->pos + len) > data->len) len = data->len - data->pos;
memcpy(buf, data->pos + data->buf, len);
data->pos += len;
return len;
}
/*
* Load GIF.
*/
cairo_status_t
Image::loadGIF(FILE *stream) {
struct stat s;
int fd = fileno(stream);
// stat
if (fstat(fd, &s) < 0) {
fclose(stream);
return CAIRO_STATUS_READ_ERROR;
}
uint8_t *buf = (uint8_t *) malloc(s.st_size);
if (!buf) {
fclose(stream);
return CAIRO_STATUS_NO_MEMORY;
}
size_t read = fread(buf, s.st_size, 1, stream);
fclose(stream);
cairo_status_t result = CAIRO_STATUS_READ_ERROR;
if (1 == read) result = loadGIFFromBuffer(buf, s.st_size);
free(buf);
return result;
}
/*
* Load give from `buf` and the given `len`.
*/
cairo_status_t
Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) {
int i = 0;
GifFileType* gif;
gif_data_t gifd = { buf, len, 0 };
#if GIFLIB_MAJOR >= 5
int errorcode;
if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory, &errorcode)) == NULL)
return CAIRO_STATUS_READ_ERROR;
#else
if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory)) == NULL)
return CAIRO_STATUS_READ_ERROR;
#endif
if (GIF_OK != DGifSlurp(gif)) {
GIF_CLOSE_FILE(gif);
return CAIRO_STATUS_READ_ERROR;
}
width = gif->SWidth;
height = gif->SHeight;
uint8_t *data = (uint8_t *) malloc(width * height * 4);
if (!data) {
GIF_CLOSE_FILE(gif);
return CAIRO_STATUS_NO_MEMORY;
}
GifImageDesc *img = &gif->SavedImages[i].ImageDesc;
// local colormap takes precedence over global
ColorMapObject *colormap = img->ColorMap
? img->ColorMap
: gif->SColorMap;
int bgColor = 0;
int alphaColor = get_gif_transparent_color(gif, i);
if (gif->SColorMap) bgColor = (uint8_t) gif->SBackGroundColor;
else if(alphaColor >= 0) bgColor = alphaColor;
uint8_t *src_data = (uint8_t*) gif->SavedImages[i].RasterBits;
uint32_t *dst_data = (uint32_t*) data;
if (!gif->Image.Interlace) {
if (width == img->Width && height == img->Height) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
*dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24
| colormap->Colors[*src_data].Red << 16
| colormap->Colors[*src_data].Green << 8
| colormap->Colors[*src_data].Blue;
dst_data++;
src_data++;
}
}
} else {
// Image does not take up whole "screen" so we need to fill-in the background
int bottom = img->Top + img->Height;
int right = img->Left + img->Width;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (y < img->Top || y >= bottom || x < img->Left || x >= right) {
*dst_data = ((bgColor == alphaColor) ? 0 : 255) << 24
| colormap->Colors[bgColor].Red << 16
| colormap->Colors[bgColor].Green << 8
| colormap->Colors[bgColor].Blue;
} else {
*dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24
| colormap->Colors[*src_data].Red << 16
| colormap->Colors[*src_data].Green << 8
| colormap->Colors[*src_data].Blue;
}
dst_data++;
src_data++;
}
}
}
} else {
// Image is interlaced so that it streams nice over 14.4k and 28.8k modems :)
// We first load in 1/8 of the image, followed by another 1/8, followed by
// 1/4 and finally the remaining 1/2.
int ioffs[] = { 0, 4, 2, 1 };
int ijumps[] = { 8, 8, 4, 2 };
uint8_t *src_ptr = src_data;
uint32_t *dst_ptr;
for(int z = 0; z < 4; z++) {
for(int y = ioffs[z]; y < height; y += ijumps[z]) {
dst_ptr = dst_data + width * y;
for(int x = 0; x < width; ++x) {
*dst_ptr = ((*src_ptr == alphaColor) ? 0 : 255) << 24
| (colormap->Colors[*src_ptr].Red) << 16
| (colormap->Colors[*src_ptr].Green) << 8
| (colormap->Colors[*src_ptr].Blue);
dst_ptr++;
src_ptr++;
}
}
}
}
GIF_CLOSE_FILE(gif);
// New image surface
_surface = cairo_image_surface_create_for_data(
data
, CAIRO_FORMAT_ARGB32
, width
, height
, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
cairo_status_t status = cairo_surface_status(_surface);
if (status) {
free(data);
return status;
}
_data = data;
return CAIRO_STATUS_SUCCESS;
}
#endif /* HAVE_GIF */
// JPEG support
#ifdef HAVE_JPEG
// libjpeg 6.2 does not have jpeg_mem_src; define it ourselves here unless
// libjpeg 8 is installed.
#if JPEG_LIB_VERSION < 80
/* Read JPEG image from a memory segment */
static void
init_source(j_decompress_ptr cinfo) {}
static boolean
fill_input_buffer(j_decompress_ptr cinfo) {
ERREXIT(cinfo, JERR_INPUT_EMPTY);
return TRUE;
}
static void
skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
if (num_bytes > 0) {
src->next_input_byte += (size_t) num_bytes;
src->bytes_in_buffer -= (size_t) num_bytes;
}
}
static void term_source (j_decompress_ptr cinfo) {}
static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes) {
struct jpeg_source_mgr* src;
if (cinfo->src == NULL) {
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(struct jpeg_source_mgr));
}
src = (struct jpeg_source_mgr*) cinfo->src;
src->init_source = init_source;
src->fill_input_buffer = fill_input_buffer;
src->skip_input_data = skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
src->bytes_in_buffer = nbytes;
src->next_input_byte = (JOCTET*)buffer;
}
#endif
/*
* Takes an initialised jpeg_decompress_struct and decodes the
* data into _surface.
*/
cairo_status_t
Image::decodeJPEGIntoSurface(jpeg_decompress_struct *args) {
int stride = width * 4;
cairo_status_t status;
uint8_t *data = (uint8_t *) malloc(width * height * 4);
if (!data) {
jpeg_abort_decompress(args);
jpeg_destroy_decompress(args);
return CAIRO_STATUS_NO_MEMORY;
}
uint8_t *src = (uint8_t *) malloc(width * args->output_components);
if (!src) {
free(data);
jpeg_abort_decompress(args);
jpeg_destroy_decompress(args);
return CAIRO_STATUS_NO_MEMORY;
}
for (int y = 0; y < height; ++y) {
jpeg_read_scanlines(args, &src, 1);
uint32_t *row = (uint32_t *)(data + stride * y);
for (int x = 0; x < width; ++x) {
if (args->jpeg_color_space == 1) {
uint32_t *pixel = row + x;
*pixel = 255 << 24
| src[x] << 16
| src[x] << 8
| src[x];
} else {
int bx = 3 * x;
uint32_t *pixel = row + x;
*pixel = 255 << 24
| src[bx + 0] << 16
| src[bx + 1] << 8
| src[bx + 2];
}
}
}
_surface = cairo_image_surface_create_for_data(
data
, CAIRO_FORMAT_ARGB32
, width
, height
, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
jpeg_finish_decompress(args);
jpeg_destroy_decompress(args);
status = cairo_surface_status(_surface);
if (status) {
free(data);
free(src);
return status;
}
free(src);
_data = data;
return CAIRO_STATUS_SUCCESS;
}
#if CAIRO_VERSION_MINOR >= 10
/*
* Takes a jpeg data buffer and assigns it as mime data to a
* dummy surface
*/
cairo_status_t
Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) {
// TODO: remove this duplicate logic
// JPEG setup
struct jpeg_decompress_struct args;
struct jpeg_error_mgr err;
args.err = jpeg_std_error(&err);
jpeg_create_decompress(&args);
jpeg_mem_src(&args, buf, len);
jpeg_read_header(&args, 1);
jpeg_start_decompress(&args);
width = args.output_width;
height = args.output_height;
// Data alloc
// 8 pixels per byte using Alpha Channel format to reduce memory requirement.
int buf_size = height * cairo_format_stride_for_width(CAIRO_FORMAT_A1, width);
uint8_t *data = (uint8_t *) malloc(buf_size);
if (!data) return CAIRO_STATUS_NO_MEMORY;
// New image surface
_surface = cairo_image_surface_create_for_data(
data
, CAIRO_FORMAT_A1
, width
, height
, cairo_format_stride_for_width(CAIRO_FORMAT_A1, width));
// Cleanup
jpeg_abort_decompress(&args);
jpeg_destroy_decompress(&args);
cairo_status_t status = cairo_surface_status(_surface);
if (status) {
free(data);
return status;
}
_data = data;
return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
}
/*
* Helper function for disposing of a mime data closure.
*/
void
clearMimeData(void *closure) {
Nan::AdjustExternalMemory(-((read_closure_t *)closure)->len);
free(((read_closure_t *) closure)->buf);
free(closure);
}
/*
* Assign a given buffer as mime data against the surface.
* The provided buffer will be copied, and the copy will
* be automatically freed when the surface is destroyed.
*/
cairo_status_t
Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) {
uint8_t *mime_data = (uint8_t *) malloc(len);
if (!mime_data) return CAIRO_STATUS_NO_MEMORY;
read_closure_t *mime_closure = (read_closure_t *) malloc(sizeof(read_closure_t));
if (!mime_closure) {
free(mime_data);
return CAIRO_STATUS_NO_MEMORY;
}
memcpy(mime_data, data, len);
mime_closure->buf = mime_data;
mime_closure->len = len;
Nan::AdjustExternalMemory(len);
return cairo_surface_set_mime_data(_surface
, mime_type
, mime_data
, len
, clearMimeData
, mime_closure);
}
#endif
/*
* Load jpeg from buffer.
*/
cairo_status_t
Image::loadJPEGFromBuffer(uint8_t *buf, unsigned len) {
// TODO: remove this duplicate logic
// JPEG setup
struct jpeg_decompress_struct args;
struct jpeg_error_mgr err;
args.err = jpeg_std_error(&err);
jpeg_create_decompress(&args);
jpeg_mem_src(&args, buf, len);
jpeg_read_header(&args, 1);
jpeg_start_decompress(&args);
width = args.output_width;
height = args.output_height;
return decodeJPEGIntoSurface(&args);
}
/*
* Load JPEG, convert RGB to ARGB.
*/
cairo_status_t
Image::loadJPEG(FILE *stream) {
cairo_status_t status;
if (data_mode == DATA_IMAGE) { // Can lazily read in the JPEG.
// JPEG setup
struct jpeg_decompress_struct args;
struct jpeg_error_mgr err;
args.err = jpeg_std_error(&err);
jpeg_create_decompress(&args);
jpeg_stdio_src(&args, stream);
jpeg_read_header(&args, 1);
jpeg_start_decompress(&args);
width = args.output_width;
height = args.output_height;
status = decodeJPEGIntoSurface(&args);
fclose(stream);
} else { // We'll need the actual source jpeg data, so read fully.
#if CAIRO_VERSION_MINOR >= 10
uint8_t *buf;
unsigned len;
fseek(stream, 0, SEEK_END);
len = ftell(stream);
fseek(stream, 0, SEEK_SET);
buf = (uint8_t *) malloc(len);
if (!buf) return CAIRO_STATUS_NO_MEMORY;
if (fread(buf, len, 1, stream) != 1) {
status = CAIRO_STATUS_READ_ERROR;
} else if ((DATA_IMAGE | DATA_MIME) == data_mode) {
status = loadJPEGFromBuffer(buf, len);
if (!status) status = assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
} else if (DATA_MIME == data_mode) {
status = decodeJPEGBufferIntoMimeSurface(buf, len);
} else {
status = CAIRO_STATUS_READ_ERROR;
}
fclose(stream);
free(buf);
#else
status = CAIRO_STATUS_READ_ERROR;
#endif
}
return status;
}
#endif /* HAVE_JPEG */
/*
* Return UNKNOWN, JPEG, or PNG based on the filename.
*/
Image::type
Image::extension(const char *filename) {
size_t len = strlen(filename);
filename += len;
if (len >= 5 && 0 == strcmp(".jpeg", filename - 5)) return Image::JPEG;
if (len >= 4 && 0 == strcmp(".gif", filename - 4)) return Image::GIF;
if (len >= 4 && 0 == strcmp(".jpg", filename - 4)) return Image::JPEG;
if (len >= 4 && 0 == strcmp(".png", filename - 4)) return Image::PNG;
return Image::UNKNOWN;
}
/*
* Sniff bytes 0..1 for JPEG's magic number ff d8.
*/
int
Image::isJPEG(uint8_t *data) {
return 0xff == data[0] && 0xd8 == data[1];
}
/*
* Sniff bytes 0..2 for "GIF".
*/
int
Image::isGIF(uint8_t *data) {
return 'G' == data[0] && 'I' == data[1] && 'F' == data[2];
}
/*
* Sniff bytes 1..3 for "PNG".
*/
int
Image::isPNG(uint8_t *data) {
return 'P' == data[1] && 'N' == data[2] && 'G' == data[3];
}
+108
View File
@@ -0,0 +1,108 @@
//
// Image.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_IMAGE_H__
#define __NODE_IMAGE_H__
#include "Canvas.h"
#ifdef HAVE_JPEG
#include <jpeglib.h>
#include <jerror.h>
#endif
#ifdef HAVE_GIF
#include <gif_lib.h>
#if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1
#define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL)
#else
#define GIF_CLOSE_FILE(gif) DGifCloseFile(gif)
#endif
#endif
class Image: public Nan::ObjectWrap {
public:
char *filename;
int width, height;
Nan::Callback *onload;
Nan::Callback *onerror;
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_GETTER(GetSource);
static NAN_GETTER(GetOnload);
static NAN_GETTER(GetOnerror);
static NAN_GETTER(GetComplete);
static NAN_GETTER(GetWidth);
static NAN_GETTER(GetHeight);
static NAN_GETTER(GetDataMode);
static NAN_SETTER(SetSource);
static NAN_SETTER(SetOnload);
static NAN_SETTER(SetOnerror);
static NAN_SETTER(SetDataMode);
inline cairo_surface_t *surface(){ return _surface; }
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
static int isPNG(uint8_t *data);
static int isJPEG(uint8_t *data);
static int isGIF(uint8_t *data);
static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len);
inline int isComplete(){ return COMPLETE == state; }
cairo_status_t loadSurface();
cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len);
cairo_status_t loadPNGFromBuffer(uint8_t *buf);
cairo_status_t loadPNG();
void clearData();
#ifdef HAVE_GIF
cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len);
cairo_status_t loadGIF(FILE *stream);
#endif
#ifdef HAVE_JPEG
cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len);
cairo_status_t loadJPEG(FILE *stream);
cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info);
#if CAIRO_VERSION_MINOR >= 10
cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len);
cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type);
#endif
#endif
void error(Local<Value> error);
void loaded();
cairo_status_t load();
Image();
enum {
DEFAULT
, LOADING
, COMPLETE
} state;
enum data_mode_t {
DATA_IMAGE = 1
, DATA_MIME = 2
} data_mode;
typedef enum {
UNKNOWN
, GIF
, JPEG
, PNG
} type;
static type extension(const char *filename);
private:
cairo_surface_t *_surface;
uint8_t *_data;
int _data_len;
~Image();
};
#endif
+135
View File
@@ -0,0 +1,135 @@
//
// ImageData.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "ImageData.h"
Nan::Persistent<FunctionTemplate> ImageData::constructor;
/*
* Initialize ImageData.
*/
void
ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(ImageData::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(Nan::New("ImageData").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction());
}
/*
* Initialize a new ImageData object.
*/
NAN_METHOD(ImageData::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
}
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
Local<v8::Object> clampedArray;
Local<Object> global = Context::GetCurrent()->Global();
#else
Local<Uint8ClampedArray> clampedArray;
#endif
uint32_t width;
uint32_t height;
int length;
if (info[0]->IsUint32() && info[1]->IsUint32()) {
width = info[0]->Uint32Value();
if (width == 0) {
Nan::ThrowRangeError("The source width is zero.");
return;
}
height = info[1]->Uint32Value();
if (height == 0) {
Nan::ThrowRangeError("The source height is zero.");
return;
}
length = width * height * 4;
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
Local<Int32> sizeHandle = Nan::New(length);
Local<Value> caargv[] = { sizeHandle };
clampedArray = global->Get(Nan::New("Uint8ClampedArray").ToLocalChecked()).As<Function>()->NewInstance(1, caargv);
#else
clampedArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), length), 0, length);
#endif
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
} else if (info[0]->ToObject()->GetIndexedPropertiesExternalArrayDataType() == kExternalPixelArray && info[1]->IsUint32()) {
clampedArray = info[0]->ToObject();
length = clampedArray->GetIndexedPropertiesExternalArrayDataLength();
#else
} else if (info[0]->IsUint8ClampedArray() && info[1]->IsUint32()) {
clampedArray = info[0].As<Uint8ClampedArray>();
length = clampedArray->Length();
#endif
if (length == 0) {
Nan::ThrowRangeError("The input data has a zero byte length.");
return;
}
if (length % 4 != 0) {
Nan::ThrowRangeError("The input data byte length is not a multiple of 4.");
return;
}
width = info[1]->Uint32Value();
int size = length / 4;
if (width == 0) {
Nan::ThrowRangeError("The source width is zero.");
return;
}
if (size % width != 0) {
Nan::ThrowRangeError("The input data byte length is not a multiple of (4 * width).");
return;
}
height = size / width;
if (info[2]->IsUint32() && info[2]->Uint32Value() != height) {
Nan::ThrowRangeError("The input data byte length is not equal to (4 * width * height).");
return;
}
} else {
Nan::ThrowTypeError("Expected (Uint8ClampedArray, width[, height]) or (width, height)");
return;
}
Nan::TypedArrayContents<uint8_t> dataPtr(clampedArray);
ImageData *imageData = new ImageData(reinterpret_cast<uint8_t*>(*dataPtr), width, height);
imageData->Wrap(info.This());
info.This()->Set(Nan::New("data").ToLocalChecked(), clampedArray);
info.GetReturnValue().Set(info.This());
}
/*
* Get width.
*/
NAN_GETTER(ImageData::GetWidth) {
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(imageData->width()));
}
/*
* Get height.
*/
NAN_GETTER(ImageData::GetHeight) {
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(imageData->height()));
}
+36
View File
@@ -0,0 +1,36 @@
//
// ImageData.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_IMAGE_DATA_H__
#define __NODE_IMAGE_DATA_H__
#include "Canvas.h"
#include <stdlib.h>
#include "v8.h"
class ImageData: public Nan::ObjectWrap {
public:
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_GETTER(GetWidth);
static NAN_GETTER(GetHeight);
inline int width() { return _width; }
inline int height() { return _height; }
inline uint8_t *data() { return _data; }
inline int stride() { return _width * 4; }
ImageData(uint8_t *data, int width, int height) : _width(width), _height(height), _data(data) {}
private:
int _width;
int _height;
uint8_t *_data;
};
#endif
+146
View File
@@ -0,0 +1,146 @@
//
// JPEGStream.h
//
#ifndef __NODE_JPEG_STREAM_H__
#define __NODE_JPEG_STREAM_H__
#include "Canvas.h"
#include <jpeglib.h>
#include <jerror.h>
/*
* Expanded data destination object for closure output,
* inspired by IJG's jdatadst.c
*/
typedef struct {
struct jpeg_destination_mgr pub;
closure_t *closure;
JOCTET *buffer;
int bufsize;
} closure_destination_mgr;
void
init_closure_destination(j_compress_ptr cinfo){
// we really don't have to do anything here
}
boolean
empty_closure_output_buffer(j_compress_ptr cinfo){
Nan::HandleScope scope;
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize).ToLocalChecked();
// emit "data"
Local<Value> argv[2] = {
Nan::Null()
, buf
};
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, argv);
dest->buffer = (JOCTET *)malloc(dest->bufsize);
cinfo->dest->next_output_byte = dest->buffer;
cinfo->dest->free_in_buffer = dest->bufsize;
return true;
}
void
term_closure_destination(j_compress_ptr cinfo){
Nan::HandleScope scope;
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
/* emit remaining data */
Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize - dest->pub.free_in_buffer).ToLocalChecked();
Local<Value> data_argv[2] = {
Nan::Null()
, buf
};
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, data_argv);
// emit "end"
Local<Value> end_argv[2] = {
Nan::Null()
, Nan::Null()
};
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, end_argv);
}
void
jpeg_closure_dest(j_compress_ptr cinfo, closure_t * closure, int bufsize){
closure_destination_mgr * dest;
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same buffer without re-executing jpeg_mem_dest.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(closure_destination_mgr));
}
dest = (closure_destination_mgr *) cinfo->dest;
cinfo->dest->init_destination = &init_closure_destination;
cinfo->dest->empty_output_buffer = &empty_closure_output_buffer;
cinfo->dest->term_destination = &term_closure_destination;
dest->closure = closure;
dest->bufsize = bufsize;
dest->buffer = (JOCTET *)malloc(bufsize);
cinfo->dest->next_output_byte = dest->buffer;
cinfo->dest->free_in_buffer = dest->bufsize;
}
void
write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, int quality, bool progressive, closure_t *closure){
int w = cairo_image_surface_get_width(surface);
int h = cairo_image_surface_get_height(surface);
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW slr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
cinfo.in_color_space = JCS_RGB;
cinfo.input_components = 3;
cinfo.image_width = w;
cinfo.image_height = h;
jpeg_set_defaults(&cinfo);
if (progressive)
jpeg_simple_progression(&cinfo);
jpeg_set_quality(&cinfo, quality, (quality<25)?0:1);
jpeg_closure_dest(&cinfo, closure, bufsize);
jpeg_start_compress(&cinfo, TRUE);
unsigned char *dst;
unsigned int *src = (unsigned int *) cairo_image_surface_get_data(surface);
int sl = 0;
dst = (unsigned char *) malloc(w * 3);
while (sl < h) {
unsigned char *dp = dst;
int x = 0;
while (x < w) {
dp[0] = (*src >> 16) & 255;
dp[1] = (*src >> 8) & 255;
dp[2] = *src & 255;
src++;
dp += 3;
x++;
}
slr = dst;
jpeg_write_scanlines(&cinfo, &slr, 1);
sl++;
}
free(dst);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
#endif
+227
View File
@@ -0,0 +1,227 @@
#ifndef _CANVAS_PNG_H
#define _CANVAS_PNG_H
#include <png.h>
#include <pngconf.h>
#include <cairo.h>
#include <stdlib.h>
#include <string.h>
#include "closure.h"
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
#ifndef CAIRO_FORMAT_INVALID
#define CAIRO_FORMAT_INVALID -1
#endif
static void canvas_png_flush(png_structp png_ptr) {
/* Do nothing; fflush() is said to be just a waste of energy. */
(void) png_ptr; /* Stifle compiler warning */
}
/* Converts native endian xRGB => RGBx bytes */
static void canvas_convert_data_to_bytes(png_structp png, png_row_infop row_info, png_bytep data) {
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *b = &data[i];
uint32_t pixel;
memcpy(&pixel, b, sizeof (uint32_t));
b[0] = (pixel & 0xff0000) >> 16;
b[1] = (pixel & 0x00ff00) >> 8;
b[2] = (pixel & 0x0000ff) >> 0;
b[3] = 0;
}
}
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) {
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *b = &data[i];
uint32_t pixel;
uint8_t alpha;
memcpy(&pixel, b, sizeof (uint32_t));
alpha = (pixel & 0xff000000) >> 24;
if (alpha == 0) {
b[0] = b[1] = b[2] = b[3] = 0;
} else {
b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
}
struct canvas_png_write_closure_t {
cairo_write_func_t write_func;
void *closure;
};
static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) {
unsigned int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
uint8_t *data;
png_structp png;
png_infop info;
png_bytep *volatile rows = NULL;
png_color_16 white;
int png_color_type;
int bpc;
unsigned int width = cairo_image_surface_get_width(surface);
unsigned int height = cairo_image_surface_get_height(surface);
data = cairo_image_surface_get_data(surface);
if (data == NULL) {
status = CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
return status;
}
cairo_surface_flush(surface);
if (width == 0 || height == 0) {
status = CAIRO_STATUS_WRITE_ERROR;
return status;
}
rows = (png_bytep *) malloc(height * sizeof (png_byte*));
if (unlikely(rows == NULL)) {
status = CAIRO_STATUS_NO_MEMORY;
return status;
}
for (i = 0; i < height; i++) {
rows[i] = (png_byte *) data + i * cairo_image_surface_get_stride(surface);
}
#ifdef PNG_USER_MEM_SUPPORTED
png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL);
#else
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
if (unlikely(png == NULL)) {
status = CAIRO_STATUS_NO_MEMORY;
free(rows);
return status;
}
info = png_create_info_struct (png);
if (unlikely(info == NULL)) {
status = CAIRO_STATUS_NO_MEMORY;
png_destroy_write_struct(&png, &info);
free(rows);
return status;
}
#ifdef PNG_SETJMP_SUPPORTED
if (setjmp (png_jmpbuf (png))) {
png_destroy_write_struct(&png, &info);
free(rows);
return status;
}
#endif
png_set_write_fn(png, closure, write_func, canvas_png_flush);
png_set_compression_level(png, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->compression_level);
png_set_filter(png, 0, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->filter);
switch (cairo_image_surface_get_format(surface)) {
case CAIRO_FORMAT_ARGB32:
bpc = 8;
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
#ifdef CAIRO_FORMAT_RGB30
case CAIRO_FORMAT_RGB30:
bpc = 10;
png_color_type = PNG_COLOR_TYPE_RGB;
break;
#endif
case CAIRO_FORMAT_RGB24:
bpc = 8;
png_color_type = PNG_COLOR_TYPE_RGB;
break;
case CAIRO_FORMAT_A8:
bpc = 8;
png_color_type = PNG_COLOR_TYPE_GRAY;
break;
case CAIRO_FORMAT_A1:
bpc = 1;
png_color_type = PNG_COLOR_TYPE_GRAY;
#ifndef WORDS_BIGENDIAN
png_set_packswap(png);
#endif
break;
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_RGB16_565:
default:
status = CAIRO_STATUS_INVALID_FORMAT;
png_destroy_write_struct(&png, &info);
free(rows);
return status;
}
png_set_IHDR(png, info, width, height, bpc, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
white.gray = (1 << bpc) - 1;
white.red = white.blue = white.green = white.gray;
png_set_bKGD(png, info, &white);
/* We have to call png_write_info() before setting up the write
* transformation, since it stores data internally in 'png'
* that is needed for the write transformation functions to work.
*/
png_write_info(png, info);
if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
png_set_write_user_transform_fn(png, canvas_unpremultiply_data);
} else if (png_color_type == PNG_COLOR_TYPE_RGB) {
png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes);
png_set_filler(png, 0, PNG_FILLER_AFTER);
}
png_write_image(png, rows);
png_write_end(png, info);
png_destroy_write_struct(&png, &info);
free(rows);
return status;
}
static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) {
cairo_status_t status;
struct canvas_png_write_closure_t *png_closure;
png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png);
status = png_closure->write_func(png_closure->closure, data, size);
if (unlikely(status)) {
cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png);
if (*error == CAIRO_STATUS_SUCCESS) {
*error = status;
}
png_error(png, NULL);
}
}
static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) {
struct canvas_png_write_closure_t png_closure;
if (cairo_surface_status(surface)) {
return cairo_surface_status(surface);
}
png_closure.write_func = write_func;
png_closure.closure = closure;
return canvas_write_png(surface, canvas_stream_write_func, &png_closure);
}
#endif
+19
View File
@@ -0,0 +1,19 @@
//
// Point.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_POINT_H__
#define __NODE_POINT_H__
template <class T>
class Point {
public:
T x, y;
Point(T x, T y): x(x), y(y) {}
};
#endif /* __NODE_POINT_H__ */
+65
View File
@@ -0,0 +1,65 @@
//
// closure.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __NODE_CLOSURE_H__
#define __NODE_CLOSURE_H__
#ifdef __unix__
#include<sys/user.h>
#endif
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#include <nan.h>
/*
* PNG stream closure.
*/
typedef struct {
Nan::Callback *pfn;
Local<Function> fn;
unsigned len;
unsigned max_len;
uint8_t *data;
Canvas *canvas;
cairo_status_t status;
uint32_t compression_level;
uint32_t filter;
} closure_t;
/*
* Initialize the given closure.
*/
cairo_status_t
closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level, unsigned int filter) {
closure->len = 0;
closure->canvas = canvas;
closure->data = (uint8_t *) malloc(closure->max_len = PAGE_SIZE);
if (!closure->data) return CAIRO_STATUS_NO_MEMORY;
closure->compression_level = compression_level;
closure->filter = filter;
return CAIRO_STATUS_SUCCESS;
}
/*
* Free the given closure's data,
* and hint V8 at the memory dealloc.
*/
void
closure_destroy(closure_t *closure) {
if (closure->len) {
free(closure->data);
Nan::AdjustExternalMemory(-((intptr_t) closure->max_len));
}
}
#endif /* __NODE_CLOSURE_H__ */
+744
View File
@@ -0,0 +1,744 @@
//
// color.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include "color.h"
#include <stdlib.h>
#include <cmath>
#include <limits>
// Compatibility with Visual Studio versions prior to VS2015
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
/*
* Parse integer value
*/
template <typename parsed_t>
static bool
parse_integer(const char** pStr, parsed_t *pParsed) {
parsed_t& c = *pParsed;
const char*& str = *pStr;
int8_t sign=1;
c = 0;
if (*str == '-') {
sign=-1;
++str;
}
else if (*str == '+')
++str;
if (*str >= '0' && *str <= '9') {
do {
c *= 10;
c += *str++ - '0';
} while (*str >= '0' && *str <= '9');
} else {
return false;
}
if (sign<0)
c=-c;
return true;
}
/*
* Parse CSS <number> value
* Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html
*/
template <typename parsed_t>
static bool
parse_css_number(const char** pStr, parsed_t *pParsed) {
parsed_t &parsed = *pParsed;
const char*& str = *pStr;
const char* startStr = str;
if (!str || !*str)
return false;
parsed_t integerPart = 0;
parsed_t fractionPart = 0;
int divisorForFraction = 1;
int sign = 1;
int exponent = 0;
int digits = 0;
bool inFraction = false;
if (*str == '-') {
++str;
sign = -1;
}
else if (*str == '+')
++str;
while (*str != '\0') {
if (*str >= '0' && *str <= '9') {
if (digits>=std::numeric_limits<parsed_t>::digits10) {
if (!inFraction)
return false;
}
else {
++digits;
if (inFraction) {
fractionPart = fractionPart*10 + (*str - '0');
divisorForFraction *= 10;
}
else {
integerPart = integerPart*10 + (*str - '0');
}
}
}
else if (*str == '.') {
if (inFraction)
break;
else
inFraction = true;
}
else if (*str == 'e') {
++str;
if (!parse_integer(&str, &exponent))
return false;
break;
}
else
break;
++str;
}
if (str != startStr) {
parsed = sign * (integerPart + fractionPart/divisorForFraction);
for (;exponent>0;--exponent)
parsed *= 10;
for (;exponent<0;++exponent)
parsed /= 10;
return true;
}
return false;
}
/*
* Clip value to the range [minValue, maxValue]
*/
template <typename T>
static T
clip(T value, T minValue, T maxValue) {
if (value > maxValue)
value = maxValue;
if (value < minValue)
value = minValue;
return value;
}
/*
* Wrap value to the range [0, limit]
*/
template <typename T>
static T
wrap_float(T value, T limit) {
return fmod(fmod(value, limit) + limit, limit);
}
/*
* Wrap value to the range [0, limit] - currently-unused integer version of wrap_float
*/
// template <typename T>
// static T wrap_int(T value, T limit) {
// return (value % limit + limit) % limit;
// }
/*
* Parse color channel value
*/
static bool
parse_rgb_channel(const char** pStr, uint8_t *pChannel) {
int channel;
if (parse_integer(pStr, &channel)) {
*pChannel = clip(channel, 0, 255);
return true;
}
return false;
}
/*
* Parse a value in degrees
*/
static bool
parse_degrees(const char** pStr, float *pDegrees) {
float degrees;
if (parse_css_number(pStr, &degrees)) {
*pDegrees = wrap_float(degrees, 360.0f);
return true;
}
return false;
}
/*
* Parse and clip a percentage value. Returns a float in the range [0, 1].
*/
static bool
parse_clipped_percentage(const char** pStr, float *pFraction) {
float percentage;
bool result = parse_css_number(pStr,&percentage);
const char*& str = *pStr;
if (result) {
if (*str == '%') {
++str;
*pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
return result;
}
}
return false;
}
/*
* Macros to help with parsing inside rgba_from_*_string
*/
#define WHITESPACE \
while (' ' == *str) ++str;
#define WHITESPACE_OR_COMMA \
while (' ' == *str || ',' == *str) ++str;
#define CHANNEL(NAME) \
if (!parse_rgb_channel(&str, &NAME)) \
return 0; \
#define HUE(NAME) \
if (!parse_degrees(&str, &NAME)) \
return 0;
#define SATURATION(NAME) \
if (!parse_clipped_percentage(&str, &NAME)) \
return 0;
#define LIGHTNESS(NAME) SATURATION(NAME)
#define ALPHA(NAME) \
if (*str >= '1' && *str <= '9') { \
NAME = 1; \
} else { \
if ('0' == *str) ++str; \
if ('.' == *str) { \
++str; \
float n = .1f; \
while (*str >= '0' && *str <= '9') { \
NAME += (*str++ - '0') * n; \
n *= .1f; \
} \
} \
} \
do {} while (0) // require trailing semicolon
/*
* Named colors.
*/
static struct named_color {
const char *name;
uint32_t val;
} named_colors[] = {
{ "transparent", 0xFFFFFF00}
, { "aliceblue", 0xF0F8FFFF }
, { "antiquewhite", 0xFAEBD7FF }
, { "aqua", 0x00FFFFFF }
, { "aquamarine", 0x7FFFD4FF }
, { "azure", 0xF0FFFFFF }
, { "beige", 0xF5F5DCFF }
, { "bisque", 0xFFE4C4FF }
, { "black", 0x000000FF }
, { "blanchedalmond", 0xFFEBCDFF }
, { "blue", 0x0000FFFF }
, { "blueviolet", 0x8A2BE2FF }
, { "brown", 0xA52A2AFF }
, { "burlywood", 0xDEB887FF }
, { "cadetblue", 0x5F9EA0FF }
, { "chartreuse", 0x7FFF00FF }
, { "chocolate", 0xD2691EFF }
, { "coral", 0xFF7F50FF }
, { "cornflowerblue", 0x6495EDFF }
, { "cornsilk", 0xFFF8DCFF }
, { "crimson", 0xDC143CFF }
, { "cyan", 0x00FFFFFF }
, { "darkblue", 0x00008BFF }
, { "darkcyan", 0x008B8BFF }
, { "darkgoldenrod", 0xB8860BFF }
, { "darkgray", 0xA9A9A9FF }
, { "darkgreen", 0x006400FF }
, { "darkgrey", 0xA9A9A9FF }
, { "darkkhaki", 0xBDB76BFF }
, { "darkmagenta", 0x8B008BFF }
, { "darkolivegreen", 0x556B2FFF }
, { "darkorange", 0xFF8C00FF }
, { "darkorchid", 0x9932CCFF }
, { "darkred", 0x8B0000FF }
, { "darksalmon", 0xE9967AFF }
, { "darkseagreen", 0x8FBC8FFF }
, { "darkslateblue", 0x483D8BFF }
, { "darkslategray", 0x2F4F4FFF }
, { "darkslategrey", 0x2F4F4FFF }
, { "darkturquoise", 0x00CED1FF }
, { "darkviolet", 0x9400D3FF }
, { "deeppink", 0xFF1493FF }
, { "deepskyblue", 0x00BFFFFF }
, { "dimgray", 0x696969FF }
, { "dimgrey", 0x696969FF }
, { "dodgerblue", 0x1E90FFFF }
, { "firebrick", 0xB22222FF }
, { "floralwhite", 0xFFFAF0FF }
, { "forestgreen", 0x228B22FF }
, { "fuchsia", 0xFF00FFFF }
, { "gainsboro", 0xDCDCDCFF }
, { "ghostwhite", 0xF8F8FFFF }
, { "gold", 0xFFD700FF }
, { "goldenrod", 0xDAA520FF }
, { "gray", 0x808080FF }
, { "green", 0x008000FF }
, { "greenyellow", 0xADFF2FFF }
, { "grey", 0x808080FF }
, { "honeydew", 0xF0FFF0FF }
, { "hotpink", 0xFF69B4FF }
, { "indianred", 0xCD5C5CFF }
, { "indigo", 0x4B0082FF }
, { "ivory", 0xFFFFF0FF }
, { "khaki", 0xF0E68CFF }
, { "lavender", 0xE6E6FAFF }
, { "lavenderblush", 0xFFF0F5FF }
, { "lawngreen", 0x7CFC00FF }
, { "lemonchiffon", 0xFFFACDFF }
, { "lightblue", 0xADD8E6FF }
, { "lightcoral", 0xF08080FF }
, { "lightcyan", 0xE0FFFFFF }
, { "lightgoldenrodyellow", 0xFAFAD2FF }
, { "lightgray", 0xD3D3D3FF }
, { "lightgreen", 0x90EE90FF }
, { "lightgrey", 0xD3D3D3FF }
, { "lightpink", 0xFFB6C1FF }
, { "lightsalmon", 0xFFA07AFF }
, { "lightseagreen", 0x20B2AAFF }
, { "lightskyblue", 0x87CEFAFF }
, { "lightslategray", 0x778899FF }
, { "lightslategrey", 0x778899FF }
, { "lightsteelblue", 0xB0C4DEFF }
, { "lightyellow", 0xFFFFE0FF }
, { "lime", 0x00FF00FF }
, { "limegreen", 0x32CD32FF }
, { "linen", 0xFAF0E6FF }
, { "magenta", 0xFF00FFFF }
, { "maroon", 0x800000FF }
, { "mediumaquamarine", 0x66CDAAFF }
, { "mediumblue", 0x0000CDFF }
, { "mediumorchid", 0xBA55D3FF }
, { "mediumpurple", 0x9370DBFF }
, { "mediumseagreen", 0x3CB371FF }
, { "mediumslateblue", 0x7B68EEFF }
, { "mediumspringgreen", 0x00FA9AFF }
, { "mediumturquoise", 0x48D1CCFF }
, { "mediumvioletred", 0xC71585FF }
, { "midnightblue", 0x191970FF }
, { "mintcream", 0xF5FFFAFF }
, { "mistyrose", 0xFFE4E1FF }
, { "moccasin", 0xFFE4B5FF }
, { "navajowhite", 0xFFDEADFF }
, { "navy", 0x000080FF }
, { "oldlace", 0xFDF5E6FF }
, { "olive", 0x808000FF }
, { "olivedrab", 0x6B8E23FF }
, { "orange", 0xFFA500FF }
, { "orangered", 0xFF4500FF }
, { "orchid", 0xDA70D6FF }
, { "palegoldenrod", 0xEEE8AAFF }
, { "palegreen", 0x98FB98FF }
, { "paleturquoise", 0xAFEEEEFF }
, { "palevioletred", 0xDB7093FF }
, { "papayawhip", 0xFFEFD5FF }
, { "peachpuff", 0xFFDAB9FF }
, { "peru", 0xCD853FFF }
, { "pink", 0xFFC0CBFF }
, { "plum", 0xDDA0DDFF }
, { "powderblue", 0xB0E0E6FF }
, { "purple", 0x800080FF }
, { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft
, { "red", 0xFF0000FF }
, { "rosybrown", 0xBC8F8FFF }
, { "royalblue", 0x4169E1FF }
, { "saddlebrown", 0x8B4513FF }
, { "salmon", 0xFA8072FF }
, { "sandybrown", 0xF4A460FF }
, { "seagreen", 0x2E8B57FF }
, { "seashell", 0xFFF5EEFF }
, { "sienna", 0xA0522DFF }
, { "silver", 0xC0C0C0FF }
, { "skyblue", 0x87CEEBFF }
, { "slateblue", 0x6A5ACDFF }
, { "slategray", 0x708090FF }
, { "slategrey", 0x708090FF }
, { "snow", 0xFFFAFAFF }
, { "springgreen", 0x00FF7FFF }
, { "steelblue", 0x4682B4FF }
, { "tan", 0xD2B48CFF }
, { "teal", 0x008080FF }
, { "thistle", 0xD8BFD8FF }
, { "tomato", 0xFF6347FF }
, { "turquoise", 0x40E0D0FF }
, { "violet", 0xEE82EEFF }
, { "wheat", 0xF5DEB3FF }
, { "white", 0xFFFFFFFF }
, { "whitesmoke", 0xF5F5F5FF }
, { "yellow", 0xFFFF00FF }
, { "yellowgreen", 0x9ACD32FF }
, { NULL, 0 }
};
/*
* Hex digit int val.
*/
static int
h(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return c - '0';
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return (c - 'a') + 10;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
return (c - 'A') + 10;
}
return 0;
}
/*
* Return rgba_t from rgba.
*/
rgba_t
rgba_create(uint32_t rgba) {
rgba_t color;
color.r = (double) (rgba >> 24) / 255;
color.g = (double) (rgba >> 16 & 0xff) / 255;
color.b = (double) (rgba >> 8 & 0xff) / 255;
color.a = (double) (rgba & 0xff) / 255;
return color;
}
/*
* Return a string representation of the color.
*/
void
rgba_to_string(rgba_t rgba, char *buf, size_t len) {
if (1 == rgba.a) {
snprintf(buf, len, "#%.2x%.2x%.2x"
, (int) (rgba.r * 255)
, (int) (rgba.g * 255)
, (int) (rgba.b * 255));
} else {
snprintf(buf, len, "rgba(%d, %d, %d, %.2f)"
, (int) (rgba.r * 255)
, (int) (rgba.g * 255)
, (int) (rgba.b * 255)
, rgba.a);
}
}
/*
* Return rgba from (r,g,b,a).
*/
static inline int32_t
rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return
r << 24
| g << 16
| b << 8
| a;
}
/*
* Helper function used in rgba_from_hsla().
* Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
*/
static float
hue_to_rgb(float t1, float t2, float hue) {
if (hue < 0)
hue += 6;
if (hue >= 6)
hue -= 6;
if (hue < 1)
return (t2 - t1) * hue + t1;
else if (hue < 3)
return t2;
else if (hue < 4)
return (t2 - t1) * (4 - hue) + t1;
else
return t1;
}
/*
* Return rgba from (h,s,l,a).
* Expects h values in the range [0, 360), and s, l, a in the range [0, 1].
* Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
*/
static inline int32_t
rgba_from_hsla(float h_deg, float s, float l, float a) {
uint8_t r, g, b;
float h = (6 * h_deg) / 360.0f, m1, m2;
if (l<=0.5)
m2=l*(s+1);
else
m2=l+s-l*s;
m1 = l*2 - m2;
// Scale and round the RGB components
r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5);
g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5);
b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5);
return rgba_from_rgba(r, g, b, (uint8_t) (a * 255));
}
/*
* Return rgba from (h,s,l).
* Expects h values in the range [0, 360), and s, l in the range [0, 1].
*/
static inline int32_t
rgba_from_hsl(float h_deg, float s, float l) {
return rgba_from_hsla(h_deg, s, l, 1.0);
}
/*
* Return rgba from (r,g,b).
*/
static int32_t
rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) {
return rgba_from_rgba(r, g, b, 255);
}
/*
* Return rgb from "#RRGGBB".
*/
static int32_t
rgba_from_hex6_string(const char *str) {
return rgba_from_rgb(
(h(str[0]) << 4) + h(str[1])
, (h(str[2]) << 4) + h(str[3])
, (h(str[4]) << 4) + h(str[5])
);
}
/*
* Return rgb from "#RGB"
*/
static int32_t
rgba_from_hex3_string(const char *str) {
return rgba_from_rgb(
(h(str[0]) << 4) + h(str[0])
, (h(str[1]) << 4) + h(str[1])
, (h(str[2]) << 4) + h(str[2])
);
}
/*
* Return rgb from "rgb()"
*/
static int32_t
rgba_from_rgb_string(const char *str, short *ok) {
if (str == strstr(str, "rgb(")) {
str += 4;
WHITESPACE;
uint8_t r = 0, g = 0, b = 0;
CHANNEL(r);
WHITESPACE_OR_COMMA;
CHANNEL(g);
WHITESPACE_OR_COMMA;
CHANNEL(b);
WHITESPACE;
return *ok = 1, rgba_from_rgb(r, g, b);
}
return *ok = 0;
}
/*
* Return rgb from "rgba()"
*/
static int32_t
rgba_from_rgba_string(const char *str, short *ok) {
if (str == strstr(str, "rgba(")) {
str += 5;
WHITESPACE;
uint8_t r = 0, g = 0, b = 0;
float a = 0;
CHANNEL(r);
WHITESPACE_OR_COMMA;
CHANNEL(g);
WHITESPACE_OR_COMMA;
CHANNEL(b);
WHITESPACE_OR_COMMA;
ALPHA(a);
WHITESPACE;
return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255));
}
return *ok = 0;
}
/*
* Return rgb from "hsla()"
*/
static int32_t
rgba_from_hsla_string(const char *str, short *ok) {
if (str == strstr(str, "hsla(")) {
str += 5;
WHITESPACE;
float h_deg = 0;
float s = 0, l = 0;
float a = 0;
HUE(h_deg);
WHITESPACE_OR_COMMA;
SATURATION(s);
WHITESPACE_OR_COMMA;
LIGHTNESS(l);
WHITESPACE_OR_COMMA;
ALPHA(a);
WHITESPACE;
return *ok = 1, rgba_from_hsla(h_deg, s, l, a);
}
return *ok = 0;
}
/*
* Return rgb from "hsl()"
*/
static int32_t
rgba_from_hsl_string(const char *str, short *ok) {
if (str == strstr(str, "hsl(")) {
str += 4;
WHITESPACE;
float h_deg = 0;
float s = 0, l = 0;
HUE(h_deg);
WHITESPACE_OR_COMMA;
SATURATION(s);
WHITESPACE_OR_COMMA;
LIGHTNESS(l);
WHITESPACE;
return *ok = 1, rgba_from_hsl(h_deg, s, l);
}
return *ok = 0;
}
/*
* Return rgb from:
*
* - "#RGB"
* - "#RRGGBB"
*
*/
static int32_t
rgba_from_hex_string(const char *str, short *ok) {
size_t len = strlen(str);
*ok = 1;
if (6 == len) return rgba_from_hex6_string(str);
if (3 == len) return rgba_from_hex3_string(str);
return *ok = 0;
}
/*
* Return named color value.
*/
static int32_t
rgba_from_name_string(const char *str, short *ok) {
int i = 0;
struct named_color color;
while ((color = named_colors[i++]).name) {
if (*str == *color.name && 0 == strcmp(str, color.name))
return *ok = 1, color.val;
}
return *ok = 0;
}
/*
* Return rgb from:
*
* - #RGB
* - #RRGGBB
* - rgb(r,g,b)
* - rgba(r,g,b,a)
* - hsl(h,s,l)
* - hsla(h,s,l,a)
* - name
*
*/
int32_t
rgba_from_string(const char *str, short *ok) {
if ('#' == str[0])
return rgba_from_hex_string(++str, ok);
if (str == strstr(str, "rgba"))
return rgba_from_rgba_string(str, ok);
if (str == strstr(str, "rgb"))
return rgba_from_rgb_string(str, ok);
if (str == strstr(str, "hsla"))
return rgba_from_hsla_string(str, ok);
if (str == strstr(str, "hsl"))
return rgba_from_hsl_string(str, ok);
return rgba_from_name_string(str, ok);
}
/*
* Inspect the given rgba color.
*/
void
rgba_inspect(int32_t rgba) {
printf("rgba(%d,%d,%d,%d)\n"
, rgba >> 24 & 0xff
, rgba >> 16 & 0xff
, rgba >> 8 & 0xff
, rgba & 0xff
);
}
+40
View File
@@ -0,0 +1,40 @@
//
// color.h
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#ifndef __COLOR_PARSER_H__
#define __COLOR_PARSER_H__
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stddef.h>
/*
* RGBA struct.
*/
typedef struct {
double r, g, b, a;
} rgba_t;
/*
* Prototypes.
*/
rgba_t
rgba_create(uint32_t rgba);
int32_t
rgba_from_string(const char *str, short *ok);
void
rgba_to_string(rgba_t rgba, char *buf, size_t len);
void
rgba_inspect(int32_t rgba);
#endif /* __COLOR_PARSER_H__ */
+82
View File
@@ -0,0 +1,82 @@
//
// init.cc
//
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
//
#include <stdio.h>
#include "Canvas.h"
#include "Image.h"
#include "ImageData.h"
#include "CanvasGradient.h"
#include "CanvasPattern.h"
#include "CanvasRenderingContext2d.h"
#ifdef HAVE_FREETYPE
#include "FontFace.h"
#include FT_FREETYPE_H
#endif
// Compatibility with Visual Studio versions prior to VS2015
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
NAN_MODULE_INIT(init) {
Canvas::Initialize(target);
Image::Initialize(target);
ImageData::Initialize(target);
Context2d::Initialize(target);
Gradient::Initialize(target);
Pattern::Initialize(target);
#ifdef HAVE_FREETYPE
FontFace::Initialize(target);
#endif
target->Set(Nan::New<String>("cairoVersion").ToLocalChecked(), Nan::New<String>(cairo_version_string()).ToLocalChecked());
#ifdef HAVE_JPEG
#ifndef JPEG_LIB_VERSION_MAJOR
#ifdef JPEG_LIB_VERSION
#define JPEG_LIB_VERSION_MAJOR (JPEG_LIB_VERSION / 10)
#else
#define JPEG_LIB_VERSION_MAJOR 0
#endif
#endif
#ifndef JPEG_LIB_VERSION_MINOR
#ifdef JPEG_LIB_VERSION
#define JPEG_LIB_VERSION_MINOR (JPEG_LIB_VERSION % 10)
#else
#define JPEG_LIB_VERSION_MINOR 0
#endif
#endif
char jpeg_version[10];
if (JPEG_LIB_VERSION_MINOR > 0) {
snprintf(jpeg_version, 10, "%d%c", JPEG_LIB_VERSION_MAJOR, JPEG_LIB_VERSION_MINOR + 'a' - 1);
} else {
snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR);
}
target->Set(Nan::New<String>("jpegVersion").ToLocalChecked(), Nan::New<String>(jpeg_version).ToLocalChecked());
#endif
#ifdef HAVE_GIF
#ifndef GIF_LIB_VERSION
char gif_version[10];
snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE);
target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(gif_version).ToLocalChecked());
#else
target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(GIF_LIB_VERSION).ToLocalChecked());
#endif
#endif
#ifdef HAVE_FREETYPE
char freetype_version[10];
snprintf(freetype_version, 10, "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
target->Set(Nan::New<String>("freetypeVersion").ToLocalChecked(), Nan::New<String>(freetype_version).ToLocalChecked());
#endif
}
NODE_MODULE(canvas,init);
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
has_ldconfig() {
hash ldconfig 2>/dev/null
}
has_system_lib() {
regex="lib$1.+(so|dylib)"
# Add /sbin to path as ldconfig is located there on some systems - e.g. Debian
# (and it still can be used by unprivileged users):
PATH="$PATH:/sbin"
export PATH
# Try using ldconfig on Linux systems
if has_ldconfig; then
for _ in $(ldconfig -p 2>/dev/null | grep -E "$regex"); do
return 0
done
fi
# Try just checking common library locations
for dir in /lib /usr/lib /usr/local/lib /opt/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu; do
test -d "$dir" && echo "$dir"/* | grep -E "$regex" && return 0
done
return 1
}
has_freetype() {
pkg-config cairo --cflags-only-I | grep freetype2
}
has_pkgconfig_lib() {
pkg-config --exists "$1"
}
case "$1" in
gif)
has_system_lib "gif" > /dev/null
result=$?
;;
jpeg)
has_system_lib "jpeg" > /dev/null
result=$?
;;
pango)
has_pkgconfig_lib "pango" > /dev/null
result=$?
;;
freetype)
has_freetype > /dev/null
result=$?
;;
*)
>&2 echo "Unknown library: $1"
exit 1
esac
if test $result -eq 0; then
echo "true"
else
echo "false"
fi