Browse Source

Merge pull request #780 in CORE/base-third from bugfix/10.0 to release/10.0

* commit '969c102ecd9207c0778087f7651c8949b14ee438':
  无jira任务,合代码出错
  REPORT-34112 review 改进
  REPORT-34112 改进
  REPORT-34112 去除无用字段
  REPORT-34112 改进
  REPORT-34112 HTML解析:table标签支持table-layout 中的fixed 布局
  REPORT-33031 review 改进
  REPORT-33031 无插件PDF导出-HTML解析:块元素(如:div、p)支持 border 属性“全家桶”
  REPORT-33569 review 改进
  REPORT-33569 无插件PDF导出-HTML解析:块元素(如:div、p)支持background-image、background-size 属性
  无JIRA任务 third pom优化
  无jira任务,反向合代码引起的错误(堵塞打包)
  KERNEL-3881 状态服务器+集群锁相关代码解耦,脱离依赖redis
release/10.0
superman 4 years ago
parent
commit
5dce2c38dc
  1. 11
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/Paragraph.java
  2. 39
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/Border.java
  3. 106
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/BorderAttribute.java
  4. 79
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/BorderEnum.java
  5. 59
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/Markup.java
  6. 16
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/ParseIndentAttrUtils.java
  7. 15
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/ChainedProperties.java
  8. 27
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/FactoryProperties.java
  9. 34
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/HtmlConstants.java
  10. 1
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/IncCell.java
  11. 69
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java
  12. 36
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/utils/BackgroundUtil.java
  13. 83
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/utils/BorderUtils.java
  14. 20
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPCell.java
  15. 15
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java
  16. 247
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPTable.java
  17. 20
      fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/TableProperties.java

11
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/Paragraph.java

@ -49,6 +49,7 @@
package com.fr.third.v2.lowagie.text; package com.fr.third.v2.lowagie.text;
import com.fr.third.v2.lowagie.text.html.BorderAttribute;
import java.util.HashMap; import java.util.HashMap;
/** /**
@ -110,6 +111,8 @@ public class Paragraph extends Phrase {
protected HashMap attributes = new HashMap(); protected HashMap attributes = new HashMap();
private BorderAttribute borderAttr;
public HashMap getAttributes() { public HashMap getAttributes() {
return attributes; return attributes;
} }
@ -527,4 +530,12 @@ public class Paragraph extends Phrase {
return this.background; return this.background;
} }
public BorderAttribute getBorderAttr() {
return borderAttr;
}
public void setBorderAttrs(BorderAttribute borderAttrs) {
this.borderAttr = borderAttrs;
}
} }

39
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/Border.java

@ -0,0 +1,39 @@
package com.fr.third.v2.lowagie.text.html;
import java.awt.Color;
/**
* @author Hugh.C
* @version 1.0
* Created by Hugh.C on 2020/6/15
*/
public class Border {
private float width;
private String style;
private Color color = Color.BLACK;
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public String getStyle() {
return style;
}
public void setStyle(String style) {
this.style = style;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}

106
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/BorderAttribute.java

@ -0,0 +1,106 @@
package com.fr.third.v2.lowagie.text.html;
import java.awt.Color;
import java.util.Map;
/**
* @author Hugh.C
* @version 1.0
* Created by Hugh.C on 2020/6/15
*/
public class BorderAttribute {
protected Border top = new Border();
protected Border right = new Border();
protected Border bottom = new Border();
protected Border left = new Border();
public Border getTop() { return top; }
public Border getRight() {
return right;
}
public Border getBottom() {
return bottom;
}
public Border getLeft() {
return left;
}
/**
* 将解析好的边框属性转化为 BorderAttribute
*
* @param map
* @return
*/
public BorderAttribute applyBorderAttr(Map<String, String> map) {
if (null == map || map.isEmpty()) {
return this;
}
String topWidth = map.get(Markup.CSS_KEY_BORDERWIDTHTOP);
String style = map.get(Markup.CSS_KEY_BORDERSTYLETOP);
if (verify(topWidth, style)) {
Color color = Markup.decodeColor(map.get(Markup.CSS_KEY_BORDERCOLORTOP));
top.setWidth(CSSUtils.parseFloat(topWidth));
top.setStyle(style);
top.setColor(null == color ? Color.BLACK : color);
}
String rightWidth = map.get(Markup.CSS_KEY_BORDERWIDTHRIGHT);
style = map.get(Markup.CSS_KEY_BORDERSTYLERIGHT);
if (verify(rightWidth, style)) {
Color color = Markup.decodeColor(map.get(Markup.CSS_KEY_BORDERCOLORRIGHT));
right.setWidth(CSSUtils.parseFloat(rightWidth));
right.setStyle(style);
right.setColor(null == color ? Color.BLACK : color);
}
String bottomWidth = map.get(Markup.CSS_KEY_BORDERWIDTHBOTTOM);
style = map.get(Markup.CSS_KEY_BORDERSTYLEBOTTOM);
if (verify(bottomWidth, style)) {
Color color = Markup.decodeColor(map.get(Markup.CSS_KEY_BORDERCOLORBOTTOM));
bottom.setWidth(CSSUtils.parseFloat(bottomWidth));
bottom.setStyle(style);
bottom.setColor(null == color ? Color.BLACK : color);
}
String leftWidth = map.get(Markup.CSS_KEY_BORDERWIDTHLEFT);
style = map.get(Markup.CSS_KEY_BORDERSTYLELEFT);
if (verify(leftWidth, style)) {
Color color = Markup.decodeColor(map.get(Markup.CSS_KEY_BORDERCOLORLEFT));
left.setWidth(CSSUtils.parseFloat(leftWidth));
left.setStyle(style);
left.setColor(null == color ? Color.BLACK : color);
}
return this;
}
/**
* 将边框属性 拼接成 html style 中的值
*
* @return
*/
public String toStyleAttr() {
StringBuffer sb = new StringBuffer();
sb.append(border2StyleAttr(Markup.CSS_KEY_BORDERTOP, top)).append(border2StyleAttr(Markup.CSS_KEY_BORDERRIGHT, right))
.append(border2StyleAttr(Markup.CSS_KEY_BORDERBOTTOM, bottom)).append(border2StyleAttr(Markup.CSS_KEY_BORDERLEFT, left));
return sb.toString();
}
private String border2StyleAttr(String key, Border border) {
if (!verify(border)) {
return "";
}
Color color = null == border.getColor() ? Color.BLACK : border.getColor();
StringBuilder sb = new StringBuilder();
sb.append(key).append(":").append(border.getWidth()).append("px ")
.append(border.getStyle()).append(" ").append(null == color ? "" : "rgb(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ");");
return sb.toString();
}
private boolean verify(String width, String style) {
return null != width && width.length() > 0 && null != style && style.length() > 0;
}
private boolean verify(Border border) {
return null != border && border.getWidth() > 0 && null != border.getStyle();
}
}

79
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/BorderEnum.java

@ -0,0 +1,79 @@
package com.fr.third.v2.lowagie.text.html;
import java.util.List;
import java.util.Map;
/**
* @author Hugh.C
* @version 1.0
* Created by Hugh.C on 2020/6/15
*/
public enum BorderEnum {
TOP {
@Override
public void fillAttr(Map<String, String> map, List<String> borderAttr) {
map.put(Markup.CSS_KEY_BORDERWIDTHTOP, borderAttr.get(0));
map.put(Markup.CSS_KEY_BORDERSTYLETOP, borderAttr.get(1));
map.put(Markup.CSS_KEY_BORDERCOLORTOP, borderAttr.get(2));
}
},
RIGHT {
@Override
public void fillAttr(Map<String, String> map, List<String> borderAttr) {
map.put(Markup.CSS_KEY_BORDERWIDTHRIGHT, borderAttr.get(0));
map.put(Markup.CSS_KEY_BORDERSTYLERIGHT, borderAttr.get(1));
map.put(Markup.CSS_KEY_BORDERCOLORRIGHT, borderAttr.get(2));
}
},
BOTTOM {
@Override
public void fillAttr(Map<String, String> map, List<String> borderAttr) {
map.put(Markup.CSS_KEY_BORDERWIDTHBOTTOM, borderAttr.get(0));
map.put(Markup.CSS_KEY_BORDERSTYLEBOTTOM, borderAttr.get(1));
map.put(Markup.CSS_KEY_BORDERCOLORBOTTOM, borderAttr.get(2));
}
},
LEFT {
public void fillAttr(Map<String, String> map, List<String> borderAttr) {
map.put(Markup.CSS_KEY_BORDERWIDTHLEFT, borderAttr.get(0));
map.put(Markup.CSS_KEY_BORDERSTYLELEFT, borderAttr.get(1));
map.put(Markup.CSS_KEY_BORDERCOLORLEFT, borderAttr.get(2));
}
},
DEFAULT {
@Override
public void fillAttr(Map<String, String> map, List<String> borderAttr) {
}
};
public static BorderEnum get(String str) {
switch (str) {
case Markup.CSS_KEY_BORDERTOP:
return TOP;
case Markup.CSS_KEY_BORDERRIGHT:
return RIGHT;
case Markup.CSS_KEY_BORDERBOTTOM:
return BOTTOM;
case Markup.CSS_KEY_BORDERLEFT:
return LEFT;
default:
return DEFAULT;
}
}
public abstract void fillAttr(Map<String, String> map, List<String> borderAttr);
public void dealAttr(Map<String, String> map, List<String> borderAttr) {
if (null == map || null == borderAttr || borderAttr.size() > 3 || borderAttr.size() < 2) {
return;
}
//保证 borderAttr 大小为3,即 线条粗细、样式、颜色都需要具备
if (2 == borderAttr.size()) {
borderAttr.add("black");
}
fillAttr(map,borderAttr);
}
}

59
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/Markup.java

@ -178,12 +178,40 @@ public class Markup {
/** the CSS tag for the margin of an object */ /** the CSS tag for the margin of an object */
public static final String CSS_KEY_PADDINGBOTTOM = "padding-bottom"; public static final String CSS_KEY_PADDINGBOTTOM = "padding-bottom";
public static final String CSS_KEY_BORDERTOP = "border-top";
public static final String CSS_KEY_BORDERRIGHT= "border-right";
public static final String CSS_KEY_BORDERBOTTOM= "border-bottom";
public static final String CSS_KEY_BORDERLEFT= "border-left";
public static final String CSS_KEY_BORDERSTYLETOP = "border-top-style";
public static final String CSS_KEY_BORDERSTYLERIGHT= "border-right-style";
public static final String CSS_KEY_BORDERSTYLEBOTTOM= "border-bottom-style";
public static final String CSS_KEY_BORDERSTYLELEFT= "border-left-style";
public static final String CSS_KEY_BORDERCOLORTOP = "border-top-color";
public static final String CSS_KEY_BORDERCOLORRIGHT= "border-right-color";
public static final String CSS_KEY_BORDERCOLORBOTTOM= "border-bottom-color";
public static final String CSS_KEY_BORDERCOLORLEFT= "border-left-color";
public static final String CSS_KEY_BORDER = "border";
/** the CSS tag for the margin of an object */ /** the CSS tag for the margin of an object */
public static final String CSS_KEY_BORDERCOLOR = "border-color"; public static final String CSS_KEY_BORDERCOLOR = "border-color";
/** the CSS tag for the margin of an object */ /** the CSS tag for the margin of an object */
public static final String CSS_KEY_BORDERWIDTH = "border-width"; public static final String CSS_KEY_BORDERWIDTH = "border-width";
public static final String CSS_KEY_BORDERSTYLE = "border-style";
/** the CSS tag for the margin of an object */ /** the CSS tag for the margin of an object */
public static final String CSS_KEY_BORDERWIDTHLEFT = "border-left-width"; public static final String CSS_KEY_BORDERWIDTHLEFT = "border-left-width";
@ -533,6 +561,37 @@ public class Markup {
return result.toString(); return result.toString();
} }
/**
* 解析类似于 border:1px solid #000 中的值
*
* @param attr 1px solid #000 or 1px solid
* @return list: 按粗细样式颜色的顺序返回 没有则为null
*/
public static List<String> parseBorderAttr(String attr) {
if (null == attr) {
return null;
}
List<String> list = new ArrayList<String>(3);
StringTokenizer st = new StringTokenizer(attr);
while (st.hasMoreElements()) {
list.add(st.nextToken());
}
switch (list.size()) {
case 2:
// 如 border:1px solid ,则默认颜色为黑色
list.add("black");
break;
case 3:
// 如 border:1px solid black ,已经写全了,不用做额外的处理
break;
default:
// 如 border:1px ,此时浏览器是无法识别的
list = null;
break;
}
return list;
}
/** /**
* 解析类似于 margin: 10px 5px 15px 20px中的值 * 解析类似于 margin: 10px 5px 15px 20px中的值
* NESW:北东南西上右下左 * NESW:北东南西上右下左

16
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/ParseIndentAttrUtils.java

@ -71,6 +71,22 @@ public class ParseIndentAttrUtils {
return indentAttribute; return indentAttribute;
} }
public static IndentAttribute parseBorderAttribute(BorderAttribute borderAttr) {
IndentAttribute widthAttr = new IndentAttribute();
if (null == borderAttr) {
return widthAttr;
}
widthAttr.setTop(verify(borderAttr.getTop()) ? borderAttr.getTop().getWidth() : 0);
widthAttr.setRight(verify(borderAttr.getRight()) ? borderAttr.getRight().getWidth() : 0);
widthAttr.setBottom(verify(borderAttr.getBottom()) ? borderAttr.getBottom().getWidth() : 0);
widthAttr.setBottom(verify(borderAttr.getLeft()) ? borderAttr.getLeft().getWidth() : 0);
return widthAttr;
}
private static boolean verify(Border border) {
return null != border && 0 < border.getWidth() && null != border.getStyle();
}
public static void createIndent(StringBuffer stringBuffer, String attr, IndentAttribute indentAttribute){ public static void createIndent(StringBuffer stringBuffer, String attr, IndentAttribute indentAttribute){
stringBuffer.append(attr).append("-").append("left").append(":").append(indentAttribute.getLeft()).append("px;") stringBuffer.append(attr).append("-").append("left").append(":").append(indentAttribute.getLeft()).append("px;")
.append(attr).append("-").append("right").append(":").append(indentAttribute.getRight()).append("px;") .append(attr).append("-").append("right").append(":").append(indentAttribute.getRight()).append("px;")

15
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/ChainedProperties.java

@ -202,6 +202,21 @@ public class ChainedProperties {
return false; return false;
} }
/**
* 获取位于最后的块标签
*
* @return
*/
public String getLastBlockTag() {
for (int i = chain.size() - 1; i >= 0; --i) {
Object obj[] = (Object[]) chain.get(i);
if (HtmlConstants.BLOCK_ELEMENTS.contains(obj[0])) {
return (String) obj[0];
}
}
return null;
}
/** /**
* 获取当前处理的标签 * 获取当前处理的标签
* *

27
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/FactoryProperties.java

@ -51,9 +51,13 @@
package com.fr.third.v2.lowagie.text.html.simpleparser; package com.fr.third.v2.lowagie.text.html.simpleparser;
import com.fr.third.v2.lowagie.text.html.CSS; import com.fr.third.v2.lowagie.text.html.CSS;
import com.fr.third.v2.lowagie.text.html.BorderAttribute;
import com.fr.third.v2.lowagie.text.html.utils.BackgroundUtil;
import com.fr.third.v2.lowagie.text.html.utils.BorderUtils;
import java.awt.Color; import java.awt.Color;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@ -128,8 +132,20 @@ public class FactoryProperties {
} }
public static void createParagraph(Paragraph p, ChainedProperties props) { public static void createParagraph(Paragraph p, ChainedProperties props) {
if(props.hasPropertyInChain("div", "background")){ String value = props.getProperty("align");
p.setBackground(props.getPropertyFromChain("div", "background")); if (value != null) {
if (value.equalsIgnoreCase("center"))
p.setAlignment(Element.ALIGN_CENTER);
else if (value.equalsIgnoreCase("right"))
p.setAlignment(Element.ALIGN_RIGHT);
else if (value.equalsIgnoreCase("justify"))
p.setAlignment(Element.ALIGN_JUSTIFIED);
}
Map<String, String> bgAttrMap = BackgroundUtil.parseBgAttr4BlockTag(props);
if (null != bgAttrMap) {
for (Map.Entry<String, String> entry : bgAttrMap.entrySet()) {
p.setAttribute(entry.getKey(), entry.getValue());
}
} }
if(props.hasProperty("line-height")){ if(props.hasProperty("line-height")){
p.setAttribute("line-height", props.getProperty("line-height")); p.setAttribute("line-height", props.getProperty("line-height"));
@ -142,6 +158,11 @@ public class FactoryProperties {
parseMarginAttr(p, props); parseMarginAttr(p, props);
parsePaddingAttr(p, props); parsePaddingAttr(p, props);
String lastBlockTag = props.getLastBlockTag();
//这里解析的背景属性不能是table标签的
if (null != lastBlockTag && !HtmlTags.TABLE.equals(lastBlockTag)) {
p.setBorderAttrs(new BorderAttribute().applyBorderAttr(BorderUtils.parse2RulesMap(props, false)));
}
if(props.hasPropertyInChain("div", "text-indent")){ if(props.hasPropertyInChain("div", "text-indent")){
String ss = props.getPropertyFromChain("div", "text-indent"); String ss = props.getPropertyFromChain("div", "text-indent");
p.setFirstLineIndent(Markup.parseLength(ss)); p.setFirstLineIndent(Markup.parseLength(ss));
@ -153,7 +174,7 @@ public class FactoryProperties {
p.setHyphenation(getHyphenation(props)); p.setHyphenation(getHyphenation(props));
setParagraphLeading(p, props.getProperty("leading")); setParagraphLeading(p, props.getProperty("leading"));
String value = props.getProperty("before"); value = props.getProperty("before");
if (value != null) { if (value != null) {
try { try {
p.setSpacingBefore(Float.parseFloat(value)); p.setSpacingBefore(Float.parseFloat(value));

34
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/HtmlConstants.java

@ -11,6 +11,8 @@ import java.util.List;
* @date 2018/5/2 * @date 2018/5/2
*/ */
public class HtmlConstants { public class HtmlConstants {
//表格相关标签集合
public static final List<String> TABLE_LABEL_GROUP = new ArrayList<String>();
//块级元素集合 //块级元素集合
public static final List<String> BLOCK_ELEMENTS = new ArrayList<String>(); public static final List<String> BLOCK_ELEMENTS = new ArrayList<String>();
//行内元素集合 //行内元素集合
@ -18,7 +20,17 @@ public class HtmlConstants {
//支持解析的属性 //支持解析的属性
public static final List<String> PADDING = new ArrayList<String>(); public static final List<String> PADDING = new ArrayList<String>();
public static final List<String> MARGIN = new ArrayList<String>(); public static final List<String> MARGIN = new ArrayList<String>();
//边框属性
public static final List<String> BORDER = new ArrayList<String>();
public static final List<String> BORDER_WIDTH = new ArrayList<String>();
public static final List<String> BORDER_STYLE = new ArrayList<String>();
public static final List<String> BORDER_COLOR = new ArrayList<String>();
static { static {
TABLE_LABEL_GROUP.add(HtmlTags.TABLE);
TABLE_LABEL_GROUP.add(HtmlTags.ROW);
TABLE_LABEL_GROUP.add(HtmlTags.CELL);
TABLE_LABEL_GROUP.add(HtmlTags.HEADERCELL);
BLOCK_ELEMENTS.add(HtmlTags.DIV); BLOCK_ELEMENTS.add(HtmlTags.DIV);
BLOCK_ELEMENTS.add(HtmlTags.UNORDEREDLIST); BLOCK_ELEMENTS.add(HtmlTags.UNORDEREDLIST);
BLOCK_ELEMENTS.add(HtmlTags.PARAGRAPH); BLOCK_ELEMENTS.add(HtmlTags.PARAGRAPH);
@ -43,5 +55,27 @@ public class HtmlConstants {
MARGIN.add(Markup.CSS_KEY_MARGINRIGHT); MARGIN.add(Markup.CSS_KEY_MARGINRIGHT);
MARGIN.add(Markup.CSS_KEY_MARGINBOTTOM); MARGIN.add(Markup.CSS_KEY_MARGINBOTTOM);
MARGIN.add(Markup.CSS_KEY_MARGINLEFT); MARGIN.add(Markup.CSS_KEY_MARGINLEFT);
//按照上 右 下 左 的顺序排
BORDER.add(Markup.CSS_KEY_BORDERTOP);
BORDER.add(Markup.CSS_KEY_BORDERRIGHT);
BORDER.add(Markup.CSS_KEY_BORDERBOTTOM);
BORDER.add(Markup.CSS_KEY_BORDERLEFT);
BORDER_WIDTH.add(Markup.CSS_KEY_BORDERWIDTHTOP);
BORDER_WIDTH.add(Markup.CSS_KEY_BORDERWIDTHRIGHT);
BORDER_WIDTH.add(Markup.CSS_KEY_BORDERWIDTHBOTTOM);
BORDER_WIDTH.add(Markup.CSS_KEY_BORDERWIDTHLEFT);
BORDER_STYLE.add(Markup.CSS_KEY_BORDERSTYLETOP);
BORDER_STYLE.add(Markup.CSS_KEY_BORDERSTYLERIGHT);
BORDER_STYLE.add(Markup.CSS_KEY_BORDERSTYLEBOTTOM);
BORDER_STYLE.add(Markup.CSS_KEY_BORDERSTYLELEFT);
BORDER_COLOR.add(Markup.CSS_KEY_BORDERCOLORTOP);
BORDER_COLOR.add(Markup.CSS_KEY_BORDERCOLORRIGHT);
BORDER_COLOR.add(Markup.CSS_KEY_BORDERCOLORBOTTOM);
BORDER_COLOR.add(Markup.CSS_KEY_BORDERCOLORLEFT);
} }
} }

1
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/IncCell.java

@ -108,6 +108,7 @@ public class IncCell implements TextElementArray {
//解析td上声明的width //解析td上声明的width
value = props.getLastChainProperty("width"); value = props.getLastChainProperty("width");
if (value != null) { if (value != null) {
cell.setOriginalStyleWidth(value);
cell.setStyleWidth(CSSUtils.parseFloat(value)); cell.setStyleWidth(CSSUtils.parseFloat(value));
} }
//解析td上声明的height //解析td上声明的height

69
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java

@ -110,19 +110,18 @@ public class IncTable {
public PdfPTable buildTable() { public PdfPTable buildTable() {
if (rows.isEmpty()) if (rows.isEmpty())
return new PdfPTable(1); return new PdfPTable(1);
int ncol = 0;
ArrayList c0 = (ArrayList) rows.get(0); ArrayList c0 = (ArrayList) rows.get(0);
for (int k = 0; k < c0.size(); ++k) { List<String> firstLineColWidths = getFirstLineColWidths();
ncol += ((PdfPCell) c0.get(k)).getColspan();
}
int ncol = getMaxColCount();
processColWidth(ncol); processColWidth(ncol);
PdfPTable table = new PdfPTable(ncol); PdfPTable table = new PdfPTable(ncol);
try { try {
TableProperties tableProperties = parseTableProperties(); TableProperties tableProperties = parseTableProperties();
table.setTableProperties(tableProperties); table.setTableProperties(tableProperties);
table.setFirstLineColWidths(firstLineColWidths);
//相对宽度 //相对宽度
float[] floats = new float[relativeColWidths.size()]; float[] floats = new float[relativeColWidths.size()];
@ -149,18 +148,69 @@ public class IncTable {
} }
for (int row = 0; row < rows.size(); ++row) { for (int row = 0; row < rows.size(); ++row) {
ArrayList col = (ArrayList) rows.get(row); ArrayList col = (ArrayList) rows.get(row);
int colCount=0;
for (int k = 0; k < col.size(); ++k) { for (int k = 0; k < col.size(); ++k) {
table.addCell((PdfPCell) col.get(k)); table.addCell((PdfPCell) col.get(k));
colCount += ((PdfPCell) col.get(k)).getColspan();
}
//补充空白列
for (int i = 0; i < ncol - colCount; i++) {
PdfPCell pdfPCell = new PdfPCell();
pdfPCell.setInvalid(true);
table.addCell(pdfPCell);
} }
} }
processRowHeight(table); processRowHeight(table);
table.adjustFixedLayoutColumnWidth();
}catch (Exception e){ }catch (Exception e){
e.printStackTrace(); e.printStackTrace();
} }
return table; return table;
} }
/**
* 获取第一行的列宽
*
* @return
*/
private List<String> getFirstLineColWidths() {
ArrayList c0 = (ArrayList) rows.get(0);
List<String> firstLineColWidths = new ArrayList<String>();
for (int i = 0; i < c0.size(); i++) {
PdfPCell pdfPCell = (PdfPCell) c0.get(i);
String width = pdfPCell.getOriginalStyleWidth();
if (null != width && 1 < pdfPCell.getColspan()) {
float w = CSSUtils.parseFloat(width);
//平分且需要保持原始的样式(有百分号的需要加上百分百)
w /= pdfPCell.getColspan();
width = width.endsWith("%") ? String.valueOf(w) + "%" : String.valueOf(w);
}
for (int j = 0; j < pdfPCell.getColspan(); j++) {
firstLineColWidths.add(width);
}
}
return firstLineColWidths;
}
/**
* 获取最大列数
*
* @return
*/
public int getMaxColCount() {
int max = 0;
for (int row = 0; row < rows.size(); ++row) {
ArrayList col = (ArrayList) rows.get(row);
int ncol = 0;
for (int k = 0; k < col.size(); ++k) {
ncol += ((PdfPCell) col.get(k)).getColspan();
}
max = Math.max(ncol, max);
}
return max;
}
/** /**
* 调整列宽每列取最大值 * 调整列宽每列取最大值
* *
@ -290,6 +340,15 @@ public class IncTable {
if(value != null){ if(value != null){
tableProperties.setCellpadding(CSSUtils.parseFloat(value)); tableProperties.setCellpadding(CSSUtils.parseFloat(value));
} }
value = (String) props.get("width");
if (value != null) {
tableProperties.setStyleWidth(value);
}
value = (String) props.get("table-layout");
if (value != null) {
tableProperties.setLayout(value);
}
ChainedProperties properties = new ChainedProperties(); ChainedProperties properties = new ChainedProperties();
properties.addToChain(HtmlTags.TABLE, props); properties.addToChain(HtmlTags.TABLE, props);
//解析background相关属性 //解析background相关属性

36
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/utils/BackgroundUtil.java

@ -45,4 +45,40 @@ public class BackgroundUtil {
} }
return backgroundRules; return backgroundRules;
} }
/**
* 将块元素的背景属性转换成mp
*
* @param props
* @return
*/
public static Map<String, String> parseBgAttr4BlockTag(ChainedProperties props) {
Map<String, String> backgroundRules = new HashMap<String, String>();
String value = props.getPropertyFromChain("div", "background-color");
if (value != null) {
backgroundRules.put("background-color", value);
}
value = props.getPropertyFromChain("div", "background-size");
if (value != null) {
backgroundRules.put("background-size", value);
}
value = props.getPropertyFromChain("div", "background");
if (value != null) {
Map<String, String> backgroundStyles = CSSUtils.processBackground(value);
backgroundRules.putAll(backgroundStyles);
}
value = props.getPropertyFromChain("div", "background-position");
if (value != null) {
backgroundRules.put("background-position", value);
}
value = props.getPropertyFromChain("div", "background-repeat");
if (value != null) {
backgroundRules.put("background-repeat", value);
}
value = props.getPropertyFromChain("div", "background-image");
if (value != null) {
backgroundRules.put("background-image", value);
}
return backgroundRules;
}
} }

83
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/html/utils/BorderUtils.java

@ -0,0 +1,83 @@
package com.fr.third.v2.lowagie.text.html.utils;
import com.fr.third.v2.lowagie.text.html.BorderEnum;
import com.fr.third.v2.lowagie.text.html.HtmlTags;
import com.fr.third.v2.lowagie.text.html.Markup;
import com.fr.third.v2.lowagie.text.html.simpleparser.ChainedProperties;
import com.fr.third.v2.lowagie.text.html.simpleparser.HtmlConstants;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Hugh.C
* @version 1.0
* Created by Hugh.C on 2020/5/27
*/
public class BorderUtils {
/**
* 解析border属性
*
* @param props
* @param lastTag true解析最后一个tag 的边框属性
*/
public static Map<String, String> parse2RulesMap(ChainedProperties props, boolean lastTag) {
Map<String, String> map = new HashMap<String, String>();
String value = lastTag ? props.getLastChainProperty(Markup.CSS_KEY_BORDER) : props.getPropertyFromChain(HtmlTags.DIV, Markup.CSS_KEY_BORDER);
//解析 border
if (null != value) {
List<String> list = Markup.parseBorderAttr(value);
for (BorderEnum border : BorderEnum.values()) {
border.dealAttr(map, list);
}
}
//解析 border-width
parseBorderAttr(Markup.CSS_KEY_BORDERWIDTH, HtmlConstants.BORDER_WIDTH, map, props, lastTag);
//解析 border-style
parseBorderAttr(Markup.CSS_KEY_BORDERSTYLE, HtmlConstants.BORDER_STYLE, map, props, lastTag);
//解析 border-color
parseBorderAttr(Markup.CSS_KEY_BORDERCOLOR, HtmlConstants.BORDER_COLOR, map, props, lastTag);
//解析 border-top|right|bottom|left
for (String border : HtmlConstants.BORDER) {
value = lastTag ? props.getLastChainProperty(border) : props.getPropertyFromChain(HtmlTags.DIV, border);
if (null != value) {
BorderEnum.get(border).dealAttr(map, Markup.parseBorderAttr(value));
}
}
//解析 border-top|right|bottom|left-width
parseBorderAttr(HtmlConstants.BORDER_WIDTH, map, props, lastTag);
//解析 border-top|right|bottom|left-style
parseBorderAttr(HtmlConstants.BORDER_STYLE, map, props, lastTag);
//解析 border-top|right|bottom|left-color
parseBorderAttr(HtmlConstants.BORDER_COLOR, map, props, lastTag);
return map;
}
private static void parseBorderAttr(List<String> attrKeys, Map<String, String> map, ChainedProperties props, boolean lastTag) {
String value = null;
for (String key : attrKeys) {
value = lastTag ? props.getLastChainProperty(key) : props.getPropertyFromChain(HtmlTags.DIV, key);
if (null != value) {
map.put(key, value);
}
}
}
private static void parseBorderAttr(String key, List<String> attrKeys, Map<String, String> map, ChainedProperties props, boolean lastTag) {
String value = lastTag ? props.getLastChainProperty(key) : props.getPropertyFromChain(HtmlTags.DIV, key);
if (null != value) {
List<String> list = Markup.parseNESW(value);
if (null != list) {
for (int i = 0; i < attrKeys.size() && i < list.size(); i++) {
map.put(attrKeys.get(i), list.get(i));
}
}
}
}
}

20
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPCell.java

@ -71,6 +71,8 @@ public class PdfPCell extends Rectangle {
private float styleWidth = 0.0f; private float styleWidth = 0.0f;
private float styleHeight = 0.0f; private float styleHeight = 0.0f;
private String originalStyleWidth;
public float getStyleHeight() { public float getStyleHeight() {
return styleHeight; return styleHeight;
} }
@ -85,6 +87,8 @@ public class PdfPCell extends Rectangle {
public Map<String, String> background ; public Map<String, String> background ;
private boolean invalid = false;
public Map<String, String> getBackground() { public Map<String, String> getBackground() {
return background; return background;
} }
@ -97,6 +101,21 @@ public class PdfPCell extends Rectangle {
this.styleWidth = styleWidth; this.styleWidth = styleWidth;
} }
public String getOriginalStyleWidth() {
return originalStyleWidth;
}
public void setOriginalStyleWidth(String originalStyleWidth) {
this.originalStyleWidth = originalStyleWidth;
}
public boolean isInvalid() {
return invalid;
}
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
private ColumnText column = new ColumnText(null); private ColumnText column = new ColumnText(null);
@ -291,6 +310,7 @@ public class PdfPCell extends Rectangle {
background = cell.background; background = cell.background;
styleWidth = cell.styleWidth; styleWidth = cell.styleWidth;
styleHeight = cell.styleHeight; styleHeight = cell.styleHeight;
invalid=cell.invalid;
} }
/** /**

15
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java

@ -141,7 +141,7 @@ public class PdfPRow {
* @param widths * @param widths
* @return true if everything went right * @return true if everything went right
*/ */
public boolean setWidths(float widths[]) { public boolean setWidths(float widths[], TableProperties tablePropertie) {
if (widths.length != cells.length) if (widths.length != cells.length)
return false; return false;
System.arraycopy(widths, 0, this.widths, 0, cells.length); System.arraycopy(widths, 0, this.widths, 0, cells.length);
@ -160,6 +160,19 @@ public class PdfPRow {
for (; k < last; ++k) for (; k < last; ++k)
total += widths[k]; total += widths[k];
--k; --k;
float borderWidth=0;
float cellspacing=0;
float cellpadding=0;
if (null != tablePropertie) {
borderWidth = tablePropertie.getBorderWidth();
cellspacing = tablePropertie.getCellspacing();
cellpadding = tablePropertie.getCellpadding();
}
if (cell.getColspan() > 1) {
total += ((cell.getColspan() - 1) * 2 * borderWidth);
total += ((cell.getColspan() - 1) * cellspacing);
total += ((cell.getColspan() - 1) * 2 * cellpadding);
}
cell.setRight(total); cell.setRight(total);
cell.setTop(0); cell.setTop(0);
processColWidth(cell.getColumn().getCompositeElements(), cell.getWidth()); processColWidth(cell.getColumn().getCompositeElements(), cell.getWidth());

247
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/PdfPTable.java

@ -49,6 +49,8 @@
package com.fr.third.v2.lowagie.text.pdf; package com.fr.third.v2.lowagie.text.pdf;
import com.fr.third.v2.lowagie.text.html.CSS;
import com.fr.third.v2.lowagie.text.html.CSSUtils;
import java.util.ArrayList; import java.util.ArrayList;
import com.fr.third.v2.lowagie.text.DocumentException; import com.fr.third.v2.lowagie.text.DocumentException;
@ -59,6 +61,7 @@ import com.fr.third.v2.lowagie.text.Image;
import com.fr.third.v2.lowagie.text.Phrase; import com.fr.third.v2.lowagie.text.Phrase;
import com.fr.third.v2.lowagie.text.Rectangle; import com.fr.third.v2.lowagie.text.Rectangle;
import com.fr.third.v2.lowagie.text.pdf.events.PdfPTableEventForwarder; import com.fr.third.v2.lowagie.text.pdf.events.PdfPTableEventForwarder;
import java.util.List;
/** /**
* This is a table that can be put at an absolute position but can also * This is a table that can be put at an absolute position but can also
@ -105,6 +108,8 @@ public class PdfPTable implements LargeElement {
protected PdfPTableEvent tableEvent; protected PdfPTableEvent tableEvent;
private TableProperties tableProperties; private TableProperties tableProperties;
private List<String> firstLineColWidths;
public TableProperties getTableProperties() { public TableProperties getTableProperties() {
return tableProperties; return tableProperties;
} }
@ -113,6 +118,10 @@ public class PdfPTable implements LargeElement {
this.tableProperties = tableProperties; this.tableProperties = tableProperties;
} }
public void setFirstLineColWidths(List<String> firstLineColWidths) {
this.firstLineColWidths = firstLineColWidths;
}
/** /**
* Holds value of property headerRows. * Holds value of property headerRows.
*/ */
@ -369,12 +378,244 @@ public class PdfPTable implements LargeElement {
return; return;
this.totalWidth = totalWidth; this.totalWidth = totalWidth;
totalHeight = 0; totalHeight = 0;
if (adjustFixedLayoutColumnWidth()) {
return;
}
calculateWidths(); calculateWidths();
// calculateHeights(true); // calculateHeights(true);
adjustRowWidth();
}
private void adjustRowWidth() {
for (int k = 0; k < rows.size(); ++k) { for (int k = 0; k < rows.size(); ++k) {
PdfPRow row = (PdfPRow) rows.get(k); PdfPRow row = (PdfPRow) rows.get(k);
row.setWidths(absoluteWidths); row.setWidths(absoluteWidths, tableProperties);
}
}
/**
* 计算非内容区域的宽度边框+cellpadding+cellspacing
*
* @return
*/
private float calOutOfContentWidth() {
int numCols = getNumberOfColumns();
float allCellspacingWidth = tableProperties.getCellspacing() * (numCols + 1);
float allCellpaddingWidth = numCols * 2 * tableProperties.getCellpadding();
float allCellBorderWidth = (numCols + 1) * 2 * tableProperties.getBorderWidth();
return allCellspacingWidth + allCellpaddingWidth + allCellBorderWidth;
}
/**
* 调整固定布局(table-layout:fixed )的列宽
*
* @return false : 不符合table-layout:fixed 的定义
*/
public boolean adjustFixedLayoutColumnWidth() {
if (!needFixedLayout()) {
return false;
}
//是fixed 布局 且设置了width(仅设置 table-layout:fixed 而不设置width 时 前台依旧使用的是auto 布局)
//内容区域外的宽度
float outOfContentWidth = calOutOfContentWidth();
//实际内容宽度
float contentWidth = totalWidth - outOfContentWidth;
//重新初始化一下
absoluteWidths = new float[relativeWidths.length];
if (dealFirstLineHasNoWidth(contentWidth)) {
adjustRowWidth();
return true;
}
//第一行列宽
float[] colWidths = new float[firstLineColWidths.size()];
//绝对宽度和
float absWidthSum = 0;
//相对宽度和
float relWidthSum = 0;
//绝对宽度 (如 10px) 的索引
ArrayList<Integer> absIndex = new ArrayList<Integer>();
//相对宽度 (如 10%) 的索引
ArrayList<Integer> relIndex = new ArrayList<Integer>();
//初始化一下上述字段
for (int i = 0; i < firstLineColWidths.size(); i++) {
String widthStr = firstLineColWidths.get(i);
float w = CSSUtils.parseFloat(widthStr);
if (null != widthStr) {
if (widthStr.endsWith("%")) {
w = w / 100 * contentWidth;
relWidthSum += w;
relIndex.add(i);
} else {
absWidthSum += w;
absIndex.add(i);
}
}
colWidths[i] = w;
}
//第一行td中指定的绝对宽度 >= table标签上指定的宽度,以td的宽度为准,将table撑开
if (absWidthSum >= contentWidth) {
for (int i = 0; i < absIndex.size(); i++) {
absoluteWidths[absIndex.get(i)] = colWidths[absIndex.get(i)];
}
totalWidth = outOfContentWidth + absWidthSum;
dealInvalidCell(absIndex);
adjustRowWidth();
return true;
}
//table 总的列数
int colNum = getNumberOfColumns();
//相对宽度与绝对宽度的列数和
int absAndRelColNum = absIndex.size() + relIndex.size();
//相对宽度与绝对宽度的列宽和
float absAndRelColWidthSum = absWidthSum + relWidthSum;
//第一行td中指定的绝对宽度+相对宽度小于table内容宽度
if (absAndRelColWidthSum < contentWidth) {
//剩余宽度
float remaindWidth = contentWidth - absAndRelColWidthSum;
//如果总列数大于第一行绝对宽度和相对宽度列数,则多余的宽度由剩余列平分
if (colNum > absAndRelColNum) {
fillAbsoluteWidths(colWidths, absIndex);
fillAbsoluteWidths(colWidths, relIndex);
float remaindAvgWidth = remaindWidth / (colNum - absAndRelColNum);
for (int i = 0; i < absoluteWidths.length; i++) {
if (absIndex.contains(i) || relIndex.contains(i)) {
continue;
}
absoluteWidths[i] = remaindAvgWidth;
}
} else {
//按比例分摊剩余宽度
for (int i = 0; i < absIndex.size(); i++) {
float width = colWidths[absIndex.get(i)];
absoluteWidths[absIndex.get(i)] = width + remaindWidth * width / absAndRelColWidthSum;
}
for (int i = 0; i < relIndex.size(); i++) {
float width = colWidths[relIndex.get(i)];
absoluteWidths[relIndex.get(i)] = width + remaindWidth * width / absAndRelColWidthSum;
}
}
} else {
//第一行td中指定的绝对宽度+相对宽度大于table标签上指定的宽度,剩余宽度由相对宽度平分
fillAbsoluteWidths(colWidths, absIndex);
//剩余宽度
float remaindWidth = contentWidth - absWidthSum;
for (int i = 0; i < relIndex.size(); i++) {
float width = colWidths[relIndex.get(i)];
absoluteWidths[relIndex.get(i)] = remaindWidth * width / relWidthSum;
} }
dealInvalidCell(absIndex, relIndex);
}
adjustRowWidth();
return true;
}
private boolean needFixedLayout() {
return totalWidth > 0 && rows.size() > 0 && CSS.Value.FIXED.equals(tableProperties.getLayout()) && null != tableProperties.getStyleWidth();
}
/**
* 获取列索引List
*/
public List<Integer> getColIndexList() {
List<Integer> list = new ArrayList<>(absoluteWidths.length);
for (int i = 0; i < absoluteWidths.length; i++) {
list.add(i);
}
return list;
}
/**
* 填充最终宽度
*
* @param colWidths 列宽
* @param indexList 要设置的列索引List
*/
private void fillAbsoluteWidths(float[] colWidths, ArrayList<Integer> indexList) {
for (int i = 0; i < indexList.size() && indexList.get(i) < absoluteWidths.length; i++) {
Integer index = indexList.get(i);
absoluteWidths[index] = colWidths[index];
}
}
/**
* validIndexList 之外的列对应的单元格设置为无效的
*
* @param validIndexList
*/
private void dealInvalidCell(List<Integer>... validIndexList) {
if (null == validIndexList) {
return;
}
//计算无效列索引
List<Integer> invalidIndexList = getColIndexList();
List<Integer> list = new ArrayList<Integer>();
for (List<Integer> item : validIndexList) {
list.addAll(item);
}
invalidIndexList.removeAll(list);
for (int row = 0; row < rows.size(); row++) {
PdfPRow pdfRow = (PdfPRow) rows.get(row);
int index = 0;
PdfPCell[] cells = pdfRow.getCells();
for (PdfPCell cell : cells) {
if (cell == null) {
index += 1;
continue;
}
if (invalidIndexList.contains(index)) {
cell.setInvalid(true);
}
index += cell.getColspan();
}
}
//将无效列的多余宽度平分给其他列
dealInvalidColWidth(invalidIndexList.size(), list);
}
/**
* 处理无效列的内容区域外的宽度平分给其他列
*
* @param invalidColNum
* @param validIndexList
*/
private void dealInvalidColWidth(int invalidColNum, List<Integer> validIndexList) {
if (0 == invalidColNum || null == validIndexList || 0 == validIndexList.size()) {
return;
}
float invalidColWidth = invalidColNum * tableProperties.getCellspacing() + 2 * invalidColNum * (tableProperties.getCellpadding() + tableProperties.getBorderWidth());
float avgWidth = invalidColWidth / validIndexList.size();
for (int i = 0; i < validIndexList.size() && validIndexList.get(i) < absoluteWidths.length; i++) {
Integer index = validIndexList.get(i);
absoluteWidths[index] += avgWidth;
}
}
/**
* 处理第一行没有设置width属性情况
*
* @param contentWidth 内容宽度
* @return
*/
private boolean dealFirstLineHasNoWidth(float contentWidth) {
if (null != firstLineColWidths && 0 != firstLineColWidths.size()) {
return false;
}
//第一行的td都没有设置width属性,则所有列平分table宽度
int length = absoluteWidths.length;
for (int i = 0; i < length; i++) {
absoluteWidths[i] = contentWidth / length;
}
return true;
} }
/** /**
@ -509,7 +750,7 @@ public class PdfPTable implements LargeElement {
} }
PdfPRow row = new PdfPRow(currentRow); PdfPRow row = new PdfPRow(currentRow);
if (totalWidth > 0) { if (totalWidth > 0) {
row.setWidths(absoluteWidths); row.setWidths(absoluteWidths, tableProperties);
// totalHeight += row.getMaxHeights(); // totalHeight += row.getMaxHeights();
} }
rows.add(row); rows.add(row);
@ -876,7 +1117,7 @@ public class PdfPTable implements LargeElement {
if (row == null) if (row == null)
return 0; return 0;
if (firsttime) if (firsttime)
row.setWidths(absoluteWidths); row.setWidths(absoluteWidths, tableProperties);
float height = row.getMaxHeights(); float height = row.getMaxHeights();
PdfPCell cell; PdfPCell cell;
PdfPRow tmprow; PdfPRow tmprow;

20
fine-itext/src/main/java/com/fr/third/v2/lowagie/text/pdf/TableProperties.java

@ -11,7 +11,11 @@ public class TableProperties {
private float cellspacing = 2.0f; private float cellspacing = 2.0f;
private float cellpadding = 1.0f; private float cellpadding = 1.0f;
private boolean collapse = false; private boolean collapse = false;
public Map<String, String> background; public Map<String, String> background;
private String styleWidth = null;
private String layout = null;
public BorderStyle getBorderStyle() { public BorderStyle getBorderStyle() {
return borderStyle; return borderStyle;
@ -57,6 +61,22 @@ public class TableProperties {
this.background = background; this.background = background;
} }
public String getStyleWidth() {
return styleWidth;
}
public void setStyleWidth(String styleWidth) {
this.styleWidth = styleWidth;
}
public String getLayout() {
return layout;
}
public void setLayout(String layout) {
this.layout = layout;
}
public String toHtmlString(){ public String toHtmlString(){
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
if(!isCollapse()){ if(!isCollapse()){

Loading…
Cancel
Save