通过openlayers加载dwg格式的CAD图并与互联网地图叠加
Openlayers介绍
Openlayers是一个基于Javacript开发,免费、开源的前端地图开发库,使用它,可以很容易的开发出WebGIS系统。目前Openlayers支持地图瓦片、矢量数据等众多地图数据格式,支持比较完整的地图交互操作。目前OpenLayers已经成为一个拥有众多开发者和帮助社区的成熟、流行的框架,在国内外的GIS相关行业中得到了广泛的应用。
openlayers 官网地址 https://openlayers.org/
openlayers 源码地址 https://github.com/openlayers/openlayers
Openlayers中加载CAD栅格瓦片
// 地图服务对象,调用唯杰地图服务打开地图,获取地图的元数据
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 打开地图
let mapId = "sys_zp";
let res = await svc.openMap({
mapid: mapId, // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
message.error(res.error)
}
// 获取地图范围
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
//自定义投影参数
let cadProjection = new ol.proj.Projection({
// extent用于确定缩放级别
extent: mapBounds.toArray(),
units: 'm'
});
// 设置每级的分辨率
let resolutions= [];
for(let i = 0; i < 25; i++) {
resolutions.push(mapBounds.width() / (512 * Math.pow(2, i - 1)))
}
// 增加自定义的cad的坐标系
ol.proj.addProjection(cadProjection);
// 创建openlayer的地图对象
let map = new ol.Map({
target: 'map', // div的id
view: new ol.View({
center: mapBounds.center().toArray(), // 地图中心点
projection: cadProjection, // 刚自定义的cad的坐标系
resolutions:resolutions, // 分辨率
zoom: 2// 初始缩放级别
})
});
// 增加一个瓦片图层
let layer = new ol.layer.Tile({
// 增加一个瓦片数据源
source: new ol.source.TileImage({
url: svc.rasterTileUrl() // 唯杰地图服务提供的cad的栅格瓦片服务地址
})
});
// 在地图中增加上面的瓦片图层
map.addLayer(layer);
Openlayers中加载CAD矢量瓦片
// 增加一个矢量瓦片图层
let layer = new ol.layer.VectorTile({
// 增加一个瓦片数据源
source: new ol.source.VectorTile({
projection: cadProjection,
format: new ol.format.MVT(),
url: svc.vectorTileUrl() // 唯杰地图服务提供的cad的矢量瓦片服务地址
}),
style: createVjMapVectorStyle(ol.style.Style, ol.style.Fill, ol.style.Stroke, ol.style.Circle)
});
// 在地图中增加上面的瓦片图层
map.addLayer(layer);
Openlayers中选择高亮CAD实体
const highlight_ent = async co => {
vectorSource.clear();
let res = await svc.pointQueryFeature({
x: co[0],
y: co[1],
zoom: map.getView().getZoom(),
fields: ""
}, pt => {
// 查询到的每个点进行坐标处理回调
return mapPrj.fromMercator(pt);// 转成cad的坐标
})
if (res && res.result && res.result.length > 0) {
let features = [];
for (let ent of res.result) {
if (ent.geom && ent.geom.geometries) {
let clr = vjmap.entColorToHtmlColor(ent.color);
for (let g = 0; g < ent.geom.geometries.length; g++) {
features.push({
type: "Feature",
properties: {
objectid: ent.objectid + "_" + g,
color: clr,
alpha: ent.alpha / 255,
lineWidth: 1,
name: ent.name,
isline: ent.isline,
layerindex: ent.layerindex
},
geometry: ent.geom.geometries[g]
})
}
// 选择提示
let content = `feature: ${ent.objectid}; layer: ${cadLayers[ent.layerindex].name}; type: ${ent.name}`
message.info({ content, key: "info", duration: 3});
}
}
geojsonObject.features = features;
if (geojsonObject.features.length > 0) {
vectorSource.addFeatures( new ol.format.GeoJSON().readFeatures(geojsonObject, {dataProjection: cadProjection}))
}
}
};
Openlayers中上传打开CAD的DWG图形
// 地图服务对象,调用唯杰地图服务打开地图,获取地图的元数据
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// 上传dwg文件
const uploadDwgFile = async file => {
message.info("正在上传图形,请稍候", 2);
let res = await svc.uploadMap(file); // 上传地图
// 输入图id
let mapid = prompt("请输入图名称ID", res.mapid);
res.mapid = mapid;
res.mapopenway = vjmap.MapOpenWay.GeomRender; // 几何渲染,内存渲染用vjmap.MapOpenWay.Memory
res.isVector = false; // 使用栅格瓦片
res.style = vjmap.openMapDarkStyle(); // 深色样式,浅色用openMapDarkStyle
message.info("正在打开图形,请稍候,第一次打开时根据图的大小可能需要几十秒至几分钟不等", 5);
let data = await svc.openMap(res); // 打开地图
if (data.error) {
message.error(data.error)
return;
}
openMap(data);
}
Openlayers中切换CAD图层
// 切换图层
const switchLayer = async layers => {
let res = await svc.cmdSwitchLayers(layers); // 调用唯杰服务切换图层,返回图层id {layerid: "xxxx"}
let source = layer.getSource();
// 重新设置新的唯杰地图服务提供的cad的栅格瓦片服务地址
source.setUrl(svc.rasterTileUrl());
// 刷新
source.refresh();
}
Openlayers中切换CAD图形
const switchToMapId = async (mapId)=> {
let res = await svc.openMap({
mapid: mapId, // 地图ID
mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap.openMapDarkStyle() // div为深色背景颜色时,这里也传深色背景样式
})
if (res.error) {
// 如果打开出错
message.error(res.error)
return;
}
// 获取地图范围
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
//自定义投影参数
let cadProjection = new ol.proj.Projection({
// extent用于确定缩放级别
extent: mapBounds.toArray(),
units: 'm'
});
// 设置每级的分辨率
let resolutions= [];
for(let i = 0; i < 25; i++) {
resolutions.push(mapBounds.width() / (512 * Math.pow(2, i - 1)))
}
// 增加自定义的cad的坐标系
ol.proj.addProjection(cadProjection);
// 重新创建openlayer的地图对象
map = new ol.Map({
target: createNewMapDivId(), // div的id
view: new ol.View({
center: mapBounds.center().toArray(), // 地图中心点
projection: cadProjection, // 刚自定义的cad的坐标系
resolutions:resolutions, // 分辨率
zoom: 2 // 初始缩放级别
})
});
// 增加一个瓦片图层
let layer = new ol.layer.Tile({
// 增加一个瓦片数据源
source: new ol.source.TileImage({
url: svc.rasterTileUrl() // 唯杰地图服务提供的cad的栅格瓦片服务地址
})
});
// 在地图中增加上面的瓦片图层
map.addLayer(layer);
map.on('click', (e) => message.info({content: `您点击的坐标为: ${JSON.stringify(e.coordinate)}`, key: "info", duration: 3}));
}
Openlayers中深色浅色切换主题
let curIsDarkTheme = true;
const switchToDarkTheme = async () => {
if (curIsDarkTheme) return;
curIsDarkTheme = true;
document.body.style.background = "#022B4F"; // 背景色改为深色
await updateStyle(curIsDarkTheme)
}
const switchToLightTheme = async () => {
if (!curIsDarkTheme) return;
curIsDarkTheme = false;
document.body.style.backgroundImage = "linear-gradient(rgba(255, 255, 255, 1), rgba(233,255,255, 1), rgba(233,255,255, 1))"
await updateStyle(curIsDarkTheme)
}
const updateStyle = async (isDarkTheme) => {
style.backcolor = isDarkTheme ? 0 : 0xFFFFFF;//深色为黑色,浅色为白色
let res = await svc.cmdUpdateStyle(style);
let source = layer.getSource();
// 重新设置新的唯杰地图服务提供的cad的栅格瓦片服务地址
source.setUrl(svc.rasterTileUrl());
// 刷新
source.refresh();
}
Openlayers中自定义CAD地图样式
通过修改CAD地图后台样式数据自定义地图
// 更改样式
const expressionList = [] ;// 表达式数组
const updateStyle = async (style) => {
let res = await svc.cmdUpdateStyle({
name: "customStyle2",
backcolor: 0,
expression: expressionList.join("\n"),
...style
});
let source = layer.getSource();
// 重新设置新的唯杰地图服务提供的cad的栅格瓦片服务地址
source.setUrl(svc.rasterTileUrl());
// 刷新
source.refresh();
}
// 表达式语法和变量请参考
// 服务端条件查询和表达式查询 https://vjmap.com/guide/svrStyleVar.html
// 服务端渲染表达式语法 https://vjmap.com/guide/expr.html
// 修改颜色 红color.r, 绿color.g, 蓝color.b, 透明度color.a,如果输入了级别的话,表示此级别及以上的设置
const modifyColor = (color, zoom) => {
let result = "";
let z = Number.isInteger(zoom) ? `[${zoom + 1}]` : '';
if ("r" in color) result += `gOutColorRed${z}:=${color.r};`;
if ("g" in color) result += `gOutColorGreen${z}:=${color.g};`;
if ("b" in color) result += `gOutColorBlue${z}:=${color.b};`;
if ("a" in color) result += `gOutColorAlpha${z}:=${color.a};`;
return result;
}
Openlayers中对CAD图处理组合
对多个cad图进行图层开关裁剪旋转缩放处理后合并成一个新的cad图
// 组合成新的图,将sys_world图进行一定的处理后,再与sys_hello进行合成,生成新的地图文件名
let rsp = await svc.composeNewMap([
{
mapid: "sys_world", // 地图id
// 下面的参数可以根据实际需要来设置,可以对图层,范围,坐标转换来进行处理
layers: ["经纬度标注","COUNTRY"], // 要显示的图层名称列表
//clipbounds: [10201.981489534268, 9040.030491346213, 26501.267379, 4445.465999], // 要显示的范围
//fourParameter: [0,0,1,0] // 对地图进行四参数转换计算
},
{
mapid: "sys_hello"
}
])
if (!rsp.status) {
message.error(rsp.error)
}
// 返回结果为
/*
{
"fileid": "pec9c5f73f1d",
"mapdependencies": "sys_world||sys_hello",
"mapfrom": "sys_world&&v1&&&&0&&&&&&&&&&00A0&&10||sys_hello&&v1&&&&0&&&&&&&&&&&&2",
"status": true
}
*/
Openlayers中查询图中所有文字并绘制边框
// 实体类型ID和名称映射
const { entTypeIdMap } = await svc.getConstData();
const getTypeNameById = name => {
for(let id in entTypeIdMap) {
if (entTypeIdMap[id] == name) {
return id
}
}
}
const queryTextAndDrawBounds = async () => {
let queryTextEntTypeId = getTypeNameById("AcDbText"); // 单行文字
let queryMTextEntTypeId = getTypeNameById("AcDbMText"); // 多行文字
let queryAttDefEntTypeId = getTypeNameById("AcDbAttributeDefinition"); // 属性定义文字
let queryAttEntTypeId = getTypeNameById("AcDbAttribute"); // 属性文字
let query = await svc.conditionQueryFeature({
condition: `name='${queryTextEntTypeId}' or name='${queryMTextEntTypeId}' or name='${queryAttDefEntTypeId}' or name='${queryAttEntTypeId}'`, // 只需要写sql语句where后面的条件内容,字段内容请参考文档"服务端条件查询和表达式查询"
fields: "",
limit: 100000 //设置很大,相当于把所有的圆都查出来。不传的话,默认只能取100条
}, pt => {
// 查询到的每个点进行坐标处理回调
return mapPrj.fromMercator(pt);// 转成cad的坐标
})
if (query.error) {
message.error(query.error)
} else {
message.info(`查询到符合的记数条数:${query.recordCount}`)
if (query.recordCount > 0) {
let features = [];
for(var i = 0; i < query.recordCount; i++) {
let bounds = vjmap.getEnvelopBounds(query.result[i].envelop, mapPrj);
let clr = vjmap.entColorToHtmlColor(query.result[i].color); // 实体颜色转html颜色(
features.push({
type: "Feature",
properties: {
name: "objectid:" + query.result[i].objectid,
color: clr
},
geometry: {
'type': 'Polygon',
'coordinates': [
bounds.toPointArray(),
],
}
})
}
if (!vectorSource) {
// 如果之前没有高亮矢量图层
addHighLightLayer();
}
vectorSource.clear();
let geojsonObject = {
'type': 'FeatureCollection',
'features': features
}
// 修改矢量数据源数据
vectorSource.addFeatures( new ol.format.GeoJSON().readFeatures(geojsonObject, {dataProjection: cadProjection}))
}
}
}
Openlayers中图形绘制
const source = new ol.source.Vector({wrapX: false});
const vector = new ol.layer.Vector({
source: source,
});
map.addLayer(vector);
let draw; // global so we can remove it later
function addInteraction(value) {
map.removeInteraction(draw);
if (value !== 'None') {
draw = new ol.interaction.Draw({
source: source,
type: value,
});
map.addInteraction(draw);
}
}
addInteraction('Point');
Openlayers中CAD图叠加互联网地图[CAD为底图]
// 增加高德地图底图
let gdlayer;
const addGaodeMap = async (isRoadway) => {
const tileUrl = svc.webMapUrl({
tileCrs: "gcj02",
tileUrl: isRoadway ? [
"https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
] :
/* 如果用影像 */
[
"https://webst0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x={x}&y={y}&z={z}",
"https://webst0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
],
tileSize: 256,
tileRetina: 1,
tileMaxZoom: 18,
tileShards: "1,2,3,4",
tileToken: "",
tileFlipY: false,
mapbounds: res.bounds,
srs: "EPSG:4527",// 可通过前两位获取 vjmap.transform.getEpsgParam(vjmap.transform.EpsgCrsTypes.CGCS2000, 39).epsg
// 因为sys_cad2000这个图只有6位,没有带系。需要在坐标转换前平移下带系 https://blog.csdn.net/thinkpang/article/details/124172626
fourParameterBefore: "39000000,0,1,0"
})
// 增加一个瓦片图层
gdlayer = new ol.layer.Tile({
// 增加一个瓦片数据源
source: new ol.source.TileImage({
url: tileUrl
})
});
gdlayer.setZIndex(-1);
// 在地图中增加上面的瓦片图层
map.addLayer(gdlayer);
// cad坐标与高德坐标相互转换示例
let webCo = await cad2webCoordinate(center, false); // cad转高德
let cadCo = await web2cadCoordinate(webCo, false); // 高德转cad
console.log(center, webCo, cadCo)
}
Openlayers中互联网地图自动叠加CAD图[互联网图为底图]
let cadEpsg = "EPSG:4544";// cad图的espg代号
// 增加cad的wms图层
let wmsUrl = svc.wmsTileUrl({
mapid: mapId, // 地图id
layers: layer, // 图层名称
bbox: '', // bbox这里不需要
srs: "EPSG:3857", //
crs: cadEpsg
})
function getQueryStringArgs(url) {
let theRequest = {};
let idx = url.indexOf("?");
if (idx != -1) {
let str = url.substr(idx + 1);
let strs = str.split("&");
for (let i = 0; i < strs.length; i++) {
let items = strs[i].split("=");
theRequest[items[0]] = items[1];
}
}
return theRequest;
}
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// cad图坐标转web wgs84坐标
const cadToWebCoordinate = async point => {
let co = await svc.cmdTransform(cadEpsg, "EPSG:4326", point);
return co[0]
}
// cad转wgs84经纬度
let boundsMin = await cadToWebCoordinate(mapBounds.min);
let boundsMax = await cadToWebCoordinate(mapBounds.max);
// wgs84经纬度转墨卡托
boundsMin = vjmap.Projection.lngLat2Mercator(boundsMin);
boundsMax = vjmap.Projection.lngLat2Mercator(boundsMax);
// 在openlayer中增加wms图层
map.addLayer(new ol.layer.Tile({
// 范围
extent: [boundsMin[0], boundsMin[1], boundsMax[0], boundsMax[1]],
source: new ol.source.TileWMS({
url: wmsUrl.substr(0, wmsUrl.indexOf("?")),
params: {...getQueryStringArgs(wmsUrl),'TILED': true}
}),
}))
Openlayers中互联网地图公共点叠加CAD图[互联网图为底图]
// cad上面的点坐标
let cadPoints = [
vjmap.geoPoint([587464448.8435847, 3104003685.208651,]),
vjmap.geoPoint([587761927.7224838, 3104005967.655292]),
vjmap.geoPoint([587463688.0280377, 3103796743.3798513]),
vjmap.geoPoint([587760406.0913897, 3103793700.1176634])
];
// 在互联网图上面拾取的与上面的点一一对应的坐标(wgs84坐标)
let webPoints = [
vjmap.geoPoint([116.48476281710168, 39.96200739703454]),
vjmap.geoPoint([116.48746772021137, 39.96022062215167]),
vjmap.geoPoint([116.48585059441585, 39.9588451134361]),
vjmap.geoPoint([116.48317418949145, 39.960515760972356])
]
// 通过坐标参数求出四参数
let epsg3857Points = webPoints.map(w => vjmap.geoPoint(vjmap.Projection.lngLat2Mercator(w)));
let param = vjmap.coordTransfromGetFourParamter(epsg3857Points, cadPoints , false); // 这里考虑旋转
let fourparam = [param.dx, param.dy, param.scale, param.rotate]
// wms图层地址
const getCadWmsUrl = (transparent) => {
let wmsUrl = svc.wmsTileUrl({
mapid: mapId, // 地图id
layers: layer, // 图层名称
bbox: '', // bbox这里不需要
fourParameter: fourparam,
transparent: transparent,
backgroundColor: 'rgba(240, 255, 255)' // 不透明时有效
})
return wmsUrl
}
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
let cadPrj = new vjmap.GeoProjection(mapBounds);
// cad图坐标转3857坐标
const cadToWebCoordinate = point => {
// 再调用四参数反算求出web的坐标
return vjmap.coordTransfromByInvFourParamter(vjmap.geoPoint(point), param)
}
// 3857转cad图坐标
const webToCadCoordinate = point => {
return vjmap.coordTransfromByFourParamter(vjmap.geoPoint(point), param)
}
let wmsLayer;
const addWmsLayer = async (transparent)=> {
removeWmsLayer();
let wmsUrl = getCadWmsUrl(transparent);
wmsLayer = new ol.layer.Tile({
// 范围
extent: bounds.toArray(),
source: new ol.source.TileWMS({
url: wmsUrl.substr(0, wmsUrl.indexOf("?")),
params: {...getQueryStringArgs(wmsUrl),'TILED': true}
}),
});
// 在openlayer中增加wms图层
map.addLayer(wmsLayer);
}
最后
可点击 https://vjmap.com/demo/#/demo/map/openlayers/01olraster 在线体验上面功能
如果需要用openlayers来加载CAD图进行开发,请参考示例 https://vjmap.com/demo/#/demo/map/openlayers/01olraster
如果需要用leaflet来加载CAD图进行开发,请参考示例 https://vjmap.com/demo/#/demo/map/leaflet/01leafletraster
如果需要用maptalks来加载CAD图进行开发,请参考示例 https://vjmap.com/demo/#/demo/map/maptalks/01maptalksraster
如何基于vue3来开发openlayers应用,可查看此开源代码 https://github.com/MelihAltintas/vue3-openlayers
如何基于vue2来开发openlayers应用,可查看此开源代码 https://github.com/ghettovoice/vuelayers
通过openlayers加载dwg格式的CAD图并与互联网地图叠加的更多相关文章
- 如何实现通过Leaflet加载dwg格式的CAD图
前言 在前面介绍了通过openlayers加载dwg格式的CAD图并与互联网地图叠加,openlayers功能很全面,但同时也很庞大,入门比较难,适合于大中型项目中.而在中小型项目中,一般用开源的 ...
- Flex 加载dwg
之前写的几种格式不是专门gis格式,这次来说说加载dwg.首先dwg格式不同于dxf格式,虽然autocad都能加载进去,真正用的比较多的是dwg格式,反正测绘,国土规划部门都是,吐槽下,然而auto ...
- Web前台直接加载GIS格式数据分析
本文以Flex直接加载Shp.DWG和MDB为例. 首先看一份现估测数据: 1) 加载Shp文件,目前直接由前台Flex代码完成: 图1 在ArcCatalog里面的Shp文件 图2 直接在前台加载 ...
- Silverlight客户端加载DWG图纸方案
前段时间一直再研究怎么才能在Silverlight客户端加载 DWG图纸,ArcGIS API For Silverlight中可以加载Shp文件,但是不能加载DWG,最后想出了一个方法步骤如下: 1 ...
- 使用getJSON()方法异步加载JSON格式数据
使用getJSON()方法异步加载JSON格式数据 使用getJSON()方法可以通过Ajax异步请求的方式,获取服务器中的数组,并对获取的数据进行解析,显示在页面中,它的调用格式为: jQuery. ...
- OpenLayers加载QQ地图(转)
OpenLayers加载QQ地图 http://www.openlayers.cn/portal.php?mod=view&aid=4 2012-10-21 17:22| 发布者: admin ...
- openlayers 加载瓦片详解 一
在这先说点题外话,本人在研究webgl 三维球过程中惊人发现,openlayers 的开发人员也在研究webgl并经证实他们也正在研发基于 webgl的三维gis开源平台,这可能是首个开源的三维平台, ...
- hive 压缩全解读(hive表存储格式以及外部表直接加载压缩格式数据);HADOOP存储数据压缩方案对比(LZO,gz,ORC)
数据做压缩和解压缩会增加CPU的开销,但可以最大程度的减少文件所需的磁盘空间和网络I/O的开销,所以最好对那些I/O密集型的作业使用数据压缩,cpu密集型,使用压缩反而会降低性能. 而hive中间结果 ...
- cesium 加载shp格式的白模建筑
ceisum加载shp格式的建筑.有两种思路,目前推荐第二种. 方法一:将shp格式转换为geojson格式,然后采用cesium提供的接口加载到ceisum中. 严重缺陷:在面对大场景问题,即数据量 ...
随机推荐
- 密码学的基础:X.690和对应的BER CER DER编码
目录 简介 BER编码 类型标识符 长度 内容 CER编码和DER编码 总结 简介 之前我们讲到了优秀的数据描述语言ASN.1,很多协议标准都是使用ASN.1来进行描述的.对于ASN.1来说,只定义了 ...
- Odoo4 tree视图左上角新增Button
# 一.直接在tree根元素中新增.这种有个限制就是必须要勾选一或多条记录的时候按钮才会显示 <tree> <header> <button type="obj ...
- vant自动上传图片/文件
vant自动上传文件/图片 vant上传图片与elementUI有所不同,没有自动上传功能,所以与后端进行接口对接的时候可以在after-read中将文件进行上传 html页面 <!-- 上传图 ...
- Spring的Model 和 Map的原理
Model 和 Map 为什么在Model和Map中放值传入后会出现在request的上面. 9.1.源码解析 准备测试代码 @GetMapping("/goto") public ...
- MyBatis-Plus 代码生成
MyBatis-Plus官网的代码生成器配置不是特别全,在此整理了较为完整的配置,供自己和大家查阅学习. // 代码生成器 AutoGenerator mpg = new AutoGenerator( ...
- Reader和Writer区别final.finally.finalize区别
Reader和Writer是字符操作流,Writer是输出的,而Reader是输入的. 首先找到一个文件,比如:File file=new File("."+File.separa ...
- HCIA-Datacom 4.1 实验一:访问控制列表配置实验
实验介绍 访问控制列表ACL(Access Control List)是由一条或多条规则组成的集合.所谓规则,是指描述报文匹配条件的判断语句,这些条件可以是报文的源地址.目的地址.端口号等.ACL本质 ...
- 升级CentOS 7 内核版本
1.查看当前内核版本 $uname -r 3.10.0-957.el7.x86_64 $uname -a Linux prometheus 3.10.0-957.el7.x86_64 #1 SMP T ...
- iOS WebRTC 点对点实时音视频流程介绍
前言 公司某个项目需要接入音视频即时通讯, 功能类似微信的拨打视频通话,语音通话的场景.那么对于音视频通讯会用到什么技术呢?没错,它就是 WebRTC . 什么是WebRTC WebRTC,名称源自网 ...
- 使用.Net对图片进行裁剪、缩放、与加水印
图片的裁剪.缩放.与加水印,是任何系统经常要用到的功能,它们现已集成到IUtility工具中,使用十分简便.(具体代码将在文末给出,支持.NET/.NET Framework/.NET Core) 现 ...