3

I have a pictureBox that's being painted to externally via a dll call.

private void myPictureBox_Paint(object sender, PaintEventArgs e)
{
     dllClass.RefreshEx(LWHANDLE, 0, 0);
}

This is working and all, but I now need to get a screenshot of that picturebox, and it's not working.

Here's what I've tried:

        Control ctrlToDraw = myPictureBox;

        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ctrlToDraw.Width, ctrlToDraw.Height);
        ctrlToDraw.DrawToBitmap(bmp, ctrlToDraw.ClientRectangle); 

I've also attempted to do it via Windows API, but it's resulting in exactly the same result as the above code: a blank (not null) image.

Could anyone name some suggestions apart from taking a screenshot of the whole screen?

David
  • 15,652
  • 26
  • 115
  • 156
  • Are you sure your external call is actually drawing to the picture box, cause I just tested your code as is, and it works perfectly. Is it drawing to the picture box, or drawing on the picturebox graphic object? Cause there is a persistence issue here perhaps – General Grey May 24 '12 at 16:28
  • @K'Leg It does work perfectly with normal pictureboxes :( It just doesn't work with this one. This is a huge damn project, I can't easily post an SSCCE. – David May 24 '12 at 16:30
  • All i need to know is how your external is talking to this program, and what code does the drawing routines – General Grey May 24 '12 at 16:37

2 Answers2

4

I don't know how much control you have over the external program, or how it draws to your picture box, but if you are using createGraphics it wont work.

private void button1_Click(object sender, EventArgs e)
    {
        //here I am calling the graphics object of the Picture Box, this will draw to the picture box
        //But the DrawToBitmap, will not reflect this change, and once the Picturebox needs to be updated, this will disappear.
        Graphics g = pictureBox1.CreateGraphics();
        g.DrawRectangle(Pens.Blue, 10, 10, 20, 20);

        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(pictureBox1.Width, pictureBox1.Height);
        Rectangle bounds = new Rectangle(Left, Top, Width, Height);
        pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
        //Draws whatever is in the PictureBox to the Forms BackgroundImage
        this.BackgroundImage = bmp;
        //It will not draw the Blue rectangle

    }

If your external program was to draw to a bitmap, then you could set that bitmap to the picturebox background

    Bitmap buffer;
    public Form1()
    {
        InitializeComponent();
        buffer = new Bitmap(pictureBox1.Width, pictureBox1.Height);
    }


    private void button1_Click(object sender, EventArgs e)
    {
        //draw to the bitmap named buffer
        using (Graphics g = Graphics.FromImage(buffer))
        {
            g.DrawRectangle(Pens.Blue, 10, 10, 20, 20);
        }
        //assign the picturebox image to buffer
        pictureBox1.Image = buffer;

        //Now this will show the blue rectangle
        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(pictureBox1.Width, pictureBox1.Height);
        Rectangle bounds = new Rectangle(Left, Top, Width, Height);
        pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);

        this.BackgroundImage = bmp;
    }

EDIT Third Times the Charm right

This will take a screen shot, cut the picturebox out, and then I changed the Forms Background, just to prove it worked.

You will need to add

using System.Drawing.Imaging;

it is for the Pixel format.

 private void button1_Click(object sender, EventArgs e)
    {
        using (Graphics G = pictureBox1.CreateGraphics())
        {
            G.DrawRectangle(Pens.Blue, 10, 10, 10, 10);
        }
        Bitmap BMP = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                        Screen.PrimaryScreen.Bounds.Height,
                                        PixelFormat.Format32bppArgb);
        using (Graphics GFX = Graphics.FromImage(BMP))
        {
            GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                Screen.PrimaryScreen.Bounds.Y,
                                0, 0,
                                Screen.PrimaryScreen.Bounds.Size,
                                CopyPixelOperation.SourceCopy);
        }
        Bitmap YourPictureBoxImage = new Bitmap(pictureBox1.Width,pictureBox1.Height);
        using (Graphics g = Graphics.FromImage(YourPictureBoxImage))
        {
            Point np = pictureBox1.PointToScreen(new Point(0, 0));
            g.DrawImage(BMP,new Rectangle(0,0,100,100),new Rectangle(np,pictureBox1.Size),GraphicsUnit.Pixel);
        }

        this.BackgroundImage = YourPictureBoxImage;
    }
General Grey
  • 3,598
  • 2
  • 25
  • 32
  • All the external program has is the "handle" of the picturebox. That's all that's passed to it. So I'm guessing it paints directly to it, not sets the image or otherwise. I'll try your code though. – David May 24 '12 at 16:49
  • "paints directly to it", possibly by using bitBlt and srcCopy maybe. I don't have access to the source code right now. – David May 24 '12 at 16:51
  • That's too bad, because it seems to me, that it is drawing on it, rather then too it. Can you see the Picturebox, when it draws on it? Once there is an image in the Picture box, try minimizing the Form and then bringing it back up, is the image still there? – General Grey May 24 '12 at 16:56
  • The image never even appears there (since it's being painted ON by other images from the external program). I can only assume it's repainting over and over again really fast. – David May 24 '12 at 17:02
  • Add something to your Picturebox in the first place, and see if it ever changes, I think the start of your problem lies there. I wrote a new sample for you, which does exactly what you want. It takes a screen shot, cuts out your picturebox for you to use, but if you can't see anything in your box, there is nothing there for the screenshot to capture either – General Grey May 24 '12 at 17:07
  • Glad I could help, only one down side to the last part, if something like task manager is placed over top of your picturebox, the capture3d picture will include it, because it doesn't care, all it's doing is taking a screen shot of whatever your monitor is displaying. – General Grey May 24 '12 at 17:15
-2

You can take a screenshot of just the active window by using ALT+PRINTSCREEN. That will capture the current active window as a bitmap to the clipboard. Paste that into a bitmap editing tool, crop to just the area you want.

Or use a screen capture utility that allows for cropping of the target area while on screen such as Evernote version 2's old screen clipper.

StarPilot
  • 2,246
  • 1
  • 16
  • 18
  • How can I do that by code please? I forgot to mention the background can change dynamically. – David May 24 '12 at 16:23
  • 1
    Your question says "not a whole screenshot". You didn't ask for a way to automatically capture a portion of the screen whenever desired in code. Those sorts of details matter when you ask a question. I know of automatic screencapture utilities, but I'll have to think on this new requirement. – StarPilot May 24 '12 at 16:28