HTML img 태크에서 DB에 저장된 이미지를 지정하는 방법

[제목] HTML img 태크에서 DB에 저장된 이미지를 지정하는 방법

이미지가 파일로 존재하는 경우, 이미지를 웹페이지에 삽입하는 것은 HTML img 태크를 통해 간단하게 표현할 수 있다. 하지만 이미지가 Database 내에 존재한다면, 이는 간단한 문제가 아니다.

이미지는 일반적으로 Database (여기서는 SQL Server라고 가정하자)내에서 Image 컬럼 혹은 varbinary(max) 컬럼에 저장된다. DB에 저장된 Binary 이미지 데이타는 HTML img 태크에서 직접 사용하지 못하기 때문에 중간 처리과정을 거쳐야 한다.

한가지 일반적인 방식을 이미지 데이타를 웹서버 내에 파일로 저장한 후, 이 파일 URL을 img 태크의 src 속성에 지정하는 방식이다. 한번 웹서버에 파일로 저장된 후에는 마치 Cache 처럼 사용해서 반복적인 이미지 파일 생성을 막을 수 있다. 물론 이미지가 DB 상에 변경된 경우 어떻게 할 것인가는 또 다른 문제이기도 하다.

이 아티클에서는 위와 같은 파일 저장 방식과는 다른 접근법에 대해 살펴 보고자 한다. 이 방식의 요점은 웹페이지에서 직접 DB의 이미지 바이너리를 메모리로 읽어 들여, 메모리 상의 이미지 스트림을 다시 웹클라이언트에 직접 보내는 방식이다.

우선 DB서버에 아래와 같은 이미지 컬럼(Img)을 갖는 Table이 있고 Id = 1 인 레코드에 PNG 이미지 바이너리가 저장되었다고 가정하자.

CREATE TABLE [dbo].[ImgTable](
	[Id] [int] PRIMARY KEY,
	[ImgType] [nvarchar](50) NOT NULL,
	[Img] [varbinary](max) NULL
)

-- ... 은 생략
INSERT ImgTable VALUES (1, 'Png', 0x89504E470D0A1A0...)
GO

새 ASP.NET 프로젝트를 생성하고 image.aspx 이라고 명명된 새 WebForm을 추가한다. 이렇게 추가되면 image.aspx와 image.aspx.cs 가 생성되는데, image.aspx에서 아래와 같은 첫 라인만 제외하고 나머지를 삭제한다.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="image.aspx.cs" Inherits="imgTestWeb.image" %>

image.aspx.cs 파일에 아래와 같은 이미지 처리를 위한 코딩을 한다.

namespace imgTestWeb
{
	using System;
	using System.Data;
	using System.Data.SqlClient;

    public partial class image : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string idString = Request["Id"].ToString();
            int id = int.Parse(idString);

            DataSet ds = LoadData(id);
            DataRow row = ds.Tables[0].Rows[0];

            byte[] imgBytes = (byte[]) row["Img"];
            string imgType = row["ImgType"].ToString();

            Response.Clear();
            // Set ContentType  (ex) image/png
            Response.ContentType = "image/" + imgType;
            Response.AppendHeader("Content-Length", imgBytes.Length.ToString());
            Response.AppendHeader("Pragma", "public");
            Response.BinaryWrite(imgBytes);
            Response.Flush();
            Response.Close();
        }

        private DataSet LoadData(int id)
        {
            string strConn = "Data Source=.;Initial Catalog=MyDB;Integrated Security=SSPI;";
            DataSet ds = new DataSet();

            using (SqlConnection conn = new SqlConnection(strConn))
            {
                conn.Open();

                string sql = "SELECT Img, ImgType FROM ImgTable WHERE Id=" + id.ToString();
                SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
                adapter.Fill(ds);
            }

            return ds;
        }		
    }
}

위의 코드를 살펴보면, DB 이미지 데이타를 읽기위해 LoadData() 메서드에서 ADO.NET을 사용하여 두 개의 컬럼 (Img, ImgType) 데이타를 읽어 온다. 다음으로 Img 컬럼의 바이너리 데이타를 imgBytes 변수에 넣고, Reponse.BinaryWrite() 메서드를 사용하여 클라이언트에게 직접 데이타를 보내게 된다. 이미지 처리에 있어 한가지 주목할 것은 서버가 보내는 바이너리가 무슨 포맷인지를 알려주는 것인데, 이를 위해 Response.ContentType 에 MIME 타임을 지정해 주고, Content-Length에 바이너리 크기를 지정해 주어야 한다. 이러한 HTTP 헤더설정과 바이너리 쓰기가 완료되면 Response.Close()를 호출하여 HTTP Response를 클라이언트로 전송하게 된다.

여기서 한가지 추가할 사항은 위의 예제에서는 DB에 Image Type을 저장하고 있지만, 때론 이미지 바이너리 자체만 보고 이미지 포맷을 유추해 내야 하는 때가 있다. 이런 경우 아래 코드를 사용하여 각 이미지 바이너리 첫부분을 Decode하여 상응하는 이미지 포맷을 유추할 수 있다.

 

private static Dictionary imageHeaderFormat = new Dictionary()
{
	{new byte[] {0x42, 0x4D}, ImageFormat.Bmp},
	{new byte[] {0x47, 0x49, 0x46, 0x38, 0x37, 0x61}, ImageFormat.Gif},
	{new byte[] {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}, ImageFormat.Gif},
	{new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}, ImageFormat.Png},
	{new byte[] {0xff, 0xd8}, ImageFormat.Jpeg}
};

이제 마지막으로 image.aspx 를 사용하는 방법을 살펴보자. 아래 예에서 보이듯이, image.aspx는 HTML의 img 태그의 src 에 직접 사용할 수 있다.

<img src="http://localhost/image.aspx?Id=1" />

ASP.NET은 이러한 요청이 오면 image.aspx를 호출하게 되고 위의 예제 Page_Load()에서 처럼 이미지를 직접 DB에서 가져와 HTTP Response로 이미지를 출력하게 된다.

이러한 접근법은 이미지를 매번 DB에서 읽어 와야 한다는 단점(?)이 있을 수 있다. 만약 이미지가 크고 다수의 클라이언트가 계속 이미지를 요청한다면, DB 서버에 부담으로 작용할 수 있다는 점에서 단점이라 할 수 있다. 하지만, 이미지의 크기가 상대적으로 작고, 이미지가 수시로 변경되는 곳에 매우 유용한 기법이라 할 수 있다.



본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.