canvas.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. 'use strict'
  2. /*!
  3. * Canvas
  4. * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
  5. * MIT Licensed
  6. */
  7. const bindings = require('./bindings')
  8. const Canvas = module.exports = bindings.Canvas
  9. const Context2d = require('./context2d')
  10. const PNGStream = require('./pngstream')
  11. const PDFStream = require('./pdfstream')
  12. const JPEGStream = require('./jpegstream')
  13. const FORMATS = ['image/png', 'image/jpeg']
  14. const util = require('util')
  15. // TODO || is for Node.js pre-v6.6.0
  16. Canvas.prototype[util.inspect.custom || 'inspect'] = function () {
  17. return `[Canvas ${this.width}x${this.height}]`
  18. }
  19. Canvas.prototype.getContext = function (contextType, contextAttributes) {
  20. if (contextType == '2d') {
  21. const ctx = this._context2d || (this._context2d = new Context2d(this, contextAttributes))
  22. this.context = ctx
  23. ctx.canvas = this
  24. return ctx
  25. }
  26. }
  27. Canvas.prototype.pngStream =
  28. Canvas.prototype.createPNGStream = function (options) {
  29. return new PNGStream(this, options)
  30. }
  31. Canvas.prototype.pdfStream =
  32. Canvas.prototype.createPDFStream = function (options) {
  33. return new PDFStream(this, options)
  34. }
  35. Canvas.prototype.jpegStream =
  36. Canvas.prototype.createJPEGStream = function (options) {
  37. return new JPEGStream(this, options)
  38. }
  39. Canvas.prototype.toDataURL = function (a1, a2, a3) {
  40. // valid arg patterns (args -> [type, opts, fn]):
  41. // [] -> ['image/png', null, null]
  42. // [qual] -> ['image/png', null, null]
  43. // [undefined] -> ['image/png', null, null]
  44. // ['image/png'] -> ['image/png', null, null]
  45. // ['image/png', qual] -> ['image/png', null, null]
  46. // [fn] -> ['image/png', null, fn]
  47. // [type, fn] -> [type, null, fn]
  48. // [undefined, fn] -> ['image/png', null, fn]
  49. // ['image/png', qual, fn] -> ['image/png', null, fn]
  50. // ['image/jpeg', fn] -> ['image/jpeg', null, fn]
  51. // ['image/jpeg', opts, fn] -> ['image/jpeg', opts, fn]
  52. // ['image/jpeg', qual, fn] -> ['image/jpeg', {quality: qual}, fn]
  53. // ['image/jpeg', undefined, fn] -> ['image/jpeg', null, fn]
  54. // ['image/jpeg'] -> ['image/jpeg', null, fn]
  55. // ['image/jpeg', opts] -> ['image/jpeg', opts, fn]
  56. // ['image/jpeg', qual] -> ['image/jpeg', {quality: qual}, fn]
  57. let type = 'image/png'
  58. let opts = {}
  59. let fn
  60. if (typeof a1 === 'function') {
  61. fn = a1
  62. } else {
  63. if (typeof a1 === 'string' && FORMATS.includes(a1.toLowerCase())) {
  64. type = a1.toLowerCase()
  65. }
  66. if (typeof a2 === 'function') {
  67. fn = a2
  68. } else {
  69. if (typeof a2 === 'object') {
  70. opts = a2
  71. } else if (typeof a2 === 'number') {
  72. opts = { quality: Math.max(0, Math.min(1, a2)) }
  73. }
  74. if (typeof a3 === 'function') {
  75. fn = a3
  76. } else if (undefined !== a3) {
  77. throw new TypeError(`${typeof a3} is not a function`)
  78. }
  79. }
  80. }
  81. if (this.width === 0 || this.height === 0) {
  82. // Per spec, if the bitmap has no pixels, return this string:
  83. const str = 'data:,'
  84. if (fn) {
  85. setTimeout(() => fn(null, str))
  86. return
  87. } else {
  88. return str
  89. }
  90. }
  91. if (fn) {
  92. this.toBuffer((err, buf) => {
  93. if (err) return fn(err)
  94. fn(null, `data:${type};base64,${buf.toString('base64')}`)
  95. }, type, opts)
  96. } else {
  97. return `data:${type};base64,${this.toBuffer(type, opts).toString('base64')}`
  98. }
  99. }