アバターのアップロードを処理するための HTML5 Canvas の画像とテキスト コードの詳細な紹介

黄舟
リリース: 2017-03-07 16:02:15
オリジナル
1750 人が閲覧しました

最近、コミュニティ システムは、ユーザー アバターのアップロードを伴うモバイル端末をサポートする必要があります。アバターには、大、中、小の 3 つのサイズがあります。PC 側では、コミュニティはアバターの編集と編集を処理します。これらの問題を考慮して、画像サイズのスケーリングと画像データの取得を完了するために、最終的に Canvas を選択しました。

等辺処理

アバターは通常正方形です。まず画像の幅と高さの最小値を取得し、その最小値を辺の長さとして使用して画像を中央で切り抜き、最後に正方形の画像を取得する必要があります。

var ImageEditor = function() {
    // 用离线canvas处理图片数据
    this.canvas = document.createElement('canvas');
    this.context = this.canvas.getContext('2d');
};
var fn = ImageEditor.prototype;
fn.resizeCanvas = function(width, height) {
    this.canvas.width = width;
    this.canvas.height = height;
};
fn.clipSquareImage = function(url, callback) {
    var that = this,
        img = new Image();
    img.src = url;
    img.onload = function() {
        // 取宽高最小值作为正方形边长
        var eLength = Math.min(img.width, img.height),
            picture = img;
        // canvas不支持局部截屏,截屏前必须先调节canvas的宽高
        that.resizeCanvas(eLength, eLength);
        // 将图片以居中裁剪的方式画到canvas中。
        // drawImage支持9个参数:图片对象,图片上的剪切坐标XY,
        // 剪切宽高,图片在canvas上的坐标XY及图片宽高
        that.context.drawImage(picture,
            (picture.width - eLength) / 2, (picture.height - eLength) / 2,
            eLength, eLength, 0, 0, eLength, eLength);
        // 截屏,即获取base64数据
        callback.call(that, that.canvas.toDataURL('image/png'));
    };
};
ログイン後にコピー

Canvas 要素のサイズ制限 問題

上記の clipSquareImage 関数では、canvas.toDataURL インターフェイスが幅と高さのパラメーターを提供していないため、画面をキャプチャすることしかできません。キャンバス全体のデータを一度に取得できるため、Canvas を使用する場合は、スクリーンショットを撮る前に、まず Canvas 要素のサイズを設定する必要があります。ただし、モバイル写真の解像度は非常に高く、幅と高さはほとんどが 3000 を超えています。写真の最小幅と高さに基づいて Canvas のサイズを設定すると、Canvas 要素の最小幅も次のようになります。高くても3000以上。

clipSquareImage函数中,由于canvas.toDataURL接口不提供宽高参数,只能够一次性把整个canvas的屏幕数据截取下来,所以在对Canvas截屏前,我们必须先设置Canvas元素的大小。然而移动端拍照的分辨率极高,宽高大多会在3000以上,当我们根据相片宽高的最小值来设置Canvas的尺寸时,Canvas元素的最小宽度也高达到3000以上。

问题在于,每个平台对Canvas的大小都有限制,如果Canvas的宽度或高度任意一个值超过了平台限制,Canvas将无法进行渲染,canvas.toDataURL只能获取一张透明的图片数据。

Maximum size of a canvas element中提到了部分平台下Canvas的尺寸限制:

chrome          = 32767x32767
iPod Touch 16GB = 1448x1448
iPad Mini       = 2290x2289
iPhone 3        = 1448x1448
iPhone 5        = 2290x2289
ログイン後にコピー

参考以上数据,我们先给Canvas设置一个最大的宽度:

var MAX_WIDTH = 1000;
ログイン後にコピー

clipSquareImage函数中加入最大宽度的检测,如果超过限制,则创建一个临时的canvas进行图片缩放处理,最后对该临时的Canvas进行居中剪切:

fn.clipSquareImage = function(url, callback) {
    var that = this,
        img = new Image();
    img.src = url;
    img.onload = function() {
         // 取图片宽高和Canvas的最大宽度的最小值作为等边长
        var eLength = Math.min(img.width, img.height, MAX_WIDTH),
            // 剪切对象
            picture = img,
            tempEditor,
            ratio;
            // 如果图片尺寸超出限制
            if (eLength === MAX_WIDTH) {
                // 创建一个临时editor
                tempEditor = new ImageEditor();
                ratio = img.width / img.height;
                // 按图片比例缩放canvas
                img.width < img.height ?
                    tempEditor.resizeCanvas(MAX_WIDTH * ratio, MAX_WIDTH) :
                    tempEditor.resizeCanvas(MAX_WIDTH, MAX_WIDTH / ratio);
                tempEditor.context.drawImage(img, 0, 0, tempEditor.canvas.width, tempEditor.canvas.height);
                // 将临时Canvas作为剪切对象
                picture = tempEditor.canvas;
                eLength = Math.min(tempEditor.canvas.width, tempEditor.canvas.height);
            }
            // 居中剪切
            // ... ...
            // 截屏操作
            // ... ...
    };
};
ログイン後にコピー

Canvas锯齿问题

上面我们已经能够通过Canvas裁剪出一张正方形的图片,接下来我们还需要处理头像图片大中小三种尺寸。在Canvas中,drawImage接口提供非常方便的缩放功能:

var editor = new ImageEditor;
// 将图片缩放到300x300
// drawImage支持5个参数:图片对象,及图片在canvas上的坐标和宽高
editor.context.drawImage(squareImage, 0, 0, 300, 300);
ログイン後にコピー

然而大尺寸图片直接用drawImage进行缩小处理会导致图片出现锯齿。在stack overflow上HTML5 canvas drawImage: how to apply antialiasing提出了一个方案:对图片进行若干次的等比例缩小,最后再放大到目标尺寸:

アバターのアップロードを処理するための HTML5 Canvas の画像とテキスト コードの詳細な紹介

参考这个方案,我们可以实现antialiasScale抗锯齿缩放函数:

fn.antialisScale = function(img, width, height) {
    var offlineCanvas = document.createElement(&#39;canvas&#39;),
        offlineCtx = offlineCanvas.getContext(&#39;2d&#39;),
        sourceWidth = img.width,
        sourceHeight = img.height,
        // 缩小操作的次数
        steps = Math.ceil(Math.log(sourceWidth / width) / Math.log(2)) - 1,
        i;
    // 渲染图片
    offlineCanvas.width = sourceWidth;
    offlineCanvas.height = sourceHeight;
    offlineCtx.drawImage(img, 0, 0, offlineCanvas.width, offlineCanvas.height);
    // 缩小操作
    // 进行steps次的减半缩小
    for(i = 0; i < steps; i++) {
        offlineCtx.drawImage(offlineCanvas, 0, 0,
            offlineCanvas.width * 0.5, offlineCanvas.height * 0.5);
    }
    // 放大操作
    // 进行steps次的两倍放大
    this.context.drawImage(offlineCanvas, 0, 0,
        offlineCanvas.width * Math.pow(0.5, steps), 
        offlineCanvas.height * Math.pow(0.5, steps),
        0, 0, width, height);
};
ログイン後にコピー

我们可以用这个函数代替drawImage完成缩放工作,生成头像图片的三种尺寸:

fn.scaleSquareImage = function(url, sizes, callback) {
    var that = this;
    // 先裁剪一个正方形
    that.clipSquareImage(url, sizes, function(data) {
        var squareImage = new Image(),
            result = [],
            i;
        squareImage.src = data;
        // 抗锯齿缩放
        for (i = 0; i < sizes.length; i++) {
            that.antialisScale(squareImage, sizes[i], size[i]);
            result.push(that.canvas.toDataURL(&#39;image/png&#39;));    
        }
        callback.call(that, result);
    });
};
ログイン後にコピー

PHP存储base64图片数据

Canvas.toDataURL()获取的默认图像数据格式是:data:image/png;base64, + base64数据:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC
ログイン後にコピー

当把Canvas截屏数据传给后台时,后台需要截断开头的字段data:image/png;base64,問題は、各プラットフォームで Canvas のサイズに制限があることです。Canvas の幅または高さの値がプラットフォームの制限を超えると、Canvas は canvas.toDataURL をレンダリングできなくなります。 > 透過画像データしか取得できません。

Canvas 要素の最大サイズには、一部のプラットフォームでの Canvas のサイズ制限が記載されています:

<?php
    $imgData = $_POST[&#39;imgData&#39;];
    // 截取有用的部分
    list($type, $imgData) = explode(&#39;;&#39;, $imgData);
    list(, $imgData)      = explode(&#39;,&#39;, $imgData);
    // base64 编码中使用了加号,
    // 如果通过url传递base64数据,+号会转换成空格
    $imgData = str_replace(&#39; &#39;, &#39;+&#39;, $imgData);
    // 存储文件
    $success = file_put_contents(&#39;PATH/XXX.png&#39;, base64_decode($imgData));
ログイン後にコピー

    上記のデータを参照して、最初に Canvas の最大幅を設定します:
  • rrreee

    clipSquareImage 関数内最大幅の検出を追加し、制限を超えている場合は、画像を拡大縮小するための一時的なキャンバスを作成し、最後に一時的なキャンバスをセンターカットします:

    rrreee
  • キャンバスのエイリアシングの問題
  • 上記では、キャンバスを通じて画像をトリミングすることができました。正方形の画像の場合, 次に、アバター写真を大、中、小の 3 つのサイズで処理する必要があります。 Canvas では、drawImage インターフェイスが非常に便利なスケーリング機能を提供します:

    rrreee
  • ただし、drawImage を直接使用して大きなサイズの画像を縮小すると、画像がギザギザになって表示されます。スタック オーバーフローで、HTML5 キャンバスのdrawImage: アンチエイリアスを適用する方法は、解決策を提案しました。画像を同じ比率で数回縮小し、最後にターゲット サイズまで拡大します:
  • canvas HD スケーリング

  • このソリューションを参照して、antialiasScale アンチを実装できます。 -aliasing scaling 関数:
  • rrreee

    drawImage の代わりにこの関数を使用して、スケーリング作業を完了し、3 つのサイズのアバター画像を生成できます:

    rrreee
  • PHP は Base64 画像データを保存します
  • Canvas.toDataURL() 取得されるデフォルトの画像 データ形式は: data:image/png;base64, + Base64 データ:

    rrreee
  • Canvas のスクリーンショット データがバックグラウンドに渡されるとき、バックグラウンドは開始部分を切り詰める必要があります。フィールド data:image/png ;base64,、背後にある実際の Base64 データを取得します:
rrreee

Reference

PHP を使用して Base64 エンコードされた Canvas イメージを PNG ファイルに保存します

Html5 Canvas drawImage: アンチエイリアスを適用する方法

キャンバス要素の最大サイズ

base64データ文字列からサーバー側でPNG画像を保存する方法

jQueryでAjaxリクエストを使用してFormDataオブジェクトを送信する方法


上記は、HTML5 Canvas がアバターをアップロードするための画像とテキスト コードを詳細に処理するものです。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。

🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜 🎜
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!