关闭

png图片里加自定义数据

标签: as3flex
1219人阅读 评论(0) 收藏 举报
分类:

有许多的应用中,图片要和数据一起使用!比较常见的做法是,加xml文件之类的表来描述!

其实可以直接把数据写在图片里!

做法很简单!我写了点代码,大家可以参考下!

https://hub004.xindong.com/yangyiqiang/AvatarTool/blob/master/src/utils/As3PngEncoder.as

原理就是把PNG数据格式中的IEND给替换成你要的数据!

上面的类库里面是把png和xml合并到一起的!要说明一点,如果图片用工具压缩的话,数据可能会掉的!一般要把图片压好,把自己的数据放进去的!

上面是写入的方法!

读出方法如下:

package utils {
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;


	/**
	 * @author yangyiqiang
	 */


	/*******************************
	PNGDecoder
	Author: Jerion
	
	A class that decodes png byte arrays and generates a bitmapdata.
	This is my first attempt at decoding images, so there are a lot of
	things that are not implemented.
	
	So far, it can only decode truecolour with alpha png images with
	no interlacing, no filter, and bit depth of 8.
	 ********************************/
	public class PNGDecoder {
		private const IHDR : uint = 0x49484452;
		private const PLTE : uint = 0x504c5445;
		private const IDAT : uint = 0x49444154;
		private const IEND : uint = 0x49454e44;
		private var imgWidth : uint = 0;
		private var imgHeight : uint = 0;
		// file info, but not used yet.
		private var bitDepth : uint = 0;
		private var colourType : uint = 0;
		private var compressionMethod : uint = 0;
		private var filterMethod : uint = 0;
		private var interlaceMethod : uint = 0;
		private var chunks : Array;
		private var input : ByteArray;
		private var output : ByteArray;


		public function PNGDecoder(ba : ByteArray = null) {
			chunks = new Array();
			input = new ByteArray();
			output = new ByteArray();


			input = ba;
			if(input)
			{
				input.position = 0;
				if (!readSignature()) throw new Error("wrong signature");
			}
		}


		public function getIendMessage(ba : ByteArray) :Object {
			chunks = new Array();
			input = new ByteArray();
			output = new ByteArray();


			input = ba;


			input.position = 0;


			if (!readSignature()) throw new Error("wrong signature");


			getIENDChunks();
			if (_IENDChunks) {
				input.position = _IENDChunks.position;
				var len : uint = _IENDChunks.length;
				var bytes:ByteArray=new ByteArray();
				bytes.writeBytes(input,input.position,len);
				bytes.position=0;
				return bytes.readObject();
			}
			return null;
		}


		// recieves the bytearray and returns a bitmapdata
		public function decode(ba : ByteArray) : BitmapData {
			chunks = new Array();
			input = new ByteArray();
			output = new ByteArray();


			input = ba;


			input.position = 0;


			if (!readSignature()) throw new Error("wrong signature");


			getChunks();


			for (var i : int = 0; i < chunks.length; ++i) {
				switch(chunks[i].type) {
					case IHDR:
						processIHDR(i);
						break;
					// case PLTE: processPLTE(i); break;
					case IDAT:
						processIDAT(i);
						break;
					// case IEND: processIEND(i); break;
				}
			}


			// Since the image is inverted in x and y, I have to flip it using a Matrix object. There should be a better solution for this..
			var bd0 : BitmapData = new BitmapData(imgWidth, imgHeight);
			var bd1 : BitmapData = new BitmapData(imgWidth, imgHeight, true, 0xffffff);


			if (output.length > 0 && (imgWidth * imgHeight * 4) == output.length) {
				output.position = 0;
				bd0.setPixels(new Rectangle(0, 0, imgWidth, imgHeight), output);


				var mat : Matrix = new Matrix();
				mat.scale(-1, -1);
				mat.translate(imgWidth, imgHeight);


				bd1.draw(bd0, mat);
			}


			return bd1;
		}


		// read the header of the image
		private function processIHDR(index : uint) : void {
			input.position = chunks[index].position;


			imgWidth = input.readUnsignedInt();
			imgHeight = input.readUnsignedInt();


			// file info, but is not used yet
			bitDepth = input.readUnsignedByte();
			colourType = input.readUnsignedByte();
			compressionMethod = input.readUnsignedByte();
			filterMethod = input.readUnsignedByte();
			interlaceMethod = input.readUnsignedByte();
		}


		// This can't handle multiple IDATs yet, and it can only decode filter 0 scanlines.
		private function processIDAT(index : uint) : void {
			var tmp : ByteArray = new ByteArray();


			var pixw : uint = imgWidth * 4;


			tmp.writeBytes(input, chunks[index].position, chunks[index].length);
			tmp.uncompress();


			for (var i : int = tmp.length - 1; i > 0; --i) {
				if (i % (pixw + 1) != 0) {
					var a : uint = tmp[i];
					var b : uint = tmp[i - 1];
					var g : uint = tmp[i - 2];
					var r : uint = tmp[i - 3];


					output.writeByte(a);
					output.writeByte(r);
					output.writeByte(g);
					output.writeByte(b);


					i -= 3;
				}
			}
		}


		private function getChunks() : void {
			var pos : uint = 0;
			var len : uint = 0;
			var type : uint = 0;


			var loopEnd : int = input.length;


			while (input.position < loopEnd) {
				len = input.readUnsignedInt();
				type = input.readUnsignedInt();
				pos = input.position;


				input.position += len;
				input.position += 4;
				// crc block. It is ignored right now, but if you want to retrieve it, replace this line with "input.readUnsignedInt()"
				chunks.push({position:pos, length:len, type:type});
			}
		}


		private var _IENDChunks : Object;
		private var _pos : uint = 0;
		private var _len : uint = 0;
		private var _type : uint = 0;


		public function getIENDChunks() : Object {
			_pos = 0;
			_len = 0;
			_type = 0;


			var loopEnd : int = input.length;


			while (input.position < loopEnd) {
				_len = input.readUnsignedInt();
				_type = input.readUnsignedInt();
				if (_type == IEND) {
					_pos = input.position;
					_IENDChunks = {position:_pos, length:_len, type:_type};
					return _IENDChunks;
				} else {
					input.position += _len;
					input.position += 4;
				}
			}
			return _IENDChunks;
		}


		private function readSignature() : Boolean {
			return (input.readUnsignedInt() == 0x89504e47 && input.readUnsignedInt() == 0x0D0A1A0A);
		}


		// transform the chunk type to a string representation
		private function fixType(num : uint) : String {
			var ret : String = "";
			var str : String = num.toString(16);


			while (str.length < 8) str = "0" + str;


			ret += String.fromCharCode(parseInt(str.substr(0, 2), 16));
			ret += String.fromCharCode(parseInt(str.substr(2, 2), 16));
			ret += String.fromCharCode(parseInt(str.substr(4, 2), 16));
			ret += String.fromCharCode(parseInt(str.substr(6, 2), 16));


			return ret;
		}
	}
}

因为我这边是把数据直接writeObject了!所以只提供了个
public function getIendMessage(ba : ByteArray) :Object
自己用时,可以换成你所希望的!个人认为还是用writeObject好点!解析成数据时效率会高点

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:41209次
    • 积分:634
    • 等级:
    • 排名:千里之外
    • 原创:17篇
    • 转载:1篇
    • 译文:0篇
    • 评论:42条
    文章分类
    最新评论