Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package me.chanjar.weixin.common.bean.ocr;

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;

import java.io.Serializable;
import java.util.List;

/**
* OCR菜单识别结果.
*
* @author GitHub Copilot
*/
@Data
public class WxOcrMenuResult implements Serializable {
private static final long serialVersionUID = -8062516251827437945L;

@SerializedName("img_size")
private WxOcrImgSize imgSize;
@SerializedName("items")
private List<Items> items;

public static WxOcrMenuResult fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxOcrMenuResult.class);
}

@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}

@Data
public static class Items implements Serializable {
private static final long serialVersionUID = 3066181677009102792L;

@SerializedName("text")
private String text;
@SerializedName("pos")
private WxOcrPos pos;

@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingLicenseResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrIdCardResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrMenuResult;

import java.io.File;

Expand Down Expand Up @@ -130,4 +131,22 @@ public interface WxOcrService {
* @throws WxErrorException .
*/
WxOcrCommResult comm(File imgFile) throws WxErrorException;

/**
* 菜单OCR识别接口
* 文件大小限制:小于2M
* @param imgUrl 图片url地址
* @return WxOcrMenuResult
* @throws WxErrorException .
*/
WxOcrMenuResult menu(String imgUrl) throws WxErrorException;

/**
* 菜单OCR识别接口
* 文件大小限制:小于2M
* @param imgFile 图片文件对象
* @return WxOcrMenuResult
* @throws WxErrorException .
*/
WxOcrMenuResult menu(File imgFile) throws WxErrorException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,23 @@ public WxOcrCommResult comm(File imgFile) throws WxErrorException {
FILE_COMM, imgFile);
return WxOcrCommResult.fromJson(result);
}

@Override
public WxOcrMenuResult menu(String imgUrl) throws WxErrorException {
try {
imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// ignore cannot happen
}

final String result = this.service.post(String.format(MENU, imgUrl), (String) null);
return WxOcrMenuResult.fromJson(result);
}

@Override
public WxOcrMenuResult menu(File imgFile) throws WxErrorException {
String result = this.service.execute(OcrDiscernRequestExecutor.create(this.service.getRequestHttp()),
FILE_MENU, imgFile);
return WxOcrMenuResult.fromJson(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ public interface Ocr {
String FILE_BIZ_LICENSE = "https://api.weixin.qq.com/cv/ocr/bizlicense";
String COMM = "https://api.weixin.qq.com/cv/ocr/comm?img_url=%s";
String FILE_COMM = "https://api.weixin.qq.com/cv/ocr/comm";
String MENU = "https://api.weixin.qq.com/cv/ocr/menu?img_url=%s";
String FILE_MENU = "https://api.weixin.qq.com/cv/ocr/menu";
}

public interface Product {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,24 @@ public WxOcrCommResult comm(File imgFile) throws WxErrorException {
FILE_COMM.getUrl(this.mainService.getWxMpConfigStorage()), imgFile);
return WxOcrCommResult.fromJson(result);
}

@Override
public WxOcrMenuResult menu(String imgUrl) throws WxErrorException {
try {
imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// ignore cannot happen
}

final String result = this.mainService.post(String.format(MENU.getUrl(this.mainService.getWxMpConfigStorage()),
imgUrl), (String) null);
return WxOcrMenuResult.fromJson(result);
}

@Override
public WxOcrMenuResult menu(File imgFile) throws WxErrorException {
String result = this.mainService.execute(OcrDiscernRequestExecutor.create(this.mainService.getRequestHttp()),
FILE_MENU.getUrl(this.mainService.getWxMpConfigStorage()), imgFile);
return WxOcrMenuResult.fromJson(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,17 @@ enum Ocr implements WxMpApiUrl {
/**
* 通用印刷体OCR识别(文件)
*/
FILE_COMM(API_DEFAULT_HOST_URL, "/cv/ocr/comm");
FILE_COMM(API_DEFAULT_HOST_URL, "/cv/ocr/comm"),

/**
* 菜单OCR识别
*/
MENU(API_DEFAULT_HOST_URL, "/cv/ocr/menu?img_url=%s"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use a supported OCR endpoint

The server-side WeChat OCR API set exposes the license-plate recognizer as /cv/ocr/platenum; menu is a mini-program OCR plugin certificateType, not a cv/ocr/menu REST endpoint. With this URL, both new menu(String) and menu(File) calls in MP (and the mirrored MiniApp constants) will post to an unsupported path, so users trying this added SDK method will get API errors rather than menu OCR results.

Useful? React with 👍 / 👎.


/**
* 菜单OCR识别(文件)
*/
FILE_MENU(API_DEFAULT_HOST_URL, "/cv/ocr/menu");

private final String prefix;
private final String path;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingLicenseResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrIdCardResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrMenuResult;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;

Expand Down Expand Up @@ -137,6 +138,22 @@ public void testComm2() throws Exception {
System.out.println(result);
}

@Test
public void testMenu() throws WxErrorException {
final WxOcrMenuResult result = this.service.getOcrService().menu("https://res.wx.qq.com/op_res/apCy0YbnEdjYsa_cjW6x3FlpCc20uQ-2BYE7aXnFsrB-ALHZNgdKXhzIUcrRnDoL");
assertThat(result).isNotNull();
System.out.println(result);
}

@Test
public void testMenu2() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg");
File tempFile = FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), TestConstants.FILE_JPG);
final WxOcrMenuResult result = this.service.getOcrService().menu(tempFile);
assertThat(result).isNotNull();
System.out.println(result);
}

private InputStream getImageStream(String url) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
Expand Down Expand Up @@ -390,5 +407,46 @@ public void testComm() throws Exception {
assertThat(result).isNotNull();
System.out.println(result);
}

@Test
public void testMenu() throws Exception {
String returnJson = "{\n" +
" \"errcode\": 0, \n" +
" \"errmsg\": \"ok\", \n" +
" \"items\": [\n" +
" {\n" +
" \"text\": \"红烧肉\", \n" +
" \"pos\": {\n" +
" \"left_top\": {\n" +
" \"x\": 575, \n" +
" \"y\": 519\n" +
" }, \n" +
" \"right_top\": {\n" +
" \"x\": 744, \n" +
" \"y\": 519\n" +
" }, \n" +
" \"right_bottom\": {\n" +
" \"x\": 744, \n" +
" \"y\": 532\n" +
" }, \n" +
" \"left_bottom\": {\n" +
" \"x\": 573, \n" +
" \"y\": 532\n" +
" }\n" +
" }\n" +
" }\n" +
" ], \n" +
" \"img_size\": {\n" +
" \"w\": 1280, \n" +
" \"h\": 720\n" +
" }\n" +
"}";
when(wxService.post(anyString(), anyString())).thenReturn(returnJson);
final WxMpOcrServiceImpl wxMpOcrService = new WxMpOcrServiceImpl(wxService);

final WxOcrMenuResult result = wxMpOcrService.menu("abc");
assertThat(result).isNotNull();
System.out.println(result);
}
}
}