Question

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.

Was it helpful?

Solution

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

OTHER TIPS

I believe that the best way to accomplish this would be to create the entire image in C# and send that down. You can get exact positioning of the barrel over the 'thermometer', and if the barrel is already a (semi) transparent PNG, you can just do a .DrawImage right over the thermostat, add text, and do anything you want before sending back the final image directly into the ResponseStream.

A couple of other suggestions for you:

Since you are handing everything directly in your Handler, you should dispose of your own internal disposable resources. "Using" blocks are the easiest way. You will need at least these two:

using (Graphics TempGraphics = GetGraphicsFromBitmap(TempImage))
{
    for (float y = 20.0f; y < 235.0f; y += 10.75f)
    {
        TempGraphics.DrawLine(TempPen, 119, y, 125, y);
        ...
    }
}

and

using (Font TempFont = new Font("Arial", 8.0f, FontStyle.Regular))
{
    ...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top