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(); }
private void SaveIconDump (BinaryWriter writer, IconDump id) { writer.Write (id.data); }