我没有经过一个正式的计算机科学培训/教育,所以我从来没有机会了解低层数据结构(比特和字节)工作机制。这一段时间我一直都想学习些这面的知识,但是很难找到相关资源,在不假设我有一个计算机科学学士学位的情况下。 昨天,FITC提交了“多伦多FITC所有视频会议”,我花了一些时间观看Lee Brimelow介绍的ByteArrays工作机制。他提供了明确而可靠的基础和理解ByteArrays和比特字节的工作机制。 不管怎么说,在看到Lee的会议后,我终于一切都安定了,昨晚花了些时间组建一个简单的解析器,在Flash中动态加载和显示一个24位BMP图像。 我将代码连同完整的意见随后张贴,提供一个简单的示例,向对较低级别的文件格式感兴趣的朋友做一个解释。 该代码需要Adobe AIR环境(所以我可直接加载BMP)。为了转换成浏览器中Flash Player可识别的,只需要替换文件调用FileReference.browse加载。
1. package 2. { 3. import flash.filesystem.File; 4. import flash.filesystem.FileStream; 5. import flash.filesystem.FileMode; 6.
7. import flash.display.Sprite; 8. import flash.display.BitmapData; 9. import flash.display.Bitmap; 10. import flash.utils.Endian; 11.
12. import flash.geom.Rectangle; 13.
14. [SWF(width='550', height='400', backgroundColor='#FFFFFF', frameRate='12')] 15. public class BMPViewer extends Sprite 16. { 17. private static const MAGIC_NUMBER:String = "BM"; 18. private static const BMP_DATA_OFFSET_POSITION:int = 0xA; 19. private static const WIDTH_POSITION:int = 0x12; 20. private static const HEIGHT_POSITION:int = 0x16; 21.
22. public function BMPViewer() 23. { 24. loadBMP(); 25. super(); 26. } 27.
28. /* 29. Loads and reads a 24 Bit bitmap file.加载读取24位BMP文件 30. 31. Based on BMP info from: 32. http://en.wikipedia.org/wiki/BMP%5Ffile%5Fformat 33. */ 34. private function loadBMP():void 35. { 36. //Load BMP. This requires AIR.加载BMP。需要AIR 37. //Use FileReference.browse for在Flash Player中用FileReference.browse 38.
39. //Flash Player 40. var bmpFile:File = new File("app:/image.bmp"); 41. var fs:FileStream = new FileStream(); 42.
43. //BMP files are Little Endian, which means their BMP采用little-endian存储机制 44. //least significant byte is first (right to left) 第一位是最低有效字节(从右到左) 45. fs.endian = Endian.LITTLE_ENDIAN; 46.
47. //open the file in READ mode打开文件至读取模式 48. fs.open(bmpFile, FileMode.READ); 49.
50. //check the first two bytes to make sure 51. //it is a valid BMP file检测BMP是否有效 52. if(fs.readUTFBytes(2) != MAGIC_NUMBER) 53. { 54. trace("FAIL : NOT A BMP FILE"); 55.
56. //not a BMP file, close steam 57. //and exit非BMP关闭流退出 58. fs.close(); 59. return; 60. } 61.
62. //note, we could also grab the length from the 63. //header and make sure the file was the correct 64. //length注意,我们还可以从头部抓取长度,并确保该文件长度是正确的 65.
66. //change the cursors position to the point 67. //in the header that contains the value / offset 68. //of where the actual bitmap data begins 69. //read in the 4 Bytes that contain the value fs.position = BMP_DATA_OFFSET_POSITION; 70. var dataPosition:int = fs.readInt(); 71.
72. //set cursor position to where the BMP 73. //width is stored 74. fs.position = WIDTH_POSITION; 75.
76. //read in the 4 Bytes that contain the width 77. var bmpWidth:int = fs.readInt(); 78.
79. //read in the 4 Bytes that contain the height 80. var bmpHeight:int = fs.readInt(); 81.
82. //set cursor to where the BMP pixel data begins 83. fs.position = dataPosition; 84.
85. var row:int = 0; 86. var column:int = 0; 87.
88. //every row length in a BMP file must bee a multiple 89. //of 4 (see the spec). So, we need to determine how much 90. //padding we need to add at the end of each line. 91. var padding:int = (bmpWidth % 4); 92.
93. //create a fixed length Vector to store the pixel 94. //values as we read them. 95. var pixels:Vector.<uint> = new Vector.<uint>(bmpWidth * bmpHeight, true); 96.
97. //loop through data (rows and columns) 98. //note that data stored in BMP is backwards to Flash and is 99. //stored from bottom row up, not top row down. 100. //So we have to loop backwards 101. var counter:int = 0; 102. for(var i:int = bmpHeight; i > 0; i--) 103. { 104. for(var k:int = 0; k < bmpWidth; k++) 105. { 106.
107. var position:int = ((i - 1) * bmpWidth) + k; 108. /* 109. This is the original code that I had which works fine 110. but is not as effecient as what I have now. 111. 112. Basically, Pixels are stored within 3 sucessive Bytes 113. in a BMP file, with one Byte each for Blue, Green and 114. Red values (in that order). 115. 116. So, this reads the Bytes for each pixel, one at a time 117. and then combines them into a single value which is 118. the combined RGB pixel value. 119. 120. I left the code as I think it make it a little easier to 121. understand what is going on, as well as how some of these 122. calls can be optimized. 123. */ 124.
125. /* 126. var blue:int = fs.readUnsignedByte(); 127. var green:int = fs.readUnsignedByte(); 128. var red:int = fs.readUnsignedByte(); 129. 130. pixels[position] = (red << 16 ^ green << 8 ^ blue); 131. */ 132.
133. /* 134. Here is the final code which is more efficient, as it only 135. needs to make 2 read calls in order to get the values. 136. 137. Thanks to Thibault Imbert (bytearray.org) for pointing out 138. and helping me understand the optimization. 139. */ 140.
141. //bytes in file are in Blue, Green, Red order 142. //int is 32 bits (8 bytes). So, we store the first two bytes of the pixel 143. // (which contain the Red value), and 144. //then shift everything over 1 byte (8bits) to make room for 145. //the green and blue values (remember the file is little endian), which we 146. // then write into the int in the right position 147. //The final value has the colors in the correct order (Red, Green, Blue) 148.
149. var pixelValue:uint = fs.readUnsignedByte() | fs.readUnsignedShort() << 8; 150. pixels[position] = pixelValue; 151. } 152.
153. //we are at the end of the row, so now we have to move the cursor 154. //forward so it ends on a multiple of 4 155. if(padding) 156. { 157. fs.position += padding; 158. } 159. } 160.
161. //done reading file, close stream. 162. fs.close(); 163.
164. //create a Rectangle with width / height of Bitmap 165. var rect:Rectangle = new Rectangle(0, 0, bmpWidth, bmpHeight); 166.
167. //create the BitmapData object to hold hold the BMP data. 168. //we do a red fill here so it is easier to see if we have any errors 169. //in our code 170. var bmpData:BitmapData = new BitmapData(bmpWidth, bmpHeight, false, 0xFF0000); 171.
172. //copy the BMP pixel data into the BitmapData 173. bmpData.setVector(rect, pixels); 174.
175. //create a new Bitmap instance using the BitmapData 176. var bitmap:Bitmap = new Bitmap(bmpData); 177. bitmap.x = 10; 178. bitmap.y = 10; 179.
180. //add Bitmap to the display list 181. addChild(bitmap); 182. } 183. } 184. }
复制代码 您可以从这里下载的例子。 感谢Lee的介绍,和Thibault Imbert帮助我了解endianes的一些细节,以及一些优化建议。 如果你有兴趣学习更多的知识,强烈建议你看看Lee的 FITC Presentation.
(责任编辑:admin) |