3

This is my issue:

I add labels to a form programmatically, including some properties to resize them on runtime by clicking and dragging them with the mouse right click event.

My situation is, that I add a label programmatically containing an image from a given file through OpenDialog, and I would like to resize this image to fill the label size as I stretch the label. Unfortunately, I cannot set the size on runtime by accessing the image.Size property in the label, since it's read only... any ideas?

This is the affected piece of code:

Point _oldPosition;
public static Label _ctrlActiveControl;

if (e.Button == MouseButtons.Right)
{
    _ctrlActiveControl.Cursor = Cursors.SizeNWSE;

    //Code to resize the control based on the mouse position
    Point newPosition = new Point(e.X, e.Y);
   _ctrlActiveControl.Width += (newPosition.X - _oldPosition.X);
   _ctrlActiveControl.Height += (newPosition.Y - _oldPosition.Y);

    //Some security to make sure I don't shrink the control too much
    if (_ctrlActiveControl.Width < 10) _ctrlActiveControl.Width = 10;
    if (_ctrlActiveControl.Height < 10) _ctrlActiveControl.Height = 10;

    //Here I check if the label contains an image and, if so, I should resize
    //The image to "Autofill" the label
    if (_ctrlActiveControl.Image != null)
    {
      Image image = _ctrlActiveControl.Image;
      image.Size = new Size(_ctrlActiveControl.Width, _ctrlActiveControl.Height);
    }

    _oldPosition = newPosition;
}

I wonder if there's any way to do this, or should I instead use other control type (I know I can use others, but I'd like to know if there's any available workaround before adding more variables).

Mario
  • 283
  • 2
  • 13
  • 1
    You are trying to change the Image size thus you could find some useful examples here http://stackoverflow.com/questions/1922040/resize-an-image-c-sharp but I think you should use a PictureBox for this task not a label – Steve Mar 31 '15 at 11:47
  • The PictureBox has a property for SizeMode which can be set to Stretch or Zoom which would do what you want automatically. – Hjalmar Z Mar 31 '15 at 11:52
  • That's the point... if it were a PicBox it'd be much easier. Problem is that later on in code I make quite some stuff with a list of the labels created, and I would like to keep the properties standarised so I can cope with one object type instead of too many, in terms of their null values mainly... – Mario Mar 31 '15 at 11:53

2 Answers2

4

You can convert it to a Bitmap and redraw it with Graphics. Then replace the old image with the newly created one. I don't know if this is viable performance-wise, but I guess it could be worth a shot.

Bitmap newImage = new Bitmap(_ctrlActiveControl.Width, _ctrlActiveControl.Height);
using (Bitmap bm = new Bitmap(_ctrlActiveControl.Image))
{
    using (Graphics g = Graphics.FromImage(newImage))
    {
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        Point[] corners = { new Point(0, 0), new Point(newImage.Width, 0), new Point(0, newImage.Height) };
        g.DrawImage(bm, corners);
    }
}
_ctrlActiveControl.Image = newImage;

You'll need usings for System.Drawing and System.Drawing.Drawing2D.

Hjalmar Z
  • 1,591
  • 1
  • 18
  • 36
  • Thanks Hjalmar. I also had problems with Graphics since object is in a child panel from another panel... long story short, Graphics DrawImage method was also another issue since the object would disappear and I didn't want to multply my issues... Thanks for the tip though! – Mario Mar 31 '15 at 12:17
  • Haha. Well the whole idea is to make some customized, simple to use report designer. Users click here and there to add images, literal text, system data etc., as well as fields in an SQL query so they create a template. Once the template is done, I store all labels with properties in an XML file to be used for different purposes. Since most of the objects are labels, I wanted to (if possible) always used this type of object to keep it simple. – Mario Mar 31 '15 at 12:28
2

As per Steve's recommendation, I have substituted

if (_ctrlActiveControl.Image != null)
{
  Image image = _ctrlActiveControl.Image;
  image.Size = new Size(_ctrlActiveControl.Width, _ctrlActiveControl.Height);
}

and wrote instead:

if (_ctrlActiveControl.Image != null)
{
     _ctrlActiveControl.Image = ResizeImage(_ctrlActiveControl.Image, _ctrlActiveControl.Width, _ctrlActiveControl.Height);
}

.....

public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new Rectangle(0, 0, width, height);
    var destImage = new Bitmap(width, height);

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    using (var graphics = Graphics.FromImage(destImage))
    {
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

        using (var wrapMode = new ImageAttributes())
        {
            wrapMode.SetWrapMode(WrapMode.TileFlipXY);
            graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            graphics.Dispose();
        }
    }

    return destImage;
}

If you play too much with the label by stretching and shrinking, it will become useless (image quality will degrade if the label is too small and then we try to re - enlarge the label). However, as a start point it could work. I could recode to reference the file directly as per the image source so I get always a fresh file... Thanks for the tip.

Mario
  • 283
  • 2
  • 13