PDA

View Full Version : [C#]problema salvare screenshot


Mattyfog
17-09-2008, 18:34
Ciao,
ho preso da pierotofy.it il codice sorgente di un programma in C# che salva uno screenshot. Il problemma è che nella riga screenshot.Save(t.Text); ho questo errore durante l'esecuzione del programma Errore generico in GDI+

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace Screenshot
{
/// <summary>
/// Descrizione di riepilogo per Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox t;
private System.Windows.Forms.SaveFileDialog sf;
/// <summary>
/// Variabile di progettazione necessaria.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Necessario per il supporto di Progettazione Windows Form
//
InitializeComponent();

//
// TODO: aggiungere il codice del costruttore dopo la chiamata a InitializeComponent
//
}

/// <summary>
/// Pulire le risorse in uso.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Codice generato da Progettazione Windows Form
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.t = new System.Windows.Forms.TextBox();
this.button2 = new System.Windows.Forms.Button();
this.sf = new System.Windows.Forms.SaveFileDialog();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 56);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(280, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Scatta Screenshot";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(200, 16);
this.label1.TabIndex = 1;
this.label1.Text = "Cartella su cui salvare lo screenshot";
//
// t
//
this.t.Location = new System.Drawing.Point(8, 24);
this.t.Name = "t";
this.t.ReadOnly = true;
this.t.Size = new System.Drawing.Size(256, 23);
this.t.TabIndex = 2;
this.t.Text = "C:\\screenshot.bmp";
//
// button2
//
this.button2.Location = new System.Drawing.Point(264, 24);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(24, 24);
this.button2.TabIndex = 3;
this.button2.Text = "...";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// sf
//
this.sf.Filter = "File bitmap (.bmp)|*.bmp";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);
this.ClientSize = new System.Drawing.Size(292, 86);
this.Controls.Add(this.button2);
this.Controls.Add(this.t);
this.Controls.Add(this.label1);
this.Controls.Add(this.button1);
this.Font = new System.Drawing.Font("Comic Sans MS", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Screenshot by Dokkis";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// Il punto di ingresso principale dell'applicazione.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

public static Bitmap ScreenShot()
{
SendKeys.SendWait("^{PRTSC}"); // serve a simulare la pressione del tasto stamp della tastiera
IDataObject iData = Clipboard.GetDataObject();
if ((iData.GetDataPresent(DataFormats.Bitmap)))
{
Bitmap memoryImage = new Bitmap(((Bitmap)(iData.GetData("System.Drawing.Bitmap"))));
return memoryImage;
}
return null;
}

private void button1_Click(object sender, System.EventArgs e)
{
this.WindowState=FormWindowState.Minimized; //minimizzo sennò nello screenshot si vede il programma al centro dello schermo (cosa inutile)
Bitmap screenshot = ScreenShot();
if(screenshot!=null)
{
screenshot.Save(t.Text);
}
this.WindowState=FormWindowState.Normal; //screenshot scattato e salvato, ripristiniamo la finestra del form come quando lanciato il programma
}

private void button2_Click(object sender, System.EventArgs e)
{
sf.ShowDialog();
t.Text=sf.FileName;
}
}
}

Mattyfog
17-09-2008, 20:54
allora ho trovato un modo semplice per creare lo screenshot ma come posso ora ritagliare l'immagine? (tra l'altro è meglio che io utilizzi jpeg bmp o png???)


// If the user has chosen a path where to save the screenshot
if (saveScreenshot.ShowDialog() == DialogResult.OK)
{
// Hide the form so that it does not appear in the screenshot
this.Hide();
// Set the bitmap object to the size of the screen
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
// Take the screenshot from the upper left corner to the right bottom corner
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
// Save the screenshot to the specified path that the user has chosen
bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Bmp);
// Show the form again
this.Show();
}

DanieleC88
18-09-2008, 10:32
PNG tutta la vita! Per ritagliarlo, credo ti basti passare diverse coordinate a CopyFromScreen(). ;)

xciaoatuttix
18-09-2008, 11:20
bello questo programma... funziona ? :stordita:

Mattyfog
19-09-2008, 20:36
Ciao,
dopo varie prove ho scoperto che i 4 numeri (correggetemi se sbaglio :D ) che si passano a copyfromscreen sono le righe di pixel da saltare rispettivamente dal basso, a sinistra, in alto, a destra.
Allora nel programma, dato due coordinate di mouse che indicano 2 estremi opposti del mouse ho scritto questo per poter salvare screenshot anche di dimensioni diverse dallo schermo nero.
Ci ho riflettuto un po' facendomi 1 disegnino e mi sembra che i ragionamenti per calcolare le righe da saltare e la dimensione dell'immagine a partire dalle coordinate mi sembrano giusti.
Spero che qualcuno abbia voglia di dargli un'occhiata :D :help:

//ora calcolo le dimensioni dell'immagine e le righe di pixel da saltare su ogni lato dello schermo
int himage = 0, bimage = 0; //altezza e lugnhezza (base) dell'immagine
int rbasso = 0, rsinistro = 0, ralto = 0, rdestro = 0; //righe da saltare per ritagliare l'immagine
if(mousepos1x>mousepos2x)
{
himage = mousepos1x - mousepos2x;
rsinistro = mousepos2x;
rdestro = Screen.PrimaryScreen.Bounds.Width - mousepos1x;
}
if(mousepos1x<mousepos2x)
{
himage = mousepos2x - mousepos1x;
rsinistro = mousepos1x;
rdestro = Screen.PrimaryScreen.Bounds.Width - mousepos2x;
}
if(mousepos1y>mousepos2y)
{
bimage = mousepos1y - mousepos2y;
rbasso = mousepos2y;
ralto = Screen.PrimaryScreen.Bounds.Height - mousepos1y;
}
if(mousepos1y<mousepos2y)
{
bimage = mousepos2y - mousepos1y;
rbasso = mousepos1y;
ralto = Screen.PrimaryScreen.Bounds.Height - mousepos2y;
}

// Hide the form so that it does not appear in the screenshot
this.Hide();
// Set the bitmap object to the size of the screen
bmpScreenshot = new Bitmap(bimage, himage, PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
// Take the screenshot from the upper left corner to the right bottom corner
//gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
gfxScreenshot.CopyFromScreen(rdestro, rbasso, rsinistro, ralto, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
//riguardo alla riga sopra: quante righe saltare da destra, basso, sinistra, alto.
// Save the screenshot to the specified path that the user has chosen
bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Bmp);
// Show the form again
this.Show();

Mattyfog
19-09-2008, 21:14
trovato primo errore:
l'immagine veniva creata capovolta di 90 gradi.
Ora le dimensioni dell'immagine sono giuste mentre l'immagine è nera sia in alto che a sinistra per cui rimane spostata.

public partial class Form1 : Form
{
int mousepos1x, mousepos1y, mousepos2x, mousepos2y;
private static Bitmap bmpScreenshot;
private static Graphics gfxScreenshot;

public Form1()
{
InitializeComponent();
}

private void btnCapture_Click(object sender, EventArgs e)
{

// If the user has chosen a path where to save the screenshot
if (saveScreenshot.ShowDialog() == DialogResult.OK)
{
//ora calcolo le dimensioni dell'immagine e le righe di pixel da saltare su ogni lato dello schermo
int himage = 0, bimage = 0;
int rbasso = 0, rsinistro = 0, ralto = 0, rdestro = 0;

if(mousepos1x>mousepos2x)
{
himage = mousepos1x - mousepos2x;
rsinistro = mousepos2x;
rdestro = Screen.PrimaryScreen.Bounds.Width - mousepos1x;
}
if(mousepos1x<mousepos2x)
{
himage = mousepos2x - mousepos1x;
rsinistro = mousepos1x;
rdestro = Screen.PrimaryScreen.Bounds.Width - mousepos2x;
textBox3.Text = Screen.PrimaryScreen.Bounds.Width.ToString() + "-" + mousepos2x.ToString();
}
if(mousepos1y>mousepos2y)
{
bimage = mousepos1y - mousepos2y;
rbasso = mousepos2y;
ralto = Screen.PrimaryScreen.Bounds.Height - mousepos1y;
}
if(mousepos1y<mousepos2y)
{
bimage = mousepos2y - mousepos1y;
rbasso = mousepos1y;
ralto = Screen.PrimaryScreen.Bounds.Height - mousepos2y;
}

// Hide the form so that it does not appear in the screenshot
this.Hide();
// Set the bitmap object to the size of the screen
bmpScreenshot = new Bitmap(himage, bimage, PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
// Take the screenshot from the upper left corner to the right bottom corner
//gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
gfxScreenshot.CopyFromScreen(rdestro, rbasso, rsinistro, ralto, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
//riguardo alla riga sopra: quante righe saltare da destra, basso, sinistra, alto.
// Save the screenshot to the specified path that the user has chosen
bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Bmp);
// Show the form again
this.Show();

}
}

DanieleC88
19-09-2008, 23:25
Ti confesso che non ho letto mezza riga di quel codice, ma ti dico che secondo me puoi anche dimezzarlo considerando solo come angolo in alto a sinistra il punto con coordinata x uguale al minimo tra le coordinate x1 ed x2, e come coordinata y uguale al minimo tra le coordinate y1 ed y2. Per l'angolo in basso a destra farai il contrario, prendendo il massimo per entrambe le coordinate.

In questo modo non devi distinguere quattro casi separati ed il codice continuerà a funzionare come previsto. ;)

Mattyfog
20-09-2008, 11:19
adesso ho capito il problema!
abituato ai diagrammi cartesiani (che palle!!!:D ) di scuola pensavo che x 0, y0 corrispondesse all'angolo in basso a destra mentre qui è quello in alto a sinistra! adesso provo a vedere ciao e grazie!

DanieleC88
20-09-2008, 11:34
Sì giusto, m'ero dimenticato di specificare che (0; 0) corrisponde all'angolo in alto a sinistra. :)
Se sei abituato a pensare in termini di assi cartesiani, fai finta che lo schermo rappresenti il quarto quadrante. ;)

Mattyfog
20-09-2008, 11:38
ecco qua i miei nuovi risultati non funzionanti:
ho scritto questa codice che funziona quando le prime coordinate corrispondono all'angolo in alto a sinistra della cattura mentre le altre 2 a quello in basso a destra. Tuttavia ci sono ancora problemi come quello di prima ossia gran parte della foto risulta nera.
Spero qualche buon amima come daniele mi possa aiutare :D. Nell'attesa continuo a :muro: kissà che salti fuori qualcosa.....

int himage = 0, bimage = 0;
int rbasso = 0, rsinistro = 0, ralto = 0, rdestro = 0;


if (mousepos1x < mousepos2x && mousepos1y < mousepos2y)
{
bimage = mousepos2x - mousepos1x;
himage = mousepos2y - mousepos1y;

ralto = mousepos1y;
rbasso = Screen.PrimaryScreen.Bounds.Height - mousepos2y;
rsinistro = mousepos1x;
rdestro = Screen.PrimaryScreen.Bounds.Width - mousepos2x;
textBox3.Text = "si";

}

DanieleC88
20-09-2008, 13:41
Secondo me sbagli a passare le coordinate, i valori non sono "i pixel da scartare a partire da un certo margine", ma sono semplicemente le coordinate (x; y) dell'angolo in alto a sinistra da catturare dallo schermo e poi quelle dell'angolo in alto a sinistra del rettangolo in cui salvare il risultato.

Quindi io abbozzerei una cosa del genere:
int ULx, ULy, LRx, LRy;
unsigned uWidth, uHeight;

ULx = (x1 < x2) ? x1 : x2;
LRx = (x1 > x2) ? x1 : x2;
ULy = (y1 < y2) ? y1 : y2;
LRy = (y1 > y2) ? y1 : y2;
uWidth = (LRx - ULx);
uHeight = (LRy - ULy);

this.Hide();
bmpScreenshot = new Bitmap(uWidth, uHeight, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(ULx, ULy, 0, 0, rSize, CopyPixelOperation.SourceCopy);
bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Bmp);
this.Show();
Insomma, credo sia sbagliata solo l'invocazione. Nota che nel chiamare CopyFromScreen() ho fatto riferimento a "rSize" che non è definita né inizializzata, perché non sono sicuro di come sia definita e non riesco a consultarla su MSDN al momento. Comunque, credo che anche bmpScreenshot ne conservi una con le sue dimensioni, quindi sostituire rSize con bmpScreenshot.Size potrebbe funzionare. :)
In caso contrario ti basterà definire ed usare una variabile di tipo Size ed assegnandovi come larghezza il valore di uWidth e come altezza il valore di uHeight e il codice sarà completo. ;)

P.S.: non sono certo che l'operatore (condizione) ? valoreSeVera : valoreSeFalsa esista in C#, io sono abituato al C purtroppo. Se non esistesse ti basta utilizzare un if al suo posto. ;)

Mattyfog
20-09-2008, 15:27
ciao,

grazie avevi ragione!!! comunque rsize non ha dato nessun problema!!!
non ti so dire dell'operatore ternario in quanto non l'ho usato (dopo aver capito cosa passare alla copyfromscreen tutto è funzionato!) ciao e grazissime!:D

||ElChE||88
20-09-2008, 15:30
P.S.: non sono certo che l'operatore (condizione) ? valoreSeVera : valoreSeFalsa esista in C#, io sono abituato al C purtroppo.
Esiste.

DanieleC88
21-09-2008, 03:12
Esiste.
Ok, dubbio eliminato. :D