📂
拖拽文件或文件夹到此处
支持任意文本格式 · 自动识别坐标 · 无坐标文件将标记为无效
⚠ 未选择本地目录 文件将保存到浏览器默认下载文件夹,保持原文件夹结构。 点击「📂 选择目录」指定保存位置(仅限 Chrome/Edge 浏览器)。
X 轴系数
所有 X 坐标 × 此值
Y 轴系数
所有 Y 坐标 × 此值
拉伸基准:
总坐标数
变更坐标
X 平均变化
Y 平均变化
📋 变更明细
行号X 原始X 涨缩后X 变化Y 原始Y 涨缩后Y 变化原文涨缩后
▸ 查看源文件 / 涨缩结果对比
📄 源文件
📝 涨缩结果

📖 帮助与操作手册

📐 工具简介

PCB 坐标文件(钻带/锣带/Gerber/钻孔等)中的坐标进行涨缩处理。根据 X/Y 轴系数,对所有坐标等比缩放。原始文件不会被修改

🚀 快速开始

1 拖拽文件或文件夹到虚线框内
2 检查 X/Y 系数,可选切换拉伸基准(原点/中心)
3 可选:设置输出目录
4 点击「批量涨缩」
5 查看变更明细,确认后下载

📂 支持的文件

任意文本格式,自动扫描 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关闭帮助

⚠️ 注意

  • 大文件分片处理,页面不卡死
  • 坐标取整:普通坐标用银行家舍入(.5 归偶,大批量统计无偏),中心拉伸与阵列 M02 偏移用四舍五入;均保留原始位数格式
  • 关闭浏览器前及时下载结果
👋 有疑问?点我问小钻
💬 小钻 · 智能客服
你好!我是PCB坐标涨缩工具的智能客服。试试点击下方快捷提问,或直接输入问题。

📡 API 开发者文档

📖 概述

项目说明
接口地址https://www.binwindai.com
协议仅 HTTPS(HTTP 自动 301 跳转)
认证无需认证,开放使用
请求体上限50 MB
跨域支持 CORS,浏览器可直接调用

POST /api/stretch   PCB坐标涨缩处理

上传一个 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.00022X 轴缩放系数,所有 X 坐标 × 此值
y_factor可选数字1.00008Y 轴缩放系数,所有 Y 坐标 × 此值
mode可选stringoriginorigin=原点拉伸,center=中心拉伸
center_x_mm条件必填floatmode=center时必填,板中心X坐标(毫米),自动按文件刻度换算
center_y_mm条件必填floatmode=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取反) 不换轴,可精确保留在阵列块内。

📤 成功时(200)

直接返回处理后的文件内容,浏览器会自动下载。文件名格式:原文件名-x1.00022y1.00008.扩展名(中心模式另加 _c-cx312mm_cy364mm;保留上传时的原始文件名)

📤 失败时(400 / 500)

{"error": "错误原因描述"}

💻 curl 示例

# 基本用法
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

💻 Python 示例

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
)

💻 Node.js 示例

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");}

💻 浏览器 JavaScript 示例

// 假设用户通过 <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);}

🔍 坐标识别规则

  • 匹配模式:字母 XY(大小写均可)后面跟数字
  • 举例:X00123450 → 取值 123450 → ×1.00022 → 四舍五入 → X00123477
  • 举例:X12.345 → 取值 12.345 → ×1.00022 → 保留3位小数 → X12.348
  • 举例:Y-12.345 → 支持负数
  • 非坐标指令(G90、M30、%FS 等)和注释保持原样不修改

📐 输出文件名举例

input.g7r   →  input-x1.00022y1.00008.g7r
PCB123.drl  →  PCB123-x1.5y1.5.drl
test.txt    →  test-x2.0y2.0.txt

POST /api/contact   联系表单

提交咨询或反馈,支持 JSONFormData 两种方式。成功后自动发邮件通知并存入数据库。

🔗 接口地址

POST https://www.binwindai.com/api/contact
Content-Type: application/json  或  multipart/form-data

📥 参数

参数名必填类型说明
name必填字符串联系人姓名
email必填字符串联系邮箱(管理员直接回复此地址)
subject必填字符串主题(最长200字)
message必填字符串详细内容(最长5000字)
phone可选字符串联系电话
files可选文件附件(可传多个,仅 FormData 模式)
html可选字符串自定义邮件 HTML 正文(不传则自动生成)

📤 成功响应(200)

{
  "success": true,
  "message": "感谢您的留言,我们会尽快回复!",
  "contactId": "cmsfvt5w50004p47evptry1m8"
}

📤 失败响应(400 / 500)

{"error": "请填写姓名、邮箱、主题和留言内容"}

💻 curl 示例 — JSON 方式

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 示例 — FormData 方式(可传附件)

# 基本表单
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"

💻 Python 示例

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())

💻 Node.js 示例

// — 方式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());

💻 浏览器 JavaScript 示例

// — 方式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 没加 Shttp:// 改成 https://
400缺少必填参数、或参数格式不对检查 file 是否上传、name/email/subject/message 是否都填了
500服务器处理异常稍后重试,如持续失败请联系技术支持

💡 实用建议

  • 批量处理:/api/stretch 每次只处理一个文件,多文件请写循环逐个调用
  • 超时设置:建议客户端超时 30 秒,大文件处理需要时间
  • 重试机制:遇到 500 错误建议重试 2 次,间隔 1 秒
  • 文件编码:用 UTF-8 编码上传,其他编码可能导致中文注释乱码(不影响坐标处理)
  • 坐标格式:支持 X123X12.3X-12.3x123(大小写均可)
  • 非坐标文本:非坐标指令和注释不会被修改
  • 安全问题:所有用户输入都会做转义处理,上传文件处理后自动清理

📞 技术支持

  • 📧 邮箱:1142729224@qq.com
  • 📞 电话:19237446050
  • 🐛 反馈问题:直接调用 /api/contact 提交(可带附件截图)