この記事では、Vueでアップロードされた画像に透かしを追加する具体的な実装コードを参考までに共有します。具体的な内容は次のとおりです。 1. カプセル化と透かしの方法 /** * 透かしを追加 * @param {blob} ファイル * @param {文字列} el * @returns {Promise} */ 非同期関数 addWaterMarker(file, el = '#markImg') をエクスポートします。 新しい Promise(async (resolve, reject) => { を返します。 試す { // 最初に画像を圧縮して回転します。file = await compressed(file) // ファイル blob を画像に変換する let img = await blobToImg(file) // キャンバスを作成する let canvas = document.createElement('canvas') キャンバスの幅 = img.naturalWidth キャンバスの高さ = img.naturalHeight ctx = canvas.getContext('2d') とします。 // アップロードされた画像を塗りつぶす ctx.drawImage(img, 0, 0, canvas.width, canvas.height) // 透かし画像を生成する const markEle = document.querySelector(el) const markWidth = markEle.clientWidth 定数スケール = キャンバス.幅 * 0.25 / マーク幅 // 最初に透かしを拡大縮小してから画像に変換します markEle.style.transform = `scale(${scale})` const markImg = htmlToCanvas(markEle) を待機します // 透かしを塗りつぶす ctx.drawImage(markImg, canvas.width - markImg.width - 15 * scale, canvas.height - markImg.height - 15 * scale, markImg.width, markImg.height) //キャンバスをblobに変換する canvas.toBlob(blob => 解決(blob)) } キャッチ(エラー){ 拒否(エラー) } }) } 関数blobToImg(blob) { 新しい Promise を返します ((resolve, reject) => { リーダーを新しいFileReader()にします リーダー.addEventListener('load', () => { img = new Image() とします。 img.src = リーダー結果 img.addEventListener('load', () => 解決(img)) }) リーダー.readAsDataURL(blob) }) } エクスポート関数 htmlToCanvas(el, backgroundColor = 'rgba(0,0,0,.1)') { 新しい Promise(async (resolve, reject) => { を返します。 試す { const markImg = html2canvas(el, {を待つ scale: 2, //デフォルト値window.devicePixelRatioはここでは使用されません。モバイル側と一致させる必要がありますallowTaint: false, //汚染を許可しますuseCORS: true, backgroundColor //'transparent' //背景色}) 解決(マーク画像) } キャッチ(エラー){ 拒否(エラー) } }) } /** * 画像を圧縮して回転する * @param {blob} ファイル * @param {number} 品質圧縮率 * @param {number} 最大幅 * @returns {Promise} */ エクスポート関数コンプレッサー(ファイル、品質 = 0.6、最大幅 = 750) { 新しいPromiseを返します(resolve => { 新しいコンプレッサー(ファイル、{ 最大幅、 品質、 成功:解決、 エラー(err) { コンソールログ(エラーメッセージ) } }) }) } 2. プロジェクトでの使用 <!-- 画像のアップロード --> <div class="flex mt20" v-if="item.questionType === 4"> <バンアップローダー v-model="item.imgアップロード" 複数="true" 遅延読み込み :deletable="!isDisabled" :disabled="無効" @delete="handleDeleteImg({ ...引数, 項目 })" :before-read="handleBeforeImgUpload" :after-read="handleAfterImgUpload" @click.native="現在のアイテム = アイテム" /> </div> <スクリプト> 輸入 { タスクの詳細を取得、 ユーザー実行、 送信フロー、 拒否フロー、 } '@/api/myTask' から; '@/utils/oss' から { uploadOSS } をインポートします。 '@/utils' から parseTime、addWaterMarker をインポートします。 'vant' から ImagePreview をインポートします。 'compressorjs' から Compressor をインポートします。 const fileExtensions = ['xlsx', 'xls', 'docx', 'doc', 'pdf']; const quality = 0.2; //画像圧縮品質 export default { メソッド: { // アップロードする前に async handleBeforeImgUpload(img, detail) { もし(!img){ 戻る } 新しい Promise(async (resolve, reject) => { を返します。 Array.isArray(画像)の場合{ 画像の長さが5より大きい場合 this.$toast('一度に最大 5 枚の写真をアップロードできます。数回に分けてアップロードしてください。') 拒否する() } ブロブを [] にする for (const ファイル img) { // 512kより大きい画像は最初に圧縮されます if (file.size > 512 * 1024 && file.type.includes('image/')) { ファイル = this.compressor(ファイル) を待機します } // 透かしを追加 let blob = await addWaterMarker(file) blob.name = ファイル名 blobs.push(blob) } 解決(ブロブ) } それ以外 { // 512kより大きい画像は最初に圧縮する必要があります if (img.size > 512 * 1024 && img.type.includes('image/')) { img = this.compressor(img) を待機します } const blob = await addWaterMarker(img) blob.name = 画像名 解決(ブロブ) } }) }, //アップロード後 async handleAfterImgUpload(img, detail) { 試す { $読み込み中.表示() Array.isArray(画像)の場合{ img.forEach(async ({ファイル},インデックス) => { if (!file.name || !file.type.includes('image/')) { this.currentItem.imgUpload.splice(detail.index + index, 1) this.$toast('アップロードに失敗しました。写真のみアップロードできます!') // アップロード完了 if (index === img.length - 1) { $loading.hide() } return // forEach の return は continue と同等です } ファイルサイズが 1024 * 1024 * 10 より大きい場合 this.currentItem.imgUpload.splice(detail.index + index, 1) this.$toast('ファイルが大きすぎます。1 つのファイルは 10 MB を超えることはできません。') // アップロード完了 if (index === img.length - 1) { $loading.hide() } 戻る } 試す { const { ファイル名, url } = アップロードOSS(ファイル)を待つ this.currentItem.answer.push({ URL、 }) } キャッチ(エラー){ this.currentItem.imgUpload.splice(detail.index + index, 1) this.$toast('アップロードに失敗しました。しばらくしてからもう一度お試しください!') コンソール.エラー(エラー) } // アップロード完了 if (index === img.length - 1) { $loading.hide() } }) } それ以外 { if (!img.file.type.includes('image')) { this.currentItem.imgUpload.splice(詳細インデックス、1) $loading.hide() this.$toast('アップロードに失敗しました。アップロードできるのは写真のみです!') 戻る } (img.file.size >= 1024 * 1024 * 10) の場合 { this.currentItem.imgUpload.splice(詳細インデックス、1) $loading.hide() this.$toast('ファイルが大きすぎるため、10MB を超えることはできません。') 戻る } // 512kより大きい場合は、まず圧縮します。let file = img.file const { ファイル名, url } = アップロードOSS(ファイル)を待つ this.currentItem.answer.push({ URL、 }) $loading.hide() } } キャッチ(エラー){ this.currentItem.imgUpload.splice(詳細インデックス、1) $loading.hide() this.$toast('アップロードに失敗しました。しばらくしてからもう一度お試しください!') コンソール.エラー(エラー) } } } 指導してくださったロング兄弟に感謝します。 3. 効果は以下のとおりです 以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: 4 つの主要な SQL ランキング関数 ROW_NUMBER、RANK、DENSE_RANK、NTILE の使用方法の紹介
>>: Linux での中国語入力方法の問題を素早く解決する
成果を達成する要件/機能: CSS + HTML を使用してハートを描く方法。分析:正方形と 2 つ...
純粋な CSS で固定ヘッダーを実装するのが難しい主な理由は 2 つあります。まず、最大のシェアを持...
序文開発中は、インターフェース要求の繰り返しによってさまざまな問題が発生することがよくあります。ネッ...
意味Calcite は、Sql を SqlNode に解析し、次に SqlNode を特定のデータベ...
Google Reader で、JunChen が書いた「フロー理論と設計」というタイトルの投稿を見...
この記事では、例を使用して、MYSQL データベース テーブル構造を最適化する方法を説明します。ご参...
1. オーバーフローOverflow はオーバーフロー(コンテナ)です。コンテンツがコンテナを越える...
1. MySQL 5.7 のアンインストール1.1查看yum是否安裝過mysql CD yum li...
目次序文REDOログの生成REDOログ送信REDOログの保存と通知ユーザースレッドに通知要約する序文...
Docker-compose は GitLab をデプロイします1. Dockerをインストールする...
<br />jb51.net では、常に記事のセマンティクスを重視してきましたが、HTM...
MySQL でメタデータ ロックがブロックされている場所を確認する方法手順: 1. セッション1の実...
var() の紹介と使用法詳細 (MDN) IEは無効ですが、他の主流のブラウザは有効ですvar()...
SEO とセキュリティを考慮して、301 リダイレクトが必要です。以下の一般的な処理には Nginx...
質問Nginx は $remote_addr を実際の IP アドレスとして受け取りますが、実際には...