| 原始路径 | 文件名 | 大小 | 坐标数 | 状态 |
|---|
| 行号 | X 原始 | X 涨缩后 | X 变化 | Y 原始 | Y 涨缩后 | Y 变化 | 原文 | 涨缩后 |
|---|
对 PCB 坐标文件(钻带/锣带/Gerber/钻孔等)中的坐标进行涨缩处理。根据 X/Y 轴系数,对所有坐标等比缩放。原始文件不会被修改。
任意文本格式,自动扫描 X/Y 坐标。常见:.g7r .drl .nc .gbr .art .txt
X00123450 Y00098760 ← 标准坐标 X-00123700 ← 负坐标 x12345 y67890 ← 小写坐标
无坐标的文件标记为「⚠ 无效」,不参与处理。
左下角原点(默认):以坐标(0,0)为基准拉伸。
板中心坐标:以板几何中心为基准四面对称拉伸,填板中心坐标(毫米),系统自动识别文件刻度(1mm=多少单位)并换算成文件坐标。中心点拉伸前后不变。
| 系数 | 效果 | 示例 |
|---|---|---|
| 1.0 | 不变 | X00123450 → X00123450 |
| 1.00022 | 拉伸 +0.022‰ | X00123450 → X00123477 (+27) |
| 0.99980 | 收缩 -0.02‰ | X00123450 → X00123425 (-25) |
文件里同时出现 M25 + M02X#Y# + M08 时,判定为拼板阵列文件(Step-and-Repeat),处理方式与普通文件不同。
M02 偏移会被重新计算 —— 坐标拉伸后实例间距必然变化,所以 M02 的数值一定会变,这是正常的。阵列块 M25/M01/M02/M08 保留,可用「还原 1:1」回到原始文件。M70(轴交换)且 X/Y 系数不相同时,M70 与各向异性缩放在数学上不可交换,块内无法精确表示,工具会自动把阵列摊平成绝对坐标。此时阵列结构不再保留,还原只能撤比例。M80(X取反) / M90(Y取反) 不交换轴,可以精确保留在阵列块里。文件名格式:原文件名-x1.00022y1.00008.扩展名;中心模式另有 _c-cx312mm_cy364mm 后缀。
选目录 → 自动写入。未选 → 浏览器下载。保持原文件夹结构。
| 快捷键 | 功能 |
|---|---|
| Ctrl+Enter | 执行涨缩 |
| Esc | 关闭帮助 |
M02 偏移用四舍五入;均保留原始位数格式| 项目 | 说明 |
|---|---|
| 接口地址 | https://www.binwindai.com |
| 协议 | 仅 HTTPS(HTTP 自动 301 跳转) |
| 认证 | 无需认证,开放使用 |
| 请求体上限 | 50 MB |
| 跨域 | 支持 CORS,浏览器可直接调用 |
上传一个 PCB 坐标文件,按 X/Y 系数缩放所有坐标,返回处理后的文件。
POST https://www.binwindai.com/api/stretch Content-Type: multipart/form-data
| 参数名 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| file | 必填 | 文件 | — | 要处理的 PCB 坐标文件(G-code .g7r .drl .nc、Gerber .gbr .art 等文本格式) |
| x_factor | 可选 | 数字 | 1.00022 | X 轴缩放系数,所有 X 坐标 × 此值 |
| y_factor | 可选 | 数字 | 1.00008 | Y 轴缩放系数,所有 Y 坐标 × 此值 |
| mode | 可选 | string | origin | origin=原点拉伸,center=中心拉伸 |
| center_x_mm | 条件必填 | float | — | mode=center时必填,板中心X坐标(毫米),自动按文件刻度换算 |
| center_y_mm | 条件必填 | float | — | mode=center时必填,板中心Y坐标(毫米) |
坐标刻度(1mm = 多少坐标单位)由服务端自动识别,无需传参:坐标含小数点→1;最大坐标 ≥ 1000000→10000;否则→1000。中心模式下 center_x_mm/center_y_mm 会按识别结果自动换算为文件坐标。 | ||||
文件同时含 M25 + M02X#Y# + M08 时按阵列文件处理,行为与普通文件不同:
M02 偏移按
C_j = T(A_j·p + o_j) − A_j·T(p) 重新计算
(T=拉伸变换,A_j=该实例的镜像操作 M70/M80/M90,o_j=累计偏移)。
阵列块结构保留,M02 数值会变(间距随坐标一起缩放,属正常)。M70(轴交换)且 X/Y 系数不同时,
M70 与各向异性缩放不可交换,块内无法精确表示,服务端改为输出绝对坐标 ——
阵列结构不再保留。M80(X取反) / M90(Y取反) 不换轴,可精确保留在阵列块内。直接返回处理后的文件内容,浏览器会自动下载。文件名格式:原文件名-x1.00022y1.00008.扩展名(中心模式另加 _c-cx312mm_cy364mm;保留上传时的原始文件名)
{"error": "错误原因描述"}# 基本用法 curl -X POST https://www.binwindai.com/api/stretch \ -F "file=@input.g7r" \ -F "x_factor=1.00022" \ -F "y_factor=1.00008" \ -o output.g7r # 中心拉伸(填毫米坐标,自动识别文件刻度换算) curl -X POST https://www.binwindai.com/api/stretch \ -F "file=@input.g7r" \ -F "x_factor=1.00022" \ -F "y_factor=1.00008" \ -F "mode=center" \ -F "center_x_mm=50.0" \ -F "center_y_mm=30.0" \ -F "scale=10000" \ -o output.g7r # 只上传文件(使用默认系数) curl -X POST https://www.binwindai.com/api/stretch \ -F "file=@input.g7r" \ -o output.g7r
import requests
# 读取文件,发送请求
with open("input.g7r", "rb") as f:
resp = requests.post(
"https://www.binwindai.com/api/stretch",
files={"file": f}, # 要处理的文件
data={
"x_factor": 1.00022, # X轴系数
"y_factor": 1.00008 # Y轴系数
},
timeout=30 # 建议设置超时
)
# 检查结果
if resp.status_code == 200:
# 成功 — 保存处理后的文件
with open("output.g7r", "wb") as out:
out.write(resp.content)
print("处理完成!")
else:
# 失败 — 打印错误信息
print("错误:", resp.json())
# — 中心拉伸(mm坐标,自动识别文件刻度换算) —
resp = requests.post(
"https://www.binwindai.com/api/stretch",
files={"file": f},
data={"x_factor": 1.00022, "y_factor": 1.00008,
"mode": "center", "center_x_mm": 50.0,
"center_y_mm": 30.0, "scale": 10000},
timeout=30
)
import fs from "fs";
import path from "path";
const fileBuffer = fs.readFileSync("input.g7r");
const form = new FormData();
// Node.js 18+ 内置 FormData
form.append("file", new Blob([fileBuffer]), path.basename("input.g7r"));
form.append("x_factor", "1.00022");
form.append("y_factor", "1.00008");
const resp = await fetch("https://www.binwindai.com/api/stretch", {
method: "POST",
body: form,
signal: AbortSignal.timeout(30000) // 30秒超时
});
if (resp.ok) {
const buffer = Buffer.from(await resp.arrayBuffer());
fs.writeFileSync("output.g7r", buffer);
console.log("处理完成!");
} else {
const err = await resp.json();
console.error("错误:", err.error);
}
// — 中心拉伸(mm坐标) —
const f2=new FormData();f2.append("file",new Blob([fileBuffer]),"input.g7r");f2.append("x_factor","1.00022");f2.append("y_factor","1.00008");f2.append("mode","center");f2.append("center_x_mm","50.0");f2.append("center_y_mm","30.0");f2.append("scale","10000");const r2=await fetch("https://www.binwindai.com/api/stretch",{method:"POST",body:f2,signal:AbortSignal.timeout(30000)});if(r2.ok){fs.writeFileSync("out.g7r",Buffer.from(await r2.arrayBuffer()));console.log("done");}
// 假设用户通过 <input type="file"> 选了文件
const fileInput = document.getElementById("myFileInput");
const file = fileInput.files[0];
const form = new FormData();
form.append("file", file); // File 对象直接传入
form.append("x_factor", "1.00022");
form.append("y_factor", "1.00008");
const resp = await fetch("https://www.binwindai.com/api/stretch", {
method: "POST",
body: form
});
if (resp.ok) {
// 触发浏览器下载
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "output.g7r"; // 下载文件名
a.click();
URL.revokeObjectURL(url);
} else {
const err = await resp.json();
alert("处理失败: " + err.error);
}
// — 中心拉伸(mm坐标) —
const f3=new FormData();f3.append("file",file);f3.append("x_factor","1.00022");f3.append("y_factor","1.00008");f3.append("mode","center");f3.append("center_x_mm","50.0");f3.append("center_y_mm","30.0");f3.append("scale","10000");const r3=await fetch("https://www.binwindai.com/api/stretch",{method:"POST",body:f3});if(r3.ok){const b3=await r3.blob();const u3=URL.createObjectURL(b3);const a3=document.createElement("a");a3.href=u3;a3.download="out.g7r";a3.click();URL.revokeObjectURL(u3);}
X 或 Y(大小写均可)后面跟数字X00123450 → 取值 123450 → ×1.00022 → 四舍五入 → X00123477X12.345 → 取值 12.345 → ×1.00022 → 保留3位小数 → X12.348Y-12.345 → 支持负数input.g7r → input-x1.00022y1.00008.g7r PCB123.drl → PCB123-x1.5y1.5.drl test.txt → test-x2.0y2.0.txt
提交咨询或反馈,支持 JSON 和 FormData 两种方式。成功后自动发邮件通知并存入数据库。
POST https://www.binwindai.com/api/contact Content-Type: application/json 或 multipart/form-data
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| name | 必填 | 字符串 | 联系人姓名 |
| 必填 | 字符串 | 联系邮箱(管理员直接回复此地址) | |
| subject | 必填 | 字符串 | 主题(最长200字) |
| message | 必填 | 字符串 | 详细内容(最长5000字) |
| phone | 可选 | 字符串 | 联系电话 |
| files | 可选 | 文件 | 附件(可传多个,仅 FormData 模式) |
| html | 可选 | 字符串 | 自定义邮件 HTML 正文(不传则自动生成) |
{
"success": true,
"message": "感谢您的留言,我们会尽快回复!",
"contactId": "cmsfvt5w50004p47evptry1m8"
}{"error": "请填写姓名、邮箱、主题和留言内容"}curl -X POST https://www.binwindai.com/api/contact \
-H "Content-Type: application/json" \
-d '{
"name": "张三",
"email": "zhangsan@example.com",
"phone": "13800138000",
"subject": "API 使用咨询",
"message": "请问 /api/stretch 支持批量上传吗?"
}'
# 返回
# {"success":true,"message":"感谢您的留言,我们会尽快回复!","contactId":"cms..."}
# 基本表单 curl -X POST https://www.binwindai.com/api/contact \ -F "name=张三" \ -F "email=zhangsan@example.com" \ -F "subject=API 使用咨询" \ -F "message=请问支持批量吗?" # 带附件 curl -X POST https://www.binwindai.com/api/contact \ -F "name=张三" \ -F "email=zhangsan@example.com" \ -F "subject=Bug 反馈" \ -F "message=详见截图" \ -F "files=@screenshot.png" \ -F "files=@error.log"
import requests
# — 方式1:JSON(简单文本咨询)—
resp = requests.post(
"https://www.binwindai.com/api/contact",
json={
"name": "张三",
"email": "zhangsan@example.com",
"phone": "13800138000",
"subject": "API 使用咨询",
"message": "请问如何批量处理多个文件?"
}
)
print(resp.json())
# {"success":true,"message":"感谢您的留言,我们会尽快回复!","contactId":"cms..."}
# — 方式2:FormData(带附件)—
resp = requests.post(
"https://www.binwindai.com/api/contact",
data={
"name": "张三",
"email": "zhangsan@example.com",
"subject": "Bug 反馈",
"message": "处理大文件时超时,详见截图"
},
files=[
("files", ("screenshot.png", open("screenshot.png", "rb"), "image/png"))
]
)
print(resp.json())
// — 方式1:JSON —
const resp = await fetch("https://www.binwindai.com/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "张三",
email: "zhangsan@example.com",
subject: "API 使用咨询",
message: "请问如何批量处理?"
})
});
const result = await resp.json();
if (result.success) {
console.log("提交成功,记录ID:", result.contactId);
}
// — 方式2:FormData + 附件 —
const form = new FormData();
form.append("name", "张三");
form.append("email", "zhangsan@example.com");
form.append("subject", "Bug 反馈");
form.append("message", "详见附件");
form.append("files", new Blob([fs.readFileSync("screenshot.png")]), "screenshot.png");
const resp2 = await fetch("https://www.binwindai.com/api/contact", {
method: "POST",
body: form
});
console.log(await resp2.json());
// — 方式1:JSON —
const resp = await fetch("https://www.binwindai.com/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "张三",
email: "zhangsan@example.com",
subject: "API 使用咨询",
message: "请问如何批量处理?"
})
});
const { success, message, contactId } = await resp.json();
console.log(success ? "✓ 提交成功" : "✗ " + message);
// — 方式2:FormData + 附件 —
const form = new FormData();
form.append("name", "张三");
form.append("email", "zhangsan@example.com");
form.append("subject", "Bug 反馈");
form.append("message", "详见附件");
// 从 <input type="file" multiple> 添加附件
const fileInput = document.getElementById("myFileInput");
for (const file of fileInput.files) {
form.append("files", file);
}
const resp2 = await fetch("https://www.binwindai.com/api/contact", {
method: "POST",
body: form // 不要手动设 Content-Type
});
console.log(await resp2.json());
| 状态码 | 原因 | 解决方法 |
|---|---|---|
| 301 | 用了 HTTP 没加 S | 把 http:// 改成 https:// |
| 400 | 缺少必填参数、或参数格式不对 | 检查 file 是否上传、name/email/subject/message 是否都填了 |
| 500 | 服务器处理异常 | 稍后重试,如持续失败请联系技术支持 |
/api/stretch 每次只处理一个文件,多文件请写循环逐个调用X123、X12.3、X-12.3、x123(大小写均可)/api/contact 提交(可带附件截图)