fix typo
[mcs.git] / class / System.Drawing / System.Drawing / Icon2.jvm.cs
blobcfe033e21a827b72cf5b750bf163349d9835f8fc
1 //
2 // System.Drawing.Icon.cs
3 //
4 // Authors:
5 // Dennis Hayes (dennish@Raytek.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 // Sanjay Gupta (gsanjay@novell.com)
8 //
9 // Copyright (C) 2002 Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004 Novell, Inc. http://www.novell.com
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System;
37 using System.IO;
38 using System.Runtime.Serialization;
39 using System.Runtime.InteropServices;
40 using System.ComponentModel;
42 namespace System.Drawing
44 [Serializable]
45 [ComVisible (false)]
46 [Editor ("System.Drawing.Design.IconEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
47 [TypeConverter(typeof(IconConverter))]
48 public sealed class Icon : MarshalByRefObject, ISerializable, ICloneable, IDisposable
50 [StructLayout(LayoutKind.Sequential)]
51 internal struct IconDirEntry {
52 internal byte width; // Width of icon
53 internal byte height; // Height of icon
54 internal byte colorCount; // colors in icon
55 internal byte reserved; // Reserved
56 internal ushort planes; // Color Planes
57 internal ushort bitCount; // Bits per pixel
58 internal uint bytesInRes; // bytes in resource
59 internal uint imageOffset; // position in file
60 };
62 [StructLayout(LayoutKind.Sequential)]
63 internal struct IconDir {
64 internal ushort idReserved; // Reserved
65 internal ushort idType; // resource type (1 for icons)
66 internal ushort idCount; // how many images?
67 internal IconDirEntry [] idEntries; // the entries for each image
70 [StructLayout(LayoutKind.Sequential)]
71 internal struct BitmapInfoHeader {
72 internal uint biSize;
73 internal int biWidth;
74 internal int biHeight;
75 internal ushort biPlanes;
76 internal ushort biBitCount;
77 internal uint biCompression;
78 internal uint biSizeImage;
79 internal int biXPelsPerMeter;
80 internal int biYPelsPerMeter;
81 internal uint biClrUsed;
82 internal uint biClrImportant;
85 [StructLayout(LayoutKind.Sequential)]
86 internal struct IconImage {
87 internal BitmapInfoHeader iconHeader; //image header
88 internal uint [] iconColors; //colors table
89 internal byte [] iconXOR; // bits for XOR mask
90 internal byte [] iconAND; //bits for AND mask
91 };
93 private Size iconSize;
94 private IntPtr winHandle = IntPtr.Zero;
95 private IconDir iconDir;
96 private ushort id;
97 private IconImage [] imageData;
98 bool destroyIcon = true;
100 private Icon ()
103 #if INTPTR_SUPPORTED
104 [MonoTODO ("Implement fully")]
105 private Icon (IntPtr handle)
107 this.winHandle = handle;
109 IconInfo ii;
110 GDIPlus.GetIconInfo (winHandle, out ii);
111 if (ii.IsIcon) {
112 // If this structure defines an icon, the hot spot is always in the center of the icon
113 iconSize = new Size (ii.xHotspot * 2, ii.yHotspot * 2);
115 else {
116 throw new NotImplementedException ();
119 this.destroyIcon = false;
121 #endif
122 public Icon (Icon original, int width, int height) : this (original, new Size(width, height))
126 public Icon (Icon original, Size size)
128 this.iconSize = size;
129 this.winHandle = original.winHandle;
130 this.iconDir = original.iconDir;
131 this.imageData = original.imageData;
133 int count = iconDir.idCount;
134 bool sizeObtained = false;
135 for (int i=0; i<count; i++){
136 IconDirEntry ide = iconDir.idEntries [i];
137 if (!sizeObtained)
138 if (ide.height==size.Height && ide.width==size.Width) {
139 this.id = (ushort) i;
140 sizeObtained = true;
141 this.iconSize.Height = ide.height;
142 this.iconSize.Width = ide.width;
143 break;
147 if (!sizeObtained){
148 uint largestSize = 0;
149 for (int j=0; j<count; j++){
150 if (iconDir.idEntries [j].bytesInRes >= largestSize){
151 largestSize = iconDir.idEntries [j].bytesInRes;
152 this.id = (ushort) j;
153 this.iconSize.Height = iconDir.idEntries [j].height;
154 this.iconSize.Width = iconDir.idEntries [j].width;
160 public Icon (Stream stream) : this (stream, 32, 32)
164 public Icon (Stream stream, int width, int height)
166 InitFromStreamWithSize (stream, width, height);
169 public Icon (string fileName) : this (new FileStream (fileName, FileMode.Open))
173 public Icon (Type type, string resource)
175 using (Stream s = type.Assembly.GetManifestResourceStream (type, resource)) {
176 if (s == null) {
177 throw new FileNotFoundException ("Resource name was not found: `" + resource + "'");
179 InitFromStreamWithSize (s, 32, 32); // 32x32 is default
183 private Icon (SerializationInfo info, StreamingContext context)
185 MemoryStream dataStream = null;
186 int width=0;
187 int height=0;
188 foreach (SerializationEntry serEnum in info) {
189 if (String.Compare(serEnum.Name, "IconData", true) == 0) {
190 dataStream = new MemoryStream ((byte []) serEnum.Value);
192 if (String.Compare(serEnum.Name, "IconSize", true) == 0) {
193 Size iconSize = (Size) serEnum.Value;
194 width = iconSize.Width;
195 height = iconSize.Height;
198 if (dataStream != null && width != 0 && height != 0) {
199 dataStream.Seek (0, SeekOrigin.Begin);
200 InitFromStreamWithSize (dataStream, width, height);
204 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
206 MemoryStream ms = new MemoryStream ();
207 Save (ms);
208 info.AddValue ("IconSize", this.Size, typeof (Size));
209 info.AddValue ("IconData", ms.ToArray ());
212 public void Dispose ()
214 #if !TARGET_JVM
215 DisposeIcon ();
216 GC.SuppressFinalize(this);
217 #endif
219 #if !TARGET_JVM
220 void DisposeIcon ()
222 if (winHandle ==IntPtr.Zero)
223 return;
225 if (destroyIcon) {
226 //TODO: will have to call some win32 icon stuff
227 winHandle = IntPtr.Zero;
230 #endif
232 public object Clone ()
234 return new Icon (this, this.Width, this.Height);
236 #if INTPTR_SUPPORTED
237 public static Icon FromHandle (IntPtr handle)
239 if (handle == IntPtr.Zero)
240 throw new ArgumentException ("handle");
242 return new Icon (handle);
244 #endif
245 public void Save (Stream outputStream)
247 if (iconDir.idEntries!=null){
248 BinaryWriter bw = new BinaryWriter (outputStream);
249 //write icondir
250 bw.Write (iconDir.idReserved);
251 bw.Write (iconDir.idType);
252 ushort count = iconDir.idCount;
253 bw.Write (count);
255 //now write iconDirEntries
256 for (int i=0; i<(int)count; i++){
257 IconDirEntry ide = iconDir.idEntries [i];
258 bw.Write (ide.width);
259 bw.Write (ide.height);
260 bw.Write (ide.colorCount);
261 bw.Write (ide.reserved);
262 bw.Write (ide.planes);
263 bw.Write (ide.bitCount);
264 bw.Write (ide.bytesInRes);
265 bw.Write (ide.imageOffset);
268 //now write iconImage data
269 for (int i=0; i<(int)count; i++){
270 BitmapInfoHeader bih = imageData [i].iconHeader;
271 bw.Write (bih.biSize);
272 bw.Write (bih.biWidth);
273 bw.Write (bih.biHeight);
274 bw.Write (bih.biPlanes);
275 bw.Write (bih.biBitCount);
276 bw.Write (bih.biCompression);
277 bw.Write (bih.biSizeImage);
278 bw.Write (bih.biXPelsPerMeter);
279 bw.Write (bih.biYPelsPerMeter);
280 bw.Write (bih.biClrUsed);
281 bw.Write (bih.biClrImportant);
283 //now write color table
284 int colCount = imageData [i].iconColors.Length;
285 for (int j=0; j<colCount; j++)
286 bw.Write (imageData [i].iconColors [j]);
288 //now write XOR Mask
289 bw.Write (imageData [i].iconXOR);
291 //now write AND Mask
292 bw.Write (imageData [i].iconAND);
294 bw.Flush();
298 public Bitmap ToBitmap ()
300 Bitmap bmp;
302 if (imageData != null) {
304 // select active icon from the iconDirEntry
305 IconImage ii = imageData [this.id];
306 MemoryStream stream = new MemoryStream ();
308 BinaryWriter writer = new BinaryWriter (stream);
310 try {
311 // write bitmap file header
312 // start with writing signature
313 writer.Write ('B');
314 writer.Write ('M');
316 // write the file size
317 // file size = bitmapfileheader + bitmapinfo +
318 // colorpalette + image bits
319 // sizeof bitmapfileheader = 14 bytes
320 // sizeof bitmapinfo = 40 bytes
321 uint offSet = (uint) (14 + 40 + ii.iconColors.Length * 4);
322 uint fileSize = (uint) (offSet + ii.iconXOR.Length);
323 writer.Write (fileSize);
325 // write reserved words
326 ushort reserved12 = 0;
327 writer.Write (reserved12);
328 writer.Write (reserved12);
330 // write offset
331 writer.Write (offSet);
333 // write bitmapfile header
334 BitmapInfoHeader bih = ii.iconHeader;
335 writer.Write (bih.biSize);
336 writer.Write (bih.biWidth);
337 writer.Write (bih.biHeight/2);
338 writer.Write (bih.biPlanes);
339 writer.Write (bih.biBitCount);
340 writer.Write (bih.biCompression);
341 writer.Write (bih.biSizeImage);
342 writer.Write (bih.biXPelsPerMeter);
343 writer.Write (bih.biYPelsPerMeter);
344 writer.Write (bih.biClrUsed);
345 writer.Write (bih.biClrImportant);
347 // write color table
348 int colCount = ii.iconColors.Length;
349 for (int j = 0; j < colCount; j++)
350 writer.Write (ii.iconColors [j]);
352 // write image bits
353 writer.Write (ii.iconXOR);
355 writer.Flush ();
357 stream.Position = 0;
359 // create bitmap from stream and return
360 if (colCount > 0) {
361 Bitmap new_bmp;
363 new_bmp = new Bitmap(stream);
364 bmp = new Bitmap(new_bmp, bih.biWidth, bih.biHeight/2);
365 new_bmp.Dispose();
366 } else {
367 bmp = new Bitmap(stream);
370 // This hack is so ugly, it's embarassing.
371 // But icons are small, so it should be ok for now
372 for (int y = 0; y < bih.biHeight/2; y++) {
373 for (int x = 0; x < bih.biWidth / 8; x++) {
374 for (int bit = 7; bit >= 0; bit--) {
375 if (((ii.iconAND[y * bih.biWidth / 8 +x] >> bit) & 1) != 0) {
376 bmp.SetPixel(x*8 + 7-bit, bih.biHeight/2 - y - 1, Color.Transparent);
382 } catch (Exception e) {
383 throw e;
384 } finally {
385 writer.Close (); // closes the underlying stream as well
387 } else {
388 bmp = new Bitmap (32, 32);
391 return bmp;
394 public override string ToString ()
396 //is this correct, this is what returned by .Net
397 return "<Icon>";
400 [Browsable (false)]
401 public IntPtr Handle {
402 get {
403 return winHandle;
407 [Browsable (false)]
408 public int Height {
409 get {
410 return iconSize.Height;
414 public Size Size {
415 get {
416 return iconSize;
420 [Browsable (false)]
421 public int Width {
422 get {
423 return iconSize.Width;
427 #if !TARGET_JVM
428 ~Icon ()
430 DisposeIcon ();
432 #endif
434 private void InitFromStreamWithSize (Stream stream, int width, int height)
436 //read the icon header
437 if (stream == null || stream.Length == 0)
438 throw new System.ArgumentException ("The argument 'stream' must be a picture that can be used as a Icon", "stream");
440 BinaryReader reader = new BinaryReader (stream);
442 //iconDir = new IconDir ();
443 iconDir.idReserved = reader.ReadUInt16();
444 if (iconDir.idReserved != 0) //must be 0
445 throw new System.ArgumentException ("Invalid Argument", "stream");
447 iconDir.idType = reader.ReadUInt16();
448 if (iconDir.idType != 1) //must be 1
449 throw new System.ArgumentException ("Invalid Argument", "stream");
451 ushort dirEntryCount = reader.ReadUInt16();
452 iconDir.idCount = dirEntryCount;
453 iconDir.idEntries = new IconDirEntry [dirEntryCount];
454 imageData = new IconImage [dirEntryCount];
455 bool sizeObtained = false;
456 //now read in the IconDirEntry structures
457 for (int i=0; i<dirEntryCount; i++){
458 IconDirEntry ide;
459 ide.width = reader.ReadByte ();
460 ide.height = reader.ReadByte ();
461 ide.colorCount = reader.ReadByte ();
462 ide.reserved = reader.ReadByte ();
463 ide.planes = reader.ReadUInt16 ();
464 ide.bitCount = reader.ReadUInt16 ();
465 ide.bytesInRes = reader.ReadUInt32 ();
466 ide.imageOffset = reader.ReadUInt32 ();
467 iconDir.idEntries [i] = ide;
468 //is this is the best fit??
469 if (!sizeObtained)
470 if (ide.height==height && ide.width==width) {
471 this.id = (ushort) i;
472 sizeObtained = true;
473 this.iconSize.Height = ide.height;
474 this.iconSize.Width = ide.width;
477 //if we havent found the best match, return the one with the
478 //largest size. Is this approach correct??
479 if (!sizeObtained){
480 uint largestSize = 0;
481 for (int j=0; j<dirEntryCount; j++){
482 if (iconDir.idEntries [j].bytesInRes >= largestSize) {
483 largestSize = iconDir.idEntries [j].bytesInRes;
484 this.id = (ushort) j;
485 this.iconSize.Height = iconDir.idEntries [j].height;
486 this.iconSize.Width = iconDir.idEntries [j].width;
491 //now read in the icon data
492 for (int j = 0; j<dirEntryCount; j++)
494 IconImage iidata = new IconImage();
495 BitmapInfoHeader bih = new BitmapInfoHeader();
496 stream.Seek (iconDir.idEntries [j].imageOffset, SeekOrigin.Begin);
497 byte [] buffer = new byte [iconDir.idEntries [j].bytesInRes];
498 stream.Read (buffer, 0, buffer.Length);
499 BinaryReader bihReader = new BinaryReader (new MemoryStream(buffer));
500 bih.biSize = bihReader.ReadUInt32 ();
501 bih.biWidth = bihReader.ReadInt32 ();
502 bih.biHeight = bihReader.ReadInt32 ();
503 bih.biPlanes = bihReader.ReadUInt16 ();
504 bih.biBitCount = bihReader.ReadUInt16 ();
505 bih.biCompression = bihReader.ReadUInt32 ();
506 bih.biSizeImage = bihReader.ReadUInt32 ();
507 bih.biXPelsPerMeter = bihReader.ReadInt32 ();
508 bih.biYPelsPerMeter = bihReader.ReadInt32 ();
509 bih.biClrUsed = bihReader.ReadUInt32 ();
510 bih.biClrImportant = bihReader.ReadUInt32 ();
512 iidata.iconHeader = bih;
513 //Read the number of colors used and corresponding memory occupied by
514 //color table. Fill this memory chunk into rgbquad[]
515 int numColors;
516 switch (bih.biBitCount){
517 case 1: numColors = 2;
518 break;
519 case 4: numColors = 16;
520 break;
521 case 8: numColors = 256;
522 break;
523 default: numColors = 0;
524 break;
527 iidata.iconColors = new uint [numColors];
528 for (int i=0; i<numColors; i++)
529 iidata.iconColors [i] = bihReader.ReadUInt32 ();
531 //XOR mask is immediately after ColorTable and its size is
532 //icon height* no. of bytes per line
534 //icon height is half of BITMAPINFOHEADER.biHeight, since it contains
535 //both XOR as well as AND mask bytes
536 int iconHeight = bih.biHeight/2;
538 //bytes per line should should be uint aligned
539 int numBytesPerLine = ((((bih.biWidth * bih.biPlanes * bih.biBitCount)+ 31)>>5)<<2);
541 //Determine the XOR array Size
542 int xorSize = numBytesPerLine * iconHeight;
543 iidata.iconXOR = new byte [xorSize];
544 for (int i=0; i<xorSize; i++)
545 iidata.iconXOR[i] = bihReader.ReadByte();
547 //Determine the AND array size
548 //For this i subtract the current position from the length.
549 //ugly hack...
550 int andSize = (int) (bihReader.BaseStream.Length - bihReader.BaseStream.Position);
551 iidata.iconAND = new byte [andSize];
552 for (int i=0; i<andSize; i++)
553 iidata.iconAND[i] = bihReader.ReadByte();
555 imageData [j] = iidata;
556 bihReader.Close();
559 reader.Close();