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

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

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

      純前端Canvas繪制海報(bào)

      封裝類:

      /**
       * Canvas繪制海報(bào)
       */
      class Poster {
        canvas: HTMLCanvasElement;
        context: CanvasRenderingContext2D;
      
        constructor(el: string, width: number, height: number) {
          const canvas = document.querySelector<HTMLCanvasElement>(el);
          if (canvas === null) {
            throw new Error("獲取canvas失敗");
          }
          canvas.width = width;
          canvas.height = height;
          this.canvas = canvas;
      
          const context = canvas.getContext("2d");
          if (context === null) {
            throw new Error("獲取context失敗");
          }
          this.context = context;
        }
      
        setFillStyle(style: string) {
          this.context.fillStyle = style;
          return this;
        }
      
        setStrokeStyle(style: string) {
          this.context.strokeStyle = style;
          return this;
        }
      
        setFont(font: string) {
          this.context.font = font;
          return this;
        }
      
        fillCanvas() {
          this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
          return this;
        }
      
        clearCanvas() {
          this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
          return this;
        }
      
        loadImage(src: string) {
          return new Promise<HTMLImageElement>((resolve, reject) => {
            const img = new Image();
            img.src = src;
            img.crossOrigin = "anonymous";
            img.onload = function () {
              resolve(img);
            };
          });
        }
      
        drawImage(image: CanvasImageSource, x: number, y: number, width: number, height: number) {
          this.context.drawImage(image, x, y, width, height);
          return this;
        }
      
        drawText(text: string, x: number, y: number, limitWidth?: number, lineHeight?: number) {
          if (limitWidth != undefined) {
            let measureTextWidth = 0;
            let lastSubstringIndex = 0;
            for (let i = 0; i < text.length; i++) {
              const metrics = this.context.measureText(text[i]);
              measureTextWidth += metrics.width;
              if (measureTextWidth > limitWidth) {
                this.context.fillText(text.substring(lastSubstringIndex, i), x, y);
                measureTextWidth = 0;
                lastSubstringIndex = i;
                y += lineHeight ?? metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
              }
              if (i === text.length - 1) {
                this.context.fillText(text.substring(lastSubstringIndex, i + 1), x, y);
              }
            }
          } else {
            this.context.fillText(text, x, y);
          }
          return this;
        }
      
        drawLine(x1: number, y1: number, x2: number, y2: number) {
          this.context.moveTo(x1, y1);
          this.context.lineTo(x2, y2);
          this.context.stroke();
          return this;
        }
      
        toDataURL(type?: string, quality?: any) {
          return this.canvas.toDataURL(type, quality);
        }
      
        download(filename: string = Date.now().toString()) {
          let ext = "png";
          if (filename.includes(".")) {
            const filenameSplit = filename.split(".");
            ext = filenameSplit[filenameSplit.length - 1].toLowerCase();
          }
          let mime = "image/png";
          if (ext === "jpg" || ext === "jpeg") {
            mime = "image/jpeg";
          }
          const base64 = this.toDataURL(mime);
          const aEl = document.createElement("a");
          aEl.href = base64;
          aEl.setAttribute("download", filename);
          aEl.click();
        }
      }
      
      export default Poster;

       

      使用示例:

      <script setup lang="ts">
      import Poster from "@/utils/poster";
      import QRCode from "qrcode";
      import { onMounted, ref } from "vue";
      
      defineOptions({
        name: "Poster",
      });
      
      // 獲取本地圖片
      function getAssetImg(name: string) {
        return new URL(`../../assets/poster/${name}`, import.meta.url).href;
      }
      
      async function generatePoster() {
        const width = 750;
        const height = 1334;
        const poster = new Poster("#canvas", width, height);
        const bgImg = await poster.loadImage(getAssetImg("bg.jpeg"));
        // 生成二維碼base64圖片
        const qrcodeUrl = await QRCode.toDataURL(`https://www.baidu.com`);
        const qrcodeImg = await poster.loadImage(qrcodeUrl);
        // 開始繪制
        poster
          .drawImage(bgImg, 0, 0, width, height)
          .drawImage(qrcodeImg, width - 150, height - 150, 100, 100)
          .setFillStyle("#fff")
          .setFont("14px bold 黑體")
          .drawText("打開愛奇藝app,掃碼領(lǐng)取積分,贏取豪華大禮,驚喜等著你~", 50, height - 100, 250, 20);
      
        return poster;
      }
      
      const posterObj = ref();
      const isLoading = ref(true);
      
      onMounted(async () => {
        posterObj.value = await generatePoster();
        isLoading.value = false;
      });
      </script>
      
      <template>
        <div>
          <div v-if="isLoading">生成中。。。</div>
          <div v-show="!isLoading">
            <canvas id="canvas"></canvas>
            <div>
              <button type="button" @click="posterObj.download()">保存海報(bào)</button>
            </div>
          </div>
        </div>
      </template>
      
      <style lang="scss" scoped></style>

       

       

      posted @ 2024-09-04 15:16  白開水  閱讀(35)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产精品一区二区三区黄| 亚洲国产超清无码专区| 国产成人精品永久免费视频| 久久精品蜜芽亚洲国产av| 亚洲精品国产免费av| 亚洲男人av天堂久久资源| 国产性色的免费视频网站| 欧美 变态 另类 人妖| 久久综合激情网| 一区二区三区综合在线视频| 国产精品视频亚洲二区| 亚洲高清免费在线观看| 色偷偷亚洲男人的天堂| 蜜臀久久精品亚洲一区| 亚洲中文字幕一区二区| 日韩一区二区三区亚洲一| 亚洲中文字幕无码av永久| 国产成人午夜在线视频极速观看| 精品国产这么小也不放过| 亚洲综合一区二区国产精品| 亚洲色成人一区二区三区| 女人喷水高潮时的视频网站| 国产小受被做到哭咬床单GV| 女高中生自慰污污网站| 亚洲av高清一区二区三| 人妻精品中文字幕av| 午夜国产小视频| 人妻精品久久无码区| 亚洲国产午夜精品福利| 国语精品一区二区三区| 国产精品亚洲欧美大片在线看 | 国产极品粉嫩尤物一线天| 亚洲AV无码一区二区一二区色戒| 噜噜噜噜私人影院| 天堂网亚洲综合在线| 國产AV天堂| 90后极品粉嫩小泬20p| 2021国产成人精品久久| 重庆市| av一区二区中文字幕| 国产一区二区四区不卡|