Afficher des images BMP dans le player Flash
Mike Chambers à trouvé une astuce bien sympa qui permet de charger et d’afficher des images 24Bit BMP dans le player Flash. Bon je sais, vouloir charger du BMP dans Flash, ça n’arrive pas tous les jours mais cet exemple met en évidence l’utilité de charger les données au format binaire.
Voici le code qu’il utilise :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | package { import flash.filesystem.File; import flash.filesystem.FileStream; import flash.filesystem.FileMode; import flash.display.Sprite; import flash.display.BitmapData; import flash.display.Bitmap; import flash.utils.Endian; import flash.geom.Rectangle; [SWF(width='550', height='400', backgroundColor='#FFFFFF', frameRate='12')] public class BMPViewer extends Sprite { private static const MAGIC_NUMBER:String = "BM"; private static const BMP_DATA_OFFSET_POSITION:int = 0xA; private static const WIDTH_POSITION:int = 0x12; private static const HEIGHT_POSITION:int = 0x16; public function BMPViewer() { loadBMP(); super(); } /* Loads and reads a 24 Bit bitmap file. Based on BMP info from: http://en.wikipedia.org/wiki/BMP%5Ffile%5Fformat */ private function loadBMP():void { //Load BMP. This requires AIR. //Use FileReference.browse for //Flash Player var bmpFile:File = new File("app:/image.bmp"); var fs:FileStream = new FileStream(); //BMP files are Little Endian, which means their //least significant byte is first (right to left) fs.endian = Endian.LITTLE_ENDIAN; //open the file in READ mode fs.open(bmpFile, FileMode.READ); //check the first two bytes to make sure //it is a valid BMP file if(fs.readUTFBytes(2) != MAGIC_NUMBER) { trace("FAIL : NOT A BMP FILE"); //not a BMP file, close steam //and exit fs.close(); return; } //note, we could also grab the length from the //header and make sure the file was the correct //length //change the cursors position to the point //in the header that contains the value / offset //of where the actual bitmap data begins //read in the 4 Bytes that contain the value fs.position = BMP_DATA_OFFSET_POSITION; var dataPosition:int = fs.readInt(); //set cursor position to where the BMP //width is stored fs.position = WIDTH_POSITION; //read in the 4 Bytes that contain the width var bmpWidth:int = fs.readInt(); //read in the 4 Bytes that contain the height var bmpHeight:int = fs.readInt(); //set cursor to where the BMP pixel data begins fs.position = dataPosition; var row:int = 0; var column:int = 0; //every row length in a BMP file must bee a multiple //of 4 (see the spec). So, we need to determine how much //padding we need to add at the end of each line. var padding:int = (bmpWidth % 4); //create a fixed length Vector to store the pixel //values as we read them. var pixels:Vector. = new Vector.(bmpWidth * bmpHeight, true); //loop through data (rows and columns) //note that data stored in BMP is backwards to Flash and is //stored from bottom row up, not top row down. //So we have to loop backwards var counter:int = 0; for(var i:int = bmpHeight; i > 0; i--) { for(var k:int = 0; k < bmpWidth; k++) { var position:int = ((i - 1) * bmpWidth) + k; /* This is the original code that I had which works fine but is not as effecient as what I have now. Basically, Pixels are stored within 3 sucessive Bytes in a BMP file, with one Byte each for Blue, Green and Red values (in that order). So, this reads the Bytes for each pixel, one at a time and then combines them into a single value which is the combined RGB pixel value. I left the code as I think it make it a little easier to understand what is going on, as well as how some of these calls can be optimized. */ /* var blue:int = fs.readUnsignedByte(); var green:int = fs.readUnsignedByte(); var red:int = fs.readUnsignedByte(); pixels[position] = (red << 16 ^ green << 8 ^ blue); */ /* Here is the final code which is more efficient, as it only needs to make 2 read calls in order to get the values. Thanks to Thibault Imbert (bytearray.org) for pointing out and helping me understand the optimization. */ //bytes in file are in Blue, Green, Red order //int is 32 bits (8 bytes). So, we store the first two bytes of the pixel // (which contain the Red value), and //then shift everything over 1 byte (8bits) to make room for //the green and blue values (remember the file is little endian), which we // then write into the int in the right position //The final value has the colors in the correct order (Red, Green, Blue) var pixelValue:uint = fs.readUnsignedByte() | fs.readUnsignedShort() << 8; pixels[position] = pixelValue; } //we are at the end of the row, so now we have to move the cursor //forward so it ends on a multiple of 4 if(padding) { fs.position += padding; } } //done reading file, close stream. fs.close(); //create a Rectangle with width / height of Bitmap var rect:Rectangle = new Rectangle(0, 0, bmpWidth, bmpHeight); //create the BitmapData object to hold hold the BMP data. //we do a red fill here so it is easier to see if we have any errors //in our code var bmpData:BitmapData = new BitmapData(bmpWidth, bmpHeight, false, 0xFF0000); //copy the BMP pixel data into the BitmapData bmpData.setVector(rect, pixels); //create a new Bitmap instance using the BitmapData var bitmap:Bitmap = new Bitmap(bmpData); bitmap.x = 10; bitmap.y = 10; //add Bitmap to the display list addChild(bitmap); } } } |
A noter que dans le même esprit, Senocular a créé une classe qui converti un displayObject en BMP.



Commentaires récents