예제 #1
0
        public static void DibToFile(Stream stream, string filePath)
        {
            // Read the DIB into a Byte array and pin it
            // This is necessary because some of the unmanaged calls
            // need a pointer to the Dib bytes.
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, (int)stream.Length);

            string   imagePath = string.Empty;
            GCHandle gcHandle  = new GCHandle();

            try
            {
                gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);

                // Reset the stream position since it was read into the byte array
                // Get the bitmapInfoHeader so we can do some calculations
                stream.Position = 0;
                BITMAPINFOHEADER bmpInfoHeader = GetBitMapInfoHeader(stream);
                if ((bmpInfoHeader.biClrUsed == 0) && (bmpInfoHeader.biBitCount < 16))
                {
                    bmpInfoHeader.biClrUsed = 1 << bmpInfoHeader.biBitCount;
                }

                // Get IntPtrs for the DIB itself as well as for the actual pixels in the DIB
                IntPtr dibPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0);
                IntPtr pixPtr = new IntPtr((int)dibPtr + bmpInfoHeader.biSize + (bmpInfoHeader.biClrUsed * 4));

                // Get a GDI Bitmap
                IntPtr img = IntPtr.Zero;

                try
                {
                    int st = GdiPlus.GdipCreateBitmapFromGdiDib(dibPtr, pixPtr, ref img);

                    // Couldn't create bitmap, return null and log
                    if ((st != 0) || (img == IntPtr.Zero))
                    {
                        throw new DIBHelperException("Couldn't get DIB IntPtr");
                    }

                    // Write the bitmap to a file of the specified type
                    Guid clsid = GetCodecClsid(filePath);
                    st = GdiPlus.GdipSaveImageToFile(img, filePath, ref clsid, IntPtr.Zero);
                    if (st != 0)
                    {
                        throw new DIBHelperException("Couldn't write Dib to File");
                    }
                }
                finally
                {
                    // Dispose of resources
                    GdiPlus.GdipDisposeImage(img);
                }
            }
            finally
            {
                gcHandle.Free();
            }
        }
예제 #2
0
파일: Program.cs 프로젝트: bangush/WInterop
        private void DrawClock(DeviceContext dc)
        {
            int iAngle;

            Point[] pt = new Point[3];

#if GDIPLUS
            using var graphics = new Graphics(dc);
            GdiPlus.SetSmoothingMode(graphics, SmoothingMode.HighQuality);
#else
            dc.SelectObject(StockBrush.Black);
#endif
            for (iAngle = 0; iAngle < 360; iAngle += 6)
            {
                pt[0].X = 0;
                pt[0].Y = 900;
                RotatePoint(pt, 1, iAngle);
                pt[2].X  = pt[2].Y = iAngle % 5 != 0 ? 33 : 100;
                pt[0].X -= pt[2].X / 2;
                pt[0].Y -= pt[2].Y / 2;
                pt[1].X  = pt[0].X + pt[2].X;
                pt[1].Y  = pt[0].Y + pt[2].Y;
#if GDIPLUS
                graphics.FillEllipse(_blackBrush, pt[0].X, pt[0].Y, pt[1].X - pt[0].X, pt[1].Y - pt[0].Y);
#else
                dc.Ellipse(Rectangle.FromLTRB(pt[0].X, pt[0].Y, pt[1].X, pt[1].Y));
#endif
            }
        }
예제 #3
0
        public unsafe FormsSolidBrush(Color color)
        {
            Color = color;
            IntPtr nativeBrush;

            GdiPlus.GdipCreateSolidFill(color.ToArgb(), &nativeBrush).ThrowIfFailed();
            SetNativeBrush(nativeBrush);
        }
        /// <summary>
        /// Calculates size information for the specified text.
        /// </summary>
        /// <param name="text">The string to measure.</param>
        /// <param name="bounds">A SizeF structure containing the maximum desired width and height of the text. Pass SizeF.Empty to disable wrapping calculations. A width or height of 0 disables the relevant calculation.</param>
        /// <param name="format">A StringFormat object which specifies the measurement format of the string. Pass null to use the default StringFormat (StringFormat.GenericDefault).</param>
        /// <param name="ranges">Fills the specified IList of RectangleF structures with position information for individual characters. If this argument is null, these calculations are skipped.</param>
        /// <returns>A RectangleF containing the bounding box for the specified text.</returns>
        public RectangleF MeasureText(string text, SizeF bounds, StringFormat format, List <RectangleF> ranges)
        {
            if (String.IsNullOrEmpty(text))
            {
                return(RectangleF.Empty);
            }

            if (bounds == SizeF.Empty)
            {
                bounds = maximum_graphics_size;
            }

            if (format == null)
            {
                format = default_string_format;
            }

            // TODO: What should we do in this case?
            if (ranges == null)
            {
                ranges = new List <RectangleF>();
            }

            ranges.Clear();

            PointF origin = PointF.Empty;
            SizeF  size   = SizeF.Empty;

            IntPtr native_graphics      = GdiPlus.GetNativeGraphics(gfx);
            IntPtr native_font          = GdiPlus.GetNativeFont(font);
            IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format);

            RectangleF layoutRect = new RectangleF(PointF.Empty, bounds);

            int height = 0;

            // It seems that the mere presence of \n and \r characters
            // is enough for Mono to botch the layout (even if these
            // characters are not processed.) We'll need to find a
            // different way to perform layout on Mono, probably
            // through Pango.
            // Todo: This workaround  allocates memory.
            //if (Configuration.RunningOnMono)
            {
                string[] lines = text.Replace("\r", String.Empty).Split(newline_characters);
                foreach (string s in lines)
                {
                    ranges.AddRange(GetCharExtents(
                                        s, height, 0, s.Length, layoutRect,
                                        native_graphics, native_font, native_string_format));
                    height += font.Height;
                }
            }

            return(new RectangleF(ranges[0].X, ranges[0].Y, ranges[ranges.Count - 1].Right, ranges[ranges.Count - 1].Bottom));
        }
예제 #5
0
        void DrawHands(DeviceContext dc, SystemTime time, bool erase = false, bool drawHourAndMinuteHands = true)
        {
            int[] handAngles =
            {
                (time.Hour * 30) % 360 + time.Minute / 2,
                time.Minute * (360 / 60),
                time.Second * (360 / 60)
            };

            Point[][] handPoints =
            {
                new Point[] { new Point(0, -150), new Point(100, 0), new Point(0, 600), new Point(-100, 0), new Point(0, -150) },
                new Point[] { new Point(0, -200), new Point(50, 0), new Point(0, 800), new Point(-50, 0), new Point(0, -200), },
                new Point[] { new Point(0, 0), new Point(0, 0), new Point(0, 0), new Point(0, 0), new Point(0, 800) }
            };

#if GDIPLUS
            using (var graphics = GdiPlus.CreateGraphics(dc))
            {
                if (erase)
                {
                    using (var brush = graphics.CreateSolidBrush(Color.White))
                    {
                        graphics.FillEllipse(brush, -830, -830, 1660, 1660);
                    }
                    return;
                }

                using (var pen = graphics.CreatePen(Color.Black))
                {
                    graphics.SetSmoothingMode(SmoothingMode.HighQuality);
#else
                    dc.SelectObject(erase ? StockPen.White : StockPen.Black);
#endif

                    for (int i = drawHourAndMinuteHands ? 0 : 2; i < 3; i++)
                    {
                        RotatePoint(handPoints[i], 5, handAngles[i]);

#if GDIPLUS
                        graphics.DrawLines(pen, handPoints[i]);
#else
                        dc.Polyline(handPoints[i]);
#endif
                    }
#if GDIPLUS
                }
            }
#endif
        }
        // Gets the bounds of each character in a line of text.
        // The line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges).
        IEnumerable <RectangleF> GetCharExtents(string text, int height, int line_start, int line_length,
                                                RectangleF layoutRect, IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format)
        {
            RectangleF rect     = new RectangleF();
            int        line_end = line_start + line_length;

            while (line_start < line_end)
            {
                //if (text[line_start] == '\n' || text[line_start] == '\r')
                //{
                //    line_start++;
                //    continue;
                //}

                int num_characters = (line_end - line_start) > GdiPlus.MaxMeasurableCharacterRanges ?
                                     GdiPlus.MaxMeasurableCharacterRanges :
                                     line_end - line_start;
                int status = 0;

                for (int i = 0; i < num_characters; i++)
                {
                    characterRanges[i] = new CharacterRange(line_start + i, 1);

                    IntPtr region;
                    status     = GdiPlus.CreateRegion(out region);
                    regions[i] = region;
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));
                }

                status = GdiPlus.SetStringFormatMeasurableCharacterRanges(native_string_format, num_characters, characterRanges);
                Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                status = GdiPlus.MeasureCharacterRanges(native_graphics, text, text.Length,
                                                        native_font, ref layoutRect, native_string_format, num_characters, regions);
                Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                for (int i = 0; i < num_characters; i++)
                {
                    GdiPlus.GetRegionBounds(regions[i], native_graphics, ref rect);
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));
                    GdiPlus.DeleteRegion(regions[i]);
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                    rect.Y += height;
                    yield return(rect);
                }

                line_start += num_characters;
            }
        }
예제 #7
0
        public static void Record()
        {
            recording = true;

            HWnd hDesk  = User32.GetDesktopWindow();
            HDc  hdcSrc = User32.GetWindowDC(hDesk);

            User32.GetWindowRect(hDesk, out Rect rect);

            int w = rect.Width;
            int h = rect.Height;


            HDc     hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);
            HBitmap hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, w, h);
            IntPtr  hold    = Gdi32.SelectObject(hdcDest, hBitmap);

            Gdi32.DeleteDC(hold);

            var m = typeof(Bitmap).GetMethod("FromGDIplus", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            Func <IntPtr, Bitmap> f = (Func <IntPtr, Bitmap>)m.CreateDelegate(typeof(Func <IntPtr, Bitmap>));

            var st  = DateTime.Now;
            int fps = 0;

            while (recording)
            {
                Gdi32.BitBlt(hdcDest, 0, 0, w, h, hdcSrc, 0, 0, TernaryRasterOperations.SRCCOPY);

                GdiPlus.GdipCreateBitmapFromHBITMAP(hBitmap, IntPtr.Zero, out IntPtr bmpPtr);
                RecordCallBack?.Invoke(f(bmpPtr));


                fps++;
                var et = DateTime.Now;
                if ((et - st).TotalMilliseconds >= 1000)
                {
                    FPS = 1000 / fps;
                    fps = 0;
                    st  = et;
                }
            }


            User32.ReleaseDC(hDesk, hdcSrc);
            Gdi32.DeleteObject(hBitmap);
        }
        // Gets the bounds of each character in a line of text.
        // Each line is processed in blocks of 32 characters (GdiPlus.MaxMeasurableCharacterRanges).
        IEnumerable <RectangleF> MeasureGlyphExtents(
            ref TextBlock block, string text,
            IntPtr native_graphics, IntPtr native_font, IntPtr native_string_format,
            ref RectangleF layoutRect, out float max_width, out float max_height)
        {
            measured_glyphs.Clear();
            max_width  = layoutRect.Left;
            max_height = layoutRect.Top;
            float last_line_width = 0, last_line_height = 0;

            int current = 0;

            while (current < text.Length)
            {
                int num_characters = (text.Length - current) > GdiPlus.MaxMeasurableCharacterRanges ?
                                     GdiPlus.MaxMeasurableCharacterRanges :
                                     text.Length - current;
                int status = 0;

                // Prepare the character ranges and region structs for the measurement.
                for (int i = 0; i < num_characters; i++)
                {
                    if (text[current + i] == '\n' || text[current + i] == '\r')
                    {
                        throw new NotSupportedException();
                    }

                    characterRanges[i] = new CharacterRange(current + i, 1);

                    IntPtr region;
                    status     = GdiPlus.CreateRegion(out region);
                    regions[i] = region;
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));
                }

                status = GdiPlus.SetStringFormatMeasurableCharacterRanges(native_string_format, num_characters, characterRanges);
                Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                status = GdiPlus.MeasureCharacterRanges(native_graphics, text, text.Length,
                                                        native_font, ref layoutRect, native_string_format, num_characters, regions);
                Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                // Read back the results of the measurement.
                for (int i = 0; i < num_characters; i++)
                {
                    RectangleF rect = new RectangleF();

                    GdiPlus.GetRegionBounds(regions[i], native_graphics, ref rect);
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));
                    GdiPlus.DeleteRegion(regions[i]);
                    Debug.Assert(status == 0, String.Format("GDI+ error: {0}", status));

                    if (rect.Bottom > max_height)
                    {
                        max_height = rect.Bottom;
                    }
                    if (rect.Right > max_width)
                    {
                        max_width = rect.Right;
                    }

                    if (rect.X > last_line_width)
                    {
                        last_line_width = rect.X;
                    }
                    if (rect.Y > last_line_height)
                    {
                        last_line_height = rect.Y;
                    }

                    measured_glyphs.Add(rect);
                }

                current += num_characters;
            }

            // Make sure the current height is updated, if the the current line has wrapped due to word-wraping.
            // Otherwise, the next line will overlap with the current one.
            if (measured_glyphs.Count > 1)
            {
                if ((block.Direction & TextDirection.Vertical) == 0)
                {
                    if (layoutRect.Y < last_line_height)
                    {
                        layoutRect.Y = last_line_height;
                    }
                }
                else
                {
                    if (layoutRect.X < last_line_width)
                    {
                        layoutRect.X = last_line_width;
                    }
                }
            }

            // Mono's GDI+ implementation suffers from an issue where the specified layoutRect is not taken into
            // account. We will try to improve the situation by moving text to the correct location on this
            // error condition. This will not help word wrapping, but it is better than nothing.
            // TODO: Mono 2.8 is supposed to ship with a Pango-based GDI+ text renderer, which should not
            // suffer from this bug. Verify that this is the case and remove the hack.
            if (Configuration.RunningOnMono && (layoutRect.X != 0 || layoutRect.Y != 0) && measured_glyphs.Count > 0)
            {
                for (int i = 0; i < measured_glyphs.Count; i++)
                {
                    RectangleF rect = measured_glyphs[i];
                    rect.X            += layoutRect.X;
                    rect.Y            += layoutRect.Y;
                    measured_glyphs[i] = rect;
                }
            }

            return(measured_glyphs);
        }
        TextExtents MeasureTextExtents(ref TextBlock block, TextQuality quality)
        {
            // TODO: Parse layout options:
            var format = block.Font.Italic ? measure_string_format : measure_string_format_tight;

            //StringFormat format = measure_string_format_tight;

            if (block.Direction == TextDirection.Vertical)
            {
                format.FormatFlags |= StringFormatFlags.DirectionVertical;
            }
            else
            {
                format.FormatFlags &= ~StringFormatFlags.DirectionVertical;
            }

            if (block.Direction == TextDirection.RightToLeft)
            {
                format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
            }
            else
            {
                format.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
            }

            if (block.Alignment == TextAlignment.Near)
            {
                format.Alignment = StringAlignment.Near;
            }
            else if (block.Alignment == TextAlignment.Center)
            {
                format.Alignment = StringAlignment.Center;
            }
            else
            {
                format.Alignment = StringAlignment.Far;
            }

            TextExtents extents = text_extents_pool.Acquire();

            RectangleF rect = block.Bounds;

            // Work around Mono/GDI+ bug, which causes incorrect
            // text wraping when block.Bounds == SizeF.Empty.
            if (block.Bounds.Size == SizeF.Empty)
            {
                rect.Size = MaximumGraphicsClipSize;
            }

            SetTextRenderingOptions(graphics, block.Font, quality);

            IntPtr native_graphics      = GdiPlus.GetNativeGraphics(graphics);
            IntPtr native_font          = GdiPlus.GetNativeFont(block.Font);
            IntPtr native_string_format = GdiPlus.GetNativeStringFormat(format);

            float max_width = 0, max_height = 0;

            // It seems that the mere presence of \n and \r characters
            // is enough for Mono to botch the layout (even if these
            // characters are not processed.) We'll need to find a
            // different way to perform layout on Mono, probably
            // through Pango.
            // TODO: This workaround allocates memory.
            //if (Configuration.RunningOnMono)
            {
                string[] lines = block.Text.Replace("\r", String.Empty).Split('\n');
                foreach (string s in lines)
                {
                    float width, height;

                    extents.AddRange(MeasureGlyphExtents(
                                         ref block, s,
                                         native_graphics, native_font, native_string_format,
                                         ref rect, out width, out height));

                    if ((block.Direction & TextDirection.Vertical) == 0)
                    {
                        rect.Y += block.Font.Height;
                    }
                    else
                    {
                        rect.X += block.Font.Height;
                    }

                    if (width > max_width)
                    {
                        max_width = width;
                    }
                    if (height > max_height)
                    {
                        max_height = height;
                    }
                }
            }

            if (extents.Count > 0)
            {
                extents.BoundingBox = new RectangleF(extents[0].X, extents[0].Y, max_width, max_height);
            }
            else
            {
                extents.BoundingBox = RectangleF.Empty;
            }

            return(extents);
        }