/*
PNGImage .NET Web Server Control Version 1.2 - November 2006
Copyright 2006 by Benjamin Ouellet
This web control can be freely used for any purpose, whether personal or commercial.
You can make any changes you want to this code. If you do make changes to improve this
control, you can submit the changes back to me and I'll consider adding the changes to my
source code. Please review license.txt for more details.
Contact me at wowitsben at yahoo.com or visit my website at http://bigbeno.dyndns.org:8000/
*/
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI.Design;
namespace Beno.WebControls
{
/// <summary>
/// Enhanced Image Web Control with PNG support.
/// </summary>
[DefaultProperty("Image"),
ToolboxData("<{0}:PNGImage runat=server></{0}:PNGImage>"),
Designer(typeof(Beno.WebControls.PNGImageDesigner)) ]
public class PNGImage : System.Web.UI.WebControls.Image
{
// PNG support level
public enum PngSupport { Supported, NotSupported, RequiresFilter };
private PngSupport pngSupport;
private System.Text.StringBuilder styles;
public PNGImage()
{
styles = new System.Text.StringBuilder();
}
protected override void OnLoad(EventArgs e)
{
pngSupport = getBrowserType();
base.OnLoad(e);
}
/// <summary>
/// Alternate image to use if browser doesn't support PNG transparency
/// </summary>
[Bindable(true), Category("Appearance"), Description("Replaces standard PNG image with an alternate image (Transparent GIF Recommended) if browser doesn't support PNG format.")]
public string AlternateImageURL {
get {
return (string)ViewState["AlternateImageURL"];
}
set {
ViewState["AlternateImageURL"] = value;
}
}
/// <summary>
/// Specifies URL to dummy image when displaying Transparent PNG image in IE.
/// </summary>
[Bindable(true), Category("Misc"), Description("For IE PNG transparency on an image to work, a dummy image is required in the image tag. Defaults to spacer.GIF.")]
public string ImageSpacerURL {
get {
return (string)ViewState["ImageSpacerURL"];
}
set {
ViewState["ImageSpacerURL"] = value;
}
}
/// <summary>
/// Render this control to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void Render(HtmlTextWriter output)
{
output.WriteBeginTag("img");
RenderBasicAttributes(output);
switch (pngSupport)
{
// PNG Transparency capable browser. Image control acts like a standard control,
// except style information is manually added.
case PngSupport.Supported:
OutputStandardPNG(output);
break;
// IE 5.5 or higher browser. PNG transparency capable, but
// requires proprietary HTML code
case PngSupport.RequiresFilter:
if (this.ImageUrl.EndsWith(".png") == true)
{
OutputIEPNG(output);
}
else
{
OutputStandardPNG(output);
}
break;
// Not capable of PNG transparency. Substitute with alternate image.
case PngSupport.NotSupported:
OutputDownlevelHTML(output);
break;
}
// Output styles
if (styles.Length > 0)
output.WriteAttribute("style", styles.ToString());
output.Write(" />");
}
// Case Supported - Web standard compliant browser.
private void OutputStandardPNG(HtmlTextWriter output)
{
RenderBorderBackground(output);
RenderAdditionalStyles(output);
output.WriteAttribute("src", this.ImageUrl);
OutputDimensions(output);
}
// Case RequiresFilter - Output img tag with AlphaImageLoader inline style and dummy image.
private void OutputIEPNG(HtmlTextWriter output)
{
RenderBorderBackground(output);
RenderAdditionalStyles(output);
// Check to see if width and height are not defined.
if ((this.Width == Unit.Empty) & (this.Height == Unit.Empty))
{
// No width and height defined.
// Set sizing method to "image" and put in a dummy width and height.
// Not adding a width and height strangely causes IE not to display the
// image at all.
AddStyle("FILTER", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.ImageUrl + "', sizingMethod='image')");
output.WriteAttribute("width", "1");
output.WriteAttribute("height", "1");
}
else
{
// We have a width and / or height. Set the image to automatically
// scale to the size specified.
AddStyle("FILTER", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.ImageUrl + "', sizingMethod='scale')");
output.WriteAttribute("width", outputAttribute(this.Width));
output.WriteAttribute("height", outputAttribute(this.Height));
}
// Output a spacer image, used as a placeholder so the AlphaImageLoader
// displays PNG image properly.
if ((string)ViewState["ImageSpacerURL"] == null)
ViewState["ImageSpacerURL"] = "spacer.gif";
output.WriteAttribute("src", (string)ViewState["ImageSpacerURL"]);
}
// Output HTML for case 2 - A browser not capable of transparent PNG images.
private void OutputDownlevelHTML(HtmlTextWriter output) {
// If it's a PNG image, substitute with alternate downlevel image.
if (this.ImageUrl.EndsWith(".png") == true) {
if (this.AlternateImageURL == null) {
// No alternate image defined.
output.WriteAttribute("src", this.ImageUrl);
}
else
// Output alternate image file name
output.WriteAttribute("src", this.AlternateImageURL);
}
else {
// Output standard image.
output.WriteAttribute("src", this.ImageUrl);
}
if (this.BorderWidth != Unit.Empty)
output.WriteAttribute("border", this.BorderWidth.ToString());
OutputDimensions(output);
RenderAdditionalStyles(output);
}
// Outputs border and background color style attributes for case Supported and
// RequiresFilter
private void RenderBorderBackground(HtmlTextWriter output) {
if (this.BorderStyle != BorderStyle.NotSet)
AddStyle("border-style", this.BorderStyle.ToString());
if (this.BorderColor.IsEmpty == false)
AddStyle("border-color", System.Drawing.ColorTranslator.ToHtml(this.BorderColor));
if (this.BorderWidth.IsEmpty == false)
AddStyle("border-width", this.BorderWidth.ToString());
if (this.BackColor.IsEmpty == false)
AddStyle("background-color", System.Drawing.ColorTranslator.ToHtml(this.BackColor));
}
// Output additional styles if defined.
private void RenderAdditionalStyles(HtmlTextWriter output) {
System.Collections.IEnumerator keys = Style.Keys.GetEnumerator();
while (keys.MoveNext()) {
AddStyle((string)keys.Current, Style[(string)keys.Current]);
}
}
// Outputs width and height.
private void OutputDimensions(HtmlTextWriter output) {
// Set width and height
if (this.Width != Unit.Empty)
output.WriteAttribute("width", outputAttribute(this.Width));
if (this.Height != Unit.Empty)
output.WriteAttribute("height", outputAttribute(this.Height));
}
// Outputs a size value - a number or a percentage value
private string outputAttribute(System.Web.UI.WebControls.Unit Size) {
string size;
if (Size.Type == UnitType.Percentage)
size = Size.ToString();
else
size = Size.Value.ToString();
return size;
}
private void RenderBasicAttributes(HtmlTextWriter output) {
// Add ID
output.WriteAttribute("id", this.ID);
// Add css class
if (this.CssClass != "")
output.WriteAttribute("class", this.CssClass);
// Alternate Text
output.WriteAttribute("alt", this.AlternateText);
// Image Alignment
if (this.ImageAlign != ImageAlign.NotSet) {
output.WriteAttribute("align", Enum.Format(typeof(ImageAlign), this.ImageAlign, "g"));
}
// Long Description URL
if (this.DescriptionUrl != "") {
output.WriteAttribute("longdesc", this.DescriptionUrl);
}
// Tooltip Text.
if (this.ToolTip != "")
output.WriteAttribute("title", this.ToolTip);
// Render other attributes
System.Collections.IEnumerator attribs = Attributes.Keys.GetEnumerator();
while (attribs.MoveNext()) {
if ((string)attribs.Current != "style")
output.WriteAttribute((string)attribs.Current, this.Attributes[(string)attribs.Current]);
}
}
// Browser detection code here.
private PngSupport getBrowserType()
{
System.Web.HttpBrowserCapabilities cap = this.Context.Request.Browser;
PngSupport browserType = PngSupport.Supported;
try
{
// Parse version numbers
string[] version = cap.Version.Split('.');
int versionMajor = 0, versionMinor = 0;
if (version.Length > 0)
{
versionMajor = int.Parse(version[0]);
}
if (version.Length > 1)
{
versionMinor = int.Parse(version[1]);
}
if (cap.Browser.ToLower() == "ie")
{
// IE7
if (versionMajor >= 7) {
browserType = PngSupport.Supported;
}
// IE 5.5 or 6
else if ((versionMajor == 5 & versionMinor >= 5) | versionMajor == 6) {
browserType = PngSupport.RequiresFilter;
}
// IE 5.0 or lower
else {
browserType = PngSupport.NotSupported;
}
}
if ((cap.Browser.ToLower() == "netscape") & (cap.MajorVersion <= 4)) {
browserType = PngSupport.NotSupported;
}
}
catch(Exception e)
{
AlternateText = e.Message;
}
return browserType;
}
/// <summary>
/// Allows the detected browser type to be overridden.
/// </summary>
/// <param name="typeCode">The browser type (0 - Modern, 1 - IE, 2 Old)</param>
public void setBrowserType(PngSupport typeCode)
{
pngSupport = typeCode;
}
// adds a style to the stringbuilder, to later be rendered on the control.
private void AddStyle(string name, string val)
{
styles.Append(name).Append(":").Append(val).Append(";");
}
}
public class PNGImageDesigner:ControlDesigner
{
/// <summary>
/// Class for design time support in Visual Studio.
/// </summary>
/// <returns></returns>
public override string GetDesignTimeHtml( )
{
Beno.WebControls.PNGImage control = (Beno.WebControls.PNGImage)this.Component;
if (control != null)
{
// Force control to display standard PNG image in Visual Studio.
control.setBrowserType(Beno.WebControls.PNGImage.PngSupport.Supported);
}
return base.GetDesignTimeHtml();
}
}
}