<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      webWorker在canvas離屏渲染中的應(yīng)用

      https://juejin.cn/post/6955013319702872095

       

      前做過一個(gè)實(shí)時(shí)語音翻譯系統(tǒng)的時(shí)候就用過webworker來提高語音翻譯識(shí)別的頁面性能,最近從梁公子的圖片渲染相關(guān)代碼中再一次見到webWorker的身影,不免還是有點(diǎn)熟悉的!

      這次業(yè)務(wù)場(chǎng)景是使用canvas在圖片上的標(biāo)注一些特征區(qū)域和特征點(diǎn),但是由于一次性頁面中繪制大量的高清圖片(下圖只是截取了頁面局部,整個(gè)頁面的圖片是非常多的)會(huì)導(dǎo)致瀏覽器頁面卡死,而采用webWorker結(jié)合OffscreenCanvas離屏渲染可以最大性能的利用客戶端的線程,把繪制放到web worker中繪制的過程不阻塞主線程的運(yùn)行,提升渲染性能。

      所以說在保持一定專注領(lǐng)域范圍內(nèi),持久的學(xué)習(xí)總有一天都是會(huì)有用的!在此特別鳴謝梁公子,也祝他前程似錦!

      OffscreenCanvas 瀏覽器離屏渲染API

      OffscreenCanvas提供了一個(gè)可以脫離屏幕渲染的canvas對(duì)象。它在窗口環(huán)境和web worker環(huán)境均有效,主要用于提升 Canvas 2D/3D 繪圖的渲染性能和使用體驗(yàn);

      OffscreenCanvas和canvas都是渲染圖形的對(duì)象。 不同的是canvas只能在window環(huán)境下使用,而OffscreenCanvas即可以在window環(huán)境下使用,也可以在web worker中使用,這讓不影響瀏覽器主線程的離屏渲染成為可能。

      具體方法參考MDN developer.mozilla.org/zh-CN/docs/…

      與之關(guān)聯(lián)的還有ImageBitmap對(duì)象和ImageBitmapRenderingContext。

      ImageBitmap

      ImageBitmap對(duì)象表示能夠被繪制到 canvas上的位圖圖像,具有低延遲的特性。 ImageBitmap提供了一種異步且高資源利用率的方式來為WebGL的渲染準(zhǔn)備基礎(chǔ)結(jié)構(gòu)。

      transferToImageBitmap函數(shù)

      通過transferToImageBitmap函數(shù)可以從OffscreenCanvas對(duì)象的繪制內(nèi)容創(chuàng)建一個(gè)ImageBitmap對(duì)象。該對(duì)象可以用于到其他canvas的繪制。

      比如本文就是,把一個(gè)比較耗費(fèi)時(shí)間的繪制放到web worker下的OffscreenCanvas對(duì)象上進(jìn)行,繪制完成后,創(chuàng)建一個(gè)ImageBitmap對(duì)象,并把該對(duì)象傳遞給頁面端,在頁面端繪制ImageBitmap對(duì)象。

      draw_workers.js

      一個(gè)進(jìn)程的worker要處理的任務(wù)代碼如下:

       
      javascript
      體驗(yàn)AI代碼助手
      代碼解讀
      復(fù)制代碼
      let ctx = self;
      
      ctx.addEventListener('message', ({ data }) => {
          console.log('OffscreenCanvas.data', data);
          let canvas = new OffscreenCanvas(data.oriSize.w, data.oriSize.h); //  瀏覽器離屏渲染API(傳入?yún)?shù)為寬高)
          let context = canvas.getContext('2d'); // 為offscreencanvas對(duì)象返回一個(gè)渲染畫布
          ctx.createImageBitmap(data.blob).then(imageBitmap => {
              // data.blob 為圖片轉(zhuǎn)換成的blob對(duì)象
              context.drawImage(imageBitmap, 0, 0);
              const px = data.oriSize.w;
              for (let item of data.point) {
                  context.fillStyle = '#ffbc00'; //'#ffbc00'
                  context.beginPath(); //標(biāo)志開始一個(gè)路徑
                  context.arc(item.x, item.y, px / 480, 0, 2 * Math.PI, true); //在canvas中繪制圓點(diǎn)
                  context.fill();
                  context.strokeStyle = '#ffbc00';
                  context.stroke();
              }
              for (let item of data.rect) {
                  context.lineWidth = px / 240;
                  context.strokeStyle = item.color;
                  context.strokeRect(item.x, item.y, item.width, item.height); //在canvas中繪制矩形框
                  context.font = parseInt(px / 19.2) + 'px Verdana';
                  context.fillStyle = item.color;
                  context.fillText(item.label || '', item.x, item.y);
              }
              // const t1 = Date.now()
              const imageBitmap2 = canvas.transferToImageBitmap();  // 繪制完成后,創(chuàng)建一個(gè)ImageBitmap對(duì)象,并把該對(duì)象傳遞給頁面端,在頁面端繪制ImageBitmap對(duì)象。
              postMessage({
                  imageBitmap: imageBitmap2
              });
              // canvas.convertToBlob({
              //     type: 'image/webp'
              // }).then((blob) => {
              //     console.log(Date.now() - t1)
              //     const reader = new FileReader();
              //     reader.readAsDataURL(blob);
              //     return new Promise(resolve => {
              //         reader.onloadend = () => {
              //             resolve(reader.result);
              //         };
              //     });
              // }).then((base64) => {
              //     // 把取到的base64 傳給主線程
              //     ctx.postMessage(base64)
              // })
          });
      });
      
      // var offscreen, ctx;
      // onmessage = function () {
      //     init();
      //     draw();
      // }
      
      // function init() {
      //     offscreen = new OffscreenCanvas(512, 512);
      //     ctx = offscreen.getContext("2d");
      // }
      
      // function draw() {
      //     ctx.clearRect(0, 0, offscreen.width, offscreen.height);
      //     for (var i = 0; i < 10000; i++) {
      //         for (var j = 0; j < 1000; j++) {
      
      //             ctx.fillRect(i * 3, j * 3, 2, 2);
      //         }
      //     }
      //     var imageBitmap = offscreen.transferToImageBitmap();
      //     postMessage({
      //         imageBitmap: imageBitmap
      //     }, [imageBitmap]);
      // }
      

      利用webWork線程池,最大化利用客戶機(jī)渲染性能

      一般電腦都是4核8線程,故此處創(chuàng)建最多8線程的線程池,用于多個(gè)圖像并行的canvas繪制

       
      javascript
      體驗(yàn)AI代碼助手
      代碼解讀
      復(fù)制代碼
      // worker線程池
      const pool = [];
      // 默認(rèn)8個(gè)常駐線程
      for (let index = 0; index < 8; index++) {
          const worker = new Worker('draw_workers.js');  // 此處注意引入路徑
          pool.push({
              workerId: index,
              worker,
              status: 'free' //   free | busy
          });
      }
      
      // 獲取當(dāng)前閑置(free)的線程,如果都在busy,則等到100ms再試一次
      async function findFreePool() {
          while (true) {
              const poolItem = pool.find(item => item.status === 'free'); // 找到一個(gè)可用線程
              if (poolItem) {
                  return poolItem;
              } else {
                  await timeOut(100);
              }
          }
      }
      
      function timeOut(s) {
          return new Promise(r => setTimeout(r, s));
      }
      
      export function work(data) {
          return new Promise(async (resolve, reject) => {
              const poolItem = await findFreePool();
              poolItem.status = 'busy'; // 獲取到free的線程就讓他busy起來,去處理事件
              poolItem.worker.onmessage = e => {
                  resolve(e);
                  poolItem.status = 'free'; // 收到工作完成的消息之后就釋放該進(jìn)程
              };
              poolItem.worker.postMessage(data);  // 將data內(nèi)容傳遞給draw_workers的worker中
          });
      }
      

      vue頁面使用

       
      html
      體驗(yàn)AI代碼助手
      代碼解讀
      復(fù)制代碼
      <template>
          <div>
              <canvas :ref="canvasDom" :width="width" :height="height" style="max-width:100%;max-height:100%;"></canvas>
          </div>
      </template>
      
      <script>
          import {
              work
          } from './workerPool'
          export default {
              name: 'drawRect',
              props: {
                  // 圖像路徑
                  url: {
                      type: String
                  },
                  // 矩形框坐標(biāo)數(shù)組
                  rect: {
                      type: Array
                  },
                  // 點(diǎn)數(shù)組
                  point: {
                      type: Array
                  }
              },
              data() {
                  return {
                      itemUrl: null,
                      canvasBitmap: null,
                      ctxBitmap: null,
                      width: 0,
                      height: 0,
                      canvasDom: Date.now() + '_' + Math.random(),
                      worker: null,
                  };
              },
              watch: {
                  url() {
                      this.draw();
                  },
                  rect() {
                      this.draw();
                  },
                  point() {
                      this.draw();
                  }
              },
              created() {},
              async mounted() {
                  this.draw();
              },
              methods: {
                  async draw() {
                      if (!this.url || !this.rect) {
                          console.warn('畫框組件缺少參數(shù)');
                          return;
                      }
                      const blob = await this.loadImageAsync(this.url);
                      var nImg = new Image();
                      nImg.onload = () => {
                          // onload之后獲取到圖像屬性
                          const w = nImg.width;
                          const h = nImg.height;
                          this.width = w
                          this.height = h
                          this.$nextTick(async () => {
                              this.canvasBitmap = this.$refs[this.canvasDom];
                              this.ctxBitmap = this.canvasBitmap.getContext('2d');  // 
                              // 拿到新的worker 并將數(shù)據(jù)傳給worker,之后workerPool 通過postmessage將數(shù)據(jù)傳遞給draw_workers中繪制canvas對(duì)象
                              const e = await work({
                                  blob,
                                  oriSize: {
                                      w,
                                      h
                                  },
                                  rect: this.rect || [],
                                  point: this.point || []
                              })
                              this.$emit('getImageData', e.data.imageBitmap)  // 將二進(jìn)制圖像向父組件拋出
                              this.ctxBitmap.drawImage(e.data.imageBitmap, 0, 0);
                              this.ctxBitmap.restore();  // 保存canvas結(jié)果
                          })
                      };
                      nImg.src = URL.createObjectURL(blob);
                  },
                  loadImageAsync(imageUrl) {
                      return new Promise(resolve => {
                          fetch(imageUrl).then(response => {
                              // fetch 不僅可以將請(qǐng)求結(jié)果轉(zhuǎn)為json,也可以直接通過response.blob()的方式直接轉(zhuǎn)為blob對(duì)象
                              resolve(response.blob());
                          });
                      });
                  }
              }
          };
      </script>
      

      最近開通了訂閱號(hào)——“前端之帆”,希望小伙伴們賞個(gè)臉,來評(píng)論騷擾哈!二維碼奉上


      作者:阿飛飛飛
      鏈接:https://juejin.cn/post/6955013319702872095
      來源:稀土掘金
      著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
      posted @ 2025-05-13 09:34  China Soft  閱讀(123)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 人妻少妇中文字幕久久| 国内自拍网红在线综合一区| 最新国产精品好看的精品| AV秘 无码一区二| 亚洲丰满熟女一区二区蜜桃| 人妻少妇偷人作爱av| 国产午夜视频在线观看| 特级做a爰片毛片免费看无码 | 国产性生大片免费观看性| 五月丁香六月综合缴情在线| 中文字幕乱妇无码AV在线| 四虎影视库国产精品一区| 婷婷四虎东京热无码群交双飞视频 | 亚洲精品一区二区三区蜜| 99精品人妻少妇一区二区| 日韩有码国产精品一区| 粉嫩一区二区三区精品视频| 无遮无挡爽爽免费视频| 亚洲人成亚洲人成在线观看| 亚洲欧美日韩在线码| 欧美大bbbb流白水| 在线播放国产精品三级网| 国产69精品久久久久777| 国产日韩综合av在线| 亚洲红杏AV无码专区首页| 国产福利片无码区在线观看| 苍井空毛片精品久久久| 在线一区二区中文字幕| japan黑人极大黑炮| 日韩国产中文字幕精品| 女人腿张开让男人桶爽| 在线免费不卡视频| 97在线视频人妻无码| 久久亚洲国产精品久久| 中文字幕在线精品国产| 亚洲国产女性内射第一区| 俺来也俺去啦最新在线| 亚洲男人AV天堂午夜在| 国产极品尤物粉嫩在线观看 | 久久乐国产精品亚洲综合| 精品乱人伦一区二区三区|