逐浪云主机

立即开通

Web优化之雪碧图—动态生成雪碧图 读凡客产品页所想

作者:本站编辑 发布时间:2012-07-16 来源:本站原创 点击数:

最近访问凡客诚品产品页留意了一下,这个页面的一些图动态做成了雪碧图,如:

从这张图片我们可以看到.SpriteWashings这个样式的背景图是通过joinimages.ashx动态生成,这个想法很好,但是没有生成样式。所以它的html使用了style="background-position: 0px -80px"这个来定位,个人认为这种方式不好,应该通过添加class 来定位,这就需要生成雪碧图的时候要生成相应的样式。

生成雪碧图的原理很简单:根据多个图片地址生成对应的Bitmap,在把这些Bitmap画到一个Bitmap上。

其核心代码如下:

 

[csharp] view plaincopyprint?
  1. private static bool GenerateSprite(ImageSettings settings, int x, int y, List<Bitmap> images, StringBuilder cssCompatOutput)
  2. {
  3. if (settings.TileInYAxis)
  4. {
  5. y += images.Count;
  6. }
  7. else
  8. {
  9. x += images.Count;
  10. }
  11.  
  12. using (Bitmap sprite = new Bitmap(x, y))
  13. {
  14. using (Graphics drawingSurface = Graphics.FromImage(sprite))
  15. {
  16.  
  17. drawingSurface.Clear(settings.BackgroundColor);
  18.  
  19. int xOffset = 0;
  20. int yOffset = 0;
  21. foreach (Bitmap image in images)
  22. {
  23. drawingSurface.DrawImage(image, new Rectangle(xOffset, yOffset, image.Width, image.Height));
  24. if (image.Tag != null)
  25. GenerateCss(xOffset, yOffset, image, cssCompatOutput, settings);
  26.  
  27. if (settings.TileInYAxis)
  28. {
  29. yOffset += image.Height + 1;
  30. }
  31. else
  32. {
  33. xOffset += image.Width + 1;
  34. }
  35. }
  36.  
  37. try
  38. {
  39. using (EncoderParameters spriteEncoderParameters = new EncoderParameters(1))
  40. {
  41. spriteEncoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, settings.Quality);
  42.  
  43. sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)), GetEncoderInfo(settings.Format), spriteEncoderParameters);
  44. }
  45. return true;
  46. }
  47. catch (Exception ex1)
  48. {
  49.  
  50. try
  51. {
  52.  
  53. sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)));
  54. return true;
  55. }
  56. catch (Exception ex2)
  57. {
  58. // sprite.Save( Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, "png")));
  59. return false;
  60. }
  61. }
  62.  
  63. }
  64.  
  65. }
  66.  
  67. }

自己做了一个简单的demo,代码结构如下:

 

SpriteImage是制作雪碧图的核心代码封装成dll,SpriteImageCreate是一个form工具。

运行效果如下:

看到效果了吧,我们的工具要求生成雪碧图同时也生成css。

我们来看看web的引用吧:

 

  1. public ActionResult Index()
  2. {
  3. string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content");
  4. FileInfo[] files = new DirectoryInfo(Path.Combine(basedirectory, "Images")).GetFiles();
  5. List<string> filesPath = files.Select(x => x.FullName).ToList();
  6. ViewData.Add("Sprites", filesPath);
  7. return View(ViewData);
  8. }
  9. [ChildActionOnly]
  10. public ActionResult Sprite(List<string> images)
  11. {
  12. if (images == null || images.Count < 1)
  13. return View();
  14. string[] filenames = images.Select(x =>
  15. {
  16. int startindex = x.LastIndexOf("\\");
  17. int endindex = x.LastIndexOf(".");
  18. return x = x.Substring(startindex + 1, endindex - startindex - 1);
  19. }).ToArray();
  20.  
  21. string spritname = string.Join("", filenames).GetHashCode().ToString();
  22. string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content/Sprites");
  23. string cssFile = Path.Combine(basedirectory, spritname + ".css");
  24. int index = this.Request.Url.OriginalString.LastIndexOf(this.Request.Url.LocalPath);
  25. string prfx = this.Request.Url.OriginalString.Substring(0, index);
  26.  
  27. if (!System.IO.File.Exists(cssFile))
  28. {
  29. ImageSettings setting = new ImageSettings(spritname, basedirectory)
  30. {
  31. CssSpriteUrl = prfx + "/Content/Sprites/",
  32. TileInYAxis = false
  33. };
  34. StringBuilder sb = new StringBuilder();
  35. var ret = ImageOptimizations.Optimizations(setting, sb, images);
  36. if (ret)
  37. {
  38. using (StreamWriter sw = new StreamWriter(cssFile, false, Encoding.UTF8))
  39. {
  40. sw.Write(sb.ToString());
  41. }
  42. }
  43. }
  44.  
  45. if (System.IO.File.Exists(cssFile))
  46. {
  47. string retFormat = " <link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}\" />";
  48. string url = prfx + "/Content/Sprites/" + spritname + ".css";
  49. return Content(string.Format(retFormat, url));
  50. }
  51. return View();
  52. }

其中Index的目的是模拟一个动态的图片地址数据,在看看你我们view的代码:

 

 

  1. @{
  2. ViewBag.Title = "Home Page";
  3. var files = ViewData["Sprites"] as List<string>;
  4. }
  5. @section HeadSection{
  6. @{ Html.RenderAction("Sprite", "Home", new { images = files });}
  7. }
  8. <div>
  9. @{
  10. foreach (var item in files)
  11. {
  12. int index = item.LastIndexOf("\\");
  13. string subname = item.Substring(index + 1);
  14. subname = subname.Replace(".", "_");
  15.  
  16. <div class="@subname" style="float:left " >
  17. </div>
  18. }
  19. }
  20. </div>


代码是不是很简单,看看运行结果:

 

 

 

看到以上html代码,你能看出来我的雪碧图是动态生成的嘛?我不只是动态生成了雪碧图而且也生成了样式。

最总的html只是一个样式引用

<link type="text/css" rel="Stylesheet" href="http://localhost:1468/Content/Sprites/602831660.css" />

来看看我们的样式文件:

大家看了我的样式文件,也就一定明白我的代码 <div class="joinimages1_png" style="float:left " >为什么用的是class而不是什么定位了

本文责任编辑: 加入会员收藏夹 点此参与评论>>
复制本网址-发给QQ/微信上的朋友