表格OCR API 簡介
概念解釋
表格識別:基于深度學(xué)習(xí)技術(shù),自動定位并識別圖片中表格的位置、結(jié)構(gòu)及文字內(nèi)容,結(jié)構(gòu)化返回可編輯的表格結(jié)果。支持用戶上傳報表、帶有表格的圖片等。
說明
Hi,您好,歡迎使用有道智云表格識別API接口服務(wù)。
本文檔主要針對需要集成API的技術(shù)開發(fā)工程師,詳細(xì)描述表格識別能力相關(guān)的技術(shù)內(nèi)容。
如果您想快速體驗服務(wù),建議您前往 體驗中心 或者在體驗中心右下側(cè)找到小程序二維碼,掃描進(jìn)行體驗。
如果您有與我們商務(wù)合作的需求,可以通過以下方式聯(lián)系我們:
商務(wù)郵箱: AIcloud_Business@corp.youdao.com
如果您對文檔內(nèi)容有任何疑問,可以通過以下幾種方式聯(lián)系我們:
客服QQ:1906538062
智云OCR技術(shù)交流QQ 1群: 654064748
智云OCR技術(shù)交流QQ 2群: 471638046
聯(lián)系郵箱: zhiyun@corp.youdao.com
溫馨提示:
接口說明
表格OCR API HTTPS地址:
https://openapi.youdao.com/ocr_table
協(xié)議須知
調(diào)用方在集成表格識別OCR API時,請遵循以下規(guī)則。
| 規(guī)則 | 描述 | 
| 傳輸方式 | HTTPS | 
| 請求方式 | POST | 
| 字符編碼 | 統(tǒng)一使用UTF-8編碼 | 
| 請求格式 | 表單 | 
| 響應(yīng)格式 | JSON | 
接口調(diào)用參數(shù)
調(diào)用API需要向接口發(fā)送以下字段來訪問服務(wù)。
| 字段名 | 類型 | 含義 | 必填 | 備注 | 
| q | text | 要識別的圖片,需要Base64編碼 | True | UTF-8編碼 | 
| type | text | 圖片類型,Base64編碼 | True | 1 | 
| appKey | text | 應(yīng)用ID | True | 可在 應(yīng)用管理 查看 | 
| salt | text | UUID,和curtime一起防請求重放 | True | uuid,唯一通用識別碼 | 
| sign | text | 簽名 | True | sha256(應(yīng)用ID+input+salt+curtime+密鑰) | 
| docType | text | 服務(wù)器響應(yīng)類型,目前支持json和Excel | True | json | 
| signType | text | 簽名類型 | true | v3 | 
| curtime | text | 當(dāng)前UTC時間戳(秒) | true | TimeStamp | 
| angle | text | 是否進(jìn)行360角度識別 | false | 0:不識別,1:識別,默認(rèn)不識別(0) | 
簽名生成方法如下:
signType=v3;
sign=sha256(應(yīng)用ID+input+salt+curtime+應(yīng)用密鑰)。
其中,input的計算方式為:input=q前10個字符 + q長度 + q后10個字符(當(dāng)q長度大于20)或 input=q字符串(當(dāng)q長度小于等于20)。
不同語言獲取時間戳,請參看 此鏈接
如果對簽名有疑問,可以參看文檔末尾各語言demo。
如果圖片有傾斜,需要調(diào)用時增加角度檢測參數(shù),以獲得更好的效果。
docType為excel時,返回json的字段中是excel的base64
輸出結(jié)果
返回的結(jié)果是json格式,具體說明如下:
| 字段 | 含義 | 
| errorCode | 識別結(jié)果錯誤碼,一定存在 | 
| Result | 識別結(jié)果,如果docType是excel則返回excel的base64字符串 | 
| -orientation | 圖片方向 | 
| -tables | 表格excel,使用base64編碼后的結(jié)果 | 
返回的結(jié)果是json格式,具體說明如下:
| 字段 | 含義 | 
| errorCode | 識別結(jié)果錯誤碼,一定存在 | 
| Result | 識別結(jié)果,如果docType是excel則返回excel的base64字符串 | 
| -orientation | 圖片方向 | 
| -tables | 返回的表格,如果一張圖像中有多個表格,返回多個 | 
| --cells | 表格中的單元格 | 
| --rowRange | 單元格行號的范圍,如果當(dāng)前行存在單元格合并情況,兩個值不同 | 
| --colRange | 單元格列號的范圍,如果當(dāng)前列存在單元格合并情況,兩個值不同 | 
| --boundingBox | 單元格文字的坐標(biāo) | 
| --dir | 單元格方向。h:水平 v:豎直 | 
| --lang | 文字種類 zh為中文 | 
| --lines | 單元格中的每一行 | 
| ---boundingBox | 行的坐標(biāo) | 
| ---text | 識別的行文字 | 
| ---words | 字級別組 | 
| ----word | 識別的文字 | 
| ----boundingBox | 字的坐標(biāo) | 
即識別結(jié)果主要在Result中,輸出結(jié)構(gòu)為:regions->lines->words。一個文檔可能有多個region,代表段落,一個段落有多行,一行有多個字。
每個段落、每行、每個字都有boundingBox,代表能夠框住段落、行、字的最大box的位置信息。
boundingBox共八個值:分別是左上角坐標(biāo)(x,y),右上角坐標(biāo)(x,y),右下角坐標(biāo)(x,y),左下角(x,y)
參考示例
{  
       "errorCode":"0",   #返回狀態(tài) 如果成功, 返回0
       "Result":"{
			"orientation":"UP",#圖片方向
                        "tables":["UEsDBBQ ... ... AsAxQIAAOQ1AAA=="]# 表格excel,使用base64編碼后的結(jié)果
                 }"
}
{  
       "errorCode":"0",   #返回狀態(tài) 如果成功, 返回0
       "Result":"   {        #如果沒有錯誤,返回識別的內(nèi)容
          "orientation":"UP",#圖片方向
          "tables":[         #返回的表格,如果一張圖像中有多個表格,返回多個
                {"cells":[      #表格中的單元格
                   {  
                      "rowRange":"0,0", #單元格行號的范圍,如果當(dāng)前行存在單元格合并情況,兩個值不同
                      "colRange":"0,0", #單元格列號的范圍,如果當(dāng)前列存在單元格合并情況,兩個值不同
                      "boundingBox":"225,209,379,209,379,240,225,240", #單元格文字的bounding box
                      "dir":"h",   #方向 h水平 v豎直
                      "lang":"zh", #文字種類 zh為中文
                      "lines":[    #單元格中的每一行
                         {  
                            "boundingBox":"225,212,379,209,379,237,225,240", #行的坐標(biāo)
                            "text":"工程項目合同名稱", #行文字
                            "words":[               #每個文字
                               {  
                                  "word":"工",
                                  "boundingBox":"231,212,238,212,238,240,231,240" #每個字的包圍框
                               },
                               {  
                                  "word":"程",
                                  "boundingBox":"245,212,258,211,258,239,245,240"
                               },
                               ......
                            ]
                         }
                      ]
                   },
                   {  
                      "rowRange":"0,0",#單元格行號的范圍,如果當(dāng)前行存在單元格合并情況,兩個值不同
                      "colRange":"1,1",#單元格列號的范圍,如果當(dāng)前列存在單元格合并情況,兩個值不同
                      "boundingBox":"441,206,536,206,536,234,441,234",
                      "dir":"h",
                      "lang":"zh",
                      "lines":[  
                         {  
                            "boundingBox":"441,206,536,206,536,234,441,234",
                            "text":"金額",
                            "words":[  
                               {  
                                  "word":"金",
                                  "boundingBox":"454,206,461,206,..."
                                        ......
                                        }
                                    ]
                                }]
                            }
                        }
                        .....
服務(wù)配置
| 支持圖片格式 | 每小時最大請求次數(shù) | 
| jpg\png\bmp | 3600 | 
錯誤代碼列表
| 錯誤碼 | 含義 | 
| 101 | 缺少必填的參數(shù),首先確保必填參數(shù)齊全,然后,確認(rèn)參數(shù)書寫是否正確。 | 
| 102 | 不支持的語言類型 | 
| 103 | 翻譯文本過長 | 
| 104 | 不支持的API類型 | 
| 105 | 不支持的簽名類型 | 
| 106 | 不支持的響應(yīng)類型 | 
| 107 | 不支持的傳輸加密類型 | 
| 108 | 應(yīng)用ID無效,注冊賬號,登錄后臺創(chuàng)建應(yīng)用和實例并完成綁定,可獲得應(yīng)用ID和應(yīng)用密鑰等信息 | 
| 109 | batchLog格式不正確 | 
| 110 | 無相關(guān)服務(wù)的有效實例,應(yīng)用沒有綁定服務(wù)實例,可以新建服務(wù)實例,綁定服務(wù)實例。注:某些服務(wù)的結(jié)果發(fā)音需要tts實例,需要在控制臺創(chuàng)建語音合成實例綁定應(yīng)用后方能使用。 | 
| 111 | 開發(fā)者賬號無效 | 
| 112 | 請求服務(wù)無效 | 
| 113 | q不能為空 | 
| 114 | 不支持的圖片傳輸方式 | 
| 201 | 解密失敗,可能為DES,BASE64,URLDecode的錯誤 | 
| 202 | 簽名檢驗失敗,如果確認(rèn)應(yīng)用ID和應(yīng)用密鑰的正確性,仍返回202,一般是編碼問題。請確保 img為UTF-8編碼. | 
| 203 | 訪問IP地址不在可訪問IP列表 | 
| 205 | 請求的接口與應(yīng)用的平臺類型不一致,確保接入方式(Android SDK、IOS SDK、API)與創(chuàng)建的應(yīng)用平臺類型一致。如有疑問請參考入門指南 | 
| 206 | 因為時間戳無效導(dǎo)致簽名校驗失敗 | 
| 207 | 重放請求 | 
| 301 | 辭典查詢失敗 | 
| 302 | 翻譯查詢失敗 | 
| 303 | 服務(wù)端的其它異常 | 
| 304 | 會話閑置太久超時 | 
| 401 | 賬戶已經(jīng)欠費停 | 
| 402 | offlinesdk不可用 | 
| 411 | 訪問頻率受限,請稍后訪問 | 
| 412 | 長請求過于頻繁,請稍后訪問 | 
| 1001 | 無效的OCR類型 | 
| 1002 | 不支持的OCR image類型 | 
| 1003 | 不支持的OCR Language類型 | 
| 1004 | 識別圖片過大 | 
| 1201 | 圖片base64解密失敗 | 
| 1301 | OCR段落識別失敗 | 
| 1411 | 訪問頻率受限 | 
| 1412 | 超過最大識別字節(jié)數(shù) | 
| 2003 | 不支持的語言識別Language類型 | 
| 2004 | 合成字符過長 | 
| 2005 | 不支持的音頻文件類型 | 
| 2006 | 不支持的發(fā)音類型 | 
| 2201 | 解密失敗 | 
| 2301 | 服務(wù)的異常 | 
| 2411 | 訪問頻率受限,請稍后訪問 | 
| 2412 | 超過最大請求字符數(shù) | 
| 3001 | 不支持的語音格式 | 
| 3002 | 不支持的語音采樣率 | 
| 3003 | 不支持的語音聲道 | 
| 3004 | 不支持的語音上傳類型 | 
| 3005 | 不支持的語言類型 | 
| 3006 | 不支持的識別類型 | 
| 3007 | 識別音頻文件過大 | 
| 3008 | 識別音頻時長過長 | 
| 3009 | 不支持的音頻文件類型 | 
| 3010 | 不支持的發(fā)音類型 | 
| 3201 | 解密失敗 | 
| 3301 | 語音識別失敗 | 
| 3302 | 語音翻譯失敗 | 
| 3303 | 服務(wù)的異常 | 
| 3411 | 訪問頻率受限,請稍后訪問 | 
| 3412 | 超過最大請求字符數(shù) | 
| 4001 | 不支持的語音識別格式 | 
| 4002 | 不支持的語音識別采樣率 | 
| 4003 | 不支持的語音識別聲道 | 
| 4004 | 不支持的語音上傳類型 | 
| 4005 | 不支持的語言類型 | 
| 4006 | 識別音頻文件過大 | 
| 4007 | 識別音頻時長過長 | 
| 4201 | 解密失敗 | 
| 4301 | 語音識別失敗 | 
| 4303 | 服務(wù)的異常 | 
| 4411 | 訪問頻率受限,請稍后訪問 | 
| 4412 | 超過最大請求時長 | 
| 5001 | 無效的OCR類型 | 
| 5002 | 不支持的OCR image類型 | 
| 5003 | 不支持的語言類型 | 
| 5004 | 識別圖片過大 | 
| 5005 | 不支持的圖片類型 | 
| 5006 | 文件為空 | 
| 5201 | 解密錯誤,圖片base64解密失敗 | 
| 5301 | OCR段落識別失敗 | 
| 5411 | 訪問頻率受限 | 
| 5412 | 超過最大識別流量 | 
| 9001 | 不支持的語音格式 | 
| 9002 | 不支持的語音采樣率 | 
| 9003 | 不支持的語音聲道 | 
| 9004 | 不支持的語音上傳類型 | 
| 9005 | 不支持的語音識別 Language類型 | 
| 9301 | ASR識別失敗 | 
| 9303 | 服務(wù)器內(nèi)部錯誤 | 
| 9411 | 訪問頻率受限(超過最大調(diào)用次數(shù)) | 
| 9412 | 超過最大處理語音長度 | 
| 10001 | 無效的OCR類型 | 
| 10002 | 不支持的OCR image類型 | 
| 10004 | 識別圖片過大 | 
| 10201 | 圖片base64解密失敗 | 
| 10301 | OCR段落識別失敗 | 
| 10411 | 訪問頻率受限 | 
| 10412 | 超過最大識別流量 | 
| 11001 | 不支持的語音識別格式 | 
| 11002 | 不支持的語音識別采樣率 | 
| 11003 | 不支持的語音識別聲道 | 
| 11004 | 不支持的語音上傳類型 | 
| 11005 | 不支持的語言類型 | 
| 11006 | 識別音頻文件過大 | 
| 11007 | 識別音頻時長過長,最大支持30s | 
| 11201 | 解密失敗 | 
| 11301 | 語音識別失敗 | 
| 11303 | 服務(wù)的異常 | 
| 11411 | 訪問頻率受限,請稍后訪問 | 
| 11412 | 超過最大請求時長 | 
| 12001 | 圖片尺寸過大 | 
| 12002 | 圖片base64解密失敗 | 
| 12003 | 引擎服務(wù)器返回錯誤 | 
| 12004 | 圖片為空 | 
| 12005 | 不支持的識別圖片類型 | 
| 12006 | 圖片無匹配結(jié)果 | 
| 13001 | 不支持的角度類型 | 
| 13002 | 不支持的文件類型 | 
| 13003 | 表格識別圖片過大 | 
| 13004 | 文件為空 | 
| 13301 | 表格識別失敗 | 
| 15001 | 需要圖片 | 
| 15002 | 圖片過大(1M) | 
| 15003 | 服務(wù)調(diào)用失敗 | 
| 17001 | 需要圖片 | 
| 17002 | 圖片過大(1M) | 
| 17003 | 識別類型未找到 | 
| 17004 | 不支持的識別類型 | 
| 17005 | 服務(wù)調(diào)用失敗 | 
版本更新記錄
| 上線日期 | 版本號 | 更新內(nèi)容 | 
| 2019.04.15 | v1.0.0 | 表格識別API上線,支持自動識別表格位置、結(jié)構(gòu)及內(nèi)容,結(jié)構(gòu)化輸出可編輯的識別結(jié)果。 | 
常用語言Demo
Java 示例
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class OcrV3Demo {
    private static Logger logger = LoggerFactory.getLogger(OcrV3Demo.class);
    private static final String YOUDAO_URL = "https://openapi.youdao.com/ocr_table";
    private static final String APP_KEY = "您的應(yīng)用ID";
    private static final String APP_SECRET = "您的應(yīng)用密鑰";
    public static void main(String[] args) throws IOException {
        Map<String,String> params = new HashMap<String,String>();
        String q = loadAsBase64("圖片的路徑");
        String salt = String.valueOf(System.currentTimeMillis());
        String type = "1";
        params.put("type", type);
        params.put("q", q);
        params.put("docType", "json");
        params.put("signType", "v3");
        String curtime = String.valueOf(System.currentTimeMillis() / 1000);
        params.put("curtime", curtime);
        String signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET;
        String sign = getDigest(signStr);
        params.put("appKey", APP_KEY);
        params.put("salt", salt);
        params.put("sign", sign);
        String result = requestForHttp(YOUDAO_URL,params);
        /** 處理結(jié)果 */
        System.out.println(result);
    }
    public static String requestForHttp(String url,Map<String,String> params) throws IOException {
        String result = "";
        /** 創(chuàng)建HttpClient */
        CloseableHttpClient httpClient = HttpClients.createDefault();
        /** httpPost */
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
        Iterator<Map.Entry<String,String>> it = params.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<String,String> en = it.next();
            String key = en.getKey();
            String value = en.getValue();
            paramsList.add(new BasicNameValuePair(key,value));
        }
        httpPost.setEntity(new UrlEncodedFormEntity(paramsList,"UTF-8"));
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try{
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity,"UTF-8");
            EntityUtils.consume(httpEntity);
        }finally {
            try{
                if(httpResponse!=null){
                    httpResponse.close();
                }
            }catch(IOException e){
                logger.info("## release resouce error ##" + e);
            }
        }
        return result;
    }
    /**
     * 生成加密字段
     */
    public static String getDigest(String string) {
        if (string == null) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
    public static String loadAsBase64(String imgFile)
  {//將圖片文件轉(zhuǎn)化為字節(jié)數(shù)組字符串,并對其進(jìn)行Base64編碼處理
    File file = new File(imgFile);
    if(!file.exists()){
        logger.error("文件不存在");
        return null;
    }
    InputStream in = null;
    byte[] data = null;
      //讀取圖片字節(jié)數(shù)組
    try
    {
        in = new FileInputStream(imgFile);
        data = new byte[in.available()];
        in.read(data);
        in.close();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
      //對字節(jié)數(shù)組Base64編碼
    return Base64.getEncoder().encodeToString(data);//返回Base64編碼過的字節(jié)數(shù)組字符串
  }
  public static String truncate(String q) {
        if (q == null) {
            return null;
        }
        int len = q.length();
        String result;
        return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
    }
}
Python 示例
# -*- coding: utf-8 -*-
import sys
import uuid
import requests
import base64
import hashlib
import time
reload(sys)
sys.setdefaultencoding('utf-8')
YOUDAO_URL = 'https://openapi.youdao.com/ocr_table'
APP_KEY = '您的應(yīng)用ID'
APP_SECRET = '您的應(yīng)用密鑰'
def truncate(q):
    if q is None:
        return None
    q_utf8 = q.decode("utf-8")
    size = len(q_utf8)
    return q_utf8 if size <= 20 else q_utf8[0:10] + str(size) + q_utf8[size - 10:size]
def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()
def do_request(data):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    return requests.post(YOUDAO_URL, data=data, headers=headers)
def connect():
    f = open(r'圖片的路徑', 'rb')  # 二進(jìn)制方式打開圖文件
    q = base64.b64encode(f.read())  # 讀取文件內(nèi)容,轉(zhuǎn)換為base64編碼
    f.close()
    data = {}
    data['type'] = '1'
    data['q'] = q
    data['docType'] = 'json'
    data['signType'] = 'v3'
    curtime = str(int(time.time()))
    data['curtime'] = curtime
    salt = str(uuid.uuid1())
    signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET
    sign = encrypt(signStr)
    data['appKey'] = APP_KEY
    data['salt'] = salt
    data['sign'] = sign
    response = do_request(data)
    print response.content
if __name__ == '__main__':
    connect()
C# 示例
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace zhiyun_csharp_demo
{
    class OcrV3Demo
    {
        public static void Main()
        {
            Dictionary dic = new Dictionary();
            string url = "https://openapi.youdao.com/ocr_table";
            string q = LoadAsBase64("圖片的路徑");
            string appKey = "您的應(yīng)用ID";
            string appSecret = "您的應(yīng)用密鑰";
            string salt = DateTime.Now.Millisecond.ToString();
            string type = "1";
            dic.Add("type", type);
            dic.Add("docType", "json");
            dic.Add("signType", "v3");
            dic.Add("img", System.Web.HttpUtility.UrlEncode(q));
            TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            long millis = (long) ts.TotalMilliseconds;
            string curtime = Convert.ToString(millis / 1000);
            dic.Add("curtime", curtime);
            string signStr = appKey + Truncate(q) + salt + curtime + appSecret;;
            string sign = ComputeHash(signStr, new SHA256CryptoServiceProvider());
            dic.Add("appKey", appKey);
            dic.Add("salt", salt);
            dic.Add("sign", sign);
            string result = Post(url, dic);
            Console.WriteLine(result);
        }
        protected static string ComputeHash(string input, HashAlgorithm algorithm)
        {
          Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
          Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
          return BitConverter.ToString(hashedBytes).Replace("-", "");
        }
        protected static string Truncate(string q)
        {
            if (q == null)
            {
               return null;
            }
            int len = q.Length;
            return len <= 20 ? q : (q.Substring(0, 10) + len + q.Substring(len - 10, 10));
        }
        protected static string LoadAsBase64(string filename)
        {
            try
            {
                FileStream filestream = new FileStream(filename, FileMode.Open);
                byte[] arr = new byte[filestream.Length];
                filestream.Position = 0;
                filestream.Read(arr, 0, (int)filestream.Length);
                filestream.Close();
                return Convert.ToBase64String(arr);
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        protected static string Post(string url, Dictionary dic)
        {
            string result = "";
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            StringBuilder builder = new StringBuilder();
            int i = 0;
            foreach (var item in dic)
            {
                if (i > 0)
                    builder.Append("&");
                builder.AppendFormat("{0}={1}", item.Key, item.Value);
                i++;
            }
            byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
            req.ContentLength = data.Length;
            using (Stream reqStream = req.GetRequestStream())
            {
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();
            }
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            Stream stream = resp.GetResponseStream();
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
            {
                result = reader.ReadToEnd();
            }
            return result;
        }
    }
}
PHP 示例
<?php
define("CURL_TIMEOUT",   2000);
define("URL",            "https://openapi.youdao.com/ocr_table");
define("APP_KEY",        "您的應(yīng)用ID"); // 替換為您的應(yīng)用ID
define("SEC_KEY",        "您的應(yīng)用密鑰"); // 替換為您的密鑰
function do_request($q)
{
     $salt = create_guid();
     $args = array(
        'appKey' => APP_KEY,
        'salt' => $salt,
     );
     $type = '1';
     $args['type'] = $type;
     $args['q'] = $q;
     $args['docType'] = 'json';
     $args['signType'] = 'v3';
     $curtime = strtotime("now");
     $args['curtime'] = $curtime;
     $signStr = APP_KEY . truncate($q) . $salt . $curtime . SEC_KEY;
     $args['sign'] = hash("sha256", $signStr);
     $ret = call(URL, $args);
     print_r($ret);
     $ret = json_decode($ret, true);
     return $ret;
}
// 發(fā)起網(wǎng)絡(luò)請求
function call($url, $args=null, $method="post", $testflag = 0, $timeout = CURL_TIMEOUT, $headers=array())
{
    $ret = false;
    $i = 0;
    while($ret === false)
    {
        if($i > 1)
            break;
        if($i > 0)
        {
            sleep(1);
        }
         $ret = callOnce($url, $args, $method, false, $timeout, $headers);
         $i++;
    }
    return $ret;
}
function callOnce($url, $args=null, $method="post", $withCookie = false, $timeout = CURL_TIMEOUT, $headers=array())
{
    $ch = curl_init();
    if($method == "post")
    {
        $data = convert($args);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_POST, 1);
    }
    else
    {
        $data = convert($args);
        if($data)
        {
            if(stripos($url, "?") > 0)
            {
                 $url .= "&$data";
            }
            else
            {
                 $url .= "?$data";
            }
        }
    }
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if(!empty($headers))
    {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    if($withCookie)
    {
        curl_setopt($ch, CURLOPT_COOKIEJAR, $_COOKIE);
    }
    $r = curl_exec($ch);
    curl_close($ch);
    return $r;
}
function convert(&$args)
{
    $data = '';
    if (is_array($args))
    {
        foreach ($args as $key=>$val)
        {
            if (is_array($val))
            {
                foreach ($val as $k=>$v)
                {
                     $data .= $key.'['.$k.']='.rawurlencode($v).'&';
                }
            }
            else
            {
                     $data .="$key=".rawurlencode($val)."&";
            }
        }
        return trim($data, "&");
    }
    return $args;
}
// uuid generator
function create_guid(){
    $microTime = microtime();
    list($a_dec, $a_sec) = explode(" ", $microTime);
    $dec_hex = dechex($a_dec* 1000000);
    $sec_hex = dechex($a_sec);
    ensure_length($dec_hex, 5);
    ensure_length($sec_hex, 6);
    $guid = "";
    $guid .= $dec_hex;
    $guid .= create_guid_section(3);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= $sec_hex;
    $guid .= create_guid_section(6);
    return $guid;
}
function truncate($q) {
    $len = abslength($q);
    return $len <= 20 ? $q : (mb_substr($q, 0, 10) . $len . mb_substr($q, $len - 10, $len));
}
function abslength($str)
{
    if(empty($str)){
        return 0;
    }
    if(function_exists('mb_strlen')){
        return mb_strlen($str,'utf-8');
    }
    else {
        preg_match_all("/./u", $str, $ar);
        return count($ar[0]);
    }
}
function ensure_length(&$string, $length){
    $strlen = strlen($string);
    if($strlen < $length)
    {
         $string = str_pad($string, $length, "0");
    }
    else if($strlen > $length)
    {
         $string = substr($string, 0, $length);
    }
}
function create_guid_section($characters){
    $return = "";
    for($i = 0; $i < $characters; $i++)
    {
         $return .= dechex(mt_rand(0,15));
    }
    return $return;
}
// 輸入
$file = "圖片的路徑";
$fp = fopen($file, "r") or die("Can't open file");
// base64編碼
$q = base64_encode(fread($fp, filesize($file)));
fclose($fp);
do_request($q);
?>