Extending the PictureEdit control with custom drawing, part deux

There’s been a bit of additional interest in the PictureEditCanvas control, which allows a user to annotate an image with some shapes and freehand drawing. To improve on it a little further, I’ve added the ability to “stamp” some text onto the canvas.

Before the last post, all of the polygon shapes were descendants of a Shape class. When I decided to add the freehand drawing functionality, this required a little bit of refactoring in which all drawing tools now implement the IDrawShapes interface. This interface contains the common properties and methods that all drawing elements use at a minimum. The abstract Shape and FillableShape classes extend this further for the elements that support them (Line, Rectangle and Ellipse).

I guess it could be argued that at the end of the day, text is just a series of shapes as well, so it certainly makes sense to make our TextStamp implement the IDrawShapes interface just like its toolbox brethren. Let’s have a look at how the TextStamp class ultimately turned out:

 sealed public class TextStamp : IDrawShapes
    {

        #region Public properties

        /// <summary>
        /// Gets or sets the Fore Color of this Text Stamp
        /// </summary>
        public Color ForeColor
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Fill Color of this Text Stamp
        /// </summary>
        public Color FillColor
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Border Width of this Text Stamp
        /// </summary>
        public float BorderWidth
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the starting X co-ordinate for the Text Stamp
        /// </summary>
        public int StartX
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the starting Y co-ordinate for the Text Stamp
        /// </summary>
        public int StartY
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Text string of this Text Stamp
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the Text Font to be used for this Text Stamp
        /// </summary>
        public Font TextFont
        {
            get;
            set;
        }

        #endregion


        /// <summary>
        /// Initializes a new instance of the TextStamp class
        /// </summary>
        public TextStamp()
        {

        }



        /// <summary>
        /// Starts this Text Stamp by registering the start location coordinates
        /// </summary>
        /// <param name="Location">Start location</param>
        public void StartDrawing(Point Location)
        {
            StartX = Location.X;
            StartY = Location.Y;

        }   //End the StartDrawing() method



        /// <summary>
        /// Ends this Text Stamp by registering the end location coordinates
        /// </summary>
        /// <param name="Location">End location</param>
        public void EndDrawing(Point Location)
        {
            StartX = Location.X;
            StartY = Location.Y;

        }   //End the EndDrawing() method



        /// <summary>
        /// Draws this Text Stamp
        /// </summary>
        /// <param name="graphics">Current Graphics context</param>
        public void Draw(Graphics graphics)
        {
            using (Pen pen = new Pen(ForeColor))
            {
                pen.Alignment = PenAlignment.Inset;
                graphics.SmoothingMode = SmoothingMode.HighQuality;

                using (GraphicsPath path = new GraphicsPath())
                {
                    path.AddString(Text, TextFont.FontFamily, (int)TextFont.Style, TextFont.Size, new Point(StartX, StartY), StringFormat.GenericDefault);
                    graphics.DrawPath(pen, path);

                    using (SolidBrush brush = new SolidBrush(FillColor))
                        graphics.FillPath(brush, path);

                }   //End the using() statement

            }   //End the using() statement

        }   //End the Draw() method



        /// <summary>
        /// Returns True if the provided text can fit on within the given image width, based on the text settings
        /// </summary>
        /// <param name="ImageWidth">Width of the Image to be test the text against</param>
        /// <param name="TextString">Text string to check</param>
        /// <param name="TextFont">Text font settings</param>
        /// <param name="graphics">Current Graphics context</param>
        /// <returns>True if the text will fit within the provided Image width</returns>
        static public bool CheckTextSizing(int ImageWidth, string TextString, Font TextFont, Graphics graphics)
        {
            int TextWidth = 0;

            TextWidth = Convert.ToInt32(graphics.MeasureString(TextString, TextFont).Width);

            return (TextWidth < ImageWidth);

        }   //End the CheckTextSizing() method


    }   //End the TextStamp class

Our class makes use of those standard IDrawShapes members and has a few additional properties responsible for storing the text string and text Font object.

Unlike the other Draw methods, I’m building a GraphicsPath object in the Draw method in order to render text that can be filled with another color (I may adopt this method in the FillableShape types as well). The text is anti-aliased, because honestly it would look pretty awful if it wasn’t.

One additional point of interest in the TextStamp class is the CheckTextSizing method. The idea behind this is perform a check in which we determine if the text being placed on the image will actually fit, given the font & length and the size of the image itself. Keep in mind though that the width of the image isn’t necessarily the width of the control (and by extension, your canvas) itself given the various methods of clipping/stretching/zooming an image in the PictureEdit control.

The Text tool was then added to the Drawing Tools window:

Extended Drawing Tools window
Extended Drawing Tools window

The Text Stamp tool is handled a little differently than the other tools by the PictureEditCanvas. Specifically, it doesn’t require the user to hold down the left mouse button while placing the text. Instead, a preview of the text simply follows the mouse cursor until the user left-clicks in the control to place it.

This mostly seems to satisfy my initial requirements for a control. It allows for simple shapes, freehand drawing and text placement. It may make sense to extend this functionality to a Panel control to create a stand-alone drawing surface control that has nothing to do with an Image (or the PictureEdit), which can easily be done by moving the majority of the PictureEditCanvas control into a Panel control descendant.

If I do decide to continue work on this control (or Panel control analog), some features I’d like to see are:

  • Ability to select shapes already placed onto the canvas to modify/remove them
  • Ability to make perfect squares & rectangles by holding SHIFT or CTRL while dragging the mouse. This is a common behavior of painting programs.
  • Ability to rotate shapes
  • Ability to enter text in-place
  • Ability to place an image onto the canvas

If there is interest in these features, I may migrate my work onto CodePlex and continue development on it. Until then, here is the updated source code for what I discussed today: PictureEditDrawing2

Extending the PictureEdit control with custom drawing, part deux

7 thoughts on “Extending the PictureEdit control with custom drawing, part deux

      1. Ahmed Adel says:

        Thanks a lot. I wish if you can recommend a specific developer(s) if you have any previous experience with them.

        Like

  1. Ahmed, I would definitely feel confident in recommending Michael’s service. I have been working with him as a volunteer DevExpress MVP for several years now and he is highly-skilled and well versed in the various DevExpress products.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s