示例#1
0
		private void InitFromStreamWithSize (Stream stream, int width, int height)
		{
			//read the icon header
			if (stream == null || stream.Length == 0)
				throw new ArgumentException ("The argument 'stream' must be a picture that can be used as a Icon", "stream");
			
			BinaryReader reader = new BinaryReader (stream);

			//iconDir = new IconDir ();
			iconDir.idReserved = reader.ReadUInt16();
			if (iconDir.idReserved != 0) //must be 0
				throw new ArgumentException ("Invalid Argument", "stream");
			
			iconDir.idType = reader.ReadUInt16();
			if (iconDir.idType != 1) //must be 1
				throw new ArgumentException ("Invalid Argument", "stream");

			ushort dirEntryCount = reader.ReadUInt16();
			imageData = new ImageData [dirEntryCount]; 
			iconDir.idCount = dirEntryCount; 
			iconDir.idEntries = new IconDirEntry [dirEntryCount];
			bool sizeObtained = false;
			// now read in the IconDirEntry structures
			for (int i = 0; i < dirEntryCount; i++) {
				IconDirEntry ide;
				ide.width = reader.ReadByte ();
				ide.height = reader.ReadByte ();
				ide.colorCount = reader.ReadByte ();
				ide.reserved = reader.ReadByte ();
				ide.planes = reader.ReadUInt16 ();
				ide.bitCount = reader.ReadUInt16 ();
				ide.bytesInRes = reader.ReadUInt32 ();
				ide.imageOffset = reader.ReadUInt32 ();
#if false
Console.WriteLine ("Entry: {0}", i);
Console.WriteLine ("\tide.width: {0}", ide.width);
Console.WriteLine ("\tide.height: {0}", ide.height);
Console.WriteLine ("\tide.colorCount: {0}", ide.colorCount);
Console.WriteLine ("\tide.reserved: {0}", ide.reserved);
Console.WriteLine ("\tide.planes: {0}", ide.planes);
Console.WriteLine ("\tide.bitCount: {0}", ide.bitCount);
Console.WriteLine ("\tide.bytesInRes: {0}", ide.bytesInRes);
Console.WriteLine ("\tide.imageOffset: {0}", ide.imageOffset);
#endif
				// Vista 256x256 icons points directly to a PNG bitmap
				// 256x256 icons are decoded as 0x0 (width and height are encoded as BYTE)
				// and we ignore them just like MS does (at least up to fx 2.0) 
				// Added: storing data so it can be saved back
				if ((ide.width == 0) && (ide.height == 0))
					ide.ignore = true;
				else
					ide.ignore = false;

				iconDir.idEntries [i] = ide;

				//is this is the best fit??
				if (!sizeObtained) {
					if (((ide.height == height) || (ide.width == width)) && !ide.ignore) {
						this.id = (ushort) i;
						sizeObtained = true;
						this.iconSize.Height = ide.height;
						this.iconSize.Width = ide.width;
					}
				}
			}

			// throw error if no valid entries found
			int valid = 0;
			for (int i = 0; i < dirEntryCount; i++) {
				if (!(iconDir.idEntries [i].ignore))
					valid++;
			}

			if (valid == 0) 
				throw new Win32Exception (0, "No valid icon entry were found.");

			// if we havent found the best match, return the one with the
			// largest size. Is this approach correct??
			if (!sizeObtained){
				uint largestSize = 0;
				for (int j=0; j<dirEntryCount; j++){ 
					if (iconDir.idEntries [j].bytesInRes >= largestSize && !iconDir.idEntries [j].ignore)	{
						largestSize = iconDir.idEntries [j].bytesInRes;
						this.id = (ushort) j;
						this.iconSize.Height = iconDir.idEntries [j].height;
						this.iconSize.Width = iconDir.idEntries [j].width;
					}
				}
			}
			
			//now read in the icon data
			for (int j = 0; j<dirEntryCount; j++) 
			{
				// process ignored into IconDump
				if (iconDir.idEntries [j].ignore) {
					IconDump id = new IconDump ();
					stream.Seek (iconDir.idEntries [j].imageOffset, SeekOrigin.Begin);
					id.data = new byte [iconDir.idEntries [j].bytesInRes];
					stream.Read (id.data, 0, id.data.Length);
					imageData [j] = id;
					continue;
				}
				// standard image
				IconImage iidata = new IconImage();
				BitmapInfoHeader bih = new BitmapInfoHeader();
				stream.Seek (iconDir.idEntries [j].imageOffset, SeekOrigin.Begin);
				byte [] buffer = new byte [iconDir.idEntries [j].bytesInRes];
				stream.Read (buffer, 0, buffer.Length);
				BinaryReader bihReader = new BinaryReader (new MemoryStream(buffer));
				bih.biSize = bihReader.ReadUInt32 ();
				bih.biWidth = bihReader.ReadInt32 ();
				bih.biHeight = bihReader.ReadInt32 ();
				bih.biPlanes = bihReader.ReadUInt16 ();
				bih.biBitCount = bihReader.ReadUInt16 ();
				bih.biCompression = bihReader.ReadUInt32 ();
				bih.biSizeImage = bihReader.ReadUInt32 ();
				bih.biXPelsPerMeter = bihReader.ReadInt32 ();
				bih.biYPelsPerMeter = bihReader.ReadInt32 ();
				bih.biClrUsed = bihReader.ReadUInt32 ();
				bih.biClrImportant = bihReader.ReadUInt32 ();
#if false
Console.WriteLine ("Entry: {0}", j);
Console.WriteLine ("\tbih.biSize: {0}", bih.biSize);
Console.WriteLine ("\tbih.biWidth: {0}", bih.biWidth);
Console.WriteLine ("\tbih.biHeight: {0}", bih.biHeight);
Console.WriteLine ("\tbih.biPlanes: {0}", bih.biPlanes);
Console.WriteLine ("\tbih.biBitCount: {0}", bih.biBitCount);
Console.WriteLine ("\tbih.biCompression: {0}", bih.biCompression);
Console.WriteLine ("\tbih.biSizeImage: {0}", bih.biSizeImage);
Console.WriteLine ("\tbih.biXPelsPerMeter: {0}", bih.biXPelsPerMeter);
Console.WriteLine ("\tbih.biYPelsPerMeter: {0}", bih.biYPelsPerMeter);
Console.WriteLine ("\tbih.biClrUsed: {0}", bih.biClrUsed);
Console.WriteLine ("\tbih.biClrImportant: {0}", bih.biClrImportant);
#endif
				iidata.iconHeader = bih;
				//Read the number of colors used and corresponding memory occupied by
				//color table. Fill this memory chunk into rgbquad[]
				int numColors;
				switch (bih.biBitCount){
					case 1: numColors = 2;
						break;
					case 4: numColors = 16;
						break;
					case 8: numColors = 256;
						break;
					default: numColors = 0;
						break;
				}
				
				iidata.iconColors = new uint [numColors];
				for (int i=0; i<numColors; i++)
					iidata.iconColors [i] = bihReader.ReadUInt32 ();

				//XOR mask is immediately after ColorTable and its size is 
				//icon height* no. of bytes per line
				
				//icon height is half of BITMAPINFOHEADER.biHeight, since it contains
				//both XOR as well as AND mask bytes
				int iconHeight = bih.biHeight/2;
				
				//bytes per line should should be uint aligned
				int numBytesPerLine = ((((bih.biWidth * bih.biPlanes * bih.biBitCount)+ 31)>>5)<<2);
				
				//Determine the XOR array Size
				int xorSize = numBytesPerLine * iconHeight;
				iidata.iconXOR = new byte [xorSize];
				int nread = bihReader.Read (iidata.iconXOR, 0, xorSize);
				if (nread != xorSize) {
                    string msg = string.Format("{0} data length expected {1}, read {2}", "XOR", xorSize, nread);
					throw new ArgumentException (msg, "stream");
				}
				
				//Determine the AND array size
				numBytesPerLine = (int)((((bih.biWidth) + 31) & ~31) >> 3);
				int andSize = numBytesPerLine * iconHeight;
				iidata.iconAND = new byte [andSize];
				nread = bihReader.Read (iidata.iconAND, 0, andSize);
				if (nread != andSize) {
                    string msg = string.Format("{0} data length expected {1}, read {2}", "AND", andSize, nread);
					throw new ArgumentException (msg, "stream");
				}
				
				imageData [j] = iidata;
				bihReader.Close();
			}			

			reader.Close();
		}
示例#2
0
		private void SaveIconDump (BinaryWriter writer, IconDump id)
		{
			writer.Write (id.data);
		}