Skip to content

Commit

Permalink
优化关键字定位,增加后缀匹配查询
Browse files Browse the repository at this point in the history
  • Loading branch information
humingzhang committed Dec 8, 2020
1 parent bb88910 commit 96bf00d
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,17 @@ public static List<KeywordPosition> getKeyWordPositionList(OFDReader reader, Str
for (String keyword : keywords) {
int textIndex = content.indexOf(keyword);
if (textIndex != -1) {
//完整包含关键字
addNormalKeyword(keyword, boundaryMapping, positionList, textCode, textIndex);
} else if (keyword.indexOf(content) == 0 && i != textCodeList.size() - 1) {
addBreakTextCodeList(keyword, boundaryMapping, textCodeList, positionList, i, textCode);
//前缀匹配关键字
addPrefixBreakTextCodeList(keyword, boundaryMapping, textCodeList, positionList, i, textCode);
} else {
int startIndex = checkPostfixMatch(content, keyword);
//后缀匹配关键字
if (startIndex != -1) {
addPostfixBreakTextCodeList(keyword, boundaryMapping, textCodeList, positionList, i, startIndex, textCode);
}
}
}
}
Expand All @@ -159,46 +167,96 @@ public static List<KeywordPosition> getKeyWordPositionList(OFDReader reader, Str
return positionList;
}


/**
* 检查后缀匹配
*
* @param content 待匹配文本
* @param keyword 关键字
* @return 是/否 匹配
*/
private static int checkPostfixMatch(String content, String keyword) {
int startIndex;
boolean match = true;
if ((startIndex = content.lastIndexOf(keyword.charAt(0))) != -1) {
for (int j = startIndex, k = 0; j < content.length(); j++, k++) {
if (content.charAt(j) != keyword.charAt(k)) {
match = false;
break;
}
}
}
return match ? startIndex : -1;
}

/**
* 处理后缀匹配断字断行文本定位关键字
*
* @param keyword 关键字字符串
* @param boundaryMapping 映射对象
* @param textCodeList 文本定位列表
* @param positionList 关键字位置列表
* @param textCodeIndex TextCode位置
* @param startIndex TextCode文本起始位置
* @param textCode 第一个文字定位
*/
private static void addPostfixBreakTextCodeList(String keyword, Map<TextCode, KeywordResource> boundaryMapping, List<TextCode> textCodeList,
List<KeywordPosition> positionList, int textCodeIndex, int startIndex, TextCode textCode) {
//文字定位合并列表
List<TextCode> mergeTextCodeList = new ArrayList<>();
//加入合并列表
mergeTextCodeList.add(textCode);
//匹配下一个字
searchNextText(keyword, textCodeList, mergeTextCodeList, boundaryMapping, textCodeIndex, textCode.getContent().substring(startIndex), textCode);
if (mergeTextCodeList.size() > 1) {
mergeKeywordPosition(keyword, startIndex, positionList, mergeTextCodeList, boundaryMapping);
}

}

/**
* 处理段字断行文本定位关键字
* 处理前缀匹配断字断行文本定位关键字
*
* @param keyword 关键字字符串
* @param boundaryMapping 映射对象
* @param textCodeList 文本定位列表
* @param positionList 关键字位置列表
* @param start 定位起始位置
* @param textCodeIndex 定位起始位置
* @param textCode 第一个文字定位
*/
private static void addBreakTextCodeList(String keyword, Map<TextCode, KeywordResource> boundaryMapping, List<TextCode> textCodeList,
List<KeywordPosition> positionList, int start, TextCode textCode) {
private static void addPrefixBreakTextCodeList(String keyword, Map<TextCode, KeywordResource> boundaryMapping, List<TextCode> textCodeList,
List<KeywordPosition> positionList, int textCodeIndex, TextCode textCode) {
//文字定位合并列表
List<TextCode> mergeTextCodeList = new ArrayList<>();
//加入合并列表
mergeTextCodeList.add(textCode);
//匹配下一个字
searchNextText(keyword, textCodeList, mergeTextCodeList, boundaryMapping, start, textCode);
searchNextText(keyword, textCodeList, mergeTextCodeList, boundaryMapping, textCodeIndex, textCode.getContent(), textCode);
if (mergeTextCodeList.size() > 1) {
mergeKeywordPosition(keyword, positionList, mergeTextCodeList, boundaryMapping);
mergeKeywordPosition(keyword, 0, positionList, mergeTextCodeList, boundaryMapping);
}
}


/**
* 检索下一个文本定位节点
*
* @param keyword 关键字字符串
* @param textCodeList 文本定位列表
* @param mergeTextCodeList 合并的TextCode列表
* @param boundaryMapping 文本资源映射对象
* @param start 起始位置
* @param textCodeIndex TextCode位置
* @param firstMatchString 最先匹配字符串
* @param textCode 第一个匹配文字
*/
private static void searchNextText(String keyword, List<TextCode> textCodeList, List<TextCode> mergeTextCodeList,
Map<TextCode, KeywordResource> boundaryMapping, int start, TextCode textCode) {
StringBuilder mergeText = new StringBuilder(textCode.getContent());
Map<TextCode, KeywordResource> boundaryMapping, int textCodeIndex, String firstMatchString,
TextCode textCode) {
StringBuilder mergeText = new StringBuilder(firstMatchString);
KeywordResource kr = boundaryMapping.get(textCode);
if (kr != null) {
int currentPage = kr.getPage();
for (int j = start + 1; j < textCodeList.size(); j++) {
for (int j = textCodeIndex + 1; j < textCodeList.size(); j++) {
TextCode next = textCodeList.get(j);
KeywordResource nextKr = boundaryMapping.get(next);
if (nextKr != null) {
Expand Down Expand Up @@ -368,16 +426,19 @@ private static double[] getMatrix(ST_Array ctm) {
* 合并关键字位置对象
*
* @param keyword 关键字
* @param firstStartIndex 第一个关键字起始匹配位置
* @param positionList 检索到的关键字列表
* @param textCodeList 合并列表
* @param boundaryMapping 外接矩形映射
*/
private static void mergeKeywordPosition(String keyword, List<KeywordPosition> positionList, List<TextCode> textCodeList,
private static void mergeKeywordPosition(String keyword, int firstStartIndex, List<KeywordPosition> positionList, List<TextCode> textCodeList,
Map<TextCode, KeywordResource> boundaryMapping) {
List<ST_Box> boxList = new ArrayList<>();
FontMetrics fontMetrics = null;
int page = 0, totalLength = 0, keywordLength = keyword.length();
for (TextCode textCode : textCodeList) {
int page = 0, totalLength = 0, keywordLength = keyword.length(), fontSize = 0;

for (int i = 0; i < textCodeList.size(); i++) {
TextCode textCode = textCodeList.get(i);
int textLength = textCode.getContent().length();
KeywordResource kr = boundaryMapping.get(textCode);
if (kr != null) {
Expand All @@ -386,22 +447,34 @@ private static void mergeKeywordPosition(String keyword, List<KeywordPosition> p
page = kr.getPage();
}
if (ctText != null && ctText.getBoundary() != null) {
if ((totalLength + textLength) > keywordLength) {
textLength = keywordLength - totalLength;
if (i == 0 && firstStartIndex > 0) {
textLength = totalLength = textCode.getContent().length() - firstStartIndex;
} else {
totalLength += textCode.getContent().length();
if ((totalLength + textLength) > keywordLength) {
textLength = keywordLength - totalLength;
} else {
totalLength += textCode.getContent().length();
}
}

List<Float> deltaX = DeltaTool.getDelta(textCode.getDeltaX(), textCode.getContent().length());
List<Float> deltaY = DeltaTool.getDelta(textCode.getDeltaY(), textCode.getContent().length());

double width = getStringWidth(0, textLength, deltaX, ctText.getSize());
double width;
if (i == 0 && firstStartIndex > 0) {
width = getStringWidth(firstStartIndex, textLength, deltaX, ctText.getSize());
} else {
width = getStringWidth(0, textLength, deltaX, ctText.getSize());
}

if (width == 0) {
width = kr.getText().getSize();
}

if (fontMetrics == null) {
int size = ctText.getSize().intValue();
if (fontMetrics == null || fontSize != size) {
fontMetrics = FontDesignMetrics.getMetrics(getFont(ctText, kr.getFont()));
fontSize = size;
}
double height = (fontMetrics.getAscent() - fontMetrics.getDescent()) / POINT_PER_MM;
ST_Pos basePoint;
Expand All @@ -410,7 +483,16 @@ private static void mergeKeywordPosition(String keyword, List<KeywordPosition> p
double[] matrix = getMatrix(ctm);
double x = textCode.getX() == null ? 0 : textCode.getX();
double y = textCode.getY() == null ? 0 : textCode.getY();

if (i == 0 && firstStartIndex > 0 && deltaX.size() > 0) {
for (int j = 0; j < firstStartIndex; j++) {
x += deltaX.get(j);
}
}
if (i == 0 && firstStartIndex > 0 && deltaY.size() > 0) {
for (int j = 0; j < firstStartIndex; j++) {
y += deltaY.get(j);
}
}
ST_Pos leftBottom = transform(matrix, x, y);
ST_Pos rightTop = transform(matrix, x + width, y - height);

Expand All @@ -423,6 +505,16 @@ private static void mergeKeywordPosition(String keyword, List<KeywordPosition> p
boxList.add(box);
} else {
basePoint = getLeftBottomPos(ctText.getBoundary(), textCode, deltaX, deltaY, 0);
if (i == 0 && firstStartIndex > 0 && deltaX.size() > 0) {
for (int j = 0; j < firstStartIndex; j++) {
basePoint.setX(basePoint.getX() + deltaX.get(j));
}
}
if (i == 0 && firstStartIndex > 0 && deltaY.size() > 0) {
for (int j = 0; j < firstStartIndex; j++) {
basePoint.setY(basePoint.getY() + deltaY.get(j));
}
}
boxList.add(new ST_Box(basePoint.getX(), basePoint.getY() - height, width, height));
}
}
Expand Down Expand Up @@ -506,6 +598,12 @@ private static KeywordPosition getKeywordPosition(TextCode textCode, int textInd
double width = getStringWidth(textIndex, keywordLength, deltaX, ctText.getSize());
double height = (fontMetrics.getAscent() - fontMetrics.getDescent()) / POINT_PER_MM;

if (!deltaY.isEmpty()) {
for (int i = 0; i < deltaY.size() && i < keywordLength - 1; i++) {
height -= deltaY.get(i);
}
}

ST_Pos basePoint = getLeftBottomPos(ctText.getBoundary(), textCode, deltaX, deltaY, textIndex);
ST_Box box = new ST_Box(basePoint.getX(), basePoint.getY() - height, width, height);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,55 @@
*/
class KeywordPosSignTest {

/**
* 多关键字,跨TextObject,后缀匹配测试
*
* @throws IOException 文件解析异常
*/
@Test
void multiKeywordSign() throws IOException, GeneralSecurityException, DocumentException {
//签署文档路径
Path src = Paths.get("src/test/resources/signedFile.ofd");
// 签署输出路径
Path out = Paths.get("target/MultiKeywordV4SignDoc.ofd");

Path userP12Path = Paths.get("src/test/resources", "USER.p12");
Path sealPath = Paths.get("src/test/resources", "UserV4.esl");

PrivateKey prvKey = PKCS12Tools.ReadPrvKey(userP12Path, "private", "777777");
Certificate signCert = PKCS12Tools.ReadUserCert(userP12Path, "private", "777777");
SESeal seal = SESeal.getInstance(Files.readAllBytes(sealPath));

String[] keyword = {"备注", "销售方", "价金", "项目名称"};
try (OFDReader reader = new OFDReader(src)) {
List<KeywordPosition> positionList = KeywordExtractor.getKeyWordPositionList(reader, keyword);
// 保证有且只有四个关键字返还
Assertions.assertEquals(4, positionList.size());
if (positionList.size() > 0) {
try (OFDSigner signer = new OFDSigner(reader, out, new NumberFormatAtomicSignID())) {
SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
// 2. 设置签名模式
// signer.setSignMode(SignMode.WholeProtected);
signer.setSignMode(SignMode.ContinueSign);
// 3. 设置签名使用的扩展签名容器
signer.setSignContainer(signContainer);
for (KeywordPosition position : positionList) {
// 4. 中心点对齐签署
ST_Box box = position.getBox();
signer.addApPos(new NormalStampPos(position.getPage(), box.getTopLeftX() + box.getWidth() / 2 - 20,
box.getTopLeftY() + box.getHeight() / 2 - 20, 40, 40));
}

// 5. 执行签名
signer.exeSign();
// 6. 关闭签名引擎,生成文档。
System.out.println(">> 生成文件位置: " + out.toAbsolutePath().toAbsolutePath());
}
}

}
}


/**
* 获取ofd文本节点
Expand All @@ -57,7 +106,7 @@ void keywordSign() throws IOException, GeneralSecurityException, DocumentExcepti
try (OFDReader reader = new OFDReader(src)) {
List<KeywordPosition> positionList = KeywordExtractor.getKeyWordPositionList(reader, keyword);
// 保证有且只有一个关键字返还
Assertions.assertEquals(positionList.size(), 1);
Assertions.assertEquals(1, positionList.size());
if (positionList.size() > 0) {
try (OFDSigner signer = new OFDSigner(reader, out, new NumberFormatAtomicSignID())) {
SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
Expand Down

0 comments on commit 96bf00d

Please sign in to comment.