最近开始学习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/