Dynamické obrázkové nadpisy v ASP.NET

20. prosince 2002

Pokud chceme mít pěkné nadpisy a jistotu, že budou u každého uživatele zobrazeny správně, nemůžeme použít „exotický“ font, anebo musíme každý nadpis připravit jako obrázek. V následujícím popisu si ukážeme, jak dynamicky generovat obrázky textu nadpisů libovolným fontem, který máme na serveru k dispozici.

Výhodou je, že díky způsobu provádění *.aspx stránek (neinterpretují se, provádí se zkompilovaný kód), si můžeme dovolit po aplikaci chtít i více než jen strohé vygenerování obrázku fontu. Na výsledný obrázek je možné aplikovat různé filtry a efekty. To samozřejmě není nic až tak nového, ovšem nějakému většímu nasazení v aplikacích, které jsou založeny na interpretovaných jazycích (ASP, PHP) brání fakt, že zatížení serveru při těchto operacích se v závislosti na podmínkách může výrazně podepsat na výkonu aplikace.

Ukážeme si, jak obrázek nadpisu vyhladit (tzv. antialiasing), čímž docílíme jemného vzhledu nadpisu nezávisle na systému klienta. Pokud například klient nemá zapnutý antialiasing, nebo má starší systém s nižší barevnou hloubkou, jsou texty velmi „zubaté“. Téměř nečitelná je při určité velikosti kurzíva, vznikne tak „kostrbaté“ písmo. S použitím naší aplikace můžeme mít krásné nadpisy i na navštěvovaném informačním serveru, výsledný obrázek nadpisu má sice obvykle okolo 1 kB, ovšem nadpisů ve stránce zase nebývá tolik.

Aplikaci připravíme tak, aby výsledný obrázek nadpisu bylo možné určit parametry, které předáme při jejím volání. Současně doplníme kontrolu (pomocí UrlReferrer), zda jde o volání aplikace z naší stránky. Jinak by se mohlo stát, že se náš skvělý program stane zdarma generátorem nadpisů pro řadu stránek. Parametry aplikace jsou navíc nepovinné, uživatel si může zadat jen ty, které chce. Princip aplikace je následující:

  • zkontrolujeme, jde-li o oprávněné volání aplikace, pokud ne, nastavíme generovaný text na „Neoprávněné použití“
  • pokud jde o oprávněné volání, převezmeme a zpracujeme zadané parametry
  • pokud je některý ze zadaných parametrů zadán chybně nebo je mimo povolený rozsah, použijí se výchozí parametry a text se nastaví na „Chybně zadané parametry!“
  • podle zadaných parametrů připravíme barevné pozadí (základ obrázku), tzv. canvas
  • do připraveného pozadí vygenerujeme patřičným fontem a stylem obrázek
  • uplatníme filtr pro vyhlazení obrázku
  • připravíme formát obrázku (jpeg, gif, png)
  • odešleme do prohlížeče patřičnou hlavičku, aby prohlížeč věděl, o jaký typ obrázku jde
  • odešleme binární data obrázku

Pro program jsem si zvolil jazyk C#, který je mi přece jen po zkušenostech s PHP bližší. Na začátku kódu je vidět zavedení tzv. namespaces, zavedení tříd, které nejsou zaváděny pro kompilaci implicitně, avšak jsou potřebné pro práci s fonty a grafické operace. Veškerý výkonný kód je napsán jako obsluha události načtení stránky Page_Load. V aplikaci je použit pro zachytávání chyb mechanismu try-catch, který byl použit například v aplikaci pro konverzi stupňů Celsia v již publikovaném článku. Navíc je využita i metoda throw pro vnucení výjimky (jako by nastala chyba), čímž se nám v našem případě zjednoduší větvení programu.

<% @Page Language=“C#“ %>
<% @Import Namespace=“System.Drawing“ %>
<% @Import Namespace=“System.IO“ %>
<% @Import Namespace=“System.Drawing.Imaging“ %>
<script language=“C#“ runat=“server“>
void Page_Load (Object sender, EventArgs e)
{// deklarace proměnných
  string HeadingText = „Neoprávněné použití aplikace!!!“;
  int DefWidth=400,DefHeight=20;
  int width=20,height=4;
  int DefRBgColor=255,DefGBgColor=255,DefBBgColor=255;
  int DefRColor=0,DefGColor=0,DefBColor=0;
  int rb=0,gb=0,bb=0,rc=0,gc=0,bc=0;
  int DefImg = 1; //png
  string ImageMIME = „image/png“;
  ImageFormat ImgType;
  ImgType=ImageFormat.Png;
  int DefStyle=1;
  string DefFont=“Garamond“;
  FontStyle FStyle;
  FStyle=FontStyle.Regular;
  if (Request.UrlReferrer != null)
    if (Request.UrlReferrer.Authority == Request.ServerVariables[„SERVER_NAME“])
    {// referer je v pořádku, naplnit parametry
      HeadingText = Request.QueryString[„text“].ToString();
      try
      { // pokus o konverzi a naplnění proměnných zadanými parametry
        if (Request.QueryString[„rb“] != null)
          rb=Convert.ToInt32(Request.QueryString[„rb“]);
        if (Request.QueryString[„gb“] != null)
          gb=Convert.ToInt32(Request.QueryString[„gb“]);
        if (Request.QueryString[„bb“] != null)
          bb=Convert.ToInt32(Request.QueryString[„bb“]);
        if (Request.QueryString[„rc“] != null)
          rc=Convert.ToInt32(Request.QueryString[„rc“]);
        if (Request.QueryString[„gc“] != null)
          gc=Convert.ToInt32(Request.QueryString[„gc“]);
        if (Request.QueryString[„bc“] != null)
          bc=Convert.ToInt32(Request.QueryString[„bc“]);
        if (Request.QueryString[„width“] != null)
          width=Convert.ToInt32(Request.QueryString[„width“]);
        if (Request.QueryString[„height“] != null)
          height=Convert.ToInt32(Request.QueryString[„height“]);
        if (Request.QueryString[„img“] != null)
          DefImg=Convert.ToInt32(Request.QueryString[„img“]);
        if (Request.QueryString[„style“] != null)
          DefStyle=Convert.ToInt32(Request.QueryString[„style“]);
        if (Request.QueryString[„font“] != null)
          DefFont=Request.QueryString[„font“];
        if (rb<256 && gb<256 && bb<256 && rc<256 && gc<256 && bc<256 && width>=20 && height>=4 && DefStyle>0 && DefStyle<6 & DefImg>0 && DefImg<4)
        { // ověřit, zda jsou zadané údaje v povoleném rozsahu, pokud ano, naplnit pracovní proměnné
          if (rb>0)
            DefRBgColor=rb;
          if (gb>0)
            DefGBgColor=gb;
          if (bb>0)
            DefBBgColor=bb;
          if (rc>0)
            DefRColor=rc;
          if (gc>0)
            DefGColor=gc;
          if (bc>0)
            DefBColor=bc;
          if (width>20)
            DefWidth=width;
          if (height>4)
            DefHeight=height;
          switch (DefStyle)
          { // styl písma
            case 2:
              FStyle=FontStyle.Bold;
            break;
            case 3:
              FStyle=FontStyle.Italic;
            break;
            case 4:
              FStyle=FontStyle.Underline;
            break;
            case 5:
              FStyle=FontStyle.Strikeout;
            break;
            default:
              FStyle=FontStyle.Regular;
            break;
          }
          switch (DefImg)
          { // typ obrázku
            case 2:
              ImageMIME = „image/jpeg“;
              ImgType=ImageFormat.Jpeg;
            break;
            case 3:
              ImageMIME = „image/gif“;
              ImgType=ImageFormat.Gif;
            break;
            default:
              ImageMIME = „image/png“;
              ImgType=ImageFormat.Png;
            break;
          }
        }
        else // některý z parametrů je mimo rozsah, vyvolat výjimku FormatException, která je ošetřena
          throw new FormatException();
      }
      catch (FormatException)
      { // obsloužit výjimku – jen se změní vypisovaný text
        HeadingText = „Chybně zadané parametry!“;
      }
    }
  // vytvořit canvas
  Bitmap newBitmap = new Bitmap(DefWidth,DefHeight,PixelFormat.Format24bppRgb);
  Graphics g = Graphics.FromImage(newBitmap);
  // barva pozadí
  g.FillRectangle(new SolidBrush(Color.FromArgb(DefRBgColor,DefGBgColor,DefBBgColor)), new Rectangle(0,0,DefWidth,DefHeight));
  // barva písma
  SolidBrush gridBrush = new SolidBrush(Color.FromArgb(DefRColor,DefGColor,DefBColor));
  Font gridFont = new Font(DefFont, DefHeight-3, FStyle, GraphicsUnit.Pixel);
  // zapnout vyhlazování
  g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
  // vykrestlit text do obrázku
  g.DrawString(HeadingText, gridFont, gridBrush,-1, -1);
  // vyprázdnit frontu hlaviček
  Response.ClearContent();
  // připravit hlavičku obrázku pro odeslání přes HTTP
  Response.ContentType = ImageMIME; // formát obrázku
  MemoryStream tempStream = new MemoryStream();
  // připravit data obrázku v patřičném formátu
  newBitmap.Save(tempStream,ImgType);
  // vypustit data do prohlížeče
  Response.BinaryWrite(tempStream.ToArray());
  Response.End();
}
</script>

Kromě povinné deklarace proměnných je dobré si povšimnout způsobu získání parametrů od uživatele, zejména jejich konverze na číselný typ, a test, zda je parametr vůbec zadán (není null). Mohli bychom sice ošetřit i výjimku ArgumentNullException, potom by se nám ale velmi těžko psala aplikace, která má parametry nepovinné, protože větvení programu by bylo mnohem složitější.

Parametry předávané přes QueryString (URL) naší aplikaci:

parametr Význam
text text nadpisu
font font nadpisu
style styl (1 ~ normální, 2 ~ tučné, 3 ~ kurzíva, 4 ~ podtržené, 5 ~ přeškrtnuté)
img formát obrázku (1 ~ png,2 ~ jpeg,3 ~ gif)
rc červená složka barvy písma (0 až 255)
gc zelená složka barvy písma (0 až 255)
bc modrá složka barvy písma (0 až 255)
rb červená složka barvy pozadí písma (0 až 255)
bg zelená složka barvy pozadí písma (0 až 255)
bb modrá složka barvy pozadí písma (0 až 255)
width šířka obrázku nadpisu
height výška obrázku nadpisu

V aplikaci máme přednastavené výchozí hodnoty a tyto jsou změněny pouze pokud jsou zadané parametry korektní. Chybně zadané parametry jsou testovány hned dvakrát. Jednou při pokusu o konverzi řetězce na číslo (zadaný parametr není číslo nebo se nedá převést na typ int) a podruhé se ověří, zda jsou v povoleném rozsahu. V případě chyby je vyvolána výjimka FormatException, výchozí hodnoty pracovních proměnných se nezmění a text v obrázku je nastaven na hlášení o chybě. Pokud totiž dojde při běhu programu k chybě, v prohlížeči uvidíme jen prázdné místo pro obrázek, který nebude zobrazen. Vypsat chybové hlášení do obrázku (a stejně tak, pokud se někdo pokouší volat náš skript z cizího serveru) je pak jediná možnost, jak uživatele aplikace upozornit, že něco není v pořádku.

Pro výklad grafických operací, přípravy dat obrázku a odesílání hlaviček odkazuji zájemce na stránky MSDN.

Nakonec ukázka použití aplikace v naší stránce. Obrázek nadpisu přidáme jako jakýkoli jiný obrázek, jen je třeba zajistit, aby zobrazovaný text předávaný do parametru v URL byl korektně zakódovaný. Pokud stránku s obrázkem nadpisu generujeme dynamicky, použijeme metodu UrlEncode pro získání zakódovaného tvaru řetězce. Pokud jde o statickou stránku, pak si pomocí uvedené metody připravíme zakódovaný text v nějaké zkušební stránce a do naší stránky jej přeneseme. Stejně zakódovaný musí být i řetězec parametru fontu, pokud obsahuje znaky mezery.

<img src=“heading.aspx?text=Zku%9Aebn%ED+nadpis+pro+%E8l%E1nek&amp;font=Trebuchet%20MS&amp;style=3&amp;img=1&amp;rc=0&amp;gc=160&amp; bc=100&amp;rb=255&amp;gb=255&amp;bb=255&amp;width=400&
amp;height=26″ width=“400″ height=“26″ alt=“Zkušební nadpis pro článek“ border=“0″ />

Všimněte si také, že pokud zadáte do prohlížeče přímo adresu na skript generující obrázek, objeví se místo zadaného textu hlášení o neoprávněném použití. Je to proto, že prohlížeč v tomto případě nepředá údaj o refereru a naše aplikace odepře text zobrazit. Stejně tak se stane, pokud bude obrázek linkovat někdo z cizího serveru.

Zdrojový kód aplikace si můžete stáhnout.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Předchozí článek Toulky po webu 14.
Další článek niky.continue.cz
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *