H 5 canvas画像を生成し、アップロードファイルをPDFに転送してcanvas文字レイアウトをダウンロードする


最近、小さなプログラム側でプレビュー機能をカスタマイズし、プレビューした画像に指定した外部フォントを使用するビジネスニーズに遭遇しました.プレビューした画像をOSSにアップロードし、バックエンドにPDFを生成し、管理システムでダウンロードします.しかし............、実践の発見を経て、小さいプログラムはパケット処理をしたにもかかわらず、依然としてローカルにフォントパケットを保存することができなくて、フォントをOSSの上で戻すことができなくて、しかしドメインをまたいで現れて、ドメインをまたいで許可することを配置したにもかかわらず、依然としてだめです.しかも!!!ウィジェットのcanvas APIはフォントを設定できず、h 5のcanvasのcontext.font = ' 'の方法はありません.最終的に曲線救国を決定し、小プログラム端のプレビュー生成canvas機能を放棄し、canvasをフォントに導入し、画像を生成するなどの操作を管理システムに置き、原生canvasを採用して実現した.
技術的要点
  • canvas文字レイアウト
  • canvas設定指定背景色
  • canvas外部フォント
  • を導入
  • canvas描画文字画像
  • canvasによって生成されたbase 64ピクチャをfileアップロード(ここではバックエンド交渉、ここではバックエンド要求)
  • に変換する.
  • 画像をPDFに生成し、一括ダウンロード
  • をクリックします.
    実装手順
    canvas文字レイアウト
    一般的なHTMLコンテナでは、文字のレイアウトを実現するには簡単です.例:
    テキストが自動改行を超えた場合、デフォルトのテキストがコンテナ幅を超えた場合に自動的に改行されます.また、word-wrap:break-wordを使用して強制改行を行うこともできます.文字の縦組みを実現するには、いくつかの方法があります.
  • テキストコンテナにwriting-modeのスタイルを設定する:(互換性の問題がある)
  • writing-mode:vertical-rl;//             。  top-bottom-right-left
      
    writing-mode:vertical-lr;//           ,        

    具体的な効果は以下の通りです.
    しかし、これはブラウザにも一定の互換性の問題があり、使用する際に注意が必要です.
  • を使用して改行を制御する:(互換性がない、推奨方式)
  • 各行の幅を1文字サイズに設定し、テキストがデフォルトの改行を超えたプロパティを使用するか、強制改行を超えたテキストの縦組みを設定します.
  • brタグ実装または文字ごとに1つのタグを格納改行:(堅苦しい書き方、比較low、推奨しない)
  • .
    文字ごとにbrのラベルを追加したり、文字ごとにラベルを1つ置いたりすると、書く柔軟性が高くなく、とてもお勧めできません.canvasでの文字レイアウトの実装
  • 文字横並び
  • を実現する.canvasでは、テキストがcanvasサイズを超えていて、自動的に改行されない場合は、超えた後に直接一列に描画されます.canvasにも改行を直接設定できるapiはありませんが、どのように改行を実現すればいいのでしょうか.jsによって制御することができ、現在の描画文字のx座標を計算することによって、x座標がcanvasの幅より大きい場合、x座標を0(描画の開始点x座標)に割り当て、y座標は1文字の高さを加算し、テキストの改行を実現する.
  • 文字縦
  • を実現する.
    縦並びの論理は横並びと同じです.文字縦列はy座標が累加されただけで、canvasの高さを超えた場合、y座標を0(描画の開始点y座標)に割り当て、x座標を1文字の高さに累加して縦列かつテキストの改行を実現する.
    部分コードクリップ
      /**
       * canvas    
       * @param {CanvasRenderingContext2D  } context  
       * @param {    } text 
       * @param {   x   } x 
       * @param {   y   } 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) {
          //              
          //         
          let code = letter.charCodeAt(0);
          //       
          let letterWidth = 22 * 2.3;
          if (code <= 256) {
            context.translate(x, y);
            //     ,  90°
            context.rotate(90 * Math.PI / 180);
            context.translate(-x, -y);
          }
          if (code !== 47) context.fillText(letter, x, y);
          //            
          context.setTransform(1, 0, 0, 1, 0, 0);
          //            8        9          
          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
            }
          }
        });
        //           
        context.textAlign = align;
        context.textBaseline = baseline;
      }

    canvas背景色の設定canvasピクチャを生成する場合はピクチャフォーマット(jpg,jpeg,pngなど)を指定できますが、 (大会歪み)のみ生成できます.canvas生成ピクチャの品質を向上させるにはhidpi-canvas-polyfillプラグインを導入し、具体的にはこの記事を参照してcanvas生成ピクチャのぼかしを解決することができます.canvas生成ピクチャの背景はデフォルトでは透明であり、背景色を個別に設定したい場合はctx.fillStyleを使用して塗りつぶすことができますが、文字色を設定すると、文字色もctx.fillStyleを使用するため、背景色が上書きされます.では、この場合は以下の方法で解決することができる:1.canvas.getImageDataを用いるキャンバス上の画素データ2を複製する.複製する各画素点を巡回し、各画素にrgbの値3を設定.設定されたストリームデータをputImageDataを介してキャンバスに戻します.
     let imageData = ctx.getImageData(0, 0, width, height);
          for (let i = 0; i < imageData.data.length; i += 4) {
            //         ,      
            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);

    しかし、背景と文字の描画順序に注意してください.です.順序が逆になると、文字は明らかに鋸歯状になり、少しぼやけてしまいます.これは、位置決め中のz-indexと原理が似ています.
    canvas外部フォントの導入
    1.まずフォントライブラリを導入します.ローカルスペースを節約するために、サービス側から導入できますが、ドメイン間の問題に注意する必要があります.また、フォントライブラリをローカルに配置し、直接パスに対して導入することもできます.
    //       
    @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オブジェクトによりフォント、文字等を設定する
    ctx.font = '24px FZCUJINLJW';
    ctx.fillStyle = '#db9a00';//     

    canvasテキストピクチャの描画
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');//    CanvasRenderingContext2D  
    
    ctx.beginPath();//       
    ctx.font = `${FONT_SIZE}px FZCUJINLJW`;
    ctx.fillStyle = '#db9a00';//     
    ctx.fillText('     ', /*   x  */, /*   y  */);
    let imgBase64 = canvas.toDataURL('image/png', 1);
    ctx.closePath();
    ctx.save();//         
    
    //              ,                ,     ,        。
    ctx.clearRect(0, 0, canvasObj.width, canvasObj.height);

    canvasは画像を生成し、サービス側をアップロードします.ctx.toDataURLによりキャンバスコンテンツのbase64 を取得できる
    let imgBase64 = canvas.toDataURL('image/png', 1);

    サービス側がbase64を使用してアップロードをサポートしている場合は、処理は必要ありません.ここでは、バックエンドにfileファイルタイプが必要であるため、base64file に変換する必要があります.コードは以下のとおりです.
    let file = dataURLtoFile(imgBase64, 'jpg'); //  base  file  
    function dataURLtoFile(urlData, fileName) {
        var bytes = window.atob(urlData.split(',')[1]);        //  url  ,    byte
        var mime = urlData.split(',')[0].match(/:(.*?);/)[1];
        //    , ascii   0      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 });
    }
    file に変換後、FormData形式でアップロード
    let formdata = new FormData();
    formdata.append('multipartList', file);
    ajax.post(url,data:formdata).then()

    ここで注意してください.canvasで生成された画像が比較的小さい場合(例えば5 kb以下)、ファイルのアップロードに失敗する可能性があります.私は前にこの穴を踏んだことがあります.
    画像をPDFに生成し、一括ダウンロードをクリックします.
    ここではバックエンドと相談して、canvasで生成したピクチャをサービス側にアップロードし、ピクチャのOSSアドレスに戻り、このアドレスをパラメータとしてバックエンドに伝え、PDFのダウンロードリンクを取得し、フロントエンドはwindow.open(url)でファイルダウンロードを実現する.
    let uploadUrl = window.interfercesPrefix + '/admin/goods/tbgoods/uploadImages';
    let downLoadUrl = '/app/goods/tbgoods/downLoadPdf';
    //     
          ajaxUploderImg({ url: uploadUrl, data: formdata }).then(res => {
            //          PDF    
            this.props.dispatch(downLoadPdf({ url: downLoadUrl, imgUrl: res.data }));
          }).catch(err => {
            if (err) {
              notification['error']({
                message: err.message,
                description:
                  '      ,   !',
              });
            } else {
              notification['error']({
                message: '    ,   '
              });
            }
          })