0

I am in the process of developing an app that will be later integrated with another app I developed some time ago.

Basically, this app will generate an image file of X and Y dimensions with a grid printed on it, of which the user also specifies it's interval.

I've done this form so far, but I am having difficulty deciding what the best way to generate an actual image with the proper dimensions and grid spacing should be.

I don't want to save the image that is displayed on the form because it is only a representation and could very well be extremely dissimilar from the final product.

So I guess my question is, what do you think the best way is to generate a black and white image when I click "save"?

Also, I have no need to see the image being saved, I just want to generate and save it behind the scenes.

Here is the "draw" button click event

private void btnDraw_Click(object sender, EventArgs e)
{
    this.Width = 560;
    using (g = pb.CreateGraphics())
    {
        g.Clear(Color.White);

        PaintCanvass canvass = new PaintCanvass();
        canvass.Width = Convert.ToDouble(tbWidth.Text);
        canvass.Height = Convert.ToDouble(tbHeight.Text);
        canvass.Resolution = Convert.ToInt32(cbResolution.Text.Substring(0,3));
        canvass.UOM = cbUOM.Text;
        canvass.Interval = Convert.ToInt32(tbInterval.Text);

        Pen pencil = new Pen(Color.Black, 2);
        int hpfact = Convert.ToInt32((double)pb.Height / (double)canvass.horizontalLinesQuantity);
        int hp = hpfact;

        for (int i = 0; i < canvass.horizontalLinesQuantity-1; i++)
        {
            g.DrawLine(pencil, new Point(0, hp), new Point(pb.Width, hp));
            hp = hp + hpfact;
        }
        int vpfact = Convert.ToInt32((double)pb.Width / (double)canvass.verticalLinesQuantity);
        int vp = vpfact;
        for (int i = 0; i < canvass.verticalLinesQuantity-1; i++)
        {
            g.DrawLine(pencil, new Point(vp, 0), new Point(vp, pb.Height));
            vp = vp + vpfact;
        }
        canvass = null;

And here is my PaintCanvass class which seems to just be ending up as a container for properties for now

   class PaintCanvass
    { 
        public double Width { get; set; }
        public double Height { get; set; }
        public string UOM { get; set; }
        public int Resolution { get; set; }
        public int Interval { get; set; } = 50;
        public int hdots
        {
            get
            {
                if (this.UOM == "mm")
                {
                    return Convert.ToInt32(Width * 0.03937008F * Resolution);
                }
                else
                {
                    return Convert.ToInt32(Width * Resolution);
                };
            }
        }
        public int vdots
        {
            get
            {
                // Set the quantity of lines
                if (this.UOM == "mm")
                {
                    return Convert.ToInt32(Height * 0.03937008F * Resolution);
                }
                else
                {
                    return Convert.ToInt32(Height * Resolution);
                };
            }
        }
        public int horizontalLinesQuantity
        {
            get
            {
                return vdots / this.Interval;
            }
        }
        public int verticalLinesQuantity
        {
            get
            {
                return hdots / this.Interval;
            }
        }
    }

Current Form Sample

Edit: as suggested I went with the bitmap method.

private void btnSave_Click(object sender, EventArgs e)
{
    SetupCanvass();
    using (Bitmap bmp = new Bitmap(canvass.hdots, canvass.vdots))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            using (SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255)))
            {
                g.FillRectangle(brush, 0, 0, canvass.hdots, canvass.vdots);
            }
            int hp = canvass.Interval;
            for (int i = 0; i < canvass.horizontalLinesQuantity - 1; i++)
            {
                g.DrawLine(pencil, new Point(0, hp), new Point(canvass.hdots, hp));
                hp = hp + canvass.Interval;
            }
            int vp = canvass.Interval;
            for (int i = 0; i < canvass.verticalLinesQuantity - 1; i++)
            {
                g.DrawLine(pencil, new Point(vp, 0), new Point(vp, canvass.vdots));
                vp = vp + canvass.Interval;
            }
        }
        bmp.Save(Path.Combine(Path.GetTempPath(), "labelGrid.png")); //Save image somwhere on disk
    }
}
addohm
  • 2,248
  • 3
  • 14
  • 40
  • 1
    Why not generate a new Bitmap, display that one in the picturebox and then save the bitmap instance when clicking on the button? No need to draw on the canvas – Icepickle Nov 22 '18 at 08:42
  • @Icepickle As stated in the post "I don't want to save the image that is displayed on the form because it is only a representation and could very well be extremely dissimilar from the final product." – addohm Nov 22 '18 at 08:48
  • Sure, I didn't suggest that either, I suggested you generate a bitmap instead of drawing to the canvas and save that bitmap, but as you till now display a preview, you could theoretically also show the bitmap in the picturebox (optionally) – Icepickle Nov 22 '18 at 08:49
  • @Icepickle Why don't you post some small example of what you mean as an answer? I am assuming you're saying to create a bitmap using the PictureBox.Image property? – addohm Nov 22 '18 at 08:51
  • No just use new `Bitmap( width, height, PixelFormat)` and create graphics from that instance – Icepickle Nov 22 '18 at 08:55
  • What are you targetting: Winforms, WPF, ASP..? YOU should __always__ TAG your questions correctly so one can see it on the questions page! - What is pb? Never use control.creategraphics. – TaW Nov 22 '18 at 09:47
  • @TaW pb is the picturebox control. Why not use the `.CreateGraphics` method? What's a better way to do the same thing? The only reason I used it was because I wanted to clear the text printed on to the form before drawing onto it. – addohm Nov 22 '18 at 10:37
  • It will only allow you to create non-persistent graphics which will go away upon resizing and can't be saved. To draw __onto__ a control use its Paint event and for saving a bitmap draw __into__ it with a realted graphis object as cmos shows. For more on the difference [see here](https://stackoverflow.com/questions/27337825/picturebox-paintevent-with-other-method/27341797?s=3|20.8275#27341797) – TaW Nov 22 '18 at 10:59
  • @TaW thanks. I will look at that. Fortunately this time I don't meet either of those requirements. :) – addohm Nov 22 '18 at 11:10

1 Answers1

0

If you want to save an image without displaying a preview, just do something like this:

using (Bitmap bmp = new Bitmap(500, 500))
{
    using (Graphics g = Graphics.FromImage(bmp))
    {
        //Draw your stuff directly onto the bitmap here
    }
    bmp.Save("C:\\image.bmp"); //Save image somwhere on disk
}
cmos
  • 482
  • 4
  • 14
  • 2
    Basically correct but a) better not save to the root and b) better pick a more reasonable format like jpg or png. Also I would recommend setting the dpiX/Y of the bitmap. – TaW Nov 22 '18 at 09:45