1. ホーム
  2. Web制作
  3. html5

複数の画像を編集するためのキャンバス画像エディタの実装方法

2022-01-27 11:43:57

前置き

イメージエディタは、絵の落書きツールですが、現在の流行のコンテキストでは、ツールはまた、ツールを使用して、学生が提出した宿題を修正するために教師のオンラインになることができます、それは大幅に宿題を修正するために教師の作業負荷を減らすことができます、私はこのソフトウェアのための市場があると信じています。
それでも、キャンバスグラフィティを実際のプロジェクトで本当に使っている人は少ないと思いますし、フォトエディターとして使っている人はさらに少なく、複数の写真を編集して、複数の写真を統一して保存・アップロードするという使い方をしている人はさらに少ないのではないでしょうか。ここで、私がやろうとしていることは、以下の通りです。以下、かつて書いたキャンバスの落書きをもとに、マルチピクチャーエディターの開発・思考過程を記録します。

画像編集ソフトの製品要件

まず第一に、要件は、実際の会社のプロジェクト開発に関連して、画像エディタのニーズを満たすために、ちょうど1枚の画像を編集することがありますが、あなたに複数の写真の編集は、ユーザーが保存する前に、ある写真のリストを与えることがあります、ユーザーは前後に切り替えることができますどの画像を編集する今すぐ。各写真編集操作は、元に戻すことができるようにすることであり、最終的に統一された保存ボタンをクリックすると、編集されていない 編集されていない画像は破棄され、落書きで編集されている画像は、サーバーにアップロードされることになります。

事前準備・必修事項

html2canvasの使用

html2canvasは、実際にWebページ上の普通のhtml要素をcanvasに変換するプラグインですが、なぜhtml要素をcanvasに変換するのでしょうか?それは、canvaにはcanvas上に絵や線を描くなどの操作ができたり、canvasに表示されている内容を画像に指示するapiが直接提供されていたりと、html要素にない機能がたくさんあるからです。スクリーンショットとちょっと似てませんか、html2canvasはこれを使っています。私がhtml2canvasを使い始めたのは、会社のh5プロジェクトで手書きボードの案件があったときです。手書きボードにサインをして、サイン後の画像をエクスポートしてアップロードする必要があったのです。その後、Web側の画像編集のプロジェクトがあり、再びhtml2canvasのこのプラグインを使用し、以下のようにプラグインを導入しました。

はじめに

html2canvasのデメリット。

html2canvas に変換されたキャンバスは、最終的な視覚効果において、元の要素に100%復元されないため、一部のピクセルが失われることになります。

html2canvasのインストール

npm install html2canvas


html2canvasの紹介

import html2canvas from 'html2canvas'


html2canvasの使用

画像(imgタグか背景画像)を含むhtml要素がcanvasに変換され、その生成されたcanvasからimgや背景画像が消えて白地になり、コンソールが「画像がドメインを越えている」と言っている場合、解決方法は以下のようになります。
以下の第1条を満たした上で、第2条と第3条はhtml要素がimgタグか背景画像かによって、異なる設定項目を追加するためです。

1. 画像サーバーの設定 Access-Control-Allow-Originまたはproxyの使用
2. html2canvas の設定項目で useCORS:true を設定する。
3.imgタグにcrossOrigin='anonymous'を追加。

htmlをcanvasに変換し、画像のクロスドメイン問題を解決します。

html2canvas(dom, {
  useCORS: true, // background image cross-domain
  scale: window.devicePixelRatio,// pixel ratio
  width: dom.offsetWidth
  height: dom.offsetHeight
}).then(canvas => {
  //get base64
  let base64 = canvas.toDateUrl() 
})


html2canvasは通常のhtmlをcanvasに変換するもので、canvasには自身をbase64に変換するメソッドがあり、base64形式のファイルはimgタグのsrcとしてページに直接表示することができるため

<img :src='base64' />


この時点で、生成された画像をアップロードしたい場合、base64は直接アップロードできないので、base64をblob形式に変換する必要があります。つまり、以下のようになります。取得したbase64データをbase64ToBlob関数に渡し、関数が返す最終結果はblobデータです。注意:このメソッドは単にbase64をblobに変換する汎用的なメソッドです。

ベース64からブロブへ

function base64ToBlob(base64){
    var arr = base64.split(','), mime = arr[0].match(/:(. *?) ;/)[1],
        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return (new Blob([u8arr], { type: mime }))
}


実はcanvasには、canaをblobオブジェクトに変換するメソッドが用意されています。

キャンバスからブロブへ

canvas.toBlob(file=>{
    //at this point file is the blob data format.
    //After successfully uploading to a blob, you need to add the name attribute to the blob data, otherwise it will report an error later on when uploaded to the server: size not set
    file.name = 'cover.png'
})


しかし、実際のプロジェクト開発では、バージョンの低いモバイルブラウザでtoBlobメソッドをサポートしていないものがあり、toBlob is not a functionというエラーが発生するため、canvas.toBloメソッドをサポートしていないブラウザ用のポリフィルを行う必要があります。

DOM canvas 要素は HTMLCanvasElement インターフェースを公開し、canvas 要素のレイアウトとレンダリングを操作するためのプロパティとメソッドを提供します。(MDNより)

toBlobメソッドの互換性書き込み

if (!HTMLCanvasElement.prototype.toBlob) {
    Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
      value: function (callback, type, quality) {
        var binStr = atob(this.toDataURL(type, quality).split(',')[1])
        var len = binStr.length
        var arr = new Uint8Array(len)

        for (var i = 0; i < len; i++) {
          arr[i] = binStr.charCodeAt(i)
        }

        callback(new Blob([arr], { type: type || 'image/png' }))
     }
    })
}



上記のコードは、現在のブラウザが HTMLCanvasElement.prototype 内に toBlob メソッドを含んでいるかどうかを判断し、含んでいない場合は HTMLCanvasElement.prototype に toBlob メソッドを追加しています。
ここまでで、base64から直接blobでも、canvasから直接blobでも、最終目的は、blobデータをサーバーにアップロードすることです。現在のページのBLOBデータは、バッファではなく、コンピュータのローカルファイルのようにハードディスクに格納されていることに注意してくださいアップロードでは、isLocalFile:falseプロパティを追加する必要があるので、 fileDataプロパティは、配列、それが画像であれば、それはBLOB形式の要素を持つ長さ1の配列です受信します。サーバーへのファイルのアップロードについては、ここでは説明しません。

サーバーへのBLOB送信

// After transferring the image data, submit it to the server
    async upload (blobArr) {
      const oss = await this.$uploadOSS.init({
        fileData: blobArr,
        isLocalFile: false,
        onProgress: percent => {},
        onSuccess: (res) => {
          console.log(res)
        }
      })
      if (oss) {
        const data = await oss.start()
        if (!data.code) {
          this.$message.error(data.message)
        }
      }
    },


以上、html2canvasとcanvasの共通プロパティを紹介しましたが、画像エディタを開発するための前提条件となるものでもあります。以下は、既存のcanvas graffiti boardをベースにしたマルチピクチャーエディターの開発について、順を追って紹介するものである。

キャンバスベースの画像編集機はどうやるの?

1、画像を編集したいので、当然、画像のアドレスを提供する必要があります、それはローカルの相対パスまたはリモートアドレスかもしれない、またはそれは1つまたは複数の画像かもしれません。1の長さである唯一の画像がある場合ので、操作のためのデータ構造は、配列であり、画像のアドレスの配列の要素は、唯一の落書き部分、および背景白、アバターや写真を生成しないようにドメイン全体の画像を解決する必要性に加えて、上記の詳細なソリューションを提供しています失われました。

2、画像エディタは、確かに普遍的なコンポーネントなので、親コンポーネントによると、同じ長さの二次元配列を埋めるために、長さの配列の画像のsrcに渡され、二次元配列の要素は、各画像の歴史の記録は、編集コレクション、つまり、各操作時にキャンバスは、編集を開始する前にbase64データを生成しました当初、画像がデフォルトで空の配列で埋められます[]、ここでは配列を埋めるために良い方法ですが、それは注目に値するです。充填の内容が参照型である場合、それは充填の各項目は、要素のいずれかの操作で、残りのすべての要素が一緒に変更された結果、同じ参照になることが発生します。

//result: [[], [],...]
this.canvasArrBase = Array(length).fill(0).map(item => {
  return []
})


2. 別の画像をクリックして、エディタコンポーネントに画像のsrcを渡すと、キャンバスの背景画像としてsrcを使用して、この時点で視覚的に画像を参照してください、DOMで実際にsrcのようにキャンバスの背景画像です。
3、ページ上でキャンバスのペイントを開始し、表面などのタッチスクリーンデバイスでキャンバスのペイントや画像編集が使用できないことを避けるために、マウスイベントの代わりにタッチイベントを使用してください。

 // Start painting
  canvas.addEventListener('touchstart', e=> {
    ...
  },false)
  
  // drawing in progress
  canvas.addEventListener('touchmove', e=> { ...
   ...
  },false)
  
  // End drawing
  canvas.addEventListener('touchend', e=>{
    ...
  },false)


4. イメージエディタに入る前に、クリックされた画像のインデックスと、画像が配置されている画像配列を、プロパティーとして一緒にイメージエディタに渡します。この画像の上に落書きや取り消しの操作を記録するために、エディタ内の現在の画像の currentIndex を覚えておいてください。ユーザーがキャンバス上で各操作、つまり、touchstartを開始し、次にtouchmove、最後にtouchendを行うと、現在のキャンバスの内容(今描いたものだけでなく、すべての内容です。git のすべてのコミットと同様、たとえそれがコードの一行であっても、git は変更されたコードの行だけでなくプロジェクト全体のスナップショットを生成します。git rollback はスナップショットのロールバックです)、この背景画像を含む canvas.toDateUrl() を使用して base64 を生成し、この中に押し込まれます。 canvasArrBase[currenIndex], この時点で currenIndex 配列内の画像に追加の履歴、つまり今描いた絵が保存されたということを意味しています。これは、キャンバス画像エディタ、アンドゥの基本でもあり、これによってアンドゥ後に何を表示すればいいのかがわかります。

// The snapshot generated by the new dirt doodle operation is stored in the array of the current index
 this.canvasArrBase[this.currentIdex].push(canvas.toDataUrl())


5. 画像の切り替えは、canvas の背景画像を変更し、currentIndex を変更し、新しい currentIndex で別の画像を編集することも意味します。これは実際には同じ手順で、現在編集中の画像を、先ほど表示したすべてのコンテンツとともに canvas に押し出すだけです。
6、ポイントはここ、元に戻すにはどうしたらいいのか?どのように元に戻すには、どのようにキャンバスにステップバイステップで元に戻すと、最後の時間、最後の絵の記録を参照してください?
各画像の編集に伴い、各画像はいくつかの履歴を生成し、我々はこれらの履歴を使用して、元に戻す操作をロールバックしています。現在の編集中の画像で、アンドゥを一度クリックすると、最後のキャンバスに表示されていたキャンバスの内容を、現在のキャンバスに描画する必要があります。取り消すときに保存したデータソースを直接削除できるので、canvas.drawImage()メソッドを使って、表示する必要がある1つのレコードをcanvasキャンバスに描画すればよいのです。

は、その

drawImageメソッドにはいくつかの引数があり、使い方はクリックで をクリックすると詳細が表示されます。

let newBaseArr = this.canvasArrBase[this.currentIdex]
let { offsetWidth: canvasWidth, offsetHeight: canvasHeight } = canvas

//generate a new image
let image = new Image()

// the image's src is assigned to the current base64 value that needs to be displayed (i.e., so that the user can see the undo screen)
image.src = this.canvasArrBase[this.currentIdex][newBaseArr.length-1]
// After assigning a value to img's src, use onload to listen to the loading of the image, and then draw it when it's done, without adding onload it will most likely fail.
image.onload = function () {
    canvas.drawImage(image, 0, 0, canvasWidth, canvasHeight)
}



7. パフォーマンスの最適化について。ユーザーがどの程度の大きさの写真を編集するか分からないので、仮に9枚の写真があり、それぞれの写真を10回編集した場合、メモリ上に存在するbase64データの量が非常に多くなり、ページ切り替え時や写真の落書き履歴を元に戻す時にページラグが発生する可能性があります。このような事態を避けるために、画像を切り替える前に、現在の画像の最後の画像のbase64だけを保存するようにします。 {これを避けるために、画像を切り替える前に、私は最後の画像のbase64だけを格納します。
8, submit, save の前に this.canvasArrBase の各項目の長さを判定し、0より大きい場合は編集し、それ以外はフィルタリングします。あとは、先ほど紹介したuploadメソッドを使って、サーバーにアップロードすれば、OKです

概要

echartやGaodeMapなど、身近なツールがcanvasをベースに作られていないことに、canvasを学ぶ過程でいつも驚きと感動を覚えます。以前、同僚にエチャートチャートの神様がいたのですが、彼の影響でだんだんエチャートの威力がわかってきましたので、このようなオープンソースのコミュニティで皆さんと一緒に学び、進歩していければと思います。

この記事は、キャンバスの複数の画像エディタを実現する方法について紹介されていますここで、キャンバス画像エディタの詳細な関連コンテンツは、スクリプトの家の前の記事を検索するか、次の関連記事を閲覧を続けてください、あなたを願っています。