系列文章目录

开源方案搭建可离线的精美矢量切片地图服务-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大图图标文件生成(附源码)的更多相关文章

  1. 开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门

    1.简介 mapbox是一家非常牛的公司,比如像特斯拉.DJI大疆创新.孤独星球.Airbnb.GitHub.Cisco.Snap.飞猪.Keep.Bosch这些在国内外各自领域中响当当的企业都是它的 ...

  2. 开源方案搭建可离线的精美矢量切片地图服务-6.Mapbox之.pbf字体库

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  3. 开源方案搭建可离线的精美矢量切片地图服务-5.Mapbox离线项目实现

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  4. 开源方案搭建可离线的精美矢量切片地图服务-4.Mapbox样式设计

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  5. 开源方案搭建可离线的精美矢量切片地图服务-7.Arcgis Pro企业级应用

    1.前言 上篇讲.pbf字体库的时候说到我们使用的字体通过Arcgis Pro 生成,Arcgis Pro样式基于Mapbox做的矢量切片地图渲染.这篇主要讲一下Arcgis Pro矢量切片生成的的具 ...

  6. 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片

    项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...

  7. Python的开源人脸识别库:离线识别率高达99.38%(附源码)

    Python的开源人脸识别库:离线识别率高达99.38%(附源码) 转https://cloud.tencent.com/developer/article/1359073   11.11 智慧上云 ...

  8. Socket实现仿QQ聊天(可部署于广域网)附源码(2)-服务器搭建

    1.前言 这是本系列的第二篇文章,第一篇文章得到了很多朋友们的支持,在这里表示非常的感谢.对于这一系列文章需要补充的是这只是一篇入门级别的Socket通信文章,对于专业人员来说完全可以跳过.本文只介绍 ...

  9. (原创)通用查询实现方案(可用于DDD)[附源码] -- 简介

    [声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3985353.html).   [系列文章] 通用查询实现方案(可用于DDD)[附源码] -- ...

随机推荐

  1. 安装sublime3

    Sublime-text-3的安装步骤1添加Sublime-text-3软件包的软件源sudo add-apt-repository ppa:webupd8team/sublime-text-3 2使 ...

  2. delphi怎么做桌面滚动文字?

    就是在桌面显示从TXT读取出来的字,并限制在1个框内移动(就是从框左边出现往右边移动并从框边消失)我用HDC+textout只是读取字显示到桌面,不知道桌面移动哪位大侠指点下啊,或用其他方法,最好有详 ...

  3. 如何获取 docker 容器(container)的 ip 地址

    1. 进入容器内部后 cat /etc/hosts 会显示自己以及(– link)软连接的容器IP 2.使用命令 docker inspect --format '{{ .NetworkSetting ...

  4. redhat安装docker

    一.禁用selinux 由于Selinux和LXC有冲突,所以需要禁用selinux.编辑/etc/selinux/config,设置两个关键变量.     SELINUX=disabled  SEL ...

  5. 安装使用Entity Framework Power Tool Bate4 (Code First)从已建好的数据自动生成项目中的对应Model(新手贴,望各位大侠给予指点)

    从开始学习使用MVC以后,同时也开始接触EF,很多原理都不是太懂,只知道安装了EF以后,点击哪里可以生成数据库对应的Model,不用再自己手写Model.这里记录的就是如何从已建立好的数据库生成项目代 ...

  6. 关于GridControl--gridview的下拉框列(下拉列表列)

    1.Run Designer→Columns→需要设置的列→Columns properties→ColumnsEdit→New→选择(repositoryItemComboBox1) 2.给下拉框列 ...

  7. .NET MVC 学习笔记(三)— MVC 数据显示

    . NET MVC 学习笔记(三)—— MVC 数据显示 在目前做的项目中,用的最多的数据展示控件就是table展示(说不是的请走开,不是一路人),以下详细阐述下table的使用方法. 先看效果: 上 ...

  8. win10 17025 触摸bug

    This article is written in both English and Chinese. 本文使用中文和英文两个版本. 在 win10 的 17025 可以容易让 UWP 触摸失效.做 ...

  9. Lerning Entity Framework 6 ------ Defining Relationships

    There are three types of relationships in database. They are: One-to-Many One-to-One Many-to-Many Th ...

  10. Jmeter_前端RSA加密下的登陆模拟_引用js文件实现

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在一次项目实战中,前端登录使用了RSA加密,使用LoadRunner压测的第一步,就是模拟用户登录,可惜loadRunner11并不能录制前端的加 ...