开源方案搭建可离线的精美矢量切片地图服务-8.mapbox 之sprite大图图标文件生成(附源码)
系列文章目录
开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址)
开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片
开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门
开源方案搭建可离线的精美矢量切片地图服务-4.Mapbox样式设计
开源方案搭建可离线的精美矢量切片地图服务-5.Mapbox离线项目实现
开源方案搭建可离线的精美矢量切片地图服务-6.Mapbox之.pbf字体库
开源方案搭建可离线的精美矢量切片地图服务-7.Arcgis Pro企业级应用
开源方案搭建可离线的精美矢量切片地图服务-8.mapbox 之sprite大图图标文件生成(附源码)
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵)。
01:中国地图:http://test.sharegis.cn/mapbox/html/3china.html
02:德国-德累斯顿市:http://test.sharegis.cn/mapbox/html/6germany.html
1.什么是sprite文件
sprite 文件主要是将一堆小图生成一种大图的方法,并且将每张小图的位置信息保存下来,方便读取。在网络请求中会减少请求的数量,mapbox借鉴前端中CSS Sprite方法存储图标信息的。sprite.png文件保存图标,sprite.json保存名称及位置信息,下图图展示的是小图标与大图文件的示例。下面我讲一下两种文件互转。
<=互转=> 
下面是这次项目实现的功能,包含Sprite大图的合成与分割,也包含对单个图标文件的宽度与高度的调整。

2.sprite大图转小图
我们上一节讲到是使用arcgis pro会将.mxd地图配图文件转为mapbox的样式文件,同样会生成sprite.png和sprite.json的图标文件。由于arcgis字体库的限制,生成的图标可能不符合的要求,我们有修改图标的需要,这里我们不仅要替换大图中的小图标而且要记录图标的的位置信息到sprite.json中。下面写了一个从大图文件中生成单个小图标文件的分割功能。
实现思路:首先读取大图图片,然后根据json文件中的位置信息,json中的图标信息如下,xy代表图标的左上角在大图中的位置,width height代表图标的大小,pixelRatio代表像素单位,spriteicon/county为文件名。
"spriteicon/county": {
"x": 75,
"y": 0,
"width": 32,
"height": 14,
"pixelRatio": 1,
"sdf": false
}
读取单个图标文件的像素信息,写到一个新建的Bitmap画布中,实现成果与代码如下:
转换为单个文件
//sprite json文件
string text = ReadFile(textBox3.Text);
JObject obj = JObject.Parse(text);
JToken item = null;
//将json转为对象
List<Param> paramlist = new List<Param>();
for (int i = ; i < obj.Count; i++)
{
if (item == null)
{
item = obj.First;
}
else
{
item = item.Next;
}
Param p = new Param();
p.name = item.Path.Substring(, item.Path.Length - ).Replace("/", "-").Replace(":", "&");
p.x = (int)item.First["x"];
p.y = (int)item.First["y"];
p.width = (int)item.First["width"];
p.height = (int)item.First["height"];
paramlist.Add(p);
}
using (Bitmap map = (Bitmap)Image.FromFile(textBox3.Text+@"\sprite.png"))
{ using (Bitmap editMap = new Bitmap(map, map.Width, map.Height))
{
foreach (var itemp in paramlist)
{
//保存图片的画布
Bitmap itemMap = new Bitmap(itemp.width, itemp.height);
for (int i = ; i < itemp.width; i++)
{
for (int j = ; j < itemp.height; j++)
{
//获取像素
Color color = editMap.GetPixel(itemp.x + i, itemp.y + j);
itemMap.SetPixel(i, j, color);
}
}
//保存
string savepath = System.Environment.CurrentDirectory + @"\spriteicon" + itemp.name+ ".png";
itemMap.Save(savepath);
}
}
}
3.小图标的调整
对于一些规则的小图标,例如标记路面信息的label,他的宽度由路的属性信息决定,展示我们要对不同长度的文字设置不同大小label这里我们要对多个图标的宽度和高度进行调整,这是只是对lable这样规则的图标进行调整,例如
宽度增加20px
实现思路:我们选择规则图形的中心线,宽度调整就是以中心线进行左右拉伸复杂增加宽度,实现代码如下:
DirectoryInfo folder = new DirectoryInfo(System.Environment.CurrentDirectory);
List<string> filenames = new List<string>();
int addnum = Convert.ToInt32(textBox2.Text);
foreach (var NextFolder in folder.GetFiles("*.png"))
{
if (NextFolder.Name.Contains(textBox1.Text))
{
filenames.Add(NextFolder.Name);
}
}
foreach (var item in filenames)
{
using (Bitmap map = (Bitmap)Image.FromFile(System.Environment.CurrentDirectory + "/" + item))
{
using (Bitmap editMap = new Bitmap(map.Width + addnum, map.Height ))
{
int centernum = map.Width / ;
for (int i = ; i < map.Width; i++)
{
for (int j = ; j < map.Height; j++)
{
//获取像素
Color color = map.GetPixel(i, j);
if (i == centernum)
{
editMap.SetPixel(i, j, color);
if (addnum > )
{
for (int m = ; m < addnum; m++)
{
editMap.SetPixel(i + m + ,j, color);
}
}
}
else if (i < centernum)
{
editMap.SetPixel(i, j, color);
}
else
{
editMap.SetPixel(i + addnum,j, color);
}
}
}
//保存
string savepath = System.Environment.CurrentDirectory + @"\result\" + item;
editMap.Save(savepath);
}
}
}
4.小图转sprite大图
将小图标合成一张sprite大图并在sprite.json中记录生成的位置信息,这里最主要的就是图标的摆放规则,
(1)获取所有的图标文件,按照高度从小到大排列
(2)根据大图生成的默认宽度,循环小图片,形成一行一行的图片集合。
(3)根据行数和宽度生成大图的宽度。
(4)循环小图标,在大图中画出小图标,并记录位置信息。
实现成果与代码如下:
转换为sprite文件
DirectoryInfo folder = new DirectoryInfo(System.Environment.CurrentDirectory);
List<Param> paramlist = new List<Param>();
foreach (var NextFolder in folder.GetFiles("*.png"))
{
using (Bitmap map = (Bitmap)Image.FromFile(System.Environment.CurrentDirectory + "/" + NextFolder.Name))
{
Param p = new Param();
p.name = NextFolder.Name.Replace(".png", "");
p.width = map.Width;
p.height = map.Height;
paramlist.Add(p);
}
}
//图片默认宽度为255,
int widthnum = ;
paramlist = paramlist.OrderBy(m => m.name).OrderBy(m => m.height).ToList();
//一行一行的图片集合
List<List<Param>> rowparams = new List<List<Param>>();
List<Param> paramnowlist = new List<Param>();
int countnum = ;
for (int i = ; i < paramlist.Count; i++)
{
countnum += paramlist[i].width;
if (countnum > widthnum)
{
i = i - ;
countnum = ;
rowparams.Add(paramnowlist);
paramnowlist = new List<Param>();
}
else
{
paramnowlist.Add(paramlist[i]);
}
if (i == paramlist.Count - )
{
rowparams.Add(paramnowlist);
break;
}
}
//计算应有的高度
int allheight = ;
foreach (var item in rowparams)
{
allheight += item.Select(m => m.height).Max();
}
string spritejson = "{";
//开始画大图
using (Bitmap editMap = new Bitmap(widthnum, allheight))
{
//保存起始高度
int heighttemp = ;
for (int i = ; i < rowparams.Count; i++)
{
int tempwidthnum = ;
for (int j = ; j < rowparams[i].Count; j++)
{
using (Bitmap map = (Bitmap)Image.FromFile(System.Environment.CurrentDirectory + "/" + rowparams[i][j].name + ".png"))
{
//循环小图片
for (int x = ; x < map.Width; x++)
{
for (int y = ; y < map.Height; y++)
{
//获取像素
Color color = map.GetPixel(x, y);
editMap.SetPixel(x+ tempwidthnum, y+ heighttemp, color);
}
}
} spritejson += "\""+ rowparams[i][j].name.Replace("-", "/").Replace("&",":") + "\":{\"x\":";
spritejson += tempwidthnum + ",\"y\":" + heighttemp + ",\"width\":" + rowparams[i][j].width;
spritejson += ",\"height\":" + rowparams[i][j].height + ",\"pixelRatio\":1,\"sdf\":false},";
//增加宽度
tempwidthnum += rowparams[i][j].width;
}
heighttemp += rowparams[i].Select(m => m.height).Max();
}
//保存大图
string savepath = System.Environment.CurrentDirectory + @"\result\sprite.png";
editMap.Save(savepath);
}
spritejson= spritejson.TrimEnd(',');
spritejson += "}";
//写入文件
using (StreamWriter fw= new StreamWriter(System.Environment.CurrentDirectory + @"\result\sprite.json"))
{
fw.WriteLine(spritejson);
}
5.结尾
我们这里的sprite大图生成了sprite.json来保存位置信息,其实css sprite的实现也是类似的。使用图片定位技术来实现的,例如像下面的这段css代码一样来对图片做定位的,大家可以简单修改一下源码便可实现,这里就不多介绍了。
.bg-spriteicon {
width: 17px; height: 17px;
background: url('css_sprites.png') -138px -47px;
}
源码地址:链接:https://pan.baidu.com/s/1tLihDaZFa--xFCzI42tfEA 密码:f3dm
github地址:https://github.com/HuHongYong/Mapbox-sprite-generation
作者:ATtuing
出处:http://www.cnblogs.com/ATtuing
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
开源方案搭建可离线的精美矢量切片地图服务-8.mapbox 之sprite大图图标文件生成(附源码)的更多相关文章
- 开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门
1.简介 mapbox是一家非常牛的公司,比如像特斯拉.DJI大疆创新.孤独星球.Airbnb.GitHub.Cisco.Snap.飞猪.Keep.Bosch这些在国内外各自领域中响当当的企业都是它的 ...
- 开源方案搭建可离线的精美矢量切片地图服务-6.Mapbox之.pbf字体库
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
- 开源方案搭建可离线的精美矢量切片地图服务-5.Mapbox离线项目实现
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
- 开源方案搭建可离线的精美矢量切片地图服务-4.Mapbox样式设计
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
- 开源方案搭建可离线的精美矢量切片地图服务-7.Arcgis Pro企业级应用
1.前言 上篇讲.pbf字体库的时候说到我们使用的字体通过Arcgis Pro 生成,Arcgis Pro样式基于Mapbox做的矢量切片地图渲染.这篇主要讲一下Arcgis Pro矢量切片生成的的具 ...
- 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
- Python的开源人脸识别库:离线识别率高达99.38%(附源码)
Python的开源人脸识别库:离线识别率高达99.38%(附源码) 转https://cloud.tencent.com/developer/article/1359073 11.11 智慧上云 ...
- Socket实现仿QQ聊天(可部署于广域网)附源码(2)-服务器搭建
1.前言 这是本系列的第二篇文章,第一篇文章得到了很多朋友们的支持,在这里表示非常的感谢.对于这一系列文章需要补充的是这只是一篇入门级别的Socket通信文章,对于专业人员来说完全可以跳过.本文只介绍 ...
- (原创)通用查询实现方案(可用于DDD)[附源码] -- 简介
[声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3985353.html). [系列文章] 通用查询实现方案(可用于DDD)[附源码] -- ...
随机推荐
- AngularJS transclude 理解及例子
一.概念理解 transclude可以在指令中让使用者自定义模板,也就是说,指令中模板的一部分,让指令的使用者动态指定:与指定中的Scope属性值为{}时候的作用类似,scope属性让指令使用者动态制 ...
- centos rpm包下载地址
这个是6.5的下载地址,其他版本可以退回目录找相应的版本 http://vault.centos.org/6.5/updates/x86_64/Packages/
- 201621123018《Java程序设计》第6周学习报告
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 2. 书面作业 1. clone方法 1.1 在 ...
- 防止sql注入的小函数 以及一些小验证
function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialch ...
- Python建代理配合burp实现自动免费用水
i春秋作家:凉风有信 Hi , 我是凉风 半年不见了啊,我又回来了因为太菜都不好意思发文章了 0×00 目录 0×01 前言0×02 利用fd分析与实战0×03 Python+burp简易搭建代理服务 ...
- PHP 获取两个时间之间的月份
## 获取两个时间之间的间距时间 $s = '2017-02-05'; $e = '2017-07-20'; $start = new \DateTime($s); $end = new \DateT ...
- Odoo 学习地址
Odoo官文文档: https://www.odoo.com/zh_cn/page/docs http://www.odoo.com/documentation/8.0/ Odoo中文文档推荐: ht ...
- java ant 编译打包build.xml完整配置范例
java ant 编译打包build.xml完整配置范例 <?xml version="1.0" encoding="UTF-8" ?> <p ...
- dex内存提取
转 http://blog.csdn.net/asmcvc/article/details/18216531 智能手机的普及将移动互联网的发展推到了一个让所有人都为之兴奋的高度,我想即使是以商业眼光见 ...
- 使用XHProf分析PHP性能瓶颈(一)
安装xhprof扩展 wget http://pecl.php.net/get/xhprof-0.9.4.tgz tar zxf xhprof-0.9.4.tgz cd xhprof-0.9.4/ex ...