Browse Source

Merge pull request #372 in CORE/base-third from ~ABBY/base-third:final/10.0 to final/10.0

* commit 'aab5a32e60c8a64f6a87c7470ad041e7a8917bf7':
  REPORT-14598 pdf HTML导出换行与浏览器不一致问题
  REPORT-14598 pdf HTML导出换行与浏览器不一致问题
  REPORT-25774 使用和报表一样的方法进行计算字符宽度
  REPORT-25774 提升权限,供外部调用
final/10.0
Kara 5 years ago
parent
commit
a38b1fbe54
  1. 30
      fine-itext/src/com/fr/third/v2/lowagie/text/html/SpaceWithPunctuationBreakIterator.java
  2. 5
      fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/HTMLWorker.java
  3. 40
      fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfChunk.java
  4. 104
      fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfFont.java
  5. 9
      fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java

30
fine-itext/src/com/fr/third/v2/lowagie/text/html/SpaceWithPunctuationBreakIterator.java

@ -13,16 +13,23 @@ public class SpaceWithPunctuationBreakIterator extends BreakIterator {
private int currentPos = -1;
private int currentIndex = -1;
private boolean[] spaceIndex;
//不作为break分词的字符
private boolean[] noSwitchIndex;
public SpaceWithPunctuationBreakIterator(String text, BreakIterator iterator){
this.iterator = iterator;
iterator.setText(text);
this.spaceIndex = new boolean[text.length()];
this.noSwitchIndex = new boolean[text.length()];
int ilen = text.length() - 1;
if(ilen > 0) {
for (int i = 0; i < ilen; i++) {
char c = text.charAt(i);
spaceIndex[i + 1] = (c == ' ' && isPunctuation(text.charAt(i + 1)) )|| c == '-' || c == '\u2010' || c== '\n';
//中文的标点符号都是可以直接断开的
spaceIndex[i + 1] = (c == ' ' && isPunctuation(text.charAt(i + 1)) )|| c == '-' || c == '\u2010' || c== '\n'|| isChinesePunctuation( c);
//需要保证下一个字符不是中文,下一个字符如果是中文的话,允许分行
char nextC = text.charAt(i+1);
noSwitchIndex[i + 1] = (c=='/' || c == '.' || c == ':' || c == ';') && !isChinese(nextC);
}
}
}
@ -32,6 +39,23 @@ public class SpaceWithPunctuationBreakIterator extends BreakIterator {
return code == 24 || code == 20 || code == 21 || code == 22 || code == 23;
}
public boolean isChinese(char c){
return c >= 0x4E00 && c <= 0x9FBF;
}
// 根据UnicodeBlock方法判断中文标点符号
public boolean isChinesePunctuation(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS) {
return true;
} else {
return false;
}
}
public int first() {
throw new UnsupportedOperationException();
}
@ -48,6 +72,10 @@ public class SpaceWithPunctuationBreakIterator extends BreakIterator {
if(currentIndex == currentPos) {
currentPos = this.iterator.next();
}
if (currentPos > -1 && currentPos < noSwitchIndex.length && noSwitchIndex[currentPos]) {
currentIndex = currentPos;
return this.next();
}
for(int i = currentIndex + 1; i < currentPos; i++){
if(spaceIndex[i]){
currentIndex = i;

5
fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/HTMLWorker.java

@ -50,6 +50,7 @@
package com.fr.third.v2.lowagie.text.html.simpleparser;
import com.fr.third.v2.lowagie.text.pdf.PdfFont;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
@ -159,6 +160,10 @@ public class HTMLWorker implements SimpleXMLDocHandler, DocListener {
return parseToList(reader, style, null);
}
public static void initDefaultFont(String fontName) {
PdfFont.initDefaultFont(fontName);
}
public static ArrayList parseToList(Reader reader, StyleSheet style,
HashMap interfaceProps) throws IOException {
HTMLWorker worker = new HTMLWorker(null);

40
fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfChunk.java

@ -53,6 +53,7 @@ import java.awt.Color;
import java.awt.FontMetrics;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -92,6 +93,8 @@ public class PdfChunk {
private static final String BREAK_TAG = "<br>";
private final static char EMPTY_SYMBOL = ' ';
private boolean breakTag = false;
public float getHeight() {
@ -309,7 +312,6 @@ public class PdfChunk {
if (splitCharacter == null)
splitCharacter = DefaultSplitCharacter.DEFAULT;
}
// methods
/** Gets the Unicode equivalent to a CID.
@ -362,11 +364,11 @@ public class PdfChunk {
// or until the totalWidth is reached
int length = value.length();
char valueArray[] = value.toCharArray();
BreakIterator iterator = BreakIterator.getLineInstance(Locale.getDefault());
BreakIterator iterator1 = new SpaceWithPunctuationBreakIterator(value, iterator);
BreakIterator iterator = new SpaceWithPunctuationBreakIterator(value, BreakIterator.getLineInstance(Locale.getDefault()));
char character = 0;
boolean hasEmptySymbolEndOfLine = false; //行末有空格存在 ps:不存在连续空格键
while (currentPosition < length) {
int next = iterator1.next();
int next = iterator.next();
if(next < 1){
break;
}
@ -386,11 +388,17 @@ public class PdfChunk {
}
String substring = value.substring(start, next);
currentWidth += font.width(substring);
if (currentWidth + indent.getRight() > width){
currentPosition = start - 1;
if (currentWidth + indent.getRight() > width) {
if (dealWithEmptySymbol(substring, currentWidth + indent.getRight(), width)) {
//行末空格(加上该空格大于限制的行宽,减去则小于限制的行宽)、需要去掉该空格,不然下划线、删除线什么的会变长
//该空格不能留给下一行
hasEmptySymbolEndOfLine=true;
start = next;
} else {
currentPosition = start - 1;
}
break;
}
start = next;
}
@ -401,12 +409,26 @@ public class PdfChunk {
}
// otherwise, the string has to be truncated
String returnValue = value.substring(start);
value = value.substring(0, start);
value = value.substring(0, start - (hasEmptySymbolEndOfLine ? 1 : 0));
PdfChunk pc = new PdfChunk(returnValue, this);
return pc;
}
/**
/**
* @param text 文本
* @param totalWidth 已经处理过的文本和当前文本的宽度和
* @param lineWidth 行宽
* @return true : 去掉text末尾的空格后小于行宽
*/
private boolean dealWithEmptySymbol(String text, float totalWidth, float lineWidth) {
if (null == text || 0 == text.length()) {
return false;
}
//HTML解析后不存在连续多个空格键存在的情况,因此只需去除末尾的空格键
return text.charAt(text.length() - 1) == EMPTY_SYMBOL && totalWidth - getFont().width(EMPTY_SYMBOL) < lineWidth;
}
/**
* Truncates this <CODE>PdfChunk</CODE> if it's too long for the given width.
* <P>
* Returns <VAR>null</VAR> if the <CODE>PdfChunk</CODE> wasn't truncated.

104
fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfFont.java

@ -52,6 +52,9 @@ package com.fr.third.v2.lowagie.text.pdf;
import com.fr.third.v2.lowagie.text.ExceptionConverter;
import com.fr.third.v2.lowagie.text.Font;
import com.fr.third.v2.lowagie.text.Image;
import java.awt.font.TextAttribute;
import java.util.HashMap;
import java.util.Map;
import sun.font.FontDesignMetrics;
import java.awt.FontMetrics;
@ -74,10 +77,13 @@ import java.awt.geom.AffineTransform;
*/
public class PdfFont implements Comparable {
private static final int ONE_THOUSAND = 1000 ;
private Font oriFont;
public static float SCALE = 100;
private static String DEFAULT_FONT_NAME = "";
/** the font metrics. */
// private BaseFont font;
@ -96,6 +102,12 @@ public class PdfFont implements Comparable {
this.oriFont = oriFont;
}
public static void initDefaultFont(String fontName) {
if ("" == DEFAULT_FONT_NAME && null != fontName) {
DEFAULT_FONT_NAME = fontName;
}
}
// methods
/**
@ -153,6 +165,20 @@ public class PdfFont implements Comparable {
return width(' ');
}
private FontMetrics metrics;
private java.awt.Font scaleFont;
private java.awt.Font scaleDefaultFont;
private FontMetrics getMetrics(java.awt.Font font) {
if (null == metrics || !font.equals(metrics.getFont())) {
metrics = FontDesignMetrics.getMetrics(font);
return metrics;
}
return metrics;
}
/**
* Returns the width of a certain character of this font.
*
@ -160,45 +186,71 @@ public class PdfFont implements Comparable {
* @return a width in Text Space
*/
float width(int character) {
FontMetrics metrics = FontDesignMetrics.getMetrics(getAwtFont());
if (image == null)
return metrics.charWidth(character) * hScale;
else
public float width(int character) {
if (null != image) {
return image.getScaledWidth();
}
java.awt.Font font = getScaleAwtFont();
font = font.canDisplay(character) ? font : getScaleDefaultAwtFont();
return getMetrics(font).charWidth(replaceNbsp(character)) / SCALE;
}
float width(String s) {
double width = 0.0d;
java.awt.Font font = this.getAwtFont();
if (font.getSize2D() > 0) {
float scale = ONE_THOUSAND / font.getSize2D();
java.awt.Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale));
width = derivedFont.getStringBounds(s, new FontRenderContext(new AffineTransform(), true, true)).getWidth();
if (derivedFont.isTransformed()){
width /= scale;
}
}
if (image == null)
return (float) width * hScale;
else
public float width(String s) {
if (null != image) {
return image.getScaledWidth();
}
if (null == s) {
return 0f;
}
float num = 0f;
for (int i = 0; i < s.length(); i++) {
num += width(s.charAt(i));
}
return num;
}
int replaceNbsp(int character) {
return character == 160 ? (canDisplayNbsp() ? character : 32) : character;
}
private boolean canDisplayNbsp() {
return getScaleAwtFont().canDisplay((char) 160);
}
BaseFont getFont() {
return oriFont.getCalculatedBaseFont(false);
return oriFont.getCalculatedBaseFont(false);
}
public java.awt.Font getAwtFont() {
int style = Font.NORMAL;
return getAwtFont(oriFont.getFontName(), 1f);
}
private java.awt.Font getScaleAwtFont() {
if (null == scaleFont) {
scaleFont = getAwtFont(oriFont.getFontName(), SCALE);
}
return scaleFont;
}
private java.awt.Font getScaleDefaultAwtFont() {
if (null == scaleDefaultFont) {
scaleDefaultFont = getAwtFont(DEFAULT_FONT_NAME, SCALE);
}
return scaleDefaultFont;
}
private java.awt.Font getAwtFont(String fontName,float scale) {
Map attrMap = new HashMap(4);
attrMap.put(TextAttribute.FAMILY, fontName);
attrMap.put(TextAttribute.SIZE, new Float(oriFont.getSize() * scale));
if (oriFont.isBold()) {
style |= Font.BOLD;
attrMap.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
}
if(oriFont.isItalic()){
style |= Font.ITALIC;
if (oriFont.isItalic()) {
attrMap.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
}
return new java.awt.Font(oriFont.getFontName(), style, (int)oriFont.getSize());
return new java.awt.Font(attrMap);
}
public Font getOriFont(){

9
fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java

@ -334,6 +334,8 @@ public final class SimpleXMLParser {
return;
}
state = restoreState();
//防止 如<br/> 等标签后面的空格键生效
nowhite = false;
break;
// we are processing CDATA
@ -376,8 +378,11 @@ public final class SimpleXMLParser {
char ce = EntitiesToUnicode.decodeEntity(cent);
if (ce == '\0')
text.append('&').append(cent).append(';');
else
text.append(ce);
else {
text.append(ce);
//防止如 &nbsp; 等标签后面的空格无效
nowhite = true;
}
} else if ((character != '#' && (character < '0' || character > '9') && (character < 'a' || character > 'z')
&& (character < 'A' || character > 'Z')) || entity.length() >= 7) {
state = restoreState();

Loading…
Cancel
Save