1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2002-2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
25 // Based on work done by:
26 // Dennis Hayes (dennish@Raytek.com)
27 // Aleksey Ryabchuk (ryabchuk@yahoo.com)
31 using System.Collections;
32 using System.Drawing.Imaging;
33 using System.Runtime.Serialization;
34 using System.Runtime.InteropServices;
37 namespace System.Windows.Forms {
40 public sealed class ImageListStreamer : ISerializable {
42 private static byte [] signature = new byte [] {77 , 83 , 70 , 116};
44 private readonly ImageList.ImageCollection imageCollection;
45 private Image [] images;
46 private Size image_size;
47 private Color back_color;
49 internal ImageListStreamer (ImageList.ImageCollection imageCollection) {
50 this.imageCollection = imageCollection;
53 private ImageListStreamer (SerializationInfo info, StreamingContext context) {
55 byte [] data = (byte [])info.GetValue ("Data", typeof (byte []));
56 if (data == null || data.Length <= signature.Length)
58 // check the signature ( 'MSFt' )
59 if (data [0] != signature [0] || data [1] != signature [1] ||
60 data [2] != signature [2] || data [3] != signature [3])
63 // calulate size of array needed for decomressed data
65 int real_byte_count = 0;
66 for (i = signature.Length; i < data.Length; i += 2)
67 real_byte_count += data [i];
69 if (real_byte_count == 0)
73 byte [] decompressed = new byte [real_byte_count];
75 for (i = signature.Length; i < data.Length; i += 2) {
76 for (int k = 0; k < data [i]; k++)
77 decompressed [j++] = data [i + 1];
80 MemoryStream stream = new MemoryStream (decompressed);
81 BinaryReader reader = new BinaryReader (stream);
84 // read image list header
85 reader.ReadUInt16 (); // usMagic
86 reader.ReadUInt16 (); // usVersion
87 ushort cCurImage = reader.ReadUInt16 ();
88 reader.ReadUInt16 (); // cMaxImage
89 reader.ReadUInt16 (); // cGrow
90 ushort cx = reader.ReadUInt16 ();
91 ushort cy = reader.ReadUInt16 ();
92 uint bkcolor = reader.ReadUInt32 ();
93 reader.ReadUInt16 (); // flags
95 short [] ovls = new short [4];
96 for (i = 0; i < ovls.Length; i++) {
97 ovls[i] = reader.ReadInt16 ();
100 image_size = new Size (cx, cy);
101 back_color = Color.FromArgb ((int) bkcolor);
103 MemoryStream start = new MemoryStream (decompressed,
104 (int) stream.Position,
105 (int) stream.Length - (int) stream.Position,
108 Image image = Image.FromStream (start);
110 // Holy calamity. This is what happens on MS
111 // if the background colour is 0xFFFFFFFF (CLR_NONE)
112 // the mask is set to the color at pixel 0, 0
113 Bitmap bmp = image as Bitmap;
114 if (bkcolor == 0xFFFFFFFF && bmp != null)
115 back_color = bmp.GetPixel (0, 0);
117 int step = image.Width / cx;
118 images = new Image [cCurImage];
120 Rectangle dest_rect = new Rectangle (0, 0, cx, cy);
121 for (int r = 0 ; r < cCurImage ; r++) {
122 Rectangle area = new Rectangle (
126 Bitmap b = new Bitmap (cx, cy);
127 using (Graphics g = Graphics.FromImage (b)) {
128 g.DrawImage (image, dest_rect, area,
131 b.MakeTransparent (back_color);
135 } catch (Exception e) {
140 [MonoTODO ("RLE is broken")]
141 public void GetObjectData (SerializationInfo info, StreamingContext context)
143 MemoryStream stream = new MemoryStream ();
144 BinaryWriter writer = new BinaryWriter (stream);
146 writer.Write (signature);
147 writer.Write (GetStreamData ());
149 info.AddValue ("Data", stream.ToArray (), typeof (byte []));
152 [MonoTODO ("Images should be written to the stream")]
153 private byte [] GetStreamData ()
155 MemoryStream stream = new MemoryStream ();
156 BinaryWriter writer = new BinaryWriter (stream);
157 Image [] images = (imageCollection != null) ? imageCollection.ToArray () : this.images;
160 int rows = images.Length / cols;
161 if (images.Length % cols > 0)
164 Bitmap main = new Bitmap (cols * ImageSize.Width, rows * ImageSize.Height);
165 using (Graphics g = Graphics.FromImage (main)) {
166 g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), 0, 0, cols * ImageSize.Width, rows * ImageSize.Height);
167 for (int i = 0; i < images.Length; i++) {
168 g.DrawImage (images [i], (i % cols) * ImageSize.Width,
169 (i / cols) * ImageSize.Height);
173 writer.Write ((ushort) (('L' << 8) | 'I')); // magic
174 writer.Write ((ushort) 0x101); // version
175 writer.Write ((ushort) images.Length);
176 writer.Write ((ushort) images.Length);
177 writer.Write ((ushort) (rows * cols));
178 writer.Write ((ushort) 0x4); // grow....not sure this should be hard coded
179 writer.Write ((ushort) image_size.Width);
180 writer.Write ((ushort) image_size.Height);
181 writer.Write (BackColor.ToArgb ());
182 writer.Write ((ushort) 0x1009); // flags
184 for (int i = 0; i < 4; i++)
185 writer.Write ((short) -1); // ovls
187 return RLEncodeData (stream.ToArray ());
190 // TODO: This is broken
191 private byte [] RLEncodeData (byte [] data)
193 MemoryStream stream = new MemoryStream ();
194 BinaryWriter writer = new BinaryWriter (stream);
196 for (int i = 0; i < data.Length; i += 2) {
198 byte item = data [i];
199 while (data [i++] == item && i < data.Length)
201 writer.Write ((byte) seq);
205 return stream.ToArray ();
209 internal Image [] Images {
210 get { return images; }
213 internal Size ImageSize {
214 get { return image_size; }
217 internal ColorDepth ColorDepth {
218 get { return ColorDepth.Depth32Bit; }
221 internal Color BackColor {
222 get { return back_color; }