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-2006 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
24 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
26 // Based on work done by:
27 // Dennis Hayes (dennish@Raytek.com)
28 // Aleksey Ryabchuk (ryabchuk@yahoo.com)
32 using System.Collections;
33 using System.Drawing.Imaging;
34 using System.Runtime.Serialization;
35 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms {
40 public sealed class ImageListStreamer : ISerializable {
41 readonly ImageList.ImageCollection imageCollection;
46 internal ImageListStreamer (ImageList.ImageCollection imageCollection)
48 this.imageCollection = imageCollection;
51 private ImageListStreamer (SerializationInfo info, StreamingContext context)
53 byte [] data = (byte []) info.GetValue ("Data", typeof (byte []));
54 if (data == null || data.Length <= 4) { // 4 is the signature
58 // check the signature ( 'MSFt' )
59 if (data [0] != 77 || data [1] != 83 || data [2] != 70 || data [3] != 116) {
63 MemoryStream decoded = GetDecodedStream (data, 4, data.Length - 4);
64 decoded.Position = 4; // jumps over 'magic' and 'version', which are 16-bits each
66 BinaryReader reader = new BinaryReader (decoded);
67 ushort nimages = reader.ReadUInt16 ();
68 reader.ReadUInt16 (); // cMaxImage
69 ushort grow = reader.ReadUInt16 (); // cGrow
70 ushort cx = reader.ReadUInt16 ();
71 ushort cy = reader.ReadUInt16 ();
72 uint bkcolor = reader.ReadUInt32 ();
73 back_color = Color.FromArgb ((int) bkcolor);
74 reader.ReadUInt16 (); // flags
76 short [] ovls = new short [4];
77 for (int i = 0; i < 4; i++) {
78 ovls[i] = reader.ReadInt16 ();
81 byte [] decoded_buffer = decoded.GetBuffer ();
83 // FileSize field from the bitmap file header
84 int filesize = decoded_buffer [bmp_offset + 2] + (decoded_buffer [bmp_offset + 3] << 8) +
85 (decoded_buffer [bmp_offset + 4] << 16) + (decoded_buffer [bmp_offset + 5] << 24);
86 // ImageSize field from the info header (can be 0)
87 int imagesize = decoded_buffer [bmp_offset + 34] + (decoded_buffer [bmp_offset + 35] << 8) +
88 (decoded_buffer [bmp_offset + 36] << 16) + (decoded_buffer [bmp_offset + 37] << 24);
90 int bmp_length = imagesize + filesize;
91 MemoryStream bmpms = new MemoryStream (decoded_buffer, bmp_offset, bmp_length);
94 bmp = new Bitmap (bmpms);
95 MemoryStream mask_stream = new MemoryStream (decoded_buffer,
96 bmp_offset + bmp_length,
97 (int) (decoded.Length - bmp_offset - bmp_length));
99 if (mask_stream.Length > 0)
100 mask = new Bitmap (mask_stream);
102 if (bkcolor == 0xFFFFFFFF)
103 back_color = bmp.GetPixel (0, 0);
106 int width = bmp.Width;
107 int height = bmp.Height;
108 Bitmap newbmp = new Bitmap (bmp);
109 for (int y = 0; y < height; y++) {
110 for (int x = 0; x < width; x++) {
111 Color mcolor = mask.GetPixel (x, y);
113 newbmp.SetPixel (x, y, Color.Transparent);
122 images = new Image [nimages];
123 image_size = new Size (cx, cy);
124 Rectangle dest_rect = new Rectangle (0, 0, cx, cy);
125 if (grow * bmp.Width > cx) // Some images store a wrong 'grow' factor
126 grow = (ushort) (bmp.Width / cx);
128 for (int r = 0 ; r < nimages ; r++) {
131 Rectangle area = new Rectangle (col * cx, row * cy, cx, cy);
132 Bitmap b = new Bitmap (cx, cy);
133 using (Graphics g = Graphics.FromImage (b)) {
134 g.DrawImage (bmp, dest_rect, area, GraphicsUnit.Pixel);
143 static void WriteToFile (MemoryStream st)
146 FileStream fs = File.OpenWrite (Path.GetTempFileName ());
147 Console.WriteLine ("Writing to {0}", fs.Name);
153 static byte [] header = new byte []{ 77, 83, 70, 116, 73, 76, 3, 0 };
154 public void GetObjectData (SerializationInfo si, StreamingContext context)
156 MemoryStream stream = new MemoryStream ();
157 BinaryWriter writer = new BinaryWriter (stream);
158 writer.Write (header);
160 Image [] images = (imageCollection != null) ? imageCollection.ToArray () : this.images;
162 int rows = images.Length / cols;
163 if (images.Length % cols > 0)
166 writer.Write ((ushort) images.Length);
167 writer.Write ((ushort) images.Length);
168 writer.Write ((ushort) 0x4);
169 writer.Write ((ushort) (images [0].Width));
170 writer.Write ((ushort) (images [0].Height));
171 writer.Write (0xFFFFFFFF); //BackColor.ToArgb ()); //FIXME: should set the right one here.
172 writer.Write ((ushort) 0x1009);
173 for (int i = 0; i < 4; i++)
174 writer.Write ((short) -1);
176 Bitmap main = new Bitmap (cols * ImageSize.Width, rows * ImageSize.Height);
177 using (Graphics g = Graphics.FromImage (main)) {
178 g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), 0, 0,
179 main.Width, main.Height);
180 for (int i = 0; i < images.Length; i++) {
181 g.DrawImage (images [i], (i % cols) * ImageSize.Width,
182 (i / cols) * ImageSize.Height);
186 MemoryStream tmp = new MemoryStream ();
187 main.Save (tmp, ImageFormat.Bmp);
188 tmp.WriteTo (stream);
190 Bitmap mask = Get1bppMask (main);
194 tmp = new MemoryStream ();
195 mask.Save (tmp, ImageFormat.Bmp);
196 tmp.WriteTo (stream);
199 stream = GetRLEStream (stream, 4);
200 si.AddValue ("Data", stream.ToArray (), typeof (byte []));
203 unsafe Bitmap Get1bppMask (Bitmap main)
205 Rectangle rect = new Rectangle (0, 0, main.Width, main.Height);
206 Bitmap result = new Bitmap (main.Width, main.Height, PixelFormat.Format1bppIndexed);
207 BitmapData dresult = result.LockBits (rect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
209 int w = images [0].Width;
210 int h = images [0].Height;
211 byte *scan = (byte *) dresult.Scan0.ToPointer ();
212 int stride = dresult.Stride;
213 Bitmap current = null;
214 for (int idx = 0; idx < images.Length; idx++) {
215 current = (Bitmap) images [idx];
216 // Hack for newly added images.
217 // Probably has to be done somewhere else.
218 Color c1 = current.GetPixel (0, 0);
219 if (c1.A != 0 && c1 == back_color)
220 current.MakeTransparent (back_color);
230 for (int y = 0; y < main.Height; y++) {
237 for (int x = 0; x < main.Width; x++) {
242 imgidx = factor_y + factor_x;
243 if (imgidx >= images.Length)
245 current = (Bitmap) images [imgidx];
246 Color color = current.GetPixel (localx, localy);
248 int ptridx = yidx + (x >> 3);
249 scan [ptridx] |= (byte) (0x80 >> (x & 7));
253 if (imgidx >= images.Length)
258 result.UnlockBits (dresult);
263 static MemoryStream GetDecodedStream (byte [] bytes, int offset, int size)
265 byte [] buffer = new byte [512];
268 MemoryStream result = new MemoryStream ();
270 count = (int) bytes [offset++];
271 data = (int) bytes [offset++];
272 if ((512 - count) < position) {
273 result.Write (buffer, 0, position);
277 for (int i = 0; i < count; i++)
278 buffer [position++] = (byte) data;
283 result.Write (buffer, 0, position);
290 static MemoryStream GetRLEStream (MemoryStream input, int start)
292 MemoryStream result = new MemoryStream ();
293 byte [] ibuffer = input.GetBuffer ();
294 result.Write (ibuffer, 0, start);
295 input.Position = start;
300 while ((current = input.ReadByte ()) != -1) {
301 if (prev != current || count == 255) {
303 result.WriteByte ((byte) count);
304 result.WriteByte ((byte) prev);
313 result.WriteByte ((byte) count);
314 result.WriteByte ((byte) current);
320 internal Image [] Images {
321 get { return images; }
324 internal Size ImageSize {
325 get { return image_size; }
328 internal ColorDepth ColorDepth {
329 get { return ColorDepth.Depth32Bit; }
332 internal Color BackColor {
333 get { return back_color; }