Trouble with images that resize

I have the attached code which performs a pretty cool job of taking three swaths of a picturebox, then pastes them together as a new image. The problem is that the image size is changing, but I need it to be the same.

See the attached image file. Notice the button on the right is taller than theone on the left. It was made with the code below.

I need to recreate the swaths exactly.

Let me know what I can change in the code to do that.

Thanks,
newbieweb
void CutImage(PictureBox pictureBox1, PictureBox pictureBox2)
        {
            Image sourceImage = pictureBox1.Image;

            int leftWidth = sourceImage.Width * 15 / 100;
            Rectangle leftSwath = new Rectangle(0, 0, leftWidth, sourceImage.Height);

            int centerWidth = sourceImage.Width * 15 / 100;
            Rectangle centerSwath = new Rectangle((sourceImage.Width - centerWidth) / 2, 0, centerWidth, sourceImage.Height);

            int rightWidth = sourceImage.Width * 15 / 100;
            Rectangle rightSwath = new Rectangle(sourceImage.Width - rightWidth, 0, sourceImage.Width * 15 / 100, sourceImage.Height);

            Bitmap targetBitmap = new Bitmap(leftWidth + centerWidth + rightWidth, sourceImage.Height);

            using (Graphics g = Graphics.FromImage(targetBitmap))
            {
                g.DrawImage(sourceImage, 0, 0, leftSwath, GraphicsUnit.Pixel);
                g.DrawImage(sourceImage, leftWidth, 0, centerSwath, GraphicsUnit.Pixel);
                g.DrawImage(sourceImage, leftWidth + centerWidth, 0, rightSwath, GraphicsUnit.Pixel);
            }

            pictureBox2.Image = targetBitmap;
        }

Open in new window

ImageSizeChanges.jpg
newbiewebSr. Software EngineerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Expert1701Commented:
I'm sorry, newbieweb, I'm not sure what you are looking for.  Can you explain in a little more detail what you are using for input, and what you would like for output (as far as a processed image)?
0
newbiewebSr. Software EngineerAuthor Commented:
That's my program. And I created the image on the right by taking slivers of the image on the left. I intend to mock up a replica, but to be "right sized" to fit the button text the user can type into the field. I left the set the font as well. So I will use those number of pixels, plus the margin the define on each end of the text, to decide how wide to make the new button, before writing the text label.

So, first I am trying to get the button replication code working. But as you can see, the right image is taller than the left. I used CutImage to create that image.

So I hope there's a change can be made to CutImage so that the image on the right is the same height, just narrower, than the one of the left.
0
Expert1701Commented:
The images should be the same height - it almost looks as though the image on the left has SizeMode = Zoom and that the image is larger than the PictureBox.  Can you try changing SizeMode to Normal on both PictureBoxes?
0
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

Expert1701Commented:
And rather than cutting up the source button (because the gradients will not line up), have you considered simply drawing your own buttons?  Here is some sample code and output.

    pictureBox1.Image = CreateButton("Experts Exchange", new Font("Times New Roman", 24f, FontStyle.Italic));
    pictureBox2.Image = CreateButton("OK", new Font("Arial", 15.75f));
    pictureBox3.Image = CreateButton("Hello World!", new Font("Arial", 48f));

    Image CreateButton(string text, Font font)
    {
        Brush textBrush = Brushes.White;

        float textHeight = font.Height;
        float textWidth;
        {
            Bitmap test = new Bitmap(1, 1);
            using (Graphics g = Graphics.FromImage(test))
                textWidth = g.MeasureString(text, font).Width;
        }

        int borderThickness = 6;
        int buttonWidth = (int)textWidth + borderThickness * 2;
        int buttonHeight = (int)Math.Max(46, textHeight + borderThickness * 2);

        int outerBorderRadius = 9, innerBorderRadius = 6;

        Color outerLightColor = Color.FromArgb(246, 251, 255);
        Color innerLightColor = Color.FromArgb(171, 187, 203);
        Color darkColor = Color.FromArgb(63, 81, 105);

        Bitmap button = new Bitmap(buttonWidth + 2, buttonHeight + 2);

        using (Graphics g = Graphics.FromImage(button))
        {
            System.Drawing.Drawing2D.LinearGradientBrush outerBrush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, button.Width, button.Height), outerLightColor, darkColor, 60f);
            using (System.Drawing.Drawing2D.GraphicsPath path = RoundRectangle(1, 1, buttonWidth, buttonHeight, outerBorderRadius))
                g.FillPath(outerBrush, path);

            using (System.Drawing.Drawing2D.GraphicsPath path = RoundRectangle(1, 1, buttonWidth, buttonHeight, outerBorderRadius))
                g.DrawPath(new Pen(darkColor), path);

            System.Drawing.Drawing2D.LinearGradientBrush innerBrush = new System.Drawing.Drawing2D.LinearGradientBrush(new Point(borderThickness, 0), new Point(button.Width, button.Height), darkColor, innerLightColor);
            using (System.Drawing.Drawing2D.GraphicsPath path = RoundRectangle(1 + borderThickness, 1 + borderThickness, buttonWidth - borderThickness * 2, buttonHeight - borderThickness * 2, innerBorderRadius))
                g.FillPath(innerBrush, path);

            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;

            float textTop = (button.Height - textHeight) / 2;
            g.DrawString(text, font, Brushes.White, new Rectangle(0, (int)textTop, button.Width, button.Height), format);
        }

        return button;
    }

    System.Drawing.Drawing2D.GraphicsPath RoundRectangle(float x, float y, float width, float height, float radius)
    {
        System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();

        path.AddLine(x + radius, y, x + width - (radius * 2), y);
        path.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90);
        path.AddLine(x + width, y + radius, x + width, y + height - (radius * 2));
        path.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
        path.AddLine(x + width - (radius * 2), y + height, x + radius, y + height);
        path.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
        path.AddLine(x, y + height - (radius * 2), x, y + radius);
        path.AddArc(x, y, radius * 2, radius * 2, 180, 90);
        path.CloseFigure();

        return path;
    }
ThreeButtons.png
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Expert1701Commented:
Also, add the following statement to the CreateButton method to make the corners smoother.

    using (Graphics g = Graphics.FromImage(button))
    {
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        ....
    }

You can also add g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality which will make the other edges a little softer.
0
newbiewebSr. Software EngineerAuthor Commented:
Wow! You are quite the button expert!

The only reason I hesitate to use your code is that I await final artwork from an artist. And I intent to then use my utility to populate many buttons with text, ans save the delay of the artist.

Unless you tell me any button an artist could make can be replicated through C# code.

In fact, if I asked him to provide me the final artwork for the button, with a description of its constituent parts, would that help?

What might "constituent parts" consist of?

thanks for all the help,
newbieweb
0
newbiewebSr. Software EngineerAuthor Commented:
Here's the first version of the button, with text. What font might that be? Otr better, which
ButonWithText.jpg
0
newbiewebSr. Software EngineerAuthor Commented:
I hit Submit too soon on my last post. The font looks small. Is that Arial?

I decided I'm going to use your code to create dozens of buttons, for a demo. This is great.  

Would you mind showing me how to alter you great code to inlude three more parameters to the function?

buttonState (Up, Down, MouseOver)
margin - pixels
fixedSize - pixels

The margin and the fixed size parameters are mutually exclusive. I added the fixed size to my program for when the user (me) wants a fixed button width. Otherwise I want the width of the text, plus a margin on either side, to determine how wide the button will be.


Thanks for all the great help,
newbieweb





0
Expert1701Commented:
In my opinion the best thing to do is to have an artist design with Microsoft Expression Studio so you can simply integrate with WPF controls (in a WPF application, or even in a Windows Forms application).  The next best thing is to have your designer provide the "vector artwork" so that you can work with the source files.  Once the images are exported as a final product, you can not resize them or change them without distortion (and perhaps not at all - depending on your agreement with the designer).

  Microsoft Expression Design
  http://www.microsoft.com/expression/products/design_overview.aspx

  Microsoft Expression Blend
  http://www.microsoft.com/expression/products/Blend_Overview.aspx

  Inkscape is an open source vector editor that can import Adobe files, and can convert graphics to XAML for use in WPF applications.
  http://www.inkscape.org/
0
Expert1701Commented:
> buttonState (Up, Down, MouseOver)

  Sorry, I do not want to create a new graphics design, or attempt to copy the work of someone else.  This falls out of the scope of c# development, but if you have some specific questions such as creating a particular graphics effect in GDI+ or WPF, I am sure you can put specific questions to the EE community for help.

  I would suggest the zone WPF and Silverlight (http://www.experts-exchange.com/Microsoft/Development/Microsoft_Programming/WPF_and_Silverlight/) if you choose to use XAML, or Visual C# (http://www.experts-exchange.com/Microsoft/Development/Microsoft_Programming/.NET/Visual_CSharp/) if you are using GDI+ (e.g. the sample code posted).

> margin - pixels

  You should be able to modify the posted code to add margins where appropriate.  You could also use a function like this to add a 'margin' of padding around an image.

    Image AddMargin(Image sourceImage, int left, int right, int top, int bottom, Brush background)
    {
        Bitmap bitmap = new Bitmap(sourceImage.Width + left + right, sourceImage.Height + top + bottom);

        using (Graphics g = Graphics.FromImage(bitmap))
        {
            g.FillRectangle(background, 0, 0, bitmap.Width, bitmap.Height);
            g.DrawImage(sourceImage, left, top);
        }

        return bitmap;
    }

> fixedSize - pixels

  The following statement ensures the button maintains a certain minimum height regardless of font size.  If the font is too large, the button will "grow".

    int buttonHeight = (int)Math.Max(46, textHeight + borderThickness * 2);

  In the same way, you could set the width of your button to maintain a minimum value (right now, the button simply grows to fit the specific text).  The button will be a minimum of 200 px wide, or longer if the text demands.

    int buttonWidth = (int)Math.Max(200, textWidth + borderThickness * 2);

  You could also just use fixed widths and heights all together:

    int buttonWidth = 200;
    int buttonHeight = 46;
0
newbiewebSr. Software EngineerAuthor Commented:
Thanks a lot. This was great and I can work with this.

newbieweb
0
newbiewebSr. Software EngineerAuthor Commented:
Expert1701,

You were a huge help and I feel bad since I already asked too much on this post. But I was unable to smooth out the corners with the code you'd provided.

I added them in here:

                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

                float textTop = (button.Height - textHeight) / 2;
                g.DrawString(text, font, Brushes.White, new Rectangle(0, (int)textTop, button.Width, button.Height), format);

but wasn't sure if that was the right place since there didn't seem to be any effect. Thanks. newbieweb
0
Expert1701Commented:
That's okay, newbieweb.  Can you post a screen shot of what you are seeing, please?
0
newbiewebSr. Software EngineerAuthor Commented:
Here is it.
RoughCorners.jpg
0
Expert1701Commented:
It looks like the text has been anti-aliased, so I am wondering SmoothingMode and PixelOffsetMode are being set after the DrawPath and FillPath statements?  This should be set at the start of your using(Graphics) block before anything is drawn.
0
newbiewebSr. Software EngineerAuthor Commented:
yes, much smoother.

Thanks.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.