觸屏版
全國服務(wù)熱線:0571-87205688
登錄
注冊
客戶中心
關(guān)注云客
提問者:蝴蝶為誰開~ | 分類:代上活動 | 瀏覽468次 | 懸賞分:4積分 2017-04-04 06:00:05
點(diǎn)附件沒有反應(yīng)
我要回答
雪晴
其他鏈接: http://tgideas.qq.com/webplat/info/news_version3/804/808/811/m579/201409/278736.shtml 從iOS 6+、Android 3+開始 (來源http://mobilehtml5.org/),移動端可以通過網(wǎng)頁中的來拍照上傳或是上傳相冊中的照片。 不過從圖片上傳到服務(wù)器后可能會遇到圖片莫名其妙旋轉(zhuǎn)的問題,如圖 default 一些設(shè)備在拍照時明明是豎著拍的(右),傳到服務(wù)端后從圖片查看器中看到的是橫著的(左),而在一些圖片處理工具或是瀏覽器中通過http協(xié)議看到的卻是正常的,原因是在照片的exif中的Orientation屬性控制了照片的旋轉(zhuǎn)方向。 //Exif 信息示例 Exif.Image.Make Ascii 6 Canon Exif.Image.Model Ascii 20 Canon PowerShot S40 Exif.Image.Orientation Short 1 top, left Exif.Image.XResolution Rational 1 180 Exif.Image.YResolution Rational 1 180 Exif.Image.ResolutionUnit Short 1 inch Exif.Image.DateTime Ascii 20 2003:12:14 12:01:44 Exif.Image.YCbCrPositioning Short 1 Centered ...... 大部分圖片查看器和編輯工具都會去根據(jù)這個屬性控制照片方向,而windows自帶的查看器等工具并不理睬他。 為什么要有Orientation屬性呢,我并沒有找到官方的解釋,見到種說法挺有道理:幾乎所有的攝像頭在出場的時候成相芯片都是有方向的,拍出來的照片的像素都是默認(rèn)方向的。如果每拍一張照片就對這些像素進(jìn)行旋轉(zhuǎn),如果數(shù)碼相機(jī)每秒連拍20張來算,旋轉(zhuǎn)操作將會非常耗時。更聰明的做法是拍照時只記錄一個方向,然后顯示的時候按方向顯示出來即可。因此exif定義了一個標(biāo)準(zhǔn)的方向參數(shù),只要讀圖的軟件都來遵守規(guī)則,加載時候讀取圖片方向,然后做相應(yīng)的旋轉(zhuǎn)即可。這樣既可以達(dá)到快速成像的目的,又能達(dá)到正確的顯示。 orient_flag2 修正圖片方向的問題 為了圖片顯示不出問題,我們得修改Orientation屬性。首先想到的是服務(wù)端來修正方案,對于圖片來說exif信息不是必須的,可以根據(jù)Orientation的值來對照片進(jìn)行手動矯正的操作,然后再去掉exif,類似這樣: switch(exif['Orientation']){ case 2: image->save; break; case 3: image->rotate(-180)->save; break; case 4: image->rotate(180)->save; break; ······ } 更好的方式是用一些圖片工具自動處理,GraphicsMagick和Imagemagick用來處理這個再合適不過了,他倆都可以用對圖像進(jìn)行旋轉(zhuǎn)、裁剪、縮放、替換顏色;添加文本、水印、圖形等常見操作,GraphicsMagick是從Imagemagick分支出來的,他倆有著幾乎一樣的API,可以在命令行工具中輕松操作。這里我用的是GraphicsMagick,他更輕便,易裝易用。在Java、PHP、Nodejs等常見后端語言中可以用相關(guān)庫輕松的操作GraphicsMagick的API。 后端以Nodejs為例。首先你需要在你的機(jī)器上安裝GraphicsMagick。 然后npm install gm 模塊就可以了。gm提供的接口非常友好,你只要 gm('/path/to/img.jpg') .autoOrient() .resize(240, 240) .write('/path/to/new.jpg', function (err) { if (err) ... }) 這樣就已經(jīng)完成了圖片的自動修正方向和壓縮尺寸的工作。 異步上傳圖片 傳統(tǒng)提交表單方式放在今天已經(jīng)不能忍了,XHR2中支持把文件放在Formdata對象中異步提交,只考慮移動端,就可以舍棄iframe之類的兼容方案了。核心代碼這樣: var xhr = new XMLHttpRequest(); var formData = new FormData(); formData.append('file', input.files[0]); xhr.open('POST', form.action); xhr.send(formData); XHR2中還可以通過process事件來監(jiān)聽進(jìn)度,實(shí)現(xiàn)類似進(jìn)度條的功能 xhr.onprogress = updateProgress; xhr.upload.onprogress = updateProgress; function updateProgress(event) { if (event.lengthComputable) { var percentComplete = event.loaded / event.total; ...... } } 用FormData發(fā)送的請求頭中你的Content-Type 會變成這樣 multipart/form-data; boundary=----WebKitFormBoundaryyqVkWF3PcCpAzZp9,如果上傳時要附帶參數(shù)也可以直接append到formData里。 然后Nodejs中可以用connect-busboy來接收文件,在express框架中大概是這樣: var express = require('express'), http = require('http'), fs = require('fs'), busboy = require('connect-busboy'), gm = require('gm'); var app = express(); app.use(busboy()); ..... app.post('/upload', function(req, res) { req.busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { ...... file.on('end', function () { gm(filePath) .autoOrient() .thumbnail(200, 200) .write(fullname, function(err){ if (err) return console.dir(arguments) res.json({ ...... }); } ) }); file.pipe(fs.createWriteStream(filePath)); }); req.pipe(req.busboy); }); ...... app.listen(3001); 前端壓縮圖片 圖片上傳的主體工作算是完成了,不過現(xiàn)在手機(jī)隨便拍張照片就是一兩兆,wifi環(huán)境下不說,移動網(wǎng)絡(luò)通過這方案上傳照片就有點(diǎn)坑了。手機(jī)客戶端中一般會先壓縮圖片再上傳,Web中如何實(shí)現(xiàn)壓縮后上傳呢? 可以把圖片讀到canvas中,然后用canvas.toDataURL()接口輸出畫布的base64編碼,再把base64編碼轉(zhuǎn)成Blob塞到Formdata里傳到后端。這樣即可以壓縮圖片減少流量,又可以在前端就修正圖片旋轉(zhuǎn)的問題。(Discuss:直接把base64傳到后端是否可行呢,后面試一試) canvasResize這個庫已經(jīng)把一切封裝好了https://github.com/gokercebeci/canvasResize ,同時他依賴Exif.js 修正了因Orientation屬性產(chǎn)生的旋轉(zhuǎn)問題。前端主要的代碼: var file = input.files[0]; canvasResize(file, { width: 300, height: 0, crop: false, quality: 100, callback: function(data, width, height) { var blob = canvasResize('dataURLtoBlob', data); var form = new FormData(); form.append('file',blob); $.ajax({ type: 'POST', url: server, data: form, contentType: false, processData: false, }).done(function (res) { ...... }).fail(function () { ...... }).always(function () { ...... }); } }); Nodejs中代碼可以參考前面的,繼續(xù)用connect-busboy模塊接收文件。 實(shí)際測試一下iOS沒問題,Android 4 有些機(jī)型不行,貌似修改過file的Blob數(shù)據(jù)發(fā)到服務(wù)端的數(shù)據(jù)字節(jié)就會為0 這是安卓的bug https://code.google.com/p/android/issues/detail?id=39882 。 網(wǎng)上有人給出的解決方案是用FileReader把文件讀出來,然后把整個二進(jìn)制文件當(dāng)請求發(fā)到服務(wù)端,這種方式要附帶參數(shù)的話只能放url里了。 var reader = new FileReader(); reader.onload = function() { $.ajax({ type: 'POST', url: server, data: this.result, contentType: false, processData: false, beforeSend: function (xhr) { xhr.overrideMimeType('application/octet-stream'); }, }).done(function (res) { ...... }).fail(function () { ...... }).always(function () { ...... }); }; reader.readAsArrayBuffer(file); 后端在接收這些數(shù)據(jù)時,會是一段一段的,我是用的拼接的方式處理 app.post('/upload', function(req, res) { var imagedata = ''; req.setEncoding('binary'); req.on('data', function (chunk) { imagedata += chunk }); req.on('end', function (chunk) { fs.writeFile(filePath, imagedata, 'binary', function(err){ if (err) throw err res.json({ ...... }); }) }); }); 實(shí)測一下,稍低端的的安卓上有點(diǎn)卡,畢竟處理一張圖片的運(yùn)算量可不小,目測目前用前端壓縮上傳方案的不多,至少微博觸屏版 (http://m.weibo.cn/) 就是把原始圖片直接上傳的,這種方式是否適合直接使用或者還有哪些可以優(yōu)化的地方有待驗(yàn)證。 這里有一個完整的demo https://github.com/xiangpaopao/mobile-upload-demo 包括上面提到的兩種方案 使用的話,依次安裝GraphicsMagick > npm install > node app.js
百度搜索推出驚雷算法,嚴(yán)厲打擊通過刷點(diǎn)擊排名
2017年11月20日
任務(wù):
任務(wù):
任務(wù):
任務(wù):
任務(wù):
任務(wù):
任務(wù):
任務(wù):