post icon

Guardar imágenes en la Base de Datos desde C#

Esto que veremos como hacer, se aplica a cualquier base de datos que soporte el tipo de dato BLOB o equivalente, aunque el ejemplo estará centrado en un motor especifico, el PostgreSQL ya que es uno de los motores que mejor tiempo de respuesta ofrece al trabajar con imágenes, hablo una vez que tenemos más del millon de imagenes, esto que digo está basado en una prueba mía con SQL Server, MySQL y Oracle XE. Por eso podría la mejor opción si necesitamos almacenar muchas imágenes y luego tener la facilidad que buscarlas con rápidez.

En éste ejemplo lo insertaremos desde C# .Net, pero primeramente debe existir la tabla que almacenará la imagen, y su tipo de dato debe ser BLOB (Binary Long, o campo binario largo). Las imagénes necesitamos convertirlas al binario para almacenarlas, veremos como tomar una imagen que está en algún directorio y lo almacenamos, también incluye el método para volver a pasarla a imágen por si necesitamos volver a visualizarla, pero no lo implementaré hoy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
using Npgsql;
using System;
using System.Data;
using System.Text;
using System.Drawing;
using System.IO;
 
class ConvertirImagen
{
	public static byte[] Image2Bytes(Image pImagen)
	{
		byte[] mImage = null;
		try
		{
			if (pImagen != null)
			{
				using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
				{
					pImagen.Save(ms, pImagen.RawFormat);
					mImage = ms.GetBuffer();
					ms.Close();
				}
			}
			else { mImage = null; }
		}
		catch (Exception ex)
		{
			throw (ex);
		}
		return mImage;
	 }
 
	public static Image Bytes2Image(byte[] bytes)
	{
		if (bytes == null) return null;
		using (MemoryStream ms = new MemoryStream(bytes))
		{
			Bitmap bm = null;
			try
			{
				bm = new Bitmap(ms);
			}
			catch (Exception ex)
			{
				throw (ex);
			}
			return bm;
		}
	}
}
 
private static void guardarFotosPostgres(string vServidor, string vBaseDatos,string vUsuario, string vPassword, string vPathFoto)
{
	//String para cadena de conexion
	StringBuilder sCadena = new StringBuilder("");
	//objeto conexion
	NpgsqlConnection Con;
 
	//construccion de la cadena para conectarse a postgres
	sCadena.Append("Host=;");
	sCadena.Append("Database=;");
	sCadena.Append("User ID=;");
	sCadena.Append("Password=;");
	sCadena.Append("Port=5432;");
	sCadena.Replace("", vServidor);
	sCadena.Replace("", vBaseDatos);
	sCadena.Replace("", vUsuario);
	sCadena.Replace("", vPassword);
 
	Con = new NpgsqlConnection(Convert.ToString(sCadena));
 
	using (NpgsqlCommand Comando = new NpgsqlCommand())
	{
		try
		{
			//abrir la conexion
			Con.Open();
 
			//convierto la imagen en binario (el tipo de dato en postgres debe ser blob)
			byte[] Blob = ConvertirImagen.Image2Bytes(Image.FromFile(String.Format("{0}\\nuestraimagen.jpg", vPathFoto)));
 
			//asigno valores a los atributos del command que invocara un Stored Procedure
			Comando.CommandType = CommandType.StoredProcedure;
			Comando.Connection = Con;
			Comando.CommandText = "public.SPGuardaImagen";
			Comando.Parameters.Add("pfichero", Blob);
 
			//ejecucion de la funcion sin retorno de valores
			Comando.ExecuteNonQuery();
 
		} //end try
		catch (Exception ex)
		{
			throw (ex);
		} //end catch
		finally
		{
			Con.Close();
			Con.Dispose();
		}//end finally
	}//end using comando
}//end guardarFotosPostgres

Comentarios desde Facebook:

  1. avatar
    ser ARGENTINA Mozilla Firefox Windows
    10 Octubre 2010 at 11:56 #

    Estoy en medio de un proyecto , que tengo que presentar en 4 dias ,
    ¿como haces para volver a traer la imagen al programa?.
    Muy bueno este post

    • avatar
      Fernando ARGENTINA Google Chrome Windows
      13 Noviembre 2012 at 12:21 #

      He logrado guardar una imagen jpg en la base de datos.
      Pero como se hace para recuperarla?

  2. avatar
    DiegoA COLOMBIA Mozilla Firefox Windows
    2 Junio 2010 at 12:42 #

    Buenas Tardes, luego de llevar a cabo varias pruebas encontramos que el la version 8.2 de PostgreSQL funciona la inserción de la imagen pero en la versión 8.4 arroja el error comentado anteriormente. Continuaré con la exploración para que todo funcione bien con la versión 8.4.

  3. avatar
    DiegoA COLOMBIA Mozilla Firefox Windows
    1 Junio 2010 at 05:31 #

    Ok, lo que haré será crear un nuevo tema en el foro de PostgreSQL ya que el error que surge es de la base de datos.

  4. avatar
    GeekZero PARAGUAY Google Chrome Windows
    1 Junio 2010 at 05:06 #

    Te sugiero que crees un topic en el foro (es nuevito por eso casi nada tiene aun) pero es mas fácil allí seguir un post largo con código..

  5. avatar
    GeekZero PARAGUAY Google Chrome Windows
    1 Junio 2010 at 05:04 #

    Buen día, es cierto he colocado la barra normal en vez de la invertida, pero no intentaba guardar un imagen en tu tabla, solo una cadena de texto, si te fija el bytea quedaría en nulo, lo único que intentaba era probar si te funcionaba la funcion, te ejecuto desde el pgAdmin o lanzo excepción alguna? Lo que intento determinar es si el problema está en tu bd o en tu app.

    Fijate que la llave del método guardarFotosPostgres() tampoco está cerrado, te compila este código?

  6. avatar
    GeekZero Google Chrome Windows
    31 Mayo 2010 at 16:38 #

    DiegoA, replique tu ambiente hasta donde puedo, creando la tabla y la función tal cual lo posteaste, luego copie tu codigo c# y funcionó, solo tuve que cerrar la llave del try, cerrar un parentesis de la linea 5 y wola! funcionó.. el StringBuilder de la línea 3 esta en valde en este código, puedes quitarlo..

    Fijate si tus objetos estan en el schema public..Tambien prueba esto desde PGAdmin directamente

    <pre lang="plsql">select * from insertarimagen (null, 'c:/devtroce.jpg');</pre> deberia probar si funciona al menos tu funcion..

    • avatar
      DiegoA COLOMBIA Mozilla Firefox Windows
      1 Junio 2010 at 08:51 #

      Buenos días, he llevado a cabo las correcciones del código, es decir, el parentesis de la lína 5:
      Con = new NpgsqlConnection(Convert.ToString(“Server=localhost; Port=5432; User Id=imagen; Password=imagen; Database=Imagenes;”/*sCadena*/));
      La llave del try y también probé la consulta:
      select * from insertarimagen (null, ‘c:/devtroce.jpg’);
      Y continuo con el error, aunque con la última consulta en el pgAdmin me surgen un par de preguntas. ¿La función envía la ruta de la imagen a la base de datos? ó ¿La función envía la variable tipo byte[]?
      Porque el error que aparece: < tiene en donde econtramos “\” son dos, como si fuese la ruta de la imagen mal formateada.

      Gracias por su atención y colaboración, espero mi ejemplo pueda funcionar.

  7. avatar
    DiegoA COLOMBIA Mozilla Firefox Windows
    31 Mayo 2010 at 13:40 #

    La función en C# a la cual aplique alguna modificación quedo así:<pre lang="csharp">

    private static void guardarFotosPostgres(string vServidor, string vBaseDatos,string vUsuario, string vPassword, string vPathFoto, string vnombrefoto)

    {

    StringBuilder sCadena = new StringBuilder("");

    NpgsqlConnection Con;

    Con = new NpgsqlConnection(Convert.ToString("Server=localhost; Port=5432; User Id=Usuario; Password=Contrasena; Database=Imagenes;");

    using (NpgsqlCommand Comando = new NpgsqlCommand())

    {

    try

    {

    Con.Open();

    byte[] Blob = ConvertirImagen.Image2Bytes(Image.FromFile(String.Format("{0}", vPathFoto)));

    Comando.CommandType = CommandType.StoredProcedure;

    Comando.Connection = Con;

    Comando.CommandText = "insertarimagen";

    Comando.Parameters.Add("imagenex", Blob);

    Comando.Parameters.Add("nombreimagen", vnombrefoto);

    Comando.ExecuteNonQuery();

    catch (Exception ex)

    {

    MessageBox.Show("Error en la funcion guardarFotosPostgres:
    " + ex.Message, "Cuidado", MessageBoxButtons.OK, MessageBoxIcon.Error);

    throw (ex);

    } //end catch

    finally

    {

    Con.Close();

    Con.Dispose();

    }//end finally

    }

    </pre>

    En la base de datos la función se encuentra así:

    <pre lang="plsql">

    CREATE OR REPLACE FUNCTION insertarimagen (imagenex bytea, nombreimagen TEXT) RETURNS VOID AS

    $BODY$

    BEGIN

    INSERT INTO imagen (imagen, nombre) VALUES (imagenex, nombreimagen);

    END;

    $BODY$

    LANGUAGE 'plpgsql' VOLATILE;

    </pre>

    Muchas Gracias por su atención (Espero se vea claro el código).

  8. avatar
    DiegoA COLOMBIA Mozilla Firefox Windows
    31 Mayo 2010 at 13:07 #

    De antemano gracias por su atención.

  9. avatar
    DiegoA COLOMBIA Mozilla Firefox Windows
    31 Mayo 2010 at 13:05 #

    Buenas tardes,

    El anterior es un excelente ejemplo, traté de implementarlo pero me encuentro con un error al momento de insertar la imagen en el procedimiento de almacenamiento (En su caso SPGuardarImagen)

    El cual me dice:

    Error de sintaxis en o cerca de

    <<",#3434(7),0144437'9=82>

    Como si la variable Blob tipo byte[] enviada como parametro tuviera un formato inválido o le faltara un cambio.

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      31 Mayo 2010 at 13:12 #

      Hola DiegoA, para ayudarte puedes copiarnos la DDL de tu tabla y de tu funcion?

  10. avatar
    GeekZero PARAGUAY Google Chrome Windows
    17 Febrero 2010 at 13:51 #

    Es sencillo, no lo puse ya que estaba considerando se tiene una tabla con un campo de tipo bytea (en el cual ira tu imagen).
    El SP quedaria algo semejante a esto, ojala te sirva de inspiracion 🙂
    <pre lang="sql">
    CREATE OR REPLACE FUNCTION public.SPGuardaImagen
    (
    pfichero               bytea
    )
    RETURNS void AS
    $$
    begin
    insert into public.imagenes
    (fichero)
    values (pfichero);
    end
    $$
    LANGUAGE 'plpgsql'
    VOLATILE
    CALLED ON NULL INPUT
    SECURITY INVOKER
    COST 100;</pre>

  11. avatar
    Carlos E. Carmona COLOMBIA Internet Explorer Windows
    17 Febrero 2010 at 13:23 #

    Felicitaciones! Este tema es realmente interesante.

    Tengo una duda con el ejemplo, ¿Donde se encuentra el código del procedimiento almacenado que guarda la imagen en Postgres?

Responder