void DispatchBitmapInfo(BitmapInfo bi)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new BitmapInfoDelegate(DispatchBitmapInfo), bi);
                return;
            }

            TabPage p    = null;
            string  name = bi.name;

            if (String.IsNullOrEmpty(name))
            {
                name = "Image";
            }
            foreach (TabPage page in this.tabControl1.TabPages)
            {
                if (page.Text == bi.name)
                {
                    p = page;
                    break;
                }
            }

            ImageBrowser ib = null;

            if (p == null)
            {
                p = new TabPage(name);
                this.tabControl1.TabPages.Add(p);

                ib = new ImageBrowser();
                p.Controls.Add(ib);
                ib.Dock = DockStyle.Fill;
            }
            else
            {
                ib = p.Controls[0] as ImageBrowser;
            }

            ib.SetImage(bi.image);
            ib.SetStatusText(string.Format("size={2}; min={0:N3}; max={1:N3}", bi.min, bi.max, bi.image.Size));
            ib.Invalidate();
        }
        internal unsafe BitmapInfo GetBitmapInfo()
        {
            BitmapInfo bi  = new BitmapInfo();
            Bitmap     bmp = new Bitmap(this.size.Width, this.size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            BitmapData bd  = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, bmp.PixelFormat);

            UInt32 *dest = (UInt32 *)bd.Scan0;
            int     h    = size.Height;
            int     w    = size.Width;

            fixed(void *src = this.recv_buffer)
            {
                if (this.type == ImageType.Luminance)
                {
                    UInt32[] palette = Palette.GetPalette(palette_type);
                    int      pmax    = palette.Length - 1;

                    if (this.channel_type == ChannelType.Float)
                    {
                        float  min, max;
                        float *fsrc = (float *)src;
                        CalculateRange(fsrc, this.size, out min, out max);

                        if (min == max)
                        {
                            for (int i = 0; i < w * h; i++)
                            {
                                *dest = palette[0];
                                dest++;
                            }
                        }
                        else
                        {
                            for (int r = 0; r < h; r++)
                            {
                                for (int c = 0; c < w; c++)
                                {
                                    int value = (int)(((*fsrc - min) * pmax) / (max - min));
                                    if (value >= 0 && value <= pmax)
                                    {
                                        *dest = palette[value];
                                    }

                                    fsrc++;
                                    dest++;
                                }
                            }
                        }

                        bi.min = min;
                        bi.max = max;
                    }

                    // -----------------------------


                    if (this.channel_type == ChannelType.U16)
                    {
                        ushort  umin, umax;
                        ushort *ussrc = (ushort *)src;
                        CalculateRange(ussrc, this.size, out umin, out umax);

                        if (umin == umax)
                        {
                            for (int i = 0; i < w * h; i++)
                            {
                                *dest = palette[0];
                                dest++;
                            }
                        }
                        else
                        {
                            for (int r = 0; r < h; r++)
                            {
                                for (int c = 0; c < w; c++)
                                {
                                    int value = (((int)*ussrc - umin) * pmax) / (umax - umin);
                                    if (value >= 0 && value <= pmax)
                                    {
                                        *dest = palette[value];
                                    }
                                    ussrc++;
                                    dest++;
                                }
                            }
                        }

                        bi.min = umin;
                        bi.max = umax;
                    }

                    // -----------------------------

                    if (this.channel_type == ChannelType.U8)
                    {
                        byte  bmin, bmax;
                        byte *bsrc = (byte *)src;
                        CalculateRange(bsrc, this.size, out bmin, out bmax);

                        if (bmin == bmax)
                        {
                            for (int i = 0; i < w * h; i++)
                            {
                                *dest = palette[0];
                                dest++;
                            }
                        }
                        else
                        {
                            for (int r = 0; r < h; r++)
                            {
                                for (int c = 0; c < w; c++)
                                {
                                    int value = (((int)*bsrc - bmin) * pmax) / (bmax - bmin);
                                    if (value >= 0 && value <= pmax)
                                    {
                                        *dest = palette[value];
                                    }
                                    bsrc++;
                                    dest++;
                                }
                            }
                        }

                        bi.min = bmin;
                        bi.max = bmax;
                    }
                }
            }

            bmp.UnlockBits(bd);

            bi.image = bmp;
            bi.name  = this.name;
            return(bi);
        }
        private void ProcessConnection(Socket cli)
        {
            DImage img = new DImage();

            byte[] b = new byte[1];

            while (true)
            {
                string line = "";
                while (true)
                {
                    cli.Receive(b);
                    if (b[0] == '\n')
                    {
                        break;
                    }
                    line += (char)b[0];
                }

                string[] command = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (command.Length == 0)
                {
                    continue;
                }

                if (command[0] == "height")
                {
                    img.size.Height = int.Parse(command[1]);
                }
                if (command[0] == "name")
                {
                    img.name = line.Substring(4).Trim();
                }
                if (command[0] == "width")
                {
                    img.size.Width = int.Parse(command[1]);
                }
                if (command[0] == "ctype") // channel type
                {
                    img.channel_type = (ChannelType)Enum.Parse(typeof(ChannelType), command[1]);
                }
                if (command[0] == "itype") // image type
                {
                    img.type = (ImageType)Enum.Parse(typeof(ImageType), command[1]);
                }
                if (command[0] == "palette") // image type
                {
                    img.palette_type = (PaletteType)Enum.Parse(typeof(PaletteType), command[1]);
                }

                if (command[0] == "data") // image type
                {
                    Debug("Pobieranie obrazu... ");
                    img.ReadStream(cli);
                    cli.Close();

                    Debug("+OK");
                    BitmapInfo bi = img.GetBitmapInfo();

                    this.DispatchBitmapInfo(bi);
                    return;
                }
            }
        }