最近访问凡客诚品产品页留意了一下,这个页面的一些图动态做成了雪碧图,如:
从这张图片我们可以看到.SpriteWashings这个样式的背景图是通过joinimages.ashx动态生成,这个想法很好,但是没有生成样式。所以它的html使用了style="background-position: 0px -80px"这个来定位,个人认为这种方式不好,应该通过添加class 来定位,这就需要生成雪碧图的时候要生成相应的样式。
生成雪碧图的原理很简单:根据多个图片地址生成对应的Bitmap,在把这些Bitmap画到一个Bitmap上。
其核心代码如下:
-
private static bool GenerateSprite(ImageSettings settings, int x, int y, List<Bitmap> images, StringBuilder cssCompatOutput)
-
{
-
if (settings.TileInYAxis)
-
{
-
y += images.Count;
-
}
-
else
-
{
-
x += images.Count;
-
}
-
-
using (Bitmap sprite = new Bitmap(x, y))
-
{
-
using (Graphics drawingSurface = Graphics.FromImage(sprite))
-
{
-
-
drawingSurface.Clear(settings.BackgroundColor);
-
-
int xOffset = 0;
-
int yOffset = 0;
-
foreach (Bitmap image in images)
-
{
-
drawingSurface.DrawImage(image, new Rectangle(xOffset, yOffset, image.Width, image.Height));
-
if (image.Tag != null)
-
GenerateCss(xOffset, yOffset, image, cssCompatOutput, settings);
-
-
if (settings.TileInYAxis)
-
{
-
yOffset += image.Height + 1;
-
}
-
else
-
{
-
xOffset += image.Width + 1;
-
}
-
}
-
-
try
-
{
-
using (EncoderParameters spriteEncoderParameters = new EncoderParameters(1))
-
{
-
spriteEncoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, settings.Quality);
-
-
sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)), GetEncoderInfo(settings.Format), spriteEncoderParameters);
-
}
-
return true;
-
}
-
catch (Exception ex1)
-
{
-
-
try
-
{
-
-
sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)));
-
return true;
-
}
-
catch (Exception ex2)
-
{
-
-
return false;
-
}
-
}
-
-
}
-
-
}
-
-
}
private static bool GenerateSprite(ImageSettings settings, int x, int y, List<Bitmap> images, StringBuilder cssCompatOutput)
{
if (settings.TileInYAxis)
{
y += images.Count;
}
else
{
x += images.Count;
}
using (Bitmap sprite = new Bitmap(x, y))
{
using (Graphics drawingSurface = Graphics.FromImage(sprite))
{
drawingSurface.Clear(settings.BackgroundColor);
int xOffset = 0;
int yOffset = 0;
foreach (Bitmap image in images)
{
drawingSurface.DrawImage(image, new Rectangle(xOffset, yOffset, image.Width, image.Height));
if (image.Tag != null)
GenerateCss(xOffset, yOffset, image, cssCompatOutput, settings);
if (settings.TileInYAxis)
{
yOffset += image.Height + 1;
}
else
{
xOffset += image.Width + 1;
}
}
try
{
using (EncoderParameters spriteEncoderParameters = new EncoderParameters(1))
{
spriteEncoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, settings.Quality);
sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)), GetEncoderInfo(settings.Format), spriteEncoderParameters);
}
return true;
}
catch (Exception ex1)
{
try
{
sprite.Save(Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, settings.Format)));
return true;
}
catch (Exception ex2)
{
// sprite.Save( Path.Combine(settings.SpritePath, GenerateSpriteFileName(settings.SpriteName, "png")));
return false;
}
}
}
}
}
自己做了一个简单的demo,代码结构如下:
SpriteImage是制作雪碧图的核心代码封装成dll,SpriteImageCreate是一个form工具。
运行效果如下:
看到效果了吧,我们的工具要求生成雪碧图同时也生成css。
我们来看看web的引用吧:
-
public ActionResult Index()
-
{
-
string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content");
-
FileInfo[] files = new DirectoryInfo(Path.Combine(basedirectory, "Images")).GetFiles();
-
List<string> filesPath = files.Select(x => x.FullName).ToList();
-
ViewData.Add("Sprites", filesPath);
-
return View(ViewData);
-
}
-
[ChildActionOnly]
-
public ActionResult Sprite(List<string> images)
-
{
-
if (images == null || images.Count < 1)
-
return View();
-
string[] filenames = images.Select(x =>
-
{
-
int startindex = x.LastIndexOf("\\");
-
int endindex = x.LastIndexOf(".");
-
return x = x.Substring(startindex + 1, endindex - startindex - 1);
-
}).ToArray();
-
-
string spritname = string.Join("", filenames).GetHashCode().ToString();
-
string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content/Sprites");
-
string cssFile = Path.Combine(basedirectory, spritname + ".css");
-
int index = this.Request.Url.OriginalString.LastIndexOf(this.Request.Url.LocalPath);
-
string prfx = this.Request.Url.OriginalString.Substring(0, index);
-
-
if (!System.IO.File.Exists(cssFile))
-
{
-
ImageSettings setting = new ImageSettings(spritname, basedirectory)
-
{
-
CssSpriteUrl = prfx + "/Content/Sprites/",
-
TileInYAxis = false
-
};
-
StringBuilder sb = new StringBuilder();
-
var ret = ImageOptimizations.Optimizations(setting, sb, images);
-
if (ret)
-
{
-
using (StreamWriter sw = new StreamWriter(cssFile, false, Encoding.UTF8))
-
{
-
sw.Write(sb.ToString());
-
}
-
}
-
}
-
-
if (System.IO.File.Exists(cssFile))
-
{
-
string retFormat = " <link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}\" />";
-
string url = prfx + "/Content/Sprites/" + spritname + ".css";
-
return Content(string.Format(retFormat, url));
-
}
-
return View();
-
}
public ActionResult Index()
{
string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content");
FileInfo[] files = new DirectoryInfo(Path.Combine(basedirectory, "Images")).GetFiles();
List<string> filesPath = files.Select(x => x.FullName).ToList();
ViewData.Add("Sprites", filesPath);
return View(ViewData);
}
[ChildActionOnly]
public ActionResult Sprite(List<string> images)
{
if (images == null || images.Count < 1)
return View();
string[] filenames = images.Select(x =>
{
int startindex = x.LastIndexOf("\\");
int endindex = x.LastIndexOf(".");
return x = x.Substring(startindex + 1, endindex - startindex - 1);
}).ToArray();
string spritname = string.Join("", filenames).GetHashCode().ToString();
string basedirectory = Path.Combine(this.Request.PhysicalApplicationPath, "Content/Sprites");
string cssFile = Path.Combine(basedirectory, spritname + ".css");
int index = this.Request.Url.OriginalString.LastIndexOf(this.Request.Url.LocalPath);
string prfx = this.Request.Url.OriginalString.Substring(0, index);
if (!System.IO.File.Exists(cssFile))
{
ImageSettings setting = new ImageSettings(spritname, basedirectory)
{
CssSpriteUrl = prfx + "/Content/Sprites/",
TileInYAxis = false
};
StringBuilder sb = new StringBuilder();
var ret = ImageOptimizations.Optimizations(setting, sb, images);
if (ret)
{
using (StreamWriter sw = new StreamWriter(cssFile, false, Encoding.UTF8))
{
sw.Write(sb.ToString());
}
}
}
if (System.IO.File.Exists(cssFile))
{
string retFormat = " <link type=\"text/css\" rel=\"Stylesheet\" href=\"{0}\" />";
string url = prfx + "/Content/Sprites/" + spritname + ".css";
return Content(string.Format(retFormat, url));
}
return View();
}
其中Index的目的是模拟一个动态的图片地址数据,在看看你我们view的代码:
-
@{
-
ViewBag.Title = "Home Page";
-
var files = ViewData["Sprites"] as List<string>;
-
}
-
@section HeadSection{
-
@{ Html.RenderAction("Sprite", "Home", new { images = files });}
-
}
-
<div>
-
@{
-
foreach (var item in files)
-
{
-
int index = item.LastIndexOf("\\");
-
string subname = item.Substring(index + 1);
-
subname = subname.Replace(".", "_");
-
-
<div class="@subname" style="float:left " >
-
</div>
-
}
-
}
-
</div>
@{
ViewBag.Title = "Home Page";
var files = ViewData["Sprites"] as List<string>;
}
@section HeadSection{
@{ Html.RenderAction("Sprite", "Home", new { images = files });}
}
<div>
@{
foreach (var item in files)
{
int index = item.LastIndexOf("\\");
string subname = item.Substring(index + 1);
subname = subname.Replace(".", "_");
<div class="@subname" style="float:left " >
</div>
}
}
</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而不是什么定位了。