Search code examples
c#gdi+system.drawingashxihttphandler

Adding a background graphic to http handler image


the following code is a handler that takes in a Percent (percent of the graph to show as blue), Max (maximum value), and a Gallons value (number) to create a thermometer-style progress meter. It outputs a graph which is added to a web form as <img src="Thermometer.ashx" alt="" />.

Since this graph is intended to show progress as the number of gallons of water saved, it would be nice to have the blue color fill up a water barrel image. To do so I have attempted to add a barrel image with a transparent interior to the web form and tried to position it in front of the thermometer image but this has not worked, as it seems impossible to layer an image on top of one created using a handler.

My question is this: is it possible to added the barrel image through code so that is serves as the outline for the blue thermometer? Or does the barrel image need to be created from scratch in the code? I fear the latter since I am probably unable to code it.

Please see below and let me know if there is anything I can do.

Thank you!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Net;
using System.Drawing.Imaging;
using System.Web.UI.HtmlControls;
namespace rainbarrel
{
    public class Thermometer : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            int Percent = 25;
            int Max = 20000;
            bool Gallon = true; 
            float Pixels = (float)Percent * 2.15f;
            Bitmap TempImage = new Bitmap(200, 250);
            Graphics TempGraphics = Graphics.FromImage(TempImage);
            TempGraphics.FillRectangle(Brushes.White, new Rectangle(0, 0, 200, 250));
            Pen TempPen = new Pen(Color.Black);
            BarrelFill(TempImage, Percent);
            bool DrawText = true;
            float Amount = Max;
            for (float y = 20.0f; y < 235.0f; y += 10.75f)
            {
                TempGraphics.DrawLine(TempPen, 119, y, 125, y);
                if (DrawText)
                {
                    Font TempFont = new Font("Arial", 8.0f, FontStyle.Regular);
                    if (Gallon)
                    {
                        TempGraphics.DrawString(Amount.ToString() + " Gal", TempFont, Brushes.Black, 130, y);
                    }
                    else
                    {
                        TempGraphics.DrawString(Amount.ToString(), TempFont, Brushes.Black, 130, y);
                    }
                    DrawText = false;
                }
                else DrawText = true;
                Amount -= ((Max / 100) * 5.0f);
            }

            string etag = "\"" + Percent.GetHashCode() + "\"";
            string incomingEtag = context.Request.Headers["If-None-Match"];

            context.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime().AddDays(1));
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.Cache.SetMaxAge(new TimeSpan(7, 0, 0, 0));
            context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
            context.Response.Cache.SetETag(etag);

            if (String.Compare(incomingEtag, etag) == 0)
            {
                context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                context.Response.End();
            }
            else
            {
                context.Response.ContentType = "image/Gif";
                TempImage.Save(context.Response.OutputStream, ImageFormat.Gif);
                TempImage.MakeTransparent();
            }
        }

        private void BarrelFill(Bitmap TempImage, int Percent)
        {
            if (Percent == 100)
            {
                FillRectangle(TempImage, 60, 20, 235);
            }
            else
            {
                FillRectangle(TempImage, 60, (int)(235.0f - ((float)Percent * 2.15f)), 235);
            }
        }

        private void FillRectangle(Bitmap TempImage, int x, int y1, int y2)
        {
            int MaxDistance = 50;
            for (int i = x - MaxDistance; i < x + MaxDistance; ++i)
            {
                for (int j = y1; j < y2; ++j)
                {
                    float Distance = (float)Math.Abs((i - x));
                    int BlueColor = (int)(255.0f * (1.0 - (Distance / (2.0f * MaxDistance))));
                    TempImage.SetPixel(i, j, Color.FromArgb(30, 144, BlueColor));
                }
            }
        }
    } 
}

UPDATE:

I found this post here which showed me how to solve: overlaying images with GDI+

Here is my solution:

Image Barrel = Image.FromFile("C:\\Inetpub\\wwwroot\\barrel\\barrel_trans.png");
            TempGraphics.DrawImage(Barrel, -5, 0, 120, 240);
            Barrel.Dispose();

However, The quality of the png layer is bad (slightly blurry), although the original is very sharp and clear. Is there a way to retain the image quality of the original?

Many thanks in advance for your help.


Solution

  • Changing TempImage.Save(context.Response.OutputStream, ImageFormat.gif); to Jpeg solved the quality issue.