diff options
Diffstat (limited to 'source/ShiftUI/Internal/ImageListStreamer.cs')
| -rw-r--r-- | source/ShiftUI/Internal/ImageListStreamer.cs | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/ImageListStreamer.cs b/source/ShiftUI/Internal/ImageListStreamer.cs new file mode 100644 index 0000000..3186747 --- /dev/null +++ b/source/ShiftUI/Internal/ImageListStreamer.cs @@ -0,0 +1,338 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2002-2006 Novell, Inc. +// +// Authors: +// Jackson Harper ([email protected]) +// Gonzalo Paniagua Javier ([email protected]) +// +// Based on work done by: +// Dennis Hayes ([email protected]) +// Aleksey Ryabchuk ([email protected]) + +using System.IO; +using System.Drawing; +using System.Collections; +using System.Drawing.Imaging; +using System.Runtime.Serialization; +using System.Runtime.InteropServices; +using System; + + +namespace ShiftUI { + [Serializable] + public sealed class ImageListStreamer : ISerializable { + readonly ImageList.ImageCollection imageCollection; + Image [] images; + Size image_size; + Color back_color; + + internal ImageListStreamer (ImageList.ImageCollection imageCollection) + { + this.imageCollection = imageCollection; + } + + private ImageListStreamer (SerializationInfo info, StreamingContext context) + { + byte [] data = (byte []) info.GetValue ("Data", typeof (byte [])); + if (data == null || data.Length <= 4) { // 4 is the signature + return; + } + + // check the signature ( 'MSFt' ) + if (data [0] != 77 || data [1] != 83 || data [2] != 70 || data [3] != 116) { + return; + } + + MemoryStream decoded = GetDecodedStream (data, 4, data.Length - 4); + decoded.Position = 4; // jumps over 'magic' and 'version', which are 16-bits each + + BinaryReader reader = new BinaryReader (decoded); + ushort nimages = reader.ReadUInt16 (); + reader.ReadUInt16 (); // cMaxImage + ushort grow = reader.ReadUInt16 (); // cGrow + ushort cx = reader.ReadUInt16 (); + ushort cy = reader.ReadUInt16 (); + uint bkcolor = reader.ReadUInt32 (); + back_color = Color.FromArgb ((int) bkcolor); + reader.ReadUInt16 (); // flags + + short [] ovls = new short [4]; + for (int i = 0; i < 4; i++) { + ovls[i] = reader.ReadInt16 (); + } + + byte [] decoded_buffer = decoded.GetBuffer (); + int bmp_offset = 28; + // FileSize field from the bitmap file header + int filesize = decoded_buffer [bmp_offset + 2] + (decoded_buffer [bmp_offset + 3] << 8) + + (decoded_buffer [bmp_offset + 4] << 16) + (decoded_buffer [bmp_offset + 5] << 24); + // ImageSize field from the info header (can be 0) + int imagesize = decoded_buffer [bmp_offset + 34] + (decoded_buffer [bmp_offset + 35] << 8) + + (decoded_buffer [bmp_offset + 36] << 16) + (decoded_buffer [bmp_offset + 37] << 24); + + int bmp_length = imagesize + filesize; + MemoryStream bmpms = new MemoryStream (decoded_buffer, bmp_offset, bmp_length); + Bitmap bmp = null; + Bitmap mask = null; + bmp = new Bitmap (bmpms); + MemoryStream mask_stream = new MemoryStream (decoded_buffer, + bmp_offset + bmp_length, + (int) (decoded.Length - bmp_offset - bmp_length)); + + if (mask_stream.Length > 0) + mask = new Bitmap (mask_stream); + + if (bkcolor == 0xFFFFFFFF) + back_color = bmp.GetPixel (0, 0); + + if (mask != null) { + int width = bmp.Width; + int height = bmp.Height; + Bitmap newbmp = new Bitmap (bmp); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + Color mcolor = mask.GetPixel (x, y); + if (mcolor.B != 0) { + newbmp.SetPixel (x, y, Color.Transparent); + } + } + } + bmp.Dispose (); + bmp = newbmp; + mask.Dispose (); + mask = null; + } + images = new Image [nimages]; + image_size = new Size (cx, cy); + Rectangle dest_rect = new Rectangle (0, 0, cx, cy); + if (grow * bmp.Width > cx) // Some images store a wrong 'grow' factor + grow = (ushort) (bmp.Width / cx); + + for (int r = 0 ; r < nimages ; r++) { + int col = r % grow; + int row = r / grow; + Rectangle area = new Rectangle (col * cx, row * cy, cx, cy); + Bitmap b = new Bitmap (cx, cy); + using (Graphics g = Graphics.FromImage (b)) { + g.DrawImage (bmp, dest_rect, area, GraphicsUnit.Pixel); + } + + images [r] = b; + } + bmp.Dispose (); + } + + /* + static void WriteToFile (MemoryStream st) + { + st.Position = 0; + FileStream fs = File.OpenWrite (Path.GetTempFileName ()); + Console.WriteLine ("Writing to {0}", fs.Name); + st.WriteTo (fs); + fs.Close (); + } + */ + + static byte [] header = new byte []{ 77, 83, 70, 116, 73, 76, 1, 1 }; + public void GetObjectData (SerializationInfo si, StreamingContext context) + { + MemoryStream stream = new MemoryStream (); + BinaryWriter writer = new BinaryWriter (stream); + writer.Write (header); + + Image [] images = (imageCollection != null) ? imageCollection.ToArray () : this.images; + int cols = 4; + int rows = images.Length / cols; + if (images.Length % cols > 0) + ++rows; + + writer.Write ((ushort) images.Length); + writer.Write ((ushort) images.Length); + writer.Write ((ushort) 0x4); + writer.Write ((ushort) (images [0].Width)); + writer.Write ((ushort) (images [0].Height)); + writer.Write (0xFFFFFFFF); //BackColor.ToArgb ()); //FIXME: should set the right one here. + writer.Write ((ushort) 0x21); + for (int i = 0; i < 4; i++) + writer.Write ((short) -1); + + Bitmap main = new Bitmap (cols * ImageSize.Width, rows * ImageSize.Height); + using (Graphics g = Graphics.FromImage (main)) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), 0, 0, + main.Width, main.Height); + for (int i = 0; i < images.Length; i++) { + g.DrawImage (images [i], (i % cols) * ImageSize.Width, + (i / cols) * ImageSize.Height); + } + } + + MemoryStream tmp = new MemoryStream (); + main.Save (tmp, ImageFormat.Bmp); + tmp.WriteTo (stream); + + Bitmap mask = Get1bppMask (main); + main.Dispose (); + main = null; + + tmp = new MemoryStream (); + mask.Save (tmp, ImageFormat.Bmp); + tmp.WriteTo (stream); + mask.Dispose (); + + stream = GetRLEStream (stream, 4); + si.AddValue ("Data", stream.ToArray (), typeof (byte [])); + } + + unsafe Bitmap Get1bppMask (Bitmap main) + { + Rectangle rect = new Rectangle (0, 0, main.Width, main.Height); + Bitmap result = new Bitmap (main.Width, main.Height, PixelFormat.Format1bppIndexed); + BitmapData dresult = result.LockBits (rect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed); + + int w = images [0].Width; + int h = images [0].Height; + byte *scan = (byte *) dresult.Scan0.ToPointer (); + int stride = dresult.Stride; + Bitmap current = null; + for (int idx = 0; idx < images.Length; idx++) { + current = (Bitmap) images [idx]; + // Hack for newly added images. + // Probably has to be done somewhere else. + Color c1 = current.GetPixel (0, 0); + if (c1.A != 0 && c1 == back_color) + current.MakeTransparent (back_color); + // + } + + int yidx = 0; + int imgidx = 0; + int localy = 0; + int localx = 0; + int factor_y = 0; + int factor_x = 0; + for (int y = 0; y < main.Height; y++) { + if (localy == h) { + localy = 0; + factor_y += 4; + } + factor_x = 0; + localx = 0; + for (int x = 0; x < main.Width; x++) { + if (localx == w) { + localx = 0; + factor_x++; + } + imgidx = factor_y + factor_x; + if (imgidx >= images.Length) + break; + current = (Bitmap) images [imgidx]; + Color color = current.GetPixel (localx, localy); + if (color.A == 0) { + int ptridx = yidx + (x >> 3); + scan [ptridx] |= (byte) (0x80 >> (x & 7)); + } + localx++; + } + if (imgidx >= images.Length) + break; + yidx += stride; + localy++; + } + result.UnlockBits (dresult); + + return result; + } + + static MemoryStream GetDecodedStream (byte [] bytes, int offset, int size) + { + byte [] buffer = new byte [512]; + int position = 0; + int count, data; + MemoryStream result = new MemoryStream (); + while (size > 0) { + count = (int) bytes [offset++]; + data = (int) bytes [offset++]; + if ((512 - count) < position) { + result.Write (buffer, 0, position); + position = 0; + } + + for (int i = 0; i < count; i++) + buffer [position++] = (byte) data; + size -= 2; + } + + if (position > 0) + result.Write (buffer, 0, position); + + result.Position = 0; + return result; + } + + //TODO: OptimizeMe + static MemoryStream GetRLEStream (MemoryStream input, int start) + { + MemoryStream result = new MemoryStream (); + byte [] ibuffer = input.GetBuffer (); + result.Write (ibuffer, 0, start); + input.Position = start; + + int prev = -1; + int count = 0; + int current; + while ((current = input.ReadByte ()) != -1) { + if (prev != current || count == 255) { + if (prev != -1) { + result.WriteByte ((byte) count); + result.WriteByte ((byte) prev); + } + prev = current; + count = 0; + } + count++; + } + + if (count > 0) { + result.WriteByte ((byte) count); + result.WriteByte ((byte) current); + } + + return result; + } + + internal Image [] Images { + get { return images; } + } + + internal Size ImageSize { + get { return image_size; } + } + + internal ColorDepth ColorDepth { + get { return ColorDepth.Depth32Bit; } + } + + internal Color BackColor { + get { return back_color; } + } + } +} + |
