tags:

views:

95

answers:

4

Hi,

I have the following C# code (not mine) which pulls an image out of a database and displays it on a web page:

public partial class Image : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        getFullImage();
    }



    public void getFullImage()
    {
        SqlConnection objCon = new SqlConnection();
        objCon = new SqlConnection(Globals.ConnectionString);
        objCon.Open();

        String TmpStr;
        try
        {

            byte[] imgData = null;

            SqlCommand objCmd = new SqlCommand("Select * from Login where user_Name='" + Request["Id"].ToString() + "'", objCon);
            SqlDataReader reader = objCmd.ExecuteReader();


            while (reader.Read())
            {
                HttpContext.Current.Response.Clear();
                HttpContext.Current.Response.AddHeader("Content-Disposition",
                    "attachment; filename=" + reader["ImageName"]);
                imgData = (byte[])reader["ImageFile"];
                TmpStr = reader["ImageFile"].ToString();
                TmpStr = TmpStr.Substring(1, TmpStr.Length - 1);
            }
            HttpContext.Current.Response.ContentType = "image/jpeg";
            HttpContext.Current.Response.BinaryWrite(imgData);
        }
        catch(Exception ex)
        {
            Response.Write(ex.Message.ToString());
        }
        finally
        {

        }
    }
}

I know it's probably really bad practice to store images in a database and use them in this way, but I'm not a hardcore .NET dev and can't rewrite this whole thing (much as I'd love to be able to!).

Anyhow, currently the method above creates full size (often huge) images, which are then resized using CSS, which causes them to degrade terribly in quality. I wondered if there was anything I could do to resize the image prior to render, so improve quality and reduce load time?

Thanks for any pointers folks...

A: 

You may use the Image class with the GetThumbnailImage method from the namespace System.Drawing.Imaging. Regarding load time there are two large parts: Transmitting the image and loading the image from database. Maybe just store a reference to a file and then use that might be on alternative.

Edit: Scaling down almost always leads to some decease in quality. Maybe the GetThumbnailImage is better as it may use embedded thumbnail data, but don't expect the same quality than from professional grade algorithms like the ones used in Photoshop.

Sascha
+1  A: 

Here are some good links/suggestions to high quality resizing of the images:

http://stackoverflow.com/questions/249587/high-quality-image-scaling-c

Luke Hutton
A: 

I've been using this function whenever I needed to resize a bitmap... didn't write this code and don't even remember where I got it from... give it a try

public static Bitmap ResizePhoto(Bitmap b, int nWidth, int nHeight)
{
    Bitmap bTemp = (Bitmap)b.Clone();
    b = new Bitmap(nWidth, nHeight, bTemp.PixelFormat);

    double nXFactor = (double)bTemp.Width / (double)nWidth;
    double nYFactor = (double)bTemp.Height / (double)nHeight;


    double fraction_x, fraction_y, one_minus_x, one_minus_y;
    int ceil_x, ceil_y, floor_x, floor_y;
    Color c1 = new Color();
    Color c2 = new Color();
    Color c3 = new Color();
    Color c4 = new Color();
    byte red, green, blue;

    byte b1, b2;

    for (int x = 0; x < b.Width; ++x)
        for (int y = 0; y < b.Height; ++y)
        {
            floor_x = (int)Math.Floor(x * nXFactor);
            floor_y = (int)Math.Floor(y * nYFactor);
            ceil_x = floor_x + 1;
            if (ceil_x >= bTemp.Width) ceil_x = floor_x;
            ceil_y = floor_y + 1;
            if (ceil_y >= bTemp.Height) ceil_y = floor_y;
            fraction_x = x * nXFactor - floor_x;
            fraction_y = y * nYFactor - floor_y;
            one_minus_x = 1.0 - fraction_x;
            one_minus_y = 1.0 - fraction_y;

            c1 = bTemp.GetPixel(floor_x, floor_y);
            c2 = bTemp.GetPixel(ceil_x, floor_y);
            c3 = bTemp.GetPixel(floor_x, ceil_y);
            c4 = bTemp.GetPixel(ceil_x, ceil_y);

            // Blue

            b1 = (byte)(one_minus_x * c1.B + fraction_x * c2.B);

            b2 = (byte)(one_minus_x * c3.B + fraction_x * c4.B);

            blue = (byte)(one_minus_y * (double)(b1) + fraction_y * (double)(b2));

            // Green

            b1 = (byte)(one_minus_x * c1.G + fraction_x * c2.G);

            b2 = (byte)(one_minus_x * c3.G + fraction_x * c4.G);

            green = (byte)(one_minus_y * (double)(b1) + fraction_y * (double)(b2));

            // Red

            b1 = (byte)(one_minus_x * c1.R + fraction_x * c2.R);

            b2 = (byte)(one_minus_x * c3.R + fraction_x * c4.R);

            red = (byte)(one_minus_y * (double)(b1) + fraction_y * (double)(b2));

            b.SetPixel(x, y, Color.FromArgb(255, red, green, blue));
        }

    return b;
}
kzen
A: 

I use something like this:

    using (Graphics g = Graphics.FromImage(targetImage)) 
    { 
        g.DrawImage(myImage, 0, 0, Width, Height); 
    } 

You may need to play around with CompositingQuality, InterpolationMode and SmoothingMode to get the best results for you specific images.

FixerMark