成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

H5 canvas生成圖片并上傳文件轉(zhuǎn)成PDF下載canvas文字排版

canopus4u / 2881人閱讀

摘要:將預(yù)覽的圖片上傳,后端生成,在管理系統(tǒng)中下載。技術(shù)要點(diǎn)文字排版設(shè)置指定背景顏色引入外部字體繪制文字圖片將生成的圖片轉(zhuǎn)成上傳這里根據(jù)后端協(xié)商,此處后端要求將圖片生成,并點(diǎn)擊批量下載實(shí)現(xiàn)步驟文字排版在一般容器中,如果要實(shí)現(xiàn)文字的排版很容易。

最近遇到一個(gè)業(yè)務(wù)需求,在小程序端定制預(yù)覽功能,并在預(yù)覽的圖片中使用指定的外部字體。將預(yù)覽的圖片上傳OSS,后端生成PDF,在管理系統(tǒng)中下載。
但是…………,經(jīng)過實(shí)踐發(fā)現(xiàn),小程序盡管做了分包處理,依舊不能在本地存放字體包,把字體放OSS上返回,但是出現(xiàn)跨域,盡管配置了允許跨域,依舊不行。而且?。?!小程序的canvas API沒法設(shè)置字體,沒有h5中canvas中的context.font = "字體名稱"方法。最終決定曲線救國(guó),放棄小程序端的預(yù)覽生成canvas功能,將canvas引入字體,生成圖片等操作放在管理系統(tǒng)中,采用原生canvas來實(shí)現(xiàn)。

技術(shù)要點(diǎn)

canvas文字排版

canvas設(shè)置指定背景顏色

canvas引入外部字體

canvas繪制文字圖片

將canvas生成的base64圖片轉(zhuǎn)成file上傳(這里根據(jù)后端協(xié)商,此處后端要求)

將圖片生成PDF,并點(diǎn)擊批量下載

實(shí)現(xiàn)步驟 canvas文字排版 在一般HTML容器中,如果要實(shí)現(xiàn)文字的排版很容易。比如:

實(shí)現(xiàn)文本超出自動(dòng)換行,默認(rèn)文本超出容器寬度就會(huì)自動(dòng)換行,也可以使用word-wrap:break-word實(shí)現(xiàn)強(qiáng)制換行。
實(shí)現(xiàn)文字豎排,有幾種方式:

給文本容器設(shè)置writing-mode樣式:(存在兼容性問題)

writing-mode:vertical-rl;//垂直方向自右而左的書寫方式。即 top-bottom-right-left
或者
writing-mode:vertical-lr;//垂直方向內(nèi)內(nèi)容從上到下,水平方向從左到右

具體效果如圖:

但是這個(gè)對(duì)于瀏覽器也存在一定兼容性問題,使用的時(shí)候需要注意。

使用寬度控制換行:(不存在兼容性,推薦方式)

設(shè)置每行的寬度為一個(gè)字大小,利用文本超出默認(rèn)換行的特性,或者設(shè)置超出強(qiáng)制換行,實(shí)現(xiàn)文本豎排。

利用br標(biāo)簽實(shí)現(xiàn)或者每個(gè)文字存放一個(gè)標(biāo)簽實(shí)現(xiàn)換行:(很死板的寫法,比較low,不推薦)

給每個(gè)文字后添加br標(biāo)簽,或者每個(gè)文字放一個(gè)標(biāo)簽,這樣寫靈活性不高,非常不推薦!

canvas中實(shí)現(xiàn)文字排版

實(shí)現(xiàn)文字橫排

canvas中,如果文本超出canvas大小,并不會(huì)自動(dòng)換行,會(huì)直接在超出的后面繼續(xù)繪制成一排。
canvas中也沒有直接可以設(shè)置換行的api,那該怎么實(shí)現(xiàn)換行呢?
可以通過js控制,通過計(jì)算當(dāng)前繪制文字的x坐標(biāo),如果x坐標(biāo)大于canvas的寬度,將x坐標(biāo)賦值為0(繪制的起始點(diǎn)x坐標(biāo)),y坐標(biāo)累加一個(gè)文字的高度,從而實(shí)現(xiàn)文本換行。

實(shí)現(xiàn)文字豎排

豎排的邏輯和橫排是一樣的。文字豎排只是y坐標(biāo)累加,趟超過canvas的高度時(shí),將y坐標(biāo)賦值為0(繪制的起始點(diǎn)y坐標(biāo)),x坐標(biāo)累加一個(gè)文字的高度,從而實(shí)現(xiàn)豎排且文本換行。

部分代碼片段
  /**
   * canvas繪制文字
   * @param {CanvasRenderingContext2D對(duì)象} context  
   * @param {繪制內(nèi)容} text 
   * @param {起始點(diǎn)x坐標(biāo)制} x 
   * @param {起始點(diǎn)y坐標(biāo)制} y 
   */
  drawTextVertical(context, text, x, y) {
    let startX = x,
      startY = y; //記錄開始的位置,用于文字換行賦值
    let spaceCount = 0;
    let arrText = text.trim().split("");
    let formatText = text.replace(///g, "").split(""); // 去掉單斜杠  
    let align = context.textAlign;
    let baseline = context.textBaseline;

    context.textAlign = "center";
    context.textBaseline = "middle";
    context.font = "Pacifico"

    // 開始逐字繪制
    arrText.forEach(function (letter, index) {
      // 確定下一個(gè)字符的縱坐標(biāo)位置
      // 是否需要旋轉(zhuǎn)判斷
      let code = letter.charCodeAt(0);
      // 計(jì)算文字間距
      let letterWidth = 22 * 2.3;
      if (code <= 256) {
        context.translate(x, y);
        // 英文字符,旋轉(zhuǎn)90°
        context.rotate(90 * Math.PI / 180);
        context.translate(-x, -y);
      }
      if (code !== 47) context.fillText(letter, x, y);
      // 旋轉(zhuǎn)坐標(biāo)系還原成初始態(tài)
      context.setTransform(1, 0, 0, 1, 0, 0);
      // 單斜杠換行或者長(zhǎng)度超過8 此處要過濾在第9字是換行的符號(hào)的情況
      if ((code === 47 && !spaceCount) || (!spaceCount && index && index % 7 === 0)) {
        //  單斜杠/ 代表換行 charCode=47
        spaceCount += 1;
        y = startY;
        x = index ? (startX + letterWidth) : x;
        startX = x;
      } else if (code !== 47) {
        // 如果是空格 減少字間距
        if (code !== 32) {
          y = y + letterWidth;
        } else {
          y = y + letterWidth / 2
        }
      }
    });
    // 水平垂直對(duì)齊方式還原
    context.textAlign = align;
    context.textBaseline = baseline;
  }

canvas設(shè)置背景顏色

canvas生成圖片的時(shí)候可以指定圖片格式(jpg,jpeg,png等),但是只能生成位圖(放大會(huì)失真)。如果想提高canvas生成圖片的質(zhì)量,可以引入 hidpi-canvas-polyfill 插件,具體使用可以參考這篇文章 解決canvas生成圖片模糊 。
canvas生成圖片的背景默認(rèn)是透明的,如果想多帶帶設(shè)置背景顏色,可以使用ctx.fillStyle進(jìn)行填充,但是設(shè)置文字顏色,則文字顏色會(huì)覆蓋背景顏色,因?yàn)樵O(shè)置文字顏色也是使用ctx.fillStyle。那么,這種情況可以使用以下辦法解決:
1.使用canvas.getImageData復(fù)制畫布上的像素?cái)?shù)據(jù)
2.循環(huán)遍歷復(fù)制的每個(gè)像素點(diǎn),然后給每個(gè)像素設(shè)置rgb
3.將設(shè)置好的流數(shù)據(jù)通過putImageData放回畫布上。

 let imageData = ctx.getImageData(0, 0, width, height);
      for (let i = 0; i < imageData.data.length; i += 4) {
        // 當(dāng)該像素是透明的,則設(shè)置成白色
        if (imageData.data[i + 3] == 0) {
          imageData.data[i] = 255;
          imageData.data[i + 1] = 255;
          imageData.data[i + 2] = 255;
          imageData.data[i + 3] = 255;
        }
      }
      ctx.putImageData(imageData, 0, 0);

但是要注意背景和文字的繪制順序,必須先繪制背景,再繪制文字,如果順序顛倒,則文字會(huì)出現(xiàn)很明顯的鋸齒狀,有點(diǎn)模糊,這就和定位中z-index原理類似。

canvas引入外部字體

1.首先引入字體庫(kù),為了節(jié)省本地空間,可以從服務(wù)端引入,但是需要注意跨域問題
也可以將字體庫(kù)放本地,直接相對(duì)路徑引入。

// 從服務(wù)端引入
@font-face {
    font-family: "FZCUJINLJW";
    src: url("https://www.xxxx.com/FZCUJINLJW.TTF") ;
}
// 本地引入
@font-face {
    font-family: "FZCUJINLJW";
    src: url("../../assets/FZCUJINLJW.TTF") ;
}

2.通過CanvasRenderingContext2D對(duì)象設(shè)置字體,字號(hào)等

ctx.font = "24px FZCUJINLJW";
ctx.fillStyle = "#db9a00";//填充顏色 
canvas繪制文字圖片
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");//拿到一個(gè)CanvasRenderingContext2D對(duì)象

ctx.beginPath();// 開始繪制文字
ctx.font = `${FONT_SIZE}px FZCUJINLJW`;
ctx.fillStyle = "#db9a00";//填充顏色 
ctx.fillText("繪制的內(nèi)容", /*繪制的x坐標(biāo)*/, /*繪制的y坐標(biāo)*/);
let imgBase64 = canvas.toDataURL("image/png", 1);
ctx.closePath();
ctx.save();// 保存當(dāng)前畫布內(nèi)容

//如果需要在畫布上循環(huán)繪制多次,需要手動(dòng)清除畫布上已經(jīng)保存的內(nèi)容,如果不清除,則畫布內(nèi)容會(huì)疊加。
ctx.clearRect(0, 0, canvasObj.width, canvasObj.height);

canvas生成圖片并上傳服務(wù)端

通過ctx.toDataURL可以獲取到畫布內(nèi)容的base64編碼

let imgBase64 = canvas.toDataURL("image/png", 1);

如果服務(wù)端支持使用base64上傳,則不用處理,此處因?yàn)楹蠖诵枰猣ile文件類型,所以需要將base64轉(zhuǎn)成file對(duì)象,代碼如下:

let file = dataURLtoFile(imgBase64, "jpg"); // 將base轉(zhuǎn)為file對(duì)象
function dataURLtoFile(urlData, fileName) {
    var bytes = window.atob(urlData.split(",")[1]);        //去掉url的頭,并轉(zhuǎn)換為byte
    var mime = urlData.split(",")[0].match(/:(.*?);/)[1];
    //處理異常,將ascii碼小于0的轉(zhuǎn)換為大于0
    var ab = new ArrayBuffer(bytes.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    return new File([ab], fileName, { type: mime });
}

轉(zhuǎn)成file對(duì)象后,通過FormData格式上傳

let formdata = new FormData();
formdata.append("multipartList", file);
ajax.post(url,data:formdata).then()

此處需要注意,當(dāng)canvas生成的圖片比較小時(shí)(比如5kb以下),有可能導(dǎo)致文件上傳失敗,我之前踩過此坑。

將圖片生成PDF,并點(diǎn)擊批量下載

此處是和后端商量,將canvas生成的圖片上傳服務(wù)端,并返回圖片的OSS地址,再將此地址作為參數(shù)傳給后端,獲取到PDF的下載鏈接,前端通過window.open(url)的方式實(shí)現(xiàn)文件下載。

let uploadUrl = window.interfercesPrefix + "/admin/goods/tbgoods/uploadImages";
let downLoadUrl = "/app/goods/tbgoods/downLoadPdf";
// 上傳圖片
      ajaxUploderImg({ url: uploadUrl, data: formdata }).then(res => {
        // 將圖片作為參數(shù)獲取PDF下載地址
        this.props.dispatch(downLoadPdf({ url: downLoadUrl, imgUrl: res.data }));
      }).catch(err => {
        if (err) {
          notification["error"]({
            message: err.message,
            description:
              "圖片繪制出錯(cuò),請(qǐng)重試!",
          });
        } else {
          notification["error"]({
            message: "下載出錯(cuò),請(qǐng)返回"
          });
        }
      })

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105169.html

相關(guān)文章

  • Javascript 將html轉(zhuǎn)成pdf,下載,支持多頁哦(html2canvas 和 jsPDF

    摘要:最近碰到個(gè)需求,需要把當(dāng)前頁面生成,并下載。但這并不是真的截圖,而是通過遍歷頁面結(jié)構(gòu),收集所有元素信息及相應(yīng)樣式,渲染出。由于只能將它能處理的生成,因此渲染出來的結(jié)果并不是與原來一致。 最近碰到個(gè)需求,需要把當(dāng)前頁面生成pdf,并下載。弄了幾天,自己整理整理,記錄下來,我覺得應(yīng)該會(huì)有人需要 :) 項(xiàng)目源碼地址:https://github.com/linwalker/... html2...

    macg0406 評(píng)論0 收藏0
  • Javascript 將html轉(zhuǎn)成pdf,下載,支持多頁哦(html2canvas 和 jsPDF

    摘要:最近碰到個(gè)需求,需要把當(dāng)前頁面生成,并下載。但這并不是真的截圖,而是通過遍歷頁面結(jié)構(gòu),收集所有元素信息及相應(yīng)樣式,渲染出。由于只能將它能處理的生成,因此渲染出來的結(jié)果并不是與原來一致。 最近碰到個(gè)需求,需要把當(dāng)前頁面生成pdf,并下載。弄了幾天,自己整理整理,記錄下來,我覺得應(yīng)該會(huì)有人需要 :) 項(xiàng)目源碼地址:https://github.com/linwalker/... html2...

    codecraft 評(píng)論0 收藏0
  • 其實(shí),前端還可以這樣做簡(jiǎn)歷

    摘要:接下來,亮出自己做的簡(jiǎn)歷。登錄進(jìn)入后,就可以選擇一個(gè)你喜歡的簡(jiǎn)歷模板進(jìn)行制作簡(jiǎn)歷了。將頁面左邊的工具欄拿掉,然后將簡(jiǎn)歷寬度放大到接近瀏覽器寬度即可達(dá)到像素最高的效果。此外,會(huì)自動(dòng)保存你做的簡(jiǎn)歷,方便下次編輯。 以下文章摘自我的博客,原文鏈接 下面的簡(jiǎn)歷圖片不上傳了,想看的點(diǎn)擊原文鏈接就能看到了。 簡(jiǎn)述下原理:首先找一個(gè)可以在線制作簡(jiǎn)歷并提供簡(jiǎn)歷模板的網(wǎng)站,然后在模板上填好自己的信息,并...

    zhaochunqi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<