123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- '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]
- 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 (this.width === 0 || this.height === 0) {
- // Per spec, if the bitmap has no pixels, return this string:
- var str = "data:,";
- if (fn) {
- setTimeout(function() {
- fn(null, str);
- });
- }
- return str;
- }
- 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);
- });
- }
- };
|