• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

在 ASP.NET 网页中显示动态生成的图片

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

概述

在上一篇随笔“【算法】从推箱子的解答步骤还原关卡地图”中,我给出一个控制台应用程序,将 LURD 数据转换为 XSB 数据。为了方便使用,我编写了一个 ASP.NET 网页实现从推箱子的解答步骤还原关卡地图:Sokoban: Lurd to Xsb,如下所示:

源程序代码

首先是 lurd2xsb.aspx 源程序文件:

01:  <%@ Page Language="C#" inherits="Skyiv.Ben.Web.Lurd2xsbPage" %>
02:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03:  <html xmlns="http://www.w3.org/1999/xhtml" >
04:  <head runat="server">
05:    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
06:    <title>Sokoban: Lurd to Xsb</title>
07:  </head>
08:  <body>
09:    <form id="form1" runat="server">
10:    <asp:Button Text="Home" OnClick="BtnUriHome_Click" runat="server" />
11:    <asp:Button Text="Start" OnClick="BtnSubmit_Click" runat="server" />
12:    <a href="http://sokoban.ws/xsb_lurd.php" target="_blank">Introduction to XSB and LURD</a>
13:    <a href="http://sokoban.ws/sokoplayer/SokoPlayer_HTML5.php" target="_blank">SokoPlayer HTML5</a>
14:    <a href="http://sokoban.ws/utility/SokoEditor.php" target="_blank">SokoEditor HTML5</a>
15:    <a href="http://www.cnblogs.com/skyivben/archive/2011/07/03/2096801.html" target="_blank">Algorithm</a>
16:    <hr />
17:    <div>
18:    <table><tbody><tr/><td>
19:    <asp:TextBox Runat="Server" Id="tbxLurd" MaxLength="102400" TextMode="MultiLine" Columns="50" Rows="11"
20:      Text="rrurruulllulldRRRRlllldlluRRurrddLLrDururrurrdLddlldlLuululldRRuurrdLLrrrRurrdLLrddlldlluUruRRlldlluRRlddddlluRdrU"/>
21:    <br />
22:    <asp:TextBox Runat="Server" Id="tbxMoves" ReadOnly="True" Columns="57" BackColor="#CFECEC"/></td><td>
23:    <asp:TextBox Runat="Server" Id="tbxXsb" ReadOnly="True" TextMode="MultiLine" Columns="60" Rows="12" Wrap="False" BackColor="#CFECEC"/>
24:    </td></tr></tbody></table>
25:    <br />
26:    <img src="xsbbitmap.aspx" /><hr />
27:    I would like to thank <a href="http://borgar.net/s/2009/07/sokoban/" target="_blank">Borgar 
28:    &#222;orsteinsson</a> for his kind permission using the elegant skin designed by him.
29:    </div>
30:    </form>
31:  </body>
32:  </html>

注意上述源程序文件中第 26 行使用了 HTML 的 <img /> 标签,而没有使用 ASP.NET 的 <asp:Image /> 控件。这是因为后者只能通过其 ImageUri 属性来显示图像。而我们的图像是根据 Xsb 数据动态生成的,这就不符合要求了。相应的 lurd2xsb.aspx.cs 源程序文件如下所示:

01:  using System;
02:  using System.IO;
03:  using System.Web.UI;
04:  using System.Web.UI.WebControls;
05:  using Skyiv.Ben.Game;
06:  
07:  namespace Skyiv.Ben.Web
08:  {
09:    public class Lurd2xsbPage : Page
10:    {
11:      protected TextBox tbxLurd;
12:      protected TextBox tbxMoves;
13:      protected TextBox tbxXsb;
14:  
15:      public void BtnUriHome_Click(object sender, EventArgs e)
16:      {
17:        Response.Redirect("~/");
18:      }
19:  
20:      public void BtnSubmit_Click(object sender, EventArgs e)
21:      {
22:        try
23:        {
24:          var runer = new Lurd2Xsb();
25:          var xsb = runer.GetXsbFromLurd(tbxLurd.Text);
26:          tbxMoves.Text = string.Format("{0:N0} moves, {1:N0} pushes", runer.Moves, runer.Pushes);
27:          tbxXsb.Text = xsb;
28:          Session["map"] = Xsb2Bitmap.GetMap(xsb);
29:        }
30:        catch (Exception ex)
31:        {
32:          tbxXsb.Text = "Error: " + ex.Message;
33:        }
34:      }
35:    }
36:  }

上述源程序代码的第 28 行将表示关卡地图的二维的字节数组存放到 Session 中,以便后面动态生成关卡地图的图像时使用。上述源程序第 24 行中使用到的 Skyiv.Ben.Game.Lurd2Xsb 类位于 lurd2xsb.cs 源程序文件中:

001:  using System;
002:  using System.Text;
003:  using System.Drawing;
004:  
005:  namespace Skyiv.Ben.Game
006:  {
007:    public sealed class Lurd2Xsb
008:    {
009:      public int Moves { get { return Steps + Pushes; } }
010:      public int Pushes { get; private set; }
011:      public int Steps { get; private set; }
012:      void SetBrick(byte[,] map, int x, int y) { map[x, y] = 8; }
013:      void SetFloor(byte[,] map, Point pt) { map[pt.X, pt.Y] |= 1; }
014:      void SetGoal(byte[,] map, Point pt) { map[pt.X, pt.Y] |= 2; }
015:      void SetBox(byte[,] map, Point pt) { map[pt.X, pt.Y] |= 4; }
016:      void UnsetBox(byte[,] map, Point pt) { map[pt.X, pt.Y] &= 0xFB; }
017:      bool HasBox(byte[,] map, int x, int y) { return (map[x, y] & 4) != 0; }
018:      bool IsGoal(byte[,] map, int x, int y) { return (map[x, y] & 2) != 0; }
019:      bool IsFloor(byte[,] map, int x, int y) { return (map[x, y] & 1) != 0; }
020:      bool IsBrick(byte[,] map, int x, int y) { return map[x, y] == 8; }
021:      bool IsWall(byte[,] map, int x, int y) { return map[x, y] == 0; }
022:      bool IsBrickOrWall(byte[,] map, int x, int y) { return IsBrick(map, x, y) || IsWall(map, x, y); }
023:      
024:      void MarkBrick(byte[,] map, int x, int y)
025:      {
026:        if (!IsWall(map, x, y)) return;
027:        if (!IsBrickOrWall(map, x - 1, y - 1)) return;
028:        if (!IsBrickOrWall(map, x - 1, y + 1)) return;
029:        if (!IsBrickOrWall(map, x + 1, y - 1)) return;
030:        if (!IsBrickOrWall(map, x + 1, y + 1)) return;
031:        if (!IsBrickOrWall(map, x - 1, y)) return;
032:        if (!IsBrickOrWall(map, x + 1, y)) return;
033:        if (!IsBrickOrWall(map, x, y - 1)) return;
034:        if (!IsBrickOrWall(map, x, y + 1)) return;
035:        SetBrick(map, x, y);
036:      }
037:      
038:      int GetX(byte[,] map, int y0, int y1, int x, int x2)
039:      {
040:        for (var y = y0; y < y1; y++)
041:          if (!IsBrick(map, x, y)) return x;
042:        return x2;
043:      }
044:  
045:      int GetY(byte[,] map, int x0, int x1, int y, int y2)
046:      {
047:        for (var x = x0; x < x1; x++)
048:          if (!IsBrick(map, x, y)) return y;
049:        return y2;
050:      }
051:  
052:      Rectangle GetRectangle(byte[,] map)
053:      {
054:        int x0 = 1, y0 = 1, x1 = map.GetLength(0) - 2, y1 = map.GetLength(1) - 2;
055:        x0 = GetX(map, y0, y1, x0, x0 + 1);
056:        x1 = GetX(map, y0, y1, x1, x1 - 1); 
057:        y0 = GetY(map, x0, x1, y0, y0 + 1);
058:        y1 = GetY(map, x0, x1, y1, y1 - 1);
059:        return Rectangle.FromLTRB(x0, y0, x1, y1);
060:      }
061:  
062:      string GetXsb(byte[,] map, Point man)
063:      {
064:        var rect = GetRectangle(map);
065:        for (var y = rect.Top; y <= rect.Bottom; y++)
066:          for (var x = rect.Left; x <= rect.Right; x++)
067:            MarkBrick(map, x, y);
068:        rect = GetRectangle(map);
069:        var xsb = new StringBuilder();
070:        for (var y = rect.Top; y <= rect.Bottom; y++)
071:        {
072:          for (var x = rect.Left; x <= rect.Right; x++)
073:          {
074:            if (IsGoal(map, x, y))
075:            {
076:              if (man.X == x && man.Y == y) xsb.Append('+');
077:              else if (HasBox(map, x, y)) xsb.Append('*');
078:              else xsb.Append('.');
079:            }
080:            else if (IsFloor(map, x, y))
081:            {
082:              if (man.X == x && man.Y == y) xsb.Append('@');
083:              else if (HasBox(map, x, y)) xsb.Append('$');
084:              else xsb.Append('-');
085:            }
086:            else if (IsBrick(map, x, y)) xsb.Append('_');
087:            else xsb.Append('#');
088:          }
089:          xsb.AppendLine();
090:        }
091:        return xsb.ToString();
092:      }
093:  
094:      void LeftOrRight(byte[,] map, ref Point man, int step)
095:      {
096:        man.X += step;
097:        if (HasBox(map, man.X, man.Y)) UnsetBox(map, man);
098:        else SetGoal(map, man);
099:        man.X -= step;
100:        SetBox(map, man);
101:        man.X -= step;
102:        SetFloor(map, man);
103:      }
104:      
105:      void UpOrDown(byte[,] map, ref Point man, int step)
106:      {
107:        man.Y += step;
108:        if (HasBox(map, man.X, man.Y)) UnsetBox(map, man);
109:        else SetGoal(map, man);
110:        man.Y -= step;
111:        SetBox(map, man);
112:        man.Y -= step;
113:        SetFloor(map, man);
114:      }
115:      
116:      byte[,] GetMap(string lurd, Size size, ref Point man)
117:      {
118:        var map = new byte[size.Width, size.Height];
119:        SetFloor(map, man);
120:        for (var i = lurd.Length - 1; i >= 0; i--)
121:        {
122:          switch (lurd[i])
123:          {
124:            case 'l': man.X++; SetFloor(map, man); Steps++; break;
125:            case 'r': man.X--; SetFloor(map, man); Steps++; break;
126:            case 'u': man.Y++; SetFloor(map, man); Steps++; break;
127:            case 'd': man.Y--; SetFloor(map, man); Steps++; break;
128:            case 'L': LeftOrRight(map, ref man, -1); Pushes++; break;
129:            case 'R': LeftOrRight(map, ref man, 1); Pushes++; break;
130:            case 'U': UpOrDown(map, ref man, -1); Pushes++; break;
131:            case 'D': UpOrDown(map, ref man, 1); Pushes++; break;
132:          }
133:        }
134:        return map;
135:      }
136:      
137:      Rectangle GetBoundary(string lurd)
138:      {
139:        var boundary = new Rectangle(0, 0, 1, 1);
140:        var man = new Point();
141:        for (var i = lurd.Length - 1; i >= 0; i--)
142:        {
143:          switch (lurd[i])
144:          {
145:            case 'l': case 'L': man.X++; if (boundary.Right <= man.X) boundary.Width++; break;
146:            case 'r': case 'R': man.X--; if (boundary.Left > man.X) { boundary.Width++; boundary.X--; } break;
147:            case 'u': case 'U': man.Y++; if (boundary.Bottom <= man.Y) boundary.Height++; break;
148:            case 'd': case 'D': man.Y--; if (boundary.Top > man.Y) { boundary.Height++; boundary.Y--; } break;
149:          }
150:        }
151:        return boundary;
152:      }
153:      
154:      public string GetXsbFromLurd(string lurd)
155:      {
156:        var boundary = GetBoundary(lurd);
157:        var size = new Size(boundary.Width + 6, boundary.Height + 6);
158:        var man = new Point(3 - boundary.X, 3 - boundary.Y);
159:        var map = GetMap(lurd, size, ref man);
160:        return GetXsb(map, man);
161:      }
162:    }
163:  }

这个源程序文件已经在上一篇随笔“【算法】从推箱子的解答步骤还原关卡地图”中介绍过了。下面是 xsb2bitmap.cs 源程序文件:

01:  using System;
02:  using System.Drawing;
03:  using System.Reflection;
04:  
05:  namespace Skyiv.Ben.Game
06:  {
07:    public sealed class Xsb2Bitmap
08:    {
09:      static Bitmap img8;
10:      static Size boxSize;
11:      byte[,] map;
12:      
13:      static Xsb2Bitmap()
14:      {
15:        img8 = new Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream("PushBox24.png"));
16:        boxSize = new Size(img8.Width / 8, img8.Height);
17:      }
18:      
19:      public static byte[,] GetMap(string xsb)
20:      {
21:        var lines = xsb.Split(default(Char[]), StringSplitOptions.RemoveEmptyEntries);
22:        var map = new byte[lines[0].Length, lines.Length];
23:        for (var y = 0; y < map.GetLength(1); y++)
24:          for (var x = 0; x < map.GetLength(0); x++)
25:            map[x, y] = GetByte(lines[y][x]);
26:        return map;
27:      }
28:      
29:      static byte GetByte(char c)
30:      {
31:        switch (c)
32:        {
33:          case ' ':
34:          case '-': return 0;
35:          case '.': return 1;
36:          case '#': return 2;
37:          case '_': return 3;
38:          case '$': return 4;
39:          case '*': return 5;
40:          case '@': return 6;
41:          case '+': return 7;
42:        }
43:        throw new Exception("invalid XSB char:[" + c + "]");
44:      }
45:      
46:      public Xsb2Bitmap(byte[,] map)
47:      {
48:        this.map = map;
49:      }
50:      
51:      public Bitmap GetBitmap()
52:      {
53:        if (map == null) return new Bitmap(1, 1);
54:        var img = new Bitmap(boxSize.Width * map.GetLength(0), boxSize.Height * map.GetLength(1));
55:        var graphics = Graphics.FromImage(img);
56:        for (var y = 0; y < map.GetLength(1); y++)
57:          for (var x = 0; x < map.GetLength(0); x++)
58:            DrawBox(graphics, map[x, y], x * boxSize.Width, y * boxSize.Height);
59:        return img;
60:      }
61:      
62:      void DrawBox(Graphics graphics, int idx, int x, int y)
63:      {
64:        graphics.DrawImage(img8, x, y, new Rectangle(idx * boxSize.Width, 0, boxSize.Width, boxSize.Height), GraphicsUnit.Pixel);
65:      }    
66:    }
67:  }

上述源程序有两个用途:

  • 静态的 GetMap 方法将 Xsb 数据(文件格式)转换为二维字节数组
  • GetBitmap 方法从上述二维字节数组动态生成表示关卡地图的图片

下面就是用于动态生成图像的 xsbbitmap.aspx 源程序文件了:

01:  <%@ Page Language="C#" inherits="Skyiv.Ben.Web.XsbBitmapPage" %>
02:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03:  <html xmlns="http://www.w3.org/1999/xhtml">
04:  <head runat="server">
05:      <title>Xsb Bitmap</title>
06:  </head>
07:  <body>
08:      <form id="form1" runat="server">
09:      </form>
10:  </body>
11:  </html>

对应的 xsbbitmap.aspx.cs 源程序文件如下所示:

01:  using System;
02:  using System.IO;
03:  using System.Drawing.Imaging;
04:  using System.Web.UI;
05:  using System.Web.UI.WebControls;
06:  using Skyiv.Ben.Game;
07:  
08:  namespace Skyiv.Ben.Web
09:  {
10:    public class XsbBitmapPage : Page
11:    {
12:      public void Page_Load(object sender, EventArgs e)
13:      {
14:        CreateImage((byte[,])Session["map"]);
15:      }
16:      
17:      void CreateImage(byte[,] map)
18:      {
19:        Session["map"] = null;
20:        var img = new Xsb2Bitmap(map).GetBitmap();
21:        try
22:        {
23:          var ms = new MemoryStream();
24:          img.Save(ms, ImageFormat.Png);
25:          Response.ClearContent();
26:          Response.ContentType = "image/Png";
27:          Response.BinaryWrite(ms.ToArray());        
28:        }
29:        finally
30:        {
31:          img.Dispose();
32:          Response.End();
33:        }
34:      }
35:    }
36:  }

上述源程序第 14 行从前面赋值的 Session 取得表示关卡地图的二维字节数组,然后在第 20 行调用 Xsb2Bitmap 类的 GetBitmap 方法得到一个 Bitmap 图像,接着就是通过 Page  类的


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap