Press "Enter" to skip to content

C# Catturare lo schermo quando vi sono schermi multipli

Oggi Stefano, ha fatto una domanda sul forum che sembrava molto semplice.

“Normalmente uso Screen.PrimaryScreen per catturare lo schermo da C# ma se ho più schermi collegati al pc come posso fare?”

La risposta era semplice, la classe screen ha una property AllScreens che è un array che ci da informazioni su tutti gli schermi connessi al PC, pertanto si può catturare semplicemente l’immagine di ogni schermo usando un ciclo for con il seguente codice:

     Bitmap ps = new Bitmap(x.Bounds.Width, x.Bounds.Height);

    Graphics graphics = Graphics.FromImage(ps as Image);
    graphics.CopyFromScreen(x.Bounds.X, x.Bounds.Y, 0, 0, x.Bounds.Size);

    ps.Save(string.Format(@"c:\MultiImage{0}.jpg", i), ImageFormat.Jpeg);

    this.textBox1.Text += string.Format("DONE <{0}> ", i) + Environment.NewLine;

Ma quello che voleva Stefano, era comporre una singola immagine con lo schermo completo, lo stesso che si ottiene usando un printscreen (STAMP), e questo non è affatto semplice.

Infatti, ho fatto un test usando 2 schermi (lui ne ha 4) usando il mio notebook, Windows Vista e Seven, (XP non ricordo se lo facesse), quando colleghi uno schermo secondario, ti permettono di posizionarlo da che lato vuoi rispetto al primario, modificando di conseguenza le property che indicano dove si trova lo schermo secondario rispetto al primario.

A causa di ciò, comporre un’immagine non è così semplice e richiede qualche calcolo, (ovviamente si può anche usare la clipboard volendo, ma essendo qui per imparare C# e .Net ci proviamo in altro modo).

Ecco che cosa ho fatto:

            int width = 0;
int height = 0;
int minx = 0;
int miny = 0;
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
    Screen z = Screen.AllScreens[i];
    if (z.Bounds.X < minx) minx = z.Bounds.X;
    if (z.Bounds.Y < miny) miny = z.Bounds.Y;
    if (i == 0)
    {
        width = z.Bounds.Width;
        height = z.Bounds.Height;
    }
    else
    {
        Screen p = Screen.AllScreens[i - 1];
        //Sta a destra
        if (z.Bounds.Right > p.Bounds.Right)
        {
            width += z.Bounds.Right - p.Bounds.Right;
        }
        else
        {
            //sta a sinistra
            if (z.Bounds.Left < p.Bounds.Left)
            {
                width += Math.Abs(p.Bounds.Left - z.Bounds.Left);
            }
        }
        //sta sopra
        if (z.Bounds.Top < p.Bounds.Top)
        {
            height += (Math.Abs(z.Bounds.Top) - Math.Abs(z.Bounds.Bottom));
        }
        else
        {
            if (z.Bounds.Bottom > p.Bounds.Bottom)
            {
                height += z.Bounds.Bottom - p.Bounds.Bottom;
            }
        }

    }
}

Basandomi sulla posizione dello schermo secondario, ho calcolato l’area dell’immagine composita e l’offset di posizionamento delle bitmap.

            Bitmap ps = new Bitmap(width, height);
Graphics graphics = Graphics.FromImage(ps as Image);

this.textBox1.Text = "";
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
    Screen x = Screen.AllScreens[i];
    this.textBox1.Text += string.Format("------------------->{0}<-------------------------", i)
+ Environment.NewLine; this.textBox1.Text += "Top:" + x.Bounds.Top.ToString() + Environment.NewLine; this.textBox1.Text += "Bottom:" + x.Bounds.Bottom.ToString() + Environment.NewLine; this.textBox1.Text += "Left:" + x.Bounds.Left.ToString() + Environment.NewLine; this.textBox1.Text += "Right:" + x.Bounds.Right.ToString() + Environment.NewLine; this.textBox1.Text += "X:" + x.Bounds.X.ToString() + Environment.NewLine; this.textBox1.Text += "Y:" + x.Bounds.Y.ToString() + Environment.NewLine; this.textBox1.Text += "Width:" + x.Bounds.Width.ToString() + Environment.NewLine; this.textBox1.Text += "Height:" + x.Bounds.Height.ToString() + Environment.NewLine; this.textBox1.Text += string.Format("-------------------<{0}>-------------------------",
i) + Environment.NewLine; graphics.CopyFromScreen(x.Bounds.X, x.Bounds.Y, x.Bounds.X + (Math.Abs(minx)),
x.Bounds.Y + Math.Abs(miny), x.Bounds.Size); ps.Save(@"c:\SingleImage.jpg", ImageFormat.Jpeg); this.textBox1.Text += string.Format("DONE <{0}> ", i) + Environment.NewLine; }

Dopodiché compongo il bitmap sommando i due pezzi dello schermo. Sono certa c’è un modo migliore per farlo e ovviamente dovrete cambiare qualcosa per farlo funzionare con tre o più schermi. Se ci provate, fatemi sapere come avete risolto.