Flex 学习笔记------读取Jpeg图片的width,height和colorSpace

最近开始学习Flex开发,遇到一个需求:上传图片之前需要在本地先预览图片。但是有两个问题:

  1.flex4里面还不支持对*.tif 和 *.tiff格式的预览,一方面可能是因为tif图的体积比较大,非常耗内存,另一方也有可能是因为tif图片的格式比较复杂。

  2.Jpeg格式的图片中颜色通道主要分为三种:rgb,cmyk,grey。而cmyk的图片在浏览器中显示时颜色会失真。

问题1没有想到好的解决的办法,虽然也在github上找到一个开源的读取tif图片的类库,但是体积过大,预览的时间很慢。关键的是tif格式的图片中颜色通道为cmyk的还是不能正确的显示。

下面是部分代码,及测试效果:

        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的文件头格式

不看不知道,没想到文件头格式这么复杂。不过还好,colorspace字段的存储位置还是相对固定的:

由上图我们可以看到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/

 

posted on 2013-07-19 15:43  花森  阅读(1066)  评论(1编辑  收藏  举报