最近開始學習Flex開發,遇到一個需求:上傳圖片以前須要在本地先預覽圖片。可是有兩個問題:html
1.flex4裏面還不支持對*.tif 和 *.tiff格式的預覽,一方面多是由於tif圖的體積比較大,很是耗內存,另外一方也有多是由於tif圖片的格式比較複雜。git
2.Jpeg格式的圖片中顏色通道主要分爲三種:rgb,cmyk,grey。而cmyk的圖片在瀏覽器中顯示時顏色會失真。github
問題1沒有想到好的解決的辦法,雖然也在github上找到一個開源的讀取tif圖片的類庫,可是體積過大,預覽的時間很慢。關鍵的是tif格式的圖片中顏色通道爲cmyk的仍是不能正確的顯示。windows
下面是部分代碼,及測試效果:瀏覽器
import mx.controls.Alert; import com.utils.Tiff.TIFF6Decoder; private var tiffDecoder:TIFF6Decoder; private var byteArray:ByteArray; private function loadFile():void { var request:URLRequest = new URLRequest("images/1.tif"); var urlLoader:URLLoader = new URLLoader(request); urlLoader.addEventListener(Event.COMPLETE, onLoadComplete); urlLoader.dataFormat = URLLoaderDataFormat.BINARY; urlLoader.load(request); } private function onLoadComplete(e:Event):void { byteArray = e.target.data; tiffDecoder = new TIFF6Decoder(); if (tiffDecoder.decode(byteArray)) { img.source = new Bitmap(tiffDecoder.bitmapData); } else { Alert.show("Failed TIFF decoding"); } }
問題2的解決辦法是先判斷Jpeg圖片的顏色通道,若是是cmyk的,不顯示預覽圖,上傳以後顯示後臺返回的縮略圖。本文的目標就是要解決這個問題。函數
上傳前讀取圖片的width和height,網上已經有不少方法了。這一點bitmapdata本身就能夠作到,甚至不須要別的類庫。學習
示例:測試
//打開瀏覽文件窗口選擇要上傳的文件 private function browse(event:MouseEvent):void { var imageTypes:FileFilter = new FileFilter("圖片 (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg; *.jpeg; *.gif; *.png"); var allTypes:Array = new Array(imageTypes); fileReferenceList.browse(allTypes); } // 選擇文件後的處理 // 若選擇多個文件,每一個文件都須要一個FileReference進行處理 private function selectHandler(event:Event):void { for (var i:int = 0; i < fileReferenceList.fileList.length; i++) { var f:FileReference = FileReference(fileReferenceList.fileList[i]); //每一個文件對應的fileReference 監聽上傳成功後, 後臺返回參數的事件 f.addEventListener(Event.COMPLETE, loadCompleteHandler); f.load(); } trace("selectHandler Called!"); } // 本地預覽 private function loadCompleteHandler(event:Event):void { var loader:Loader = new Loader(); var file:FileReference = event.target as FileReference; if (file.size > 1024 * 1024 * 100) { Alert.show("文件不能超過100M.", "錯誤"); return; } loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void { var bmp:Bitmap = loader.content as Bitmap; var bmd:BitmapData; var scale:Number, width:Number, height:Number; trace("imgWidth:" + bmp.width + " imgHeight:" + bmp.height ); file.removeEventListener(Event.COMPLETE,loadCompleteHandler); }); loader.loadBytes(event.target.data); trace("loadCompleteHandler Called!"); }
可是這個方法也只能處理圖片的大小,不能判斷colorspace。通常圖片的文件頭部分存儲了關於這個圖片的全部相關信息,要想判斷Jpeg的colorspace,固然先得了解一下Jpeg的文件頭格式。flex
不看不知道,沒想到文件頭格式這麼複雜。不過還好,colorspace字段的存儲位置仍是相對固定的:ui
由上圖咱們能夠看到Jpeg中的S0F0字段存儲了colorspace信息,但在S0F0以前可能有一些APPn字段,這些字段須要先跳過去。所以,知道了colorspace的存放位置以後,代碼以下:
package com { import flash.net.URLStream; import flash.net.URLRequest; import flash.events.Event; import flash.events.ProgressEvent; import flash.utils.Endian; public class JpegColorSpaceExtractor extends URLStream { public static const PARSE_COMPLETE : String = "parseComplete"; public static const PARSE_FAILED : String = "parseFailed"; protected var jumpLength : uint; protected var stopWhenParseComplete : Boolean; protected var address : int; protected var dataLoaded : uint; protected var jpgWidth : uint; protected var jpgHeight : uint; protected var jpgColorSpace : int; // 構造函數 public function JpegColorSpaceExtractor() { // 設置字節序 endian = Endian.BIG_ENDIAN; } protected function progressHandler( e:ProgressEvent ) : void { // bytesAvailable 當前加載進來的數據 dataLoaded = bytesAvailable; var seg1: uint = 0; var seg2: uint = 0; while ( bytesAvailable ) { var match : Boolean = false; if ( jumpLength == 0 ) { seg1 = readUnsignedByte( ); address++; if(seg1 == 0xff){ seg2 = readUnsignedByte( ); address++; if(seg2 >= 0xE0 && seg2 <= 0xEF){ jumpLength = readUnsignedShort( ) - 2; address += 2; match = false; } if(seg2 >= 0xC0 && seg2 <= 0xCF){ readUnsignedShort( ); // 0x00 ox11 address += 2; jumpLength = 0; trace("find!!!"); match = true; } } } if ( jumpLength > 0 ) { if ( bytesAvailable >= jumpLength ) { jumpBytes( jumpLength ); jumpLength = 0; } else break; } if(match){ readUnsignedByte(); // bit depth jpgHeight = readUnsignedShort( ); // height jpgWidth = readUnsignedShort( ); // width jpgColorSpace = readUnsignedByte(); // colorSpace address += 6; removeEventListener( ProgressEvent.PROGRESS, progressHandler ); if ( stopWhenParseComplete && connected ){ close(); } dispatchEvent( new Event( PARSE_COMPLETE ) ); break; } } } protected function jumpBytes( count : uint ) : void { for ( var i : uint = 0; i < count; i++ ) { readByte( ); address++; } } protected function fileCompleteHandler( e : Event ) : void { if ( !jpgWidth || !jpgHeight || !jpgColorSpace ) dispatchEvent( new Event( PARSE_FAILED ) ); } public function extractJpegColorSpace( fileURL : String, stopWhenParsed : Boolean = true ) : void { addEventListener( ProgressEvent.PROGRESS, progressHandler ); addEventListener( Event.COMPLETE, fileCompleteHandler ); address = 0; dataLoaded = 0; jumpLength = 0; jpgColorSpace = 0; stopWhenParseComplete = stopWhenParsed; super.load( new URLRequest( fileURL ) ); } public function get loaded( ) : uint { return dataLoaded; } public function get width( ) : uint { return jpgWidth; } public function get height( ) : uint { return jpgHeight; } public function get colorSpace(): uint{ return jpgColorSpace; } } }
資料:
Image-MetaData-Jpeg:https://metacpan.org/release/Image-MetaData-JPEG
Getting Jpeg Dimensions: http://www.anttikupila.com/flash/getting-jpg-dimensions-with-as3-without-loading-the-entire-file/