Initial commit
This commit is contained in:
+25
@@ -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
@@ -0,0 +1,6 @@
|
||||
testing
|
||||
build
|
||||
benchmarks
|
||||
examples
|
||||
support
|
||||
test
|
||||
+23
@@ -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
@@ -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
@@ -0,0 +1,348 @@
|
||||
node-canvas
|
||||
===========
|
||||
### Canvas graphics API backed by Cairo
|
||||
[](https://travis-ci.org/Automattic/node-canvas)
|
||||
[](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 <dev@learnboost.com>
|
||||
|
||||
Copyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com>
|
||||
|
||||
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
@@ -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
@@ -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
|
||||
Generated
Vendored
+1
@@ -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")
|
||||
+1
@@ -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")
|
||||
Generated
Vendored
+1
@@ -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
|
||||
Generated
Vendored
+1
@@ -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
|
||||
Generated
Vendored
+95
@@ -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:
|
||||
Generated
Vendored
+58
@@ -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:
|
||||
Generated
Vendored
+59
@@ -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:
|
||||
Generated
Vendored
+90
@@ -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:
|
||||
Generated
Vendored
+80
@@ -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:
|
||||
Generated
Vendored
+57
@@ -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:
|
||||
Generated
Vendored
+58
@@ -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:
|
||||
Generated
Vendored
+4
@@ -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:
|
||||
Generated
Vendored
+88
@@ -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:
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+6
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/canvas');
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('../build/Release/canvas');
|
||||
+312
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
+2475
File diff suppressed because it is too large
Load Diff
+185
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, °rees)) {
|
||||
*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
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user