検索
ホームページウェブフロントエンドH5 チュートリアルフロントエンドの画像のトリミングとアップロード機能を実装する方法

フロントエンドはローカルファイルを直接操作できないため、ユーザーがクリックしてファイルを選択するか、フラッシュなどのサードパーティコントロールを使用することになりますが、フラッシュは日に日に減少しているため、フラッシュの使用は減少しています。まだお勧めできません。同時に、HTML5 の台頭により、多くの API 制御が提供され、フロントエンドでネイティブ API を使用して画像を処理できるようになり、バックエンド サーバーの負荷が軽減され、使いやすくなりました。

最終的な効果は次のとおりです:

フロントエンドの画像のトリミングとアップロード機能を実装する方法

それにはいくつかの機能があり、1つ目はドラッグアンドドロップをサポートすること、2つ目は圧縮すること、3つ目はトリミングと編集を行うこと、4つ目はアップロードと編集を行うことです。アップロード進行状況の表示、以下 各機能の実装を順番に紹介します:

1. ドラッグアンドドロップして画像を表示します

ドラッグアンドドロップの読み取り機能は主に HTML5 のドラッグイベントをリッスンするためのものです。これを行う方法は、API を確認することでわかります。重要なのは、ユーザーがドラッグした画像を読み取り、ローカル表示用に Base64 に変換する方法です。

ドラッグ アンド ドロップ イベントをリッスンします

varhandler={
    init:function($container){
        //需要把dragover的默认行为禁掉,不然会跳页
        $container.on("dragover",function(event){
            event.preventDefault();
        });
        $container.on("drop",function(event){
            event.preventDefault();
            //这里获取拖过来的图片文件,为一个File对象
            varfile=event.originalEvent.dataTransfer.files[0];
            handler.handleDrop($(this),file);
        });
     }
}

コードの 10 行目で画像ファイルを取得し、それを処理のために 11 行目に渡します。

input が使用されている場合は、input の変更イベントをリッスンします:

        $container.on("change","input[type=file]",function(event){
            if(!this.value)return;
            varfile=this.files[0];
            handler.handleDrop($(this).closest(".container"),file);
            this.value="";
        });

コードの 3 行目で、File オブジェクトを取得し、それを処理のために handleDrop にも渡します

次に、handleDrop 関数で、次のコンテンツを読み取ります。ファイルをbase64形式に転送します:

handleDrop:function($container,file){
    var$img=  $container.find("img");
    handler.readImgFile(file,$img,$container);
},

私のコードはreadImgFile関数も調整しました。主に大きなモジュールを逆アセンブルし、小さなモジュールを再利用するためのヘルパー関数がたくさんあります。

readImgFileで画像ファイルの内容を読み取ります:

FileReaderを使用してファイルを読み取ります

readImgFile:function(file,$img,$container){
    varreader=newFileReader(file);
    //检验用户是否选则是图片文件
    if(file.type.split("/")[0]!=="image"){
        util.toast("You should choose an image file");
        return;
    }  
    reader.onload=function(event){
        varbase64=event.target.result;
        handler.compressAndUpload($img,base64,file,  $container);
    }  
    reader.readAsDataURL(file);
}

ここでは、ファイルの内容はFileReaderを通じて読み取られ、readAsDataURLが調整されます。 このAPIは、バイナリ画像の内容をbase64形式に変換して読み取ることができます。完了後、onload イベントがトリガーされて表示され、onload にアップロードされます:

//获取图片base64内容
varbase64=event.target.result;
//如果图片大于1MB,将body置半透明
if(file.size>ONE_MB){
    $("body").css("opacity",0.5);
}
//因为这里图片太大会被卡一下,整个页面会不可操作
$img.attr("src",baseUrl);
//还原
if(file.size>ONE_MB){
    $("body").css("opacity",1);
}
//然后再调一个压缩和上传的函数
handler.compressAndUpload($img,file,$container);

画像のサイズが数 MB の場合、上記の 8 行目で表示されるときにスタックします。作者は Web ワーカーのマルチスレッドを使用しようとしました。この問題を解決するには、マルチスレッドにはウィンドウオブジェクトがなく、DOM を操作できないため、この問題をうまく解決できません。ページを空白にすることで、現在処理中であることをユーザーに伝え、しばらくお待ちください

ここで別の問題が発生します。つまり、写真が撮影された場合です。 iOS システムにより、水平方向に撮影されないため、ディスプレイ上で撮影された写真の回転角度に問題が発生します。次のような垂直方向に撮影された写真:

フロントエンドの画像のトリミングとアップロード機能を実装する方法

つまり、どのように撮っても、実際のiOS で保存された写真は横向きに配置されるため、ユーザーは手動で回転する必要があります。回転角度は exif データ構造に配置されており、これを読み取るには EXIF ライブラリを使用します。

exif 情報を読み取る

readImgFile:function(file,$img,$container){
    EXIF.getData(file,function(){
        varorientation=this.exifdata.Orientation,
            rotateDeg=0;
        //如果不是ios拍的照片或者是横拍的,则不用处理,直接读取
        if(typeoforientation==="undefined"||orientation===1){
            //原本的readImgFile,添加一个rotateDeg的参数
            handler.doReadImgFile(file,$img,$container,rotateDeg);
        }  
        //否则用canvas旋转一下
        else{
            rotateDeg=orientation===6?90*Math.PI/180:
                            orientation===8?-90*Math.PI/180:
                            orientation===3?180*Math.PI/180:0;
            handler.doReadImgFile(file,$img,$container,rotateDeg);
        }  
    });
}

角度がわかったら、 Canvas 処理では、圧縮でも Canvas を使用するため、次の圧縮画像について説明します

圧縮画像は、Canvas を使用して簡単に圧縮を実現できます。キャンバスのコンテンツを Base64 にエクスポートすると、圧縮された画像を取得できます:

//设定图片最大压缩宽度为1500px
varmaxWidth=1500;
varresultImg=handler.compress($img[0],maxWidth,file.type);

compress 関数で圧縮します。この関数では、最初にキャンバス オブジェクトを作成し、次にキャンバスのサイズを計算します。 Size:

compress:function(img,maxWidth,mimeType){
    //创建一个canvas对象
    varcvs=document.createElement('canvas');
    varwidth=img.naturalWidth,
        height=img.naturalHeight,
        imgRatio=width/height;
    //如果图片维度超过了给定的maxWidth 1500,
    //为了保持图片宽高比,计算画布的大小
    if(width>maxWidth){
        width=maxWidth;
        height=width/imgRatio;
    }  
    cvs.width=width;
    cvs.height=height;
}

次に、大きな画像を小さなキャンバスに配置し、エクスポートします。

圧縮処理

    //把大图片画到一个小画布
    varctx=cvs.getContext("2d").drawImage(img,0,0,img.naturalWidth,img.naturalHeight,0,0,width,height);
    //图片质量进行适当压缩
    varquality=width>=1500?0.5:
                    width>600?0.6:1;
    //导出图片为base64
    varnewImageData=cvs.toDataURL(mimeType,quality);
 
    varresultImg=newImage();
    resultImg.src=newImageData;
    returnresultImg;

最後の行は、圧縮された小さな画像を返します。これは切り取ることができます。

トリミングについて説明する前に、2番目のポイントでiOSで撮影した写真を回転する必要があると述べたので、圧縮するときに一緒に処理できます。つまり、回転する必要がある場合は、キャンバス上に描画して回転させます。

キャンバスを回転

varctx=cvs.getContext("2d");
vardestX=0,
    destY=0;
if(rotateDeg){
    ctx.translate(cvs.width/2,cvs.height/2);
    ctx.rotate(rotateDeg);
    destX=-width/2,
    destY=-height/2;
}
ctx.drawImage(img,0,0,img.naturalWidth,img.naturalHeight,destX,destY,width,height);

これにより、回転および圧縮された画像を取得した後、それをトリミングやトリミングに使用できます。編集

3. 画像をトリミングします

このプラグインは非常に強力で、トリミング、回転、反転をサポートしていますが、実際には画像を処理するだけです。ユーザーが行った変更を記録し、それを自分で処理します。変換されたデータは、処理のためにバックエンドに渡すことができます。 IE8と互換性がある必要がないため、ここではフロントエンドで処理します。

如下,我把一张图片,旋转了一下,同时翻转了一下:

フロントエンドの画像のトリミングとアップロード機能を実装する方法

它的输出是:

{
    height:319.2000000000001,
    rotate:45,
    scaleX:-1,
    scaleY:1,
    width:319.2000000000001
    x:193.2462838120872
    y:193.2462838120872
}

通过这些信息就知道了:图片被左右翻转了一下,同时顺时针转了45度,还知道裁剪选框的位置和大小。通过这些完整的信息就可以做一对一的处理。

在展示的时候,插件使用的是img标签,设置它的css的transform属性进行变换。真正的处理还是要借助canvas,这里分三步说明:

1. 假设用户没有进行旋转和翻转,只是选了简单地选了下区域裁剪了一下,那就简单很多。最简单的办法就是创建一个canvas,它的大小就是选框的大小,然后根据起点x、y和宽高把图片相应的位置画到这个画布,再导出图片就可以了。由于考虑到需要翻转,所以用第二种方法,创建一个和图片一样大小的canvas,把图片原封不动地画上去,然后把选中区域的数据imageData存起来,重新设置画布的大小为选中框的大小,再把imageData画上去,最后再导出就可以了:

简单裁剪实现

varcvs=document.createElement('canvas');
varimg=$img[0];
varwidth=img.naturalWidth,
    height=img.naturalHeight;
cvs.width=width;
cvs.height=height;
 
varctx=cvs.getContext("2d");
vardestX=0,
    destY=0;
ctx.drawImage(img,destX,destY);
 
//把选中框里的图片内容存起来
varimageData=ctx.getImageData(cropOptions.x,cropOptions.y,cropOptions.width,cropOptions.height);
cvs.width=cropOptions.width;
cvs.height=cropOptions.height;
//然后再画上去
ctx.putImageData(imageData,0,0);

代码14行,通过插件给的数据,保存选中区域的图片数据,18行再把它画上去

2. 如果用户做了翻转,用上面的结构很容易可以实现,只需要在第11行drawImage之前对画布做一下翻转变化:

canvas flip实现

//fip
if(cropOptions.scaleX===-1||cropOptions.scaleY===-1){
    destX=cropOptions.scaleX===-1?width*-1:0;      // Set x position to -100% if flip horizontal
    destY=cropOptions.scaleY===-1?height*-1:0;     // Set y position to -100% if flip vertical
    ctx.scale(cropOptions.scaleX,cropOptions.scaleY);
}
ctx.drawImage(img,destX,destY);

其它的都不用变,就可以实现上下左右翻转了,难点在于既要翻转又要旋转

3. 两种变换叠加没办法直接通过变化canvas的坐标,一次性drawImage上去。还是有两种办法,第一种是用imageData进行数学变换,计算一遍得到imageData里面,从第一行到最后一行每个像素新的rgba值是多少,然后再画上去;第二种办法,就是创建第二个canvas,第一个canvas作翻转,把它的结果画到第二个canvas,然后再旋转,最后导到。由于第二种办法相对比较简单,我们采取第二种办法:

同上,在第一个canvas画完之后:

实现旋转、翻转结合

ctx.drawImage(img,destX,destY);
//rotate
if(cropOptions.rotate!==0){
    varnewCanvas=document.createElement("canvas"),
        deg=cropOptions.rotate/180*Math.PI;
    //旋转之后,导致画布变大,需要计算一下
    newCanvas.width=Math.abs(width*Math.cos(deg))+Math.abs(height*Math.sin(deg));
    newCanvas.height=Math.abs(width*Math.sin(deg))+Math.abs(height*Math.cos(deg));
    varnewContext=newCanvas.getContext("2d");
    newContext.save();
    newContext.translate(newCanvas.width/2,newCanvas.height/2);
    newContext.rotate(deg);
    destX=-width/2,
    destY=-height/2;
    //将第一个canvas的内容在经旋转后的坐标系画上来
    newContext.drawImage(cvs,destX,destY);
    newContext.restore();
    ctx=newContext;
    cvs=newCanvas;
}

将第二步的代码插入第一步,再将第三步的代码插入第二步,就是一个完整的处理过程了。

最后再介绍下上传

4. 文件上传和上传进度

文件上传只能通过表单提交的形式,编码方式为multipart/form-data,这个我在《三种上传文件不刷新页面的方法讨论:iframe/FormData/FileReader》已做详细讨论,可以通过写一个form标签进行提交,但也可以模拟表单提交的格式,表单提交的格式在那篇文章已提及。

首先创建一个ajax请求:

varxhr=newXMLHttpRequest();
xhr.open('POST',upload_url,true);
varboundary='someboundary';
xhr.setRequestHeader('Content-Type','multipart/form-data; boundary='+boundary);

并设置编码方式,然后拼表单格式的数据进行上传:

ajax上传

vardata=img.src;
data=data.replace('data:'+file.type+';base64,','');
xhr.sendAsBinary([
    //name=data
    '--'+boundary,
        'Content-Disposition: form-data; name="data"; filename="'+file.name+'"',
        'Content-Type: '+file.type,'',
        atob(data),'--'+boundary,
    //name=docName
    '--'+boundary,
        'Content-Disposition: form-data; name="docName"','',
        file.name,
    '--'+boundary+'--'
].join('\r\n'));

表单数据不同的字段是用boundary的随机字符串分隔的。拼好之后用sendAsBinary发出去,在调这个函数之前先监听下它的事件,包括
1) 上传的进度:

xhr.upload.onprogress=function(event){
    if(event.lengthComputable){
        duringCallback((event.loaded/event.total)*100);
    }
};

这里凋duringCallback的回调函数,给这个回调函数传了当前进度的参数,用这个参数就可以设置进度条的过程了。进度条可以自己实现,或者直接上网找一个,随便一搜就有了。
2) 成功和失败:

xhr.onreadystatechange=function(){
    if(this.readyState==4){
        if(this.status==200){
            successCallback(this.responseText);
        }elseif(this.status>=400){
            if(errorCallback&&  errorCallback instanceofFunction){
                errorCallback(this.responseText);
            }      
        }      
    }
};

这个上传功能参考了一个JIC插件

至此整个功能就拆解说明完了,上面的代码可以兼容到IE10,FileReader的api到IE10才兼容,问题应该不大,因为微软都已经放弃了IE11以下的浏览器,为啥我们还要去兼容呢。

这个东西一来减少了后端的压力,二来不用和后端来回交互,对用户来说还是比较好的,除了上面说的一个地方会被卡一下之外。核心代码已在上面说明,完整代码和demo就不再放出来了。


声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
H5コードの分解:タグ、要素、属性H5コードの分解:タグ、要素、属性Apr 18, 2025 am 12:06 AM

HTML5コードは、タグ、要素、属性で構成されています。1。タグはコンテンツタイプを定義し、などの角度ブラケットに囲まれています。 2。要素は、startタグ、内容、および内容などのエンドタグで構成されています。 3。属性は、開始タグのキー値のペアを定義し、ような関数を強化します。これらは、Web構造を構築するための基本ユニットです。

H5コードの理解:HTML5の基礎H5コードの理解:HTML5の基礎Apr 17, 2025 am 12:08 AM

HTML5は、最新のWebページを構築するための重要なテクノロジーであり、多くの新しい要素と機能を提供します。 1。HTML5は、Webページの構造とSEOを強化するなどのセマンティック要素を導入します。 2。プラグインなしのマルチメディア要素と埋め込みメディアをサポートします。 3.フォームは、新しい入力タイプと検証プロパティを強化し、検証プロセスを簡素化します。 4.オフラインおよびローカルストレージ機能を提供して、Webページのパフォーマンスとユーザーエクスペリエンスを向上させます。

H5コード:Web開発者向けのベストプラクティスH5コード:Web開発者向けのベストプラクティスApr 16, 2025 am 12:14 AM

H5コードのベストプラクティスには以下が含まれます。1。正しいDoctype宣言と文字エンコーディングを使用します。 2。セマンティックタグを使用します。 3。HTTPリクエストを削減します。 4.非同期負荷を使用します。 5。画像を最適化します。これらのプラクティスは、Webページの効率、保守性、ユーザーエクスペリエンスを向上させることができます。

H5:Web標準とテクノロジーの進化H5:Web標準とテクノロジーの進化Apr 15, 2025 am 12:12 AM

Web標準とテクノロジーは、これまでにHTML4、CSS2、および単純なJavaScriptから進化し、重要な開発を受けてきました。 1)HTML5は、CanvasやWebstorageなどのAPIを導入し、Webアプリケーションの複雑さと互換性を高めます。 2)CSS3はアニメーション関数とトランジション関数を追加して、ページをより効果的にします。 3)JavaScriptは、矢印関数やクラスなど、node.jsおよびES6の最新の構文を通じて開発効率とコードの読みやすさを向上させます。これらの変更により、パフォーマンスの最適化とWebアプリケーションのベストプラクティスの開発が促進されました。

H5はHTML5の速記ですか?詳細の調査H5はHTML5の速記ですか?詳細の調査Apr 14, 2025 am 12:05 AM

H5はHTML5の略語だけでなく、より広い最新のWeb開発テクノロジーエコシステムを表しています。1。H5にはHTML5、CSS3、JavaScript、および関連するAPIおよびテクノロジーが含まれます。 2.より豊かでインタラクティブでスムーズなユーザーエクスペリエンスを提供し、複数のデバイスでシームレスに実行できます。 3. H5テクノロジースタックを使用して、レスポンシブWebページと複雑なインタラクティブ機能を作成できます。

H5およびHTML5:Web開発で一般的に使用される用語H5およびHTML5:Web開発で一般的に使用される用語Apr 13, 2025 am 12:01 AM

H5とHTML5は、同じこと、つまりHTML5を参照します。 HTML5はHTMLの5番目のバージョンであり、セマンティックタグ、マルチメディアサポート、キャンバスとグラフィックス、オフラインストレージ、ローカルストレージなどの新しい機能をもたらし、Webページの表現力と互換性を向上させます。

H5は何を参照していますか?コンテキストの探索H5は何を参照していますか?コンテキストの探索Apr 12, 2025 am 12:03 AM

H5ReferStoHtml5、apivotaltechnologyinwebdevelopment.1)html5introduceSnewelementsandapisforrich、dynamicwebapplications.2)Itupp ortsmultimediawithoutplugins、endancingurexperiencecrossdevices.3)semanticelementsimprovecontentstructurendseo.4)H5'srespo

H5:ツール、フレームワーク、およびベストプラクティスH5:ツール、フレームワーク、およびベストプラクティスApr 11, 2025 am 12:11 AM

H5開発で習得する必要があるツールとフレームワークには、Vue.JS、React、Webpackが含まれます。 1.Vue.jsは、ユーザーインターフェイスの構築に適しており、コンポーネント開発をサポートします。 2.複雑なアプリケーションに適した仮想DOMを介したページレンダリングを最適化します。 3.Webpackは、モジュールのパッケージングに使用され、リソースの読み込みを最適化します。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、