Creating "on the fly" images, using fonts from the server
Normally you are stuck using the same set of web fonts, and having dynamic text using other fonts is impossible. By using a method of having a page "output" an image we can get around this limitation. This can also be used for any image manipulation (I've also done an image sizer that can smoothly resize and composite images).
In the html of the page you want to show the text in the img tag just references the .aspx page. The .aspx page sets its content type to be an image, so the img referencing it just treats the output like one.
Create an .aspx page called imgtext.aspx with nothing in the file and a cs file like this
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
public partial class imgtext : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Response.ContentType = "image/png";
// arbitrary big size, can make to wrap
System.Drawing.Image textImage = new Bitmap(800, 2000, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(textImage);
// Create a private font collection (so we can load any font, otherwise .NET only allows standard fonts)
System.Drawing.Text.PrivateFontCollection textCollection = new System.Drawing.Text.PrivateFontCollection();
textCollection.AddFontFile(Server.MapPath("fonts\\segoeuib.ttf")); // I just stuck this ttf file on the server
// Create font family for font
FontFamily textFamily = new FontFamily(textCollection.Families[0].Name, textCollection);
// font size of 16
Font textFont = new Font(textFamily, 16, FontStyle.Bold);
Brush textBrush = new System.Drawing.SolidBrush(Color.FromArgb(140, 0, 0)); // color of the text
String strTitleText = Request.QueryString["text"].ToString();
SizeF areaSize = new SizeF(800, 2000);
SizeF textSize = g.MeasureString(strTitleText, textFont, areaSize);
textImage.Dispose();
// Create new image with the correct size to exactly fit the text
Int32 nWidth = Convert.ToInt32(textSize.Width + .5);
Int32 nHeight = Convert.ToInt32(textSize.Height + .5);
textImage = new Bitmap(nWidth, nHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
g = Graphics.FromImage(textImage);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.FillRectangle(System.Drawing.Brushes.White, -1, -1, nWidth + 1, nHeight + 1);
RectangleF textRect;
// just positioned to look right
textRect = new RectangleF(0, 0, nWidth, nHeight + 6); // +6 helps with decenders
g.DrawString(strTitleText, textFont, textBrush, textRect);
MemoryStream memStream = new MemoryStream();
textImage.Save(memStream, System.Drawing.Imaging.ImageFormat.Png); // can output different formats here
context.Response.BinaryWrite(memStream.ToArray());
context.Response.Flush();
memStream.Dispose();
textBrush.Dispose();
textFont.Dispose();
textFamily.Dispose();
textCollection.Dispose();
g.Dispose();
textImage.Dispose();
}
}
Now just stick an image tag on any page, looking like this:
<img src="imgtext.aspx?text=Testing"/>
Of course with GDI calls at our disposal we could manipulate (color correct, resize, apply masks, etc). Also we could create informational image for another site to reference (a stock chart created in real time on the server, viewed on a page from another server). I believe the only performance impact is to the server, and for most things won't be measurable (DrawString will be pretty speedy).
Another way I've used this is to allow for dithered resizing of images. Browsers will resize images really poorly. DrawImage will do a much better job. Since the "image" sent to the browser is just the size rendered image, this could allow for having only one version of a high resolution image to be on the server, and the references can ask for the size they need and not affect load time. (For instance a picture of someone used in several places at different sizes would only need the one "source" image).
Note: for SEO you don't want to make all of your text images, even if you alt tag them it'll hurt your search rankings if you do this too much.
In the html of the page you want to show the text in the img tag just references the .aspx page. The .aspx page sets its content type to be an image, so the img referencing it just treats the output like one.
Create an .aspx page called imgtext.aspx with nothing in the file and a cs file like this
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
public partial class imgtext : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Response.ContentType = "image/png";
// arbitrary big size, can make to wrap
System.Drawing.Image textImage = new Bitmap(800, 2000, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(textImage);
// Create a private font collection (so we can load any font, otherwise .NET only allows standard fonts)
System.Drawing.Text.PrivateFontCollection textCollection = new System.Drawing.Text.PrivateFontCollection();
textCollection.AddFontFile(Server.MapPath("fonts\\segoeuib.ttf")); // I just stuck this ttf file on the server
// Create font family for font
FontFamily textFamily = new FontFamily(textCollection.Families[0].Name, textCollection);
// font size of 16
Font textFont = new Font(textFamily, 16, FontStyle.Bold);
Brush textBrush = new System.Drawing.SolidBrush(Color.FromArgb(140, 0, 0)); // color of the text
String strTitleText = Request.QueryString["text"].ToString();
SizeF areaSize = new SizeF(800, 2000);
SizeF textSize = g.MeasureString(strTitleText, textFont, areaSize);
textImage.Dispose();
// Create new image with the correct size to exactly fit the text
Int32 nWidth = Convert.ToInt32(textSize.Width + .5);
Int32 nHeight = Convert.ToInt32(textSize.Height + .5);
textImage = new Bitmap(nWidth, nHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
g = Graphics.FromImage(textImage);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.FillRectangle(System.Drawing.Brushes.White, -1, -1, nWidth + 1, nHeight + 1);
RectangleF textRect;
// just positioned to look right
textRect = new RectangleF(0, 0, nWidth, nHeight + 6); // +6 helps with decenders
g.DrawString(strTitleText, textFont, textBrush, textRect);
MemoryStream memStream = new MemoryStream();
textImage.Save(memStream, System.Drawing.Imaging.ImageFormat.Png); // can output different formats here
context.Response.BinaryWrite(memStream.ToArray());
context.Response.Flush();
memStream.Dispose();
textBrush.Dispose();
textFont.Dispose();
textFamily.Dispose();
textCollection.Dispose();
g.Dispose();
textImage.Dispose();
}
}
Now just stick an image tag on any page, looking like this:
<img src="imgtext.aspx?text=Testing"/>
Of course with GDI calls at our disposal we could manipulate (color correct, resize, apply masks, etc). Also we could create informational image for another site to reference (a stock chart created in real time on the server, viewed on a page from another server). I believe the only performance impact is to the server, and for most things won't be measurable (DrawString will be pretty speedy).
Another way I've used this is to allow for dithered resizing of images. Browsers will resize images really poorly. DrawImage will do a much better job. Since the "image" sent to the browser is just the size rendered image, this could allow for having only one version of a high resolution image to be on the server, and the references can ask for the size they need and not affect load time. (For instance a picture of someone used in several places at different sizes would only need the one "source" image).
Note: for SEO you don't want to make all of your text images, even if you alt tag them it'll hurt your search rankings if you do this too much.
