证件照制作 API 实战:网站如何自动生成合规证件照

0 阅读8分钟

在很多业务场景中,证件照自动生成已经成为刚需能力,比如:

  • 报名系统自动生成证件照
  • 招聘/考试平台用户照片规范化
  • 小程序一键生成证件照
  • 出海产品 Photo ID 自动处理

如果完全手写图像处理算法,成本非常高。因此现在更主流的方案是:

👉 通过证件照制作 API,实现全自动合规生成

这篇文章带你从 0 到 1 搭建完整流程,并给出可直接落地的接入思路。

证件照换衣服3-2.jpg


一、证件照自动生成的核心难点

很多人以为证件照制作只是「裁剪 + 换底色 + 换衣服」,但真实线上系统远不止如此。 一个合规证件照通常要解决以下问题:

✅ 人像检测必须精准

如果定位不准,很容易出现:

  • 裁到头顶
  • 人脸偏移
  • 多人误识别

这一步直接决定后续全部质量。


✅ 智能裁剪与比例控制

不同证件照规格要求非常严格,例如:

  • 一寸 / 二寸
  • 各国签证尺寸
  • 不同考试报名规格

系统需要自动保证:

  • 头部占比正确
  • 人脸居中
  • 上下留白合规

👉 这也是很多前端手动裁剪方案翻车的原因。


✅ 高质量背景替换(发丝级抠图)

用户上传的照片往往背景复杂:

  • 家庭环境
  • 光线不均
  • 背景杂乱

如果抠图不干净,会直接影响通过率。

合格方案需要做到:

  • 发丝级边缘
  • 无白边
  • 无锯齿
  • 自然融合

✅ 合规性检测(很多团队会忽略)

在真实业务中,还经常需要自动判断:

  • 是否多人
  • 是否遮挡
  • 是否模糊
  • 是否过曝

否则用户提交后仍然会被人工审核打回。


二、推荐的自动化技术流程

一个成熟的网站自动生成流程通常是:

用户上传照片
   ↓
人脸检测
   ↓
智能抠图
   ↓
背景替换
   ↓
尺寸裁剪
   ↓
合规检测
   ↓
返回标准证件照

如果全部自研,通常需要:

  • 人脸算法
  • 抠图模型
  • 图像处理链路
  • 各国规格库

👉 完整开发周期往往 ≥ 3–6 个月

因此,大多数团队会选择直接接入成熟 API。


三、快速接入证件照制作 API(实战)

下面给出一个通用接入流程,可直接嵌入:

  • 网站
  • 小程序
  • App
  • SaaS 系统

Step 1:前端上传照片

最简单的方式:

<input type="file" id="upload" />

你也可以替换成现有上传组件。


Step 2:调用证件照制作 API

如果你正在做系统集成,可以参考完整的接口文档(含多语言示例),通常几分钟即可跑通。

👉 接口文档地址:www.shiliuai.com/api/zhengji…

image.png

Python 示例

# -*- coding: utf-8 -*-
import requests
import base64
import cv2
import json
import numpy as np

api_key = '******'  # 你的API KEY
file_path = '...'  # 图片路径

with open(file_path, 'rb') as fp:
    photo_base64 = base64.b64encode(fp.read()).decode('utf8')

url = 'https://api.shiliuai.com/api/id_photo/v1'
headers = {'APIKEY': api_key, "Content-type": "application/json"}
data = {
    "base64": photo_base64,
    "bgColor": "FFFFFF",
    "dpi": 300,
    "mmHeight": 35,
    "mmWidth": 25
}

response = requests.post(url=url, headers=headers, json=data)
response = json.loads(response.content)
"""
成功:{'code': 0, 'msg': 'OK', 'msg_cn': '成功', 'id': id, 'result_base64': result_base64}
or
失败:{'code': error_code, 'msg': error_msg, 'msg_cn': 错误信息}
"""
result_base64 = response.get('result_base64', '')
img_id = response.get('id', '')
file_bytes = base64.b64decode(result_base64) if result_base64 else b''
if file_bytes:
    with open('result.jpg', 'wb') as f:
        f.write(file_bytes)

    image = np.asarray(bytearray(file_bytes), dtype=np.uint8)
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    cv2.imshow('result', image)
    cv2.waitKey(0)

# 同一张图片,参数改变,再次请求(复用 id)
data2 = {
    "id": img_id,
    "bgColor": "FF0000",
    "dpi": 300,
    "pxHeight": 640,
    "pxWidth": 480
}
response2 = requests.post(url=url, headers=headers, json=data2)
response2 = json.loads(response2.content)

java 示例

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.Base64;
import org.json.JSONObject;

public class IDPhotoAPIExample {

    public static void main(String[] args) {
        String apiKey = "******"; // 你的API KEY
        String filePath = "path/to/your/image.jpg"; // 图片路径

        try {
            // 读取图片并编码为 Base64
            byte[] fileBytes = Files.readAllBytes(new File(filePath).toPath());
            String photoBase64 = Base64.getEncoder().encodeToString(fileBytes);

            // API 请求的 URL
            String apiUrl = "https://api.shiliuai.com/api/id_photo/v1";

            // 请求参数 (初次请求)
            JSONObject requestData = new JSONObject();
            requestData.put("base64", photoBase64);
            requestData.put("bgColor", "FFFFFF");
            requestData.put("dpi", 300);
            requestData.put("mmHeight", 35);
            requestData.put("mmWidth", 25);

            // 发送 POST 请求
            JSONObject response = sendPostRequest(apiUrl, apiKey, requestData);

            // 检查响应是否成功
            if (response.getInt("code") == 0) {
                String resultBase64 = response.getString("result_base64");
                String id = response.getString("id");

                // 解码并保存图片
                byte[] resultBytes = Base64.getDecoder().decode(resultBase64);
                try (FileOutputStream fos = new FileOutputStream("result.jpg")) {
                    fos.write(resultBytes);
                }

                System.out.println("图片生成成功,文件已保存为 result.jpg");

                // 同一张图片,参数改变,再次请求
                JSONObject newRequestData = new JSONObject();
                newRequestData.put("id", id);
                newRequestData.put("bgColor", "FF0000");
                newRequestData.put("dpi", 300);
                newRequestData.put("pxHeight", 640);
                newRequestData.put("pxWidth", 480);

                // 发送新的请求
                JSONObject newResponse = sendPostRequest(apiUrl, apiKey, newRequestData);
                if (newResponse.getInt("code") == 0) {
                    String newResultBase64 = newResponse.getString("result_base64");
                    byte[] newResultBytes = Base64.getDecoder().decode(newResultBase64);
                    try (FileOutputStream fos = new FileOutputStream("result_red_bg.jpg")) {
                        fos.write(newResultBytes);
                    }
                    System.out.println("参数改变后的图片生成成功,文件已保存为 result_red_bg.jpg");
                } else {
                    System.out.println("新的请求失败: " + newResponse.getString("msg_cn"));
                }

            } else {
                System.out.println("初次请求失败: " + response.getString("msg_cn"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 发送 POST 请求
    private static JSONObject sendPostRequest(String urlStr, String apiKey, JSONObject jsonData) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("APIKEY", apiKey);
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setDoOutput(true);

        // 写入请求数据
        try (OutputStream os = conn.getOutputStream()) {
            byte[] input = jsonData.toString().getBytes("utf-8");
            os.write(input, 0, input.length);
        }

        // 读取响应
        StringBuilder response = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) {
            String responseLine;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
        }

        return new JSONObject(response.toString());
    }
}

JavaScript 示例

const fs = require('fs');
const fetch = require('node-fetch'); // 需安装:npm install node-fetch

const apiKey = '******'; // 你的API KEY
const filePath = 'path/to/your/image.jpg'; // 图片路径

(async () => {
  try {
    // 读取图片并编码为 Base64
    const fileBuffer = fs.readFileSync(filePath);
    const photoBase64 = fileBuffer.toString('base64');

    // API 请求的 URL
    const apiUrl = 'https://api.shiliuai.com/api/id_photo/v1';

    // 请求参数 (初次请求)
    const requestData = {
      base64: photoBase64,
      bgColor: "FFFFFF",
      dpi: 300,
      mmHeight: 35,
      mmWidth: 25
    };

    // 发送 POST 请求
    let response = await fetch(apiUrl, {
      method: 'POST',
      headers: {
        'APIKEY': apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(requestData)
    });

    let responseData = await response.json();

    // 检查响应是否成功
    if (responseData.code === 0) {
      const resultBase64 = responseData.result_base64;
      const id = responseData.id;

      // 解码并保存图片
      const resultBuffer = Buffer.from(resultBase64, 'base64');
      fs.writeFileSync('result.jpg', resultBuffer);
      console.log("图片生成成功,文件已保存为 result.jpg");

      // 同一张图片,参数改变,再次请求
      const newRequestData = {
        id: id,
        bgColor: "FF0000",
        dpi: 300,
        pxHeight: 640,
        pxWidth: 480
      };

      response = await fetch(apiUrl, {
        method: 'POST',
        headers: {
          'APIKEY': apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(newRequestData)
      });

      responseData = await response.json();

      if (responseData.code === 0) {
        const newResultBase64 = responseData.result_base64;
        const newResultBuffer = Buffer.from(newResultBase64, 'base64');
        fs.writeFileSync('result_red_bg.jpg', newResultBuffer);
        console.log("参数改变后的图片生成成功,文件已保存为 result_red_bg.jpg");
      } else {
        console.error("新的请求失败:", responseData.msg_cn);
      }

    } else {
      console.error("初次请求失败:", responseData.msg_cn);
    }
  } catch (error) {
    console.error("发生错误:", error);
  }
})();

Step 3:展示生成结果

接口一般会返回:

  • 标准证件照 base64的图片
  • 排版证件照 base64的图片
  • 合规检测结果
  • 接口返回码,返回信息,id等 以下是示例返回结果
{
  "code": 0,
  "msg": "OK",
  "msg_cn": "成功",
  "id": "xxxxxx",
  "result_base64": "/9j/4AAQSkZJRgABAQAAAQABAAD...(省略)",
  "layout_base64": "/9j/4AAQSkZJRgABAQAAAQABAAD...(可选,layout==1 时返回)",
  "info": {
    "qualified": true,
    "msg": "OK",
    "msg_cn": "合规",
    "width": 295,
    "height": 413
  },
  "advanced_info": {
    "qualified": true,
    "msg": "OK",
    "msg_cn": "高级合规"
  },
  "request_id": "req_xxxxxxxx"
}

建议保存返回的图片后,前端展示即可:

<img src="返回的证件照URL" />

到这里,一个最小可用版本就已经跑通了。


四、实战中最常见的 3 个坑

如果你准备自己做,这几类问题几乎必遇。


❗ 坑 1:前端裁剪 ≠ 合规证件照

很多团队早期方案是:

  • canvas 裁剪
  • 用户手动拖拽

上线后常见问题:

  • 头部比例不对
  • 人脸不居中
  • 审核不过

👉 证件照必须依赖人脸比例算法,而不是纯前端裁图。


❗ 坑 2:通用抠图达不到证件照标准

普通抠图常见问题:

  • 发丝断裂
  • 白边明显
  • 背景溢色

证件照对边缘要求比电商抠图更严格。


❗ 坑 3:不同国家/规格维护成本极高

例如:

  • 中国一寸
  • 美国签证
  • 日本证件照

尺寸 + 头部比例都不同。

👉 如果不想自己维护规格库,建议直接使用内置多规格的证件照 API,会省掉大量适配成本。


五、在线体验 vs API 接入怎么选?

很多团队在这里会犹豫,其实可以这样判断:


✅ 如果你是普通用户

建议先用在线工具快速生成一张,确认效果是否满足需求。

如果你只是想测试效果,可以直接体验在线生成:

👉 在线体验(无需注册): www.shiliuai.com/zhengjianzh…


✅ 如果你是开发者 / 平台方

更推荐直接接入 API,可以实现:

  • 批量自动生成
  • 嵌入业务流程
  • 降低人工审核成本
  • 提升用户转化率

六、一个更稳的落地路径(实战经验)

很多成熟项目的推进路径是:

1️⃣ 先用在线工具验证效果
2️⃣ 再接入 API 自动化
3️⃣ 最后接入业务闭环

这样风险和试错成本最低。

七、最后补充

证件照自动生成看起来简单,但真正商用落地,核心在三点:

  • 人脸比例是否准确
  • 抠图是否干净
  • 是否符合各类证件规范

选对方案,通常可以帮团队节省 数周到数月 的开发时间。

如果你的项目涉及:

  • 报名系统
  • 招聘平台
  • 教育系统
  • 出海工具站
  • AI 图像处理产品

证件照自动生成基本都会成为一个高频能力模块,建议尽早自动化。