钥匙要点
- >利用node.js构建一个服务器,该服务器扩展了现有功能以包括Wi-Fi网络信息,从而使仪表板更全面。 >实现ractive.js,以更有效地管理客户端来管理实时更新和交互,从而通过动态内容更新来增强用户体验。
- > process wi-fi命令在服务器上输出以提取和显示可用的网络详细信息,确保数据结构并准备好客户端使用。
- >设计和使用带有ractive.js的HTML模板显示Wi-Fi网络数据,从而启用了可以提高导航和可用性的交互式和响应性的网络元素。
- > >通过添加新的端点并有效地处理Ajax来扩展仪表板的功能,以确保仪表板保持可扩展且可维护。

在服务器端,我们将重复使用并扩展为电池组创建的内容。在本教程中,我们将专注于Ubuntu,但是服务器代码的结构是使您只需要编写几个适配器来支持Mac或Windows的机器。
> bash命令首先,我们通过为新端点添加命令和回调来扩展原始配置方法。有必要重命名以防止与电池小部件的命令发生冲突。
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>处理命令输出
我们处理命令输出的方式确实与已经为电池所做的事情相似。我们逐行浏览输出,然后对其进行处理以从读取中提取有意义的参数。但是在这种情况下,我们会收到有关项目列表的阅读,而不是单个项目的列表!因此,我们需要确定何时在输出中真正启动新项目,并为每个项目创建一个新对象。然后,我们将过滤有效的行,将读取的属性添加到当前项目中。
在详细查看ProcessWifilineForlinux中发生的情况之前,我要重点介绍几点:<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>
- >由于我们仅在下一个启动的描述时向哈希添加一个单元格,因此我们会错过最终if语句(捕获输出中的最后一个网络)。
- >上面的代码假定两个单元格无法共享相同的名称。这是一个合理的假设,因为网络没有被其名称索引(该信息由Essid字段捕获)。它们被列出并分配了一个渐进式标识符 “ cell 0x”
- 。>。
- 我们在存储属性之前要做的最后一件事是呼叫MapWifikeySforlinux,在这种情况下,它们只是返回键未改变的键。
即使处理每行的处理功能也与我们为电池创建的功能非常相似:由于每行都有一个字段名称及其值,我们首先检查需要以特殊方式处理的边缘案例,以及剩余的行我们只是将它们分开并安装钥匙值对。> - 我们在存储属性之前要做的最后一件事是呼叫MapWifikeySforlinux,在这种情况下,它们只是返回键未改变的键。
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>>端点
由于Node的HHTP模块和我们在上一位教程中创建的助手方法,因此将新端点添加到我们的服务器上是微不足道的。我们只需要定义要响应的路径的正则表达式,然后在传入请求上触发的服务器回调中添加IF语句:
在这一点上,我们要做的就是创建一个回调,该回调将运行命令,转换其输出并最终将JSON结果发送给客户端,并包含在HTTP.Createserver提供的HTTP响应中。<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>在最后一步中,请注意,我们重复了我们为电池端点方便定义的ONSUCCESS函数(对于OnError处理程序而言相同的东西)。
<span>function processWifiLineForLinux(cell<span>, line</span>) { </span> <span>var key; </span> <span>var val; </span> line <span>= line.trim(); </span> <span>if (line.length > 0) { </span> <span>switch (true) { </span> <span>case stringStartsWith(line, NET_ADDRESS_PREFIX): </span> line <span>= line.split(':'); </span> line<span>.splice(0, 1); </span> <span>//INVARIANT: Address in the format Address: DC:0B:1A:47:BA:07 </span> <span>if (line.length > 0) { </span> cell<span>[NET_ADDRESS_PREFIX] = line.join(":"); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_QUALITY_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Quality=41/70 Signal level=-69 dBm </span> line <span>= line.split(NET_SIGNAL_PREFIX); </span> cell<span>[NET_QUALITY_PREFIX] = line[0].split("=")[1].trim(); </span> <span>if (line.length > 1) { </span> cell<span>[NET_SIGNAL_PREFIX] = line[1].split("=")[1].trim(); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_EXTRA_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Extra: Last beacon: 1020ms ago </span> line <span>= line.split(":"); </span> <span>//we can ignore the prefix of the string </span> <span>if (line.length > 2) { </span> cell<span>[line[1].trim()] = line[2].trim(); </span> <span>} </span> <span>break; </span> <span>default: </span> <span>//INVARIANT: the field must be formatted as "key : value" </span> line <span>= line.split(":"); </span> <span>if (line.length > 1) { </span> <span>//Just stores the key-value association, so that coupling with client is reduced to the min: </span> <span>//values will be examined only on the client side </span> cell<span>[line[0].trim()] = line[1].trim(); </span> <span>} </span> <span>} </span> <span>} </span> <span>return cell; </span> <span>}</span>>客户端
现在,让我向您介绍此示例中最有趣的部分。我们将为Web客户端大量使用RACTIVE.JS。这是一个轻巧,功能强大的框架,将双向绑定(AngularJS风格)与HTML模板结合在一起 或车把)。 模板上的压力(甚至比Angularjs更重要,而不是反应),这确实是ractive.js的标志之一,以及其巨大的快速性能,这是由于聪明的引擎始终计算最小可能的DOM元素的结果当数据更改时刷新。 我们将在仪表板上添加两个面板:
- 一个用于我们周围环境中网络列表的一个(显示了每个项目的简短摘要)。
- > 仅选择网络并显示该Wi-Fi连接的详细信息。
首先,让我们讨论HTML模板以显示我们的数据,然后我们将查看如何将服务器的数据绑定到它们。
> wi-fi列表我们需要的最复杂的模板是显示可用网络列表的模板。第一批行只是定义容器面板,然后使用ractive.js的绑定来有条件地显示有关服务器错误的图标警告,以及一个按钮,以暂停/简历服务器进行轮询:
双stache {{}},如胡子和车把,是动态注入内容的标记。 ractive.js允许我们在括号内使用表达式并运行功能,只要这些功能和所使用的数据在全球范围内可用(例如,Math. -Round)或已添加到JavaScript对象的数据字段中,模板。 括号内表达式的结果将被逃脱,因此将是纯文本。但是有时您可能需要在元素中添加几行。还有一种其他方法可以做到,但是如果您真的认为需要它,则可以使用三重速度{{{{}}}。 使用Triple-STACHE是安全的,因为脚本将被逃脱且未执行,但它比双静止速度慢,因此您应该尽量避免它。模板的第二部分更有趣。我们通过{{#wifinetworks:num}}迭代网络列表,捕获数字变量中每个项目的索引。 对于列表中的每个项目,我们添加了一个回调处理点击(请参阅下文),并显示其值的摘要。 请注意,关闭标签如何不必匹配打开标签文字:
<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>开头是一个函数的if标签,这将使它在关闭的函数中再次运行它。因此,我们可以使用有意义的消息对两个标签进行配对,只是为了维护的目的。
>选择的Wi-Fi详细信息
<span>function processWifiStdoutForLinux(stdout) { </span> <span>var networks = {}; </span> <span>var net_cell = ""; </span> <span>var cell = {}; </span> stdout<span>.split('\n').map(trimParam).forEach(function (line) { </span> <span>if (line.length > 0) { </span> <span>//check if the line starts a new cell </span> <span>if (stringStartsWith(line, NET_CELL_PREFIX)) { </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> cell <span>= {}; </span> line <span>= line.split("-"); </span> net_cell <span>= line[0].trim(); </span> line <span>= line[1]; </span> <span>} </span> <span>//Either way, now we are sure we have a non empty line with (at least one) key-value pair </span> <span>// and that cell has been properly initialized </span> <span>processWifiLineForLinux(cell, line); </span> <span>} </span> <span>}); </span> <span>if (net_cell.length > 0) { </span> networks<span>[net_cell] = mapWifiKeysForLinux(cell); </span> <span>} </span> <span>return networks; </span> <span>}</span>网络详细信息的面板非常简单:我们仅在ractive对象中为所选网络字段分配值时才显示它。然后,我们显示网络的名称(ESSID字段),并显示我们从服务器收到的所有键值对。 这是为了获得最低的耦合,但是您当然可以对其进行修改以突出显示某些信息或以更有意义的方式显示它们。
> javascript
我们将设置一个民意调查的守护程序,该守护程序异步以给定的时间间隔对服务器进行查询。每个AJAX呼叫都将提供Wi-Fi网络的更新列表。当我们收到服务器的JSON响应时,我们要做的就是确认我们收到了成功的响应,并更新了我们在ractive对象中存储网络列表的字段。>设置
正如我们在上一篇文章中显示的那样,要将模板绑定到某些数据,我们只需要创建一个新的ractive对象,将其与模板的ID(#MeTervizTemplate)相连(下面的#MeTervizTemplate),而目标DOM元素(即节点)那将是DOM树中模板的父 以下)。 然后,我们只需要在模板中添加所有要在ractive.data字段中使用的对象或值即可。可以使用ractive.set()对初始化(如下)或更高版本进行此操作。<span>function processWifiLineForLinux(cell<span>, line</span>) { </span> <span>var key; </span> <span>var val; </span> line <span>= line.trim(); </span> <span>if (line.length > 0) { </span> <span>switch (true) { </span> <span>case stringStartsWith(line, NET_ADDRESS_PREFIX): </span> line <span>= line.split(':'); </span> line<span>.splice(0, 1); </span> <span>//INVARIANT: Address in the format Address: DC:0B:1A:47:BA:07 </span> <span>if (line.length > 0) { </span> cell<span>[NET_ADDRESS_PREFIX] = line.join(":"); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_QUALITY_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Quality=41/70 Signal level=-69 dBm </span> line <span>= line.split(NET_SIGNAL_PREFIX); </span> cell<span>[NET_QUALITY_PREFIX] = line[0].split("=")[1].trim(); </span> <span>if (line.length > 1) { </span> cell<span>[NET_SIGNAL_PREFIX] = line[1].split("=")[1].trim(); </span> <span>} </span> <span>break; </span> <span>case stringStartsWith(line, NET_EXTRA_PREFIX): </span> <span>//INVARIANT: this line must have a similar format: Extra: Last beacon: 1020ms ago </span> line <span>= line.split(":"); </span> <span>//we can ignore the prefix of the string </span> <span>if (line.length > 2) { </span> cell<span>[line[1].trim()] = line[2].trim(); </span> <span>} </span> <span>break; </span> <span>default: </span> <span>//INVARIANT: the field must be formatted as "key : value" </span> line <span>= line.split(":"); </span> <span>if (line.length > 1) { </span> <span>//Just stores the key-value association, so that coupling with client is reduced to the min: </span> <span>//values will be examined only on the client side </span> cell<span>[line[0].trim()] = line[1].trim(); </span> <span>} </span> <span>} </span> <span>} </span> <span>return cell; </span> <span>}</span>
我们将使用与电池相同的机制进行守护程序,并暂停/重新启动服务器查询。为了简洁起见,我们不会在此处重复,但是如果您想加深此主题,您可以查看本文或GitHub存储库。
ajax调用我们的新守护程序要做的唯一的事情就是进行Ajax调用,然后在成功或现场信号网络问题的情况下更新我们的数据,以防发生错误。
我们还应该检查我们获得的JSON文件是否格式化。我们不必担心脚本注入,因为ractive.js在将其添加到DOM之前已经逃脱了字段值。 值得注意的是,jquery.getjson()方法是上述$ .ajax()方法的快捷方式,只要是: 1。您在URL中不包含'callback ='字符串(这将允许执行JSON代码)。<span>var server = http.createServer(function (request<span>, response</span>) { </span> <span>var requestUrl = request.url; </span> <span>var filePath = BASE_URL + requestUrl; </span> <span>if (requestUrl === '/' || requestUrl === '') { </span> response<span>.writeHead(301, </span> <span>{ </span> <span>Location: BASE_URL + 'public/demo.html' </span> <span>}); </span> response<span>.end(); </span> <span>} else if (RE_BATTERY.test(requestUrl)) { </span> <span>getBatteryStatus(response, onBatteryInfo, onError); </span> <span>} else if (RE_NETWORKS.test(requestUrl)) { </span> <span>getWifiStatus(response, onWifiInfo, onError); </span> <span>} </span> <span>... </span> <span>}</span>2。您可以信任您正在调用的服务器。 由于我们不使用用户提供的URL内容,因此会认为这不应该担心。 但是,如果要妥协我们的服务器,那么我们将没有障碍来保护我们免受注射代码的侵害。如果未设置明确的“数据类型”标头,则jQuery将尝试猜测响应中的内容,而恶意服务器的响应可能包含JavaScript代码。 尽管这种可能性并不常见,但我们不能完全排除它。因此,以更多的打字价格增加了额外的保护层并不是一个坏主意。
更新仪表板
此步骤中最相关的附加组件是我们响应列表的点击s并显示所选网络的详细信息:<span>function switchConfigForCurrentOS () { </span> <span>switch(process.platform) { </span> <span>case 'linux': </span> <span>return { </span> <span>batteryCommand: 'upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -E "state|time to empty|to full|percentage"', </span> <span>batteryProcessFunction: processBatteryStdoutForLinux, </span> <span>wifiCommand: 'iwlist wlan0 scanning | egrep "Cell |Address|Channel|Frequency|Encryption|Quality|Signal level|Last beacon|Mode|Group Cipher|Pairwise Ciphers|Authentication Suites|ESSID"', </span> <span>wifiProcessFunction: processWifiStdoutForLinux </span> <span>}; </span> <span>case 'darwin': //MAc OsX </span> <span>... </span> <span>} </span> <span>}</span>为此,我们定义了临时事件处理程序。如上所述,当我们单击任何列表条目时,它将被调用,然后与点击关联的事件将携带有关所选网络本身的信息。 现在,如果我们不使用ractive.js,假设我们只使用jQuery,则必须:
- 调用一种方法,该方法将采用选定的网络的ID;
> >使用它来找到该ID的网络对象(可能存储在字典中); - > 找到“选定网络面板”的DOM元素;
- > >删除面板内的旧DOM树,然后迭代地创建一个新列表,显示键值关联,混合了我们的JavaScript代码中的许多HTML字符串。
- > ractive.js将为我们照顾所有这一切,它将比我们(平均而言)的能力更好,而仅更改最小的DOM子树。 首先,发送到点击处理程序的事件对象将具有一个上下文字段,其中包含绑定到DOM元素的数据。换句话说,我们“免费”获得网络数据对象。 一旦有了,我们唯一要做的就是使用它来更新已经绑定到模板的ractive对象。 ractive.js的引擎将完成其余的,更新DOM并显示更改。
完成的!我们的仪表板“ Pimped”。正如我在介绍中所说的那样,这只是一个起点。
如果您遵循的话,现在应该能够轻松显示复杂项目的列表,处理项目选择并安全地与服务器通信。 您可以将这些技能用于许多其他任务,不一定涉及笔记本电脑的统计数据。从显示用户周围的餐馆清单到列举家用电器,您可以通过网络界面或手机进行控制。选择是您的,没有限制。 如果您想加深本文所涵盖的主题,我建议您看看这些良好的资源:- 使用node.js创建电池:入门和服务器
- > 关于ractive.js
- > jQuery $ .getjson方法
- 关于stackoverflow的讨论jquery.get()方法
>构建Wi-Fi仪表板的前提是什么?您还需要在计算机上安装NODE.JS和NPM(节点软件包管理器)。如果您没有安装这些,则可以从官方Node.js网站下载它们。此外,您还需要文本编辑器来编写代码。您可以使用您选择的任何文本编辑器,但是一些受欢迎的编辑器包括Visual Studio代码,Atom和Sublime Text。
如何安装Node-Wifi Module?
>
>如何使用node-wifi模块连接到Wi-Fi网络?您可以用来连接到Wi-Fi网络的“连接”功能。您需要将对象传递到包含网络的SSID和密码的此功能。以下是一个示例: var wifi = require('node-wifi');if(err){
console.log(err);}
console.log('成功连接到网络');
>}) >如何扫描可用的Wi-Fi网络?
var wifi = require('node-wifi');
wifi.scan(function(erry,networks){
}
console.log(networks);
>我如何从Wi-Fi网络中断开连接? WiFi模块提供了一个“断开连接”功能,您可以使用该功能与Wi-Fi网络断开连接。您无需将任何参数传递给此功能。这是一个示例: var wifi = require('node-wifi');
var wifi = require('node-wifi');
wifi.disconnect(function(err){erra){
}
console.log('成功与网络断开连接');
})>如何获得当前的Wi-Fi状态?
wifi.getCurrentConnections(function(err,currentConnections){
(err);
}
console.log(currentConnections);
});
如何处理node-wifi模块中的错误? -WIFI模块遵循标准node.js错误处理模式。所有功能都将回调作为最后一个参数。此回调是一个有两个参数的函数:一个错误对象和结果。如果发生错误,则错误对象将包含有关错误的信息。否则,错误对象将为null,结果将包含操作的结果。
>>
>我可以将Node-Wifi模块与其他node.js模块一起使用吗?
以上是如何使用node.js和ractive.js构建Wi-Fi仪表板的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Atom编辑器mac版下载
最流行的的开源编辑器