bv7_canvas_b

canvas

当前为 2018-03-12 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/39257/258137/bv7_canvas_b.js

  1. // ==UserScript==
  2. // @name bv7_canvas_b
  3. // @namespace bv7
  4. // @version 0.3
  5. // @description canvas
  6. // @author bv7
  7. // @require https://greasyfork.org/scripts/39428-bv7-jpeg-encoder-b/code/bv7_jpeg_encoder_b.js
  8. // @require https://greasyfork.org/scripts/38665-bv7-jpeg2array-b/code/bv7_jpeg2array_b.user.js
  9. // ==/UserScript==
  10.  
  11.  
  12. // include file:///D:/projects/JSProjects/bv7bbc/bv7_bbc_dark/bv_dev_canvas*.html
  13. // run-at document-idle
  14. // grant GM_xmlhttpRequest
  15.  
  16. class Canvas {
  17. constructor() {
  18. this.domCanvas = document.createElement('canvas');
  19. this.jpegEncoder = new JpegEncoder();
  20. }
  21. set width(v) {
  22. this.domCanvas.width = v;
  23. this.onresize();
  24. }
  25. set height(v) {
  26. this.domCanvas.height = v;
  27. this.onresize();
  28. }
  29. get width () {
  30. return this.domCanvas.width;
  31. }
  32. get height() {
  33. return this.domCanvas.height;
  34. }
  35. onresize() {
  36. }
  37. getContext(_id) {
  38. switch (_id) {
  39. case '2d':
  40. this.context = new class {
  41. constructor(canvas) {
  42. this.canvas = canvas;
  43. this.domContext = this.canvas.domCanvas.getContext('2d');
  44. this.imageData = this.domContext.getImageData(0, 0, this.canvas.domCanvas.width, this.canvas.domCanvas.height);
  45. }
  46. drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, then) {
  47. let myImage;
  48. let draw = () => {
  49. if (dWidth && sWidth && dHeight && sHeight) {
  50. let syStep = sHeight / dHeight;
  51. let sxStep = sWidth / dWidth;
  52. let dyStep = dHeight / sHeight;
  53. let dxStep = dWidth / sWidth ;
  54. let syStart = Math.max(0, sy, sy - dy / dyStep);
  55. let sxStart = Math.max(0, sx, sx - dx / dxStep);
  56. let syEnd = Math.min(myImage.height, sy + sHeight, sy + (this.imageData.height - dy) / dyStep);
  57. let sxEnd = Math.min(myImage.width , sx + sWidth , sx + (this.imageData.width - dx) / dxStep);
  58. let dyStart = dy + (syStart - sy) * dyStep;
  59. let dxStart = dx + (sxStart - sx) * dxStep;
  60. let dyEnd = dy + (syEnd - sy) * dyStep;
  61. let dxEnd = dx + (sxEnd - sx) * dxStep;
  62. let sh1 = Math.max(1, syStep);
  63. let sw1 = Math.max(1, sxStep);
  64. let dh1 = Math.max(1, dyStep);
  65. let dw1 = Math.max(1, dxStep);
  66. let siPerLine, siStartLine, siStart;
  67. let diPerLine, diStartLine, diStart;
  68. let sy1, sy1Next, sy2Start, sy2End;
  69. let sx1, sx1Next, sx2Start, sx2End;
  70. let dy1, dy1Next, dy2Start, dy2End;
  71. let dx1, dx1Next, dx2Start, dx2End;
  72. let s2count;
  73. let r, g, b, a;
  74. siPerLine = myImage.imageData.width * 4;
  75. diPerLine = this.imageData.width * 4;
  76. sy2Start = Math.round(sy1 = syStart);
  77. dy2Start = Math.round(dy1 = dyStart);
  78. while (sy1 < syEnd) {
  79. sy2End = Math.round(sy1Next = sy1 + sh1);
  80. dy2End = Math.round(dy1Next = dy1 + dh1);
  81. sx2Start = Math.round(sx1 = sxStart);
  82. dx2Start = Math.round(dx1 = dxStart);
  83. siStartLine = sy2Start * siPerLine;
  84. diStartLine = dy2Start * diPerLine;
  85. while (sx1 < sxEnd) {
  86. sx2End = Math.round(sx1Next = sx1 + sw1);
  87. dx2End = Math.round(dx1Next = dx1 + dw1);
  88. siStart = siStartLine + sx2Start * 4;
  89. diStart = diStartLine + dx2Start * 4;
  90. s2count = (sy2End - sy2Start) * (sx2End - sx2Start);
  91. r = g = b = a = 0;
  92. for (let sy2 = sy2Start; sy2 < sy2End; sy2++, siStart += siPerLine) for (let sx2 = sx2Start, si = siStart; sx2 < sx2End; sx2++) {
  93. r += myImage.imageData.data[si++];
  94. g += myImage.imageData.data[si++];
  95. b += myImage.imageData.data[si++];
  96. a += myImage.imageData.data[si++];
  97. }
  98. for (let dy2 = dy2Start; dy2 < dy2End; dy2++, diStart += diPerLine) for (let dx2 = dx2Start, di = diStart; dx2 < dx2End; dx2++) {
  99. this.imageData.data[di++] = (r - r % s2count) / s2count;
  100. this.imageData.data[di++] = (g - g % s2count) / s2count;
  101. this.imageData.data[di++] = (b - b % s2count) / s2count;
  102. this.imageData.data[di++] = (a - a % s2count) / s2count;
  103. }
  104. sx1 = sx1Next;
  105. dx1 = dx1Next;
  106. sx2Start = sx2End;
  107. dx2Start = dx2End;
  108. }
  109. sy1 = sy1Next;
  110. dy1 = dy1Next;
  111. sy2Start = sy2End;
  112. dy2Start = dy2End;
  113. }
  114. this.domContext.putImageData(this.imageData, 0, 0);
  115. }
  116. if (then) then();
  117. };
  118. if (Canvas.images.some((v) => (myImage = v).src == image.src))
  119. draw();
  120. else {
  121. myImage = new JpegImage();
  122. myImage.onload = () => {
  123. //let t = new Date();
  124. myImage.imageData = this.domContext.createImageData(myImage.width, myImage.height);
  125. myImage.copyToImageData(myImage.imageData);
  126. Canvas.images.push(myImage);
  127. draw();
  128. //console.log((new Date()) - t);
  129. };
  130. myImage.src = image.src;
  131. }
  132. };
  133. } (this);
  134. break;
  135. }
  136. return this.context;
  137. }
  138. toDataUrl(type = 'image/png', encoderOptions = 0.92) {
  139. let r;
  140. switch (type) {
  141. case 'image/jpeg':
  142. r = this.jpegEncoder.encode(this.context.imageData, encoderOptions);
  143. break;
  144. default:
  145. r = '';
  146. }
  147. return r;
  148. }
  149. }
  150. Canvas.images = [];
  151.  
  152. /*
  153. let canvas = new Canvas();
  154. canvas.width = 500;
  155. canvas.height = 500;
  156. canvas.getContext('2d').drawImage(document.getElementById('img1'), -20, 20, 600, 500, 20, -10, 300, 400, () => {
  157. let b64 = canvas.toDataUrl('image/jpeg');
  158. console.log('b64 =', b64);
  159. document.getElementById('imgBase64').src = b64;
  160. });
  161. document.body.appendChild(canvas.domCanvas);
  162. */