C sharp - Guardar dibujo

   
Vista:

Guardar dibujo

Publicado por Ephesia (24 intervenciones) el 06/06/2014 22:12:15
Hola a todos.

Tengo el siguiente problema:
Dibujo círculos en un control PictureBox que tiene una imagen.
En el evento paint del PictureBox utilizo PaintEventArgs e:

g.DrawEllipse(p, r);

Los círculos los dibujan perfectamente. Hasta aquí no hay ningún problema.

Lo que quiero es guardar el resultado en un archivo y hago:

this.pictureBox.Image.Save(this.saveFileDialog1.FileName, formato);

Pues bien, me guarda sólo la imagen original y no los círculos, lo cual parece lógico puesto que el objeto Graphics
está dibujando en pantalla en la zona del picture.
Lo he intentado de mil maneras y no se como pasar y tomar el objeto Graphics para que
lo guarde en un objeto Image, Bitmap, etc y poder guardarlo en un archivo o fijarlo en la propiedad Image del picture para utilizar Save...
Por favor ¿Alguien sabe como podría guardar los círculos dibujados junto con la imagen del PictureBox en un archivo?
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Guardar dibujo

Publicado por Pico (114 intervenciones) el 07/06/2014 10:17:59
Sí, tú lo has dicho, lo que haces es solamente dibujar en la pantalla. El bmp original del picture no lo modificas, y lo que el save hace es guardar esa imagen original. Si lo que quieres es grabar lo que sale en la pantalla tienes que usar un sistema como el que he usado yo para una lupa ahí: http://www.lawebdelprogramador.com/foros/Visual_CSharp_.NET/1443385-obtener_datos_de_una_ventana_inferior.html

Eso pilla lo que haya en el picture: imagen original, lo que pintes tú, otra ventana que esté encima....

Otra manera es no pintar en la pantalla sino en la imagen del picture. Así, cuando se refresque el picture, permanecerá lo dibujado, no como ahora.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Guardar dibujo

Publicado por Ephesia (24 intervenciones) el 07/06/2014 13:51:27
Gracias Pico:

El código que aparece en el enlace, lo que hace es guardar la zona capturada de la pantalla, con lo cual desaparece la resolución de la imagen original del fondo.

Yo lo que quiero es guardar la imagen con la resolución original y además con los círculos dibujados.

En el evento paint del PictureBox utilizo PaintEventArgs e y en 'e' es donde dibujo, por lo tanto creo que ya le especifico que es en el PictureBox. Debería modificarse no la imagen original, pero sí la que se pinta en el PictureBox , ahí va el código resumido de lo que hago:

Graphics gCirculos;
Color col;

private void picture_Paint(object sender, PaintEventArgs e)
{
Pen pcol = new Pen(col, Convert.ToSingle(this.nuDLinea.Value));
gCirculos = e.Graphics;
gCirculos.DrawEllipse(pcol, aLine.startPoint.X, aLine.startPoint.Y, Convert.ToInt16(s), Convert.ToInt16(s));
}

Si mando imprimir el picture lo imprime perfectamente con los círculos pero si utilizo save solo guarda la imagen del fondo...

¿Qué debería hacer?
Cordiales saludos a todos los foreros.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Guardar dibujo

Publicado por Pico (114 intervenciones) el 07/06/2014 14:51:21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void timer1_Tick(object sender, EventArgs e)
        {
            Point P = System.Windows.Forms.Control.MousePosition;
            float f = (trackBar1.Value/10) + 1;
            Graphics grPanel = panel1.CreateGraphics();
            Bitmap bp = new Bitmap(panel1.Width, panel1.Height);
            Graphics gr = Graphics.FromImage(bp);
            Size s = new System.Drawing.Size(panel1.Width, panel1.Height);
            gr.CopyFromScreen((int)(P.X - ((panel1.Width/f)/2)),(int)(P.Y - (panel1.Height/f) / 2), 0, 0, s);
            grPanel.DrawImage(bp, 0, 0, panel1.Width * f, panel1.Height * f);
            //grPanel.DrawString(f.ToString(), new Font("Arial", 20), new
            gr.Dispose();
            grPanel.Dispose();
        }


Si pones en un proyecto un timer, un panel y un trackbar, el timer a 10 por segundo, y en el evento del timer pones ese código te sale una lupa, una ampliación, según el valor del trackbar, de lo que esté debajo del puntero del ratón. Eso hace el programa.

Por partes:

Point P = System.Windows.Forms.Control.MousePosition; esto mira dónde está el cursor del ratón

Graphics grPanel = panel1.CreateGraphics(); esto crea un device context del mismo tipo que el panel. Misma resolución, profundidad de color... Para ver lo que es un device context http://msdn.microsoft.com/en-us/library/azz5wt61.aspx

Bitmap bp = new Bitmap(panel1.Width, panel1.Height); eso crea un bitmap. Se puede especificar resolución y todo lo que quieras, pero en este caso no interesa. Bitmap http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371%28v=vs.85%29.aspx

Graphics gr = Graphics.FromImage(bp); eso crea un graphisc, un device context, a partir del bitmap

gr.CopyFromScreen((int)(P.X - ((panel1.Width/f)/2)),(int)(P.Y - (panel1.Height/f) / 2), 0, 0, s); copia en el device context gr lo que haya en la pantalla.

grPanel.DrawImage(bp, 0, 0, panel1.Width * f, panel1.Height * f); y esto copia en el panel, en su device context, el bitmap bp. O sea, en bp está la imagen que aparezca en la pantalla, tal cual. Si aquí, en ve de un DrawImage del Graphics hiciera un Save del bp, grabaría la imagen de la pantalla en el disco, que es, mira tú por dónde, lo que quieres hacer.

La pantalla no muestra una imagen original. La pantalla es un device context, con su resolución, profundidad de color, y otras muchas características que definen un device context, y lo que quiereas pintar, un bmp, un vídeo, una entrada por capturador..., es otro, con lo que tiene que adaptar uno a otro. La impresora es otro device context. Cuando tú mandas imprimir algo, lo que hace el windows es crear un device context para esa impresora y mandar un WM_PRINT al programa.

WM_PRINT
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);

Como vemos, es idéntico a un WM_PAINT. La única diferencia es que en vez de mandar un handle de una ventana, le manda un handle de la impresora. O sea, una vez creada la superficie de dibujo de la impresora, le manda un mensaje al programa para que pinte en ella. Y pintará exactamente lo mismo que pinta en un WM_PAINT, o en tu picture_Paint.

Cuando un programa recibe un WM_PAINT lo que hace es pintar en la pantalla. En tu picturebox, primero pinta la imagen cargada y luego llama tu función, la picture_Paint, que pinta lo que le hayas puesto.

Ahorá viene lo gordo. ¿Qué quieres hacer?
"Yo lo que quiero es guardar la imagen con la resolución original y además con los círculos dibujados", dices. Vale. Si no es un simple juego lo que estás haciendo, lo que tienes que hacer es algo como simular una impresora. Yo tuve que hacer una cosa parecida: un programa sacaba un montón de cosas para imprimir, pero quise que todo lo que imprimiera se guardara también en un archivo jpg, para que si un día quería comprobar algo no tuviera que irse a buscarlo a las hojas de papel, y lo tuviera más a mano en el disco duro. Entonces lo que hice fue crear un bitmap, un graphics de ese bitmap, y todo lo que dibujaba en el printdocument, en la impresora, lo dibujaba también el el graphics del bmp. Luego, bitmap.Save("aqui.jpg") y ya lo tenía en disco. O sea, si no es un juego lo que quieres hacer, crea un bitmap con las características de lo que quieras guardar, todo lo que se pinta en la pantalla píntalo es ese bitmap, y guardas ese bitmap. Fácil.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Guardar dibujo

Publicado por Ephesia (24 intervenciones) el 09/06/2014 13:01:37
Hola:
Muchas gracias por tu extensa y clara explicación.
Lo que quería decir en el anterior mensaje es que:

gr.CopyFromScreen((int)(P.X - ((panel1.Width/f)/2)),(int)(P.Y - (panel1.Height/f) / 2), 0, 0, s);
copia lo que haya en pantalla y por tanto disminuye la resolución y eso no me interesa.

No, no es para un juego, es para una aplicación de coordenadas geográficas que dibuja círculos en un mapa ortofoto en su longitud y latitud en la ubicación correcta a partir de la lectura de la coordenadas en una tabla de datos de especies.
Es para control de biodiversidad y lo hago para intentar ayudar a unos biólogos que andan bajos de fondos (el tema de la investigación está fatal) no cobro.

El problema de utilizar printDocument (con una variable bool para bifurcar la orden imprimir o guardar) es que no hay manera de obviar el pequeño cuadro de diálogo (imprimiendo...) que sale unos segundos al llamar el evento.

O al menos yo no encuentro la manera...

¿Tu sabes?

Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Guardar dibujo

Publicado por Pico (114 intervenciones) el 09/06/2014 13:15:40
Lo de printDocument es sólo para imprimir. Es decir, lo que te digo es que tienes que hacer lo mismo que yo cuando hago el printDocument, no que tengas que hacer el printDocument.

Se trata de enfocar el problema de distinta manera. Lo que preguntas al inicio es cómo guardar un PictureBox al que le has modificado la imagen pintando cosas, y no es eso.

Lo que tienes que hacer es tener una imagen, un bmp. En ese bmp está la imagen que cargas, lo que dibujas, lo que quieras. Luego, ese bmp lo muestras en el PictureBox, y cuando quieras lo grabas. O sea, no se trata de guardar lo que haya en el PictureBox, sino de mostar en el PictureBox el bmp que manipulas. Verás que la clase Bitmap tiene una función Save, que puedes asignarle un Graphics con el que puedes dibujar, como te he puesto en el ejemplo de antes, y esa imagen puedes asignásela a un PictureBox, que tendrá que ajustarse para caber o lo que sea, pero la imagen original, la que luego grabarás, permanecerá intacta.

Ya somos dos los que no cobramos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar