【前端】智能库房综合管理系统前端项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.2 KiB

  1. import { Fill } from '../../utils'
  2. export default class CanvasRenderer {
  3. /** @type {HTMLCanvasElement} */
  4. canvas
  5. /**
  6. *
  7. * @param {import('../../types').PlayerOptions} options
  8. */
  9. constructor(options) {
  10. this.canvas = options.canvas ?? document.createElement('canvas')
  11. this.width = this.canvas.width
  12. this.height = this.canvas.height
  13. this.enabled = true
  14. this.context = this.canvas.getContext('2d')
  15. }
  16. destroy() {
  17. // Nothing to do here
  18. }
  19. clear() {
  20. if (!this.context) return
  21. const w = this.canvas.width
  22. const h = this.canvas.height
  23. this.context.fillStyle = '#000'
  24. this.context.fillRect(0, 0, w, h)
  25. }
  26. resize(width, height) {
  27. this.width = width | 0
  28. this.height = height | 0
  29. this.canvas.width = this.width
  30. this.canvas.height = this.height
  31. this.imageData = this.context.getImageData(0, 0, this.width, this.height)
  32. Fill(this.imageData.data, 255)
  33. }
  34. renderProgress(progress) {
  35. const w = this.canvas.width
  36. const h = this.canvas.height
  37. const ctx = this.context
  38. ctx.fillStyle = '#222'
  39. ctx.fillRect(0, 0, w, h)
  40. ctx.fillStyle = '#fff'
  41. ctx.fillRect(0, h - h * progress, w, h * progress)
  42. }
  43. render(y, cb, cr) {
  44. this.YCbCrToRGBA(y, cb, cr, this.imageData.data)
  45. this.context.putImageData(this.imageData, 0, 0)
  46. }
  47. YCbCrToRGBA(y, cb, cr, rgba) {
  48. if (!this.enabled) {
  49. return
  50. }
  51. // Chroma values are the same for each block of 4 pixels, so we proccess
  52. // 2 lines at a time, 2 neighboring pixels each.
  53. // I wish we could use 32bit writes to the RGBA buffer instead of writing
  54. // each byte separately, but we need the automatic clamping of the RGBA
  55. // buffer.
  56. const w = ((this.width + 15) >> 4) << 4
  57. const w2 = w >> 1
  58. let yIndex1 = 0
  59. let yIndex2 = w
  60. const yNext2Lines = w + (w - this.width)
  61. let cIndex = 0
  62. const cNextLine = w2 - (this.width >> 1)
  63. let rgbaIndex1 = 0
  64. let rgbaIndex2 = this.width * 4
  65. const rgbaNext2Lines = this.width * 4
  66. const cols = this.width >> 1
  67. const rows = this.height >> 1
  68. let ccb, ccr, r, g, b
  69. for (let row = 0; row < rows; row++) {
  70. for (let col = 0; col < cols; col++) {
  71. ccb = cb[cIndex]
  72. ccr = cr[cIndex]
  73. cIndex++
  74. r = ccb + ((ccb * 103) >> 8) - 179
  75. g = ((ccr * 88) >> 8) - 44 + ((ccb * 183) >> 8) - 91
  76. b = ccr + ((ccr * 198) >> 8) - 227
  77. // Line 1
  78. const y1 = y[yIndex1++]
  79. const y2 = y[yIndex1++]
  80. rgba[rgbaIndex1] = y1 + r
  81. rgba[rgbaIndex1 + 1] = y1 - g
  82. rgba[rgbaIndex1 + 2] = y1 + b
  83. rgba[rgbaIndex1 + 4] = y2 + r
  84. rgba[rgbaIndex1 + 5] = y2 - g
  85. rgba[rgbaIndex1 + 6] = y2 + b
  86. rgbaIndex1 += 8
  87. // Line 2
  88. const y3 = y[yIndex2++]
  89. const y4 = y[yIndex2++]
  90. rgba[rgbaIndex2] = y3 + r
  91. rgba[rgbaIndex2 + 1] = y3 - g
  92. rgba[rgbaIndex2 + 2] = y3 + b
  93. rgba[rgbaIndex2 + 4] = y4 + r
  94. rgba[rgbaIndex2 + 5] = y4 - g
  95. rgba[rgbaIndex2 + 6] = y4 + b
  96. rgbaIndex2 += 8
  97. }
  98. yIndex1 += yNext2Lines
  99. yIndex2 += yNext2Lines
  100. rgbaIndex1 += rgbaNext2Lines
  101. rgbaIndex2 += rgbaNext2Lines
  102. cIndex += cNextLine
  103. }
  104. }
  105. }