diff --git a/fine-itext-old/src/com/fr/third/com/lowagie/text/pdf/PdfGraphics2D.java b/fine-itext-old/src/com/fr/third/com/lowagie/text/pdf/PdfGraphics2D.java index 5a13315c3..ee5a7cfcf 100755 --- a/fine-itext-old/src/com/fr/third/com/lowagie/text/pdf/PdfGraphics2D.java +++ b/fine-itext-old/src/com/fr/third/com/lowagie/text/pdf/PdfGraphics2D.java @@ -382,7 +382,10 @@ public class PdfGraphics2D extends Graphics2D { // value. When they are the same value then we are normally dealing // with a single font that has been made into an italic or bold // font. - if (font.isItalic() && font.getFontName().equals(font.getName())) { + if (font.isItalic()) + //awt.font只要样式,不验证是否安装,真实绘制的字体是 baseFont + // && font.getFontName().equals(font.getName())) + { float angle = baseFont.getFontDescriptor(BaseFont.ITALICANGLE, 1000); float angle2 = font.getItalicAngle(); // We don't have an italic version of this font so we need @@ -419,10 +422,13 @@ public class PdfGraphics2D extends Graphics2D { weight = (font.isBold()) ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR; } - if ((font.isBold() || (weight.floatValue() >= TextAttribute.WEIGHT_SEMIBOLD.floatValue())) - && (font.getFontName().equals(font.getName()))) { + if ((font.isBold() || (weight.floatValue() >= TextAttribute.WEIGHT_SEMIBOLD.floatValue()))) + //awt.font只要样式,不验证是否安装,真实绘制的字体是 baseFont + // && (font.getFontName().equals(font.getName()))) + { // Simulate a bold font. - float strokeWidth = font.getSize2D() * (weight.floatValue() - TextAttribute.WEIGHT_REGULAR.floatValue()) / 30f; + // 30有点粗 ,换成40 + float strokeWidth = font.getSize2D() * (weight.floatValue() - TextAttribute.WEIGHT_REGULAR.floatValue()) / 40f; if (strokeWidth != 1) { if(realPaint instanceof Color){ cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE); diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/html/SpaceWithPunctuationBreakIterator.java b/fine-itext/src/com/fr/third/v2/lowagie/text/html/SpaceWithPunctuationBreakIterator.java index 94322266b..1d4c7b035 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/html/SpaceWithPunctuationBreakIterator.java +++ b/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; diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/html/WebColors.java b/fine-itext/src/com/fr/third/v2/lowagie/text/html/WebColors.java index 1004d2414..512def96d 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/html/WebColors.java +++ b/fine-itext/src/com/fr/third/v2/lowagie/text/html/WebColors.java @@ -66,147 +66,170 @@ public class WebColors extends HashMap { /** HashMap containing all the names and corresponding color values. */ public static final WebColors NAMES = new WebColors(); static { - NAMES.put("aliceblue", new int[] { 0xf0, 0xf8, 0xff, 0x00 }); - NAMES.put("antiquewhite", new int[] { 0xfa, 0xeb, 0xd7, 0x00 }); - NAMES.put("aqua", new int[] { 0x00, 0xff, 0xff, 0x00 }); - NAMES.put("aquamarine", new int[] { 0x7f, 0xff, 0xd4, 0x00 }); - NAMES.put("azure", new int[] { 0xf0, 0xff, 0xff, 0x00 }); - NAMES.put("beige", new int[] { 0xf5, 0xf5, 0xdc, 0x00 }); - NAMES.put("bisque", new int[] { 0xff, 0xe4, 0xc4, 0x00 }); - NAMES.put("black", new int[] { 0x00, 0x00, 0x00, 0x00 }); - NAMES.put("blanchedalmond", new int[] { 0xff, 0xeb, 0xcd, 0x00 }); - NAMES.put("blue", new int[] { 0x00, 0x00, 0xff, 0x00 }); - NAMES.put("blueviolet", new int[] { 0x8a, 0x2b, 0xe2, 0x00 }); - NAMES.put("brown", new int[] { 0xa5, 0x2a, 0x2a, 0x00 }); - NAMES.put("burlywood", new int[] { 0xde, 0xb8, 0x87, 0x00 }); - NAMES.put("cadetblue", new int[] { 0x5f, 0x9e, 0xa0, 0x00 }); - NAMES.put("chartreuse", new int[] { 0x7f, 0xff, 0x00, 0x00 }); - NAMES.put("chocolate", new int[] { 0xd2, 0x69, 0x1e, 0x00 }); - NAMES.put("coral", new int[] { 0xff, 0x7f, 0x50, 0x00 }); - NAMES.put("cornflowerblue", new int[] { 0x64, 0x95, 0xed, 0x00 }); - NAMES.put("cornsilk", new int[] { 0xff, 0xf8, 0xdc, 0x00 }); - NAMES.put("crimson", new int[] { 0xdc, 0x14, 0x3c, 0x00 }); - NAMES.put("cyan", new int[] { 0x00, 0xff, 0xff, 0x00 }); - NAMES.put("darkblue", new int[] { 0x00, 0x00, 0x8b, 0x00 }); - NAMES.put("darkcyan", new int[] { 0x00, 0x8b, 0x8b, 0x00 }); - NAMES.put("darkgoldenrod", new int[] { 0xb8, 0x86, 0x0b, 0x00 }); - NAMES.put("darkgray", new int[] { 0xa9, 0xa9, 0xa9, 0x00 }); - NAMES.put("darkgreen", new int[] { 0x00, 0x64, 0x00, 0x00 }); - NAMES.put("darkkhaki", new int[] { 0xbd, 0xb7, 0x6b, 0x00 }); - NAMES.put("darkmagenta", new int[] { 0x8b, 0x00, 0x8b, 0x00 }); - NAMES.put("darkolivegreen", new int[] { 0x55, 0x6b, 0x2f, 0x00 }); - NAMES.put("darkorange", new int[] { 0xff, 0x8c, 0x00, 0x00 }); - NAMES.put("darkorchid", new int[] { 0x99, 0x32, 0xcc, 0x00 }); - NAMES.put("darkred", new int[] { 0x8b, 0x00, 0x00, 0x00 }); - NAMES.put("darksalmon", new int[] { 0xe9, 0x96, 0x7a, 0x00 }); - NAMES.put("darkseagreen", new int[] { 0x8f, 0xbc, 0x8f, 0x00 }); - NAMES.put("darkslateblue", new int[] { 0x48, 0x3d, 0x8b, 0x00 }); - NAMES.put("darkslategray", new int[] { 0x2f, 0x4f, 0x4f, 0x00 }); - NAMES.put("darkturquoise", new int[] { 0x00, 0xce, 0xd1, 0x00 }); - NAMES.put("darkviolet", new int[] { 0x94, 0x00, 0xd3, 0x00 }); - NAMES.put("deeppink", new int[] { 0xff, 0x14, 0x93, 0x00 }); - NAMES.put("deepskyblue", new int[] { 0x00, 0xbf, 0xff, 0x00 }); - NAMES.put("dimgray", new int[] { 0x69, 0x69, 0x69, 0x00 }); - NAMES.put("dodgerblue", new int[] { 0x1e, 0x90, 0xff, 0x00 }); - NAMES.put("firebrick", new int[] { 0xb2, 0x22, 0x22, 0x00 }); - NAMES.put("floralwhite", new int[] { 0xff, 0xfa, 0xf0, 0x00 }); - NAMES.put("forestgreen", new int[] { 0x22, 0x8b, 0x22, 0x00 }); - NAMES.put("fuchsia", new int[] { 0xff, 0x00, 0xff, 0x00 }); - NAMES.put("gainsboro", new int[] { 0xdc, 0xdc, 0xdc, 0x00 }); - NAMES.put("ghostwhite", new int[] { 0xf8, 0xf8, 0xff, 0x00 }); - NAMES.put("gold", new int[] { 0xff, 0xd7, 0x00, 0x00 }); - NAMES.put("goldenrod", new int[] { 0xda, 0xa5, 0x20, 0x00 }); - NAMES.put("gray", new int[] { 0x80, 0x80, 0x80, 0x00 }); - NAMES.put("green", new int[] { 0x00, 0x80, 0x00, 0x00 }); - NAMES.put("greenyellow", new int[] { 0xad, 0xff, 0x2f, 0x00 }); - NAMES.put("honeydew", new int[] { 0xf0, 0xff, 0xf0, 0x00 }); - NAMES.put("hotpink", new int[] { 0xff, 0x69, 0xb4, 0x00 }); - NAMES.put("indianred", new int[] { 0xcd, 0x5c, 0x5c, 0x00 }); - NAMES.put("indigo", new int[] { 0x4b, 0x00, 0x82, 0x00 }); - NAMES.put("ivory", new int[] { 0xff, 0xff, 0xf0, 0x00 }); - NAMES.put("khaki", new int[] { 0xf0, 0xe6, 0x8c, 0x00 }); - NAMES.put("lavender", new int[] { 0xe6, 0xe6, 0xfa, 0x00 }); - NAMES.put("lavenderblush", new int[] { 0xff, 0xf0, 0xf5, 0x00 }); - NAMES.put("lawngreen", new int[] { 0x7c, 0xfc, 0x00, 0x00 }); - NAMES.put("lemonchiffon", new int[] { 0xff, 0xfa, 0xcd, 0x00 }); - NAMES.put("lightblue", new int[] { 0xad, 0xd8, 0xe6, 0x00 }); - NAMES.put("lightcoral", new int[] { 0xf0, 0x80, 0x80, 0x00 }); - NAMES.put("lightcyan", new int[] { 0xe0, 0xff, 0xff, 0x00 }); - NAMES.put("lightgoldenrodyellow", new int[] { 0xfa, 0xfa, 0xd2, 0x00 }); - NAMES.put("lightgreen", new int[] { 0x90, 0xee, 0x90, 0x00 }); - NAMES.put("lightgrey", new int[] { 0xd3, 0xd3, 0xd3, 0x00 }); - NAMES.put("lightpink", new int[] { 0xff, 0xb6, 0xc1, 0x00 }); - NAMES.put("lightsalmon", new int[] { 0xff, 0xa0, 0x7a, 0x00 }); - NAMES.put("lightseagreen", new int[] { 0x20, 0xb2, 0xaa, 0x00 }); - NAMES.put("lightskyblue", new int[] { 0x87, 0xce, 0xfa, 0x00 }); - NAMES.put("lightslategray", new int[] { 0x77, 0x88, 0x99, 0x00 }); - NAMES.put("lightsteelblue", new int[] { 0xb0, 0xc4, 0xde, 0x00 }); - NAMES.put("lightyellow", new int[] { 0xff, 0xff, 0xe0, 0x00 }); - NAMES.put("lime", new int[] { 0x00, 0xff, 0x00, 0x00 }); - NAMES.put("limegreen", new int[] { 0x32, 0xcd, 0x32, 0x00 }); - NAMES.put("linen", new int[] { 0xfa, 0xf0, 0xe6, 0x00 }); - NAMES.put("magenta", new int[] { 0xff, 0x00, 0xff, 0x00 }); - NAMES.put("maroon", new int[] { 0x80, 0x00, 0x00, 0x00 }); - NAMES.put("mediumaquamarine", new int[] { 0x66, 0xcd, 0xaa, 0x00 }); - NAMES.put("mediumblue", new int[] { 0x00, 0x00, 0xcd, 0x00 }); - NAMES.put("mediumorchid", new int[] { 0xba, 0x55, 0xd3, 0x00 }); - NAMES.put("mediumpurple", new int[] { 0x93, 0x70, 0xdb, 0x00 }); - NAMES.put("mediumseagreen", new int[] { 0x3c, 0xb3, 0x71, 0x00 }); - NAMES.put("mediumslateblue", new int[] { 0x7b, 0x68, 0xee, 0x00 }); - NAMES.put("mediumspringgreen", new int[] { 0x00, 0xfa, 0x9a, 0x00 }); - NAMES.put("mediumturquoise", new int[] { 0x48, 0xd1, 0xcc, 0x00 }); - NAMES.put("mediumvioletred", new int[] { 0xc7, 0x15, 0x85, 0x00 }); - NAMES.put("midnightblue", new int[] { 0x19, 0x19, 0x70, 0x00 }); - NAMES.put("mintcream", new int[] { 0xf5, 0xff, 0xfa, 0x00 }); - NAMES.put("mistyrose", new int[] { 0xff, 0xe4, 0xe1, 0x00 }); - NAMES.put("moccasin", new int[] { 0xff, 0xe4, 0xb5, 0x00 }); - NAMES.put("navajowhite", new int[] { 0xff, 0xde, 0xad, 0x00 }); - NAMES.put("navy", new int[] { 0x00, 0x00, 0x80, 0x00 }); - NAMES.put("oldlace", new int[] { 0xfd, 0xf5, 0xe6, 0x00 }); - NAMES.put("olive", new int[] { 0x80, 0x80, 0x00, 0x00 }); - NAMES.put("olivedrab", new int[] { 0x6b, 0x8e, 0x23, 0x00 }); - NAMES.put("orange", new int[] { 0xff, 0xa5, 0x00, 0x00 }); - NAMES.put("orangered", new int[] { 0xff, 0x45, 0x00, 0x00 }); - NAMES.put("orchid", new int[] { 0xda, 0x70, 0xd6, 0x00 }); - NAMES.put("palegoldenrod", new int[] { 0xee, 0xe8, 0xaa, 0x00 }); - NAMES.put("palegreen", new int[] { 0x98, 0xfb, 0x98, 0x00 }); - NAMES.put("paleturquoise", new int[] { 0xaf, 0xee, 0xee, 0x00 }); - NAMES.put("palevioletred", new int[] { 0xdb, 0x70, 0x93, 0x00 }); - NAMES.put("papayawhip", new int[] { 0xff, 0xef, 0xd5, 0x00 }); - NAMES.put("peachpuff", new int[] { 0xff, 0xda, 0xb9, 0x00 }); - NAMES.put("peru", new int[] { 0xcd, 0x85, 0x3f, 0x00 }); - NAMES.put("pink", new int[] { 0xff, 0xc0, 0xcb, 0x00 }); - NAMES.put("plum", new int[] { 0xdd, 0xa0, 0xdd, 0x00 }); - NAMES.put("powderblue", new int[] { 0xb0, 0xe0, 0xe6, 0x00 }); - NAMES.put("purple", new int[] { 0x80, 0x00, 0x80, 0x00 }); - NAMES.put("red", new int[] { 0xff, 0x00, 0x00, 0x00 }); - NAMES.put("rosybrown", new int[] { 0xbc, 0x8f, 0x8f, 0x00 }); - NAMES.put("royalblue", new int[] { 0x41, 0x69, 0xe1, 0x00 }); - NAMES.put("saddlebrown", new int[] { 0x8b, 0x45, 0x13, 0x00 }); - NAMES.put("salmon", new int[] { 0xfa, 0x80, 0x72, 0x00 }); - NAMES.put("sandybrown", new int[] { 0xf4, 0xa4, 0x60, 0x00 }); - NAMES.put("seagreen", new int[] { 0x2e, 0x8b, 0x57, 0x00 }); - NAMES.put("seashell", new int[] { 0xff, 0xf5, 0xee, 0x00 }); - NAMES.put("sienna", new int[] { 0xa0, 0x52, 0x2d, 0x00 }); - NAMES.put("silver", new int[] { 0xc0, 0xc0, 0xc0, 0x00 }); - NAMES.put("skyblue", new int[] { 0x87, 0xce, 0xeb, 0x00 }); - NAMES.put("slateblue", new int[] { 0x6a, 0x5a, 0xcd, 0x00 }); - NAMES.put("slategray", new int[] { 0x70, 0x80, 0x90, 0x00 }); - NAMES.put("snow", new int[] { 0xff, 0xfa, 0xfa, 0x00 }); - NAMES.put("springgreen", new int[] { 0x00, 0xff, 0x7f, 0x00 }); - NAMES.put("steelblue", new int[] { 0x46, 0x82, 0xb4, 0x00 }); - NAMES.put("tan", new int[] { 0xd2, 0xb4, 0x8c, 0x00 }); - NAMES.put("transparent", new int[] { 0x00, 0x00, 0x00, 0xff }); - NAMES.put("teal", new int[] { 0x00, 0x80, 0x80, 0x00 }); - NAMES.put("thistle", new int[] { 0xd8, 0xbf, 0xd8, 0x00 }); - NAMES.put("tomato", new int[] { 0xff, 0x63, 0x47, 0x00 }); - NAMES.put("turquoise", new int[] { 0x40, 0xe0, 0xd0, 0x00 }); - NAMES.put("violet", new int[] { 0xee, 0x82, 0xee, 0x00 }); - NAMES.put("wheat", new int[] { 0xf5, 0xde, 0xb3, 0x00 }); - NAMES.put("white", new int[] { 0xff, 0xff, 0xff, 0x00 }); - NAMES.put("whitesmoke", new int[] { 0xf5, 0xf5, 0xf5, 0x00 }); - NAMES.put("yellow", new int[] { 0xff, 0xff, 0x00, 0x00 }); - NAMES.put("yellowgreen", new int[] { 0x9, 0xacd, 0x32, 0x00 }); + //比对 https://html-color-codes.info/color-names/ + //Red color names + NAMES.put("indianred", new int[]{0xcd, 0x5c, 0x5c, 0xff}); + NAMES.put("lightcoral", new int[]{0xf0, 0x80, 0x80, 0xff}); + NAMES.put("salmon", new int[]{0xfa, 0x80, 0x72, 0xff}); + NAMES.put("darksalmon", new int[]{0xe9, 0x96, 0x7a, 0xff}); + NAMES.put("lightsalmon", new int[]{0xff, 0xa0, 0x7a, 0xff}); + NAMES.put("crimson", new int[]{0xdc, 0x14, 0x3c, 0xff}); + NAMES.put("firebrick", new int[]{0xb2, 0x22, 0x22, 0xff}); + NAMES.put("darkred", new int[]{0x8b, 0x00, 0x00, 0xff}); + NAMES.put("red", new int[]{0xff, 0x00, 0x00, 0xff}); + + //Pink color names + NAMES.put("pink", new int[]{0xff, 0xc0, 0xcb, 0xff}); + NAMES.put("lightpink", new int[]{0xff, 0xb6, 0xc1, 0xff}); + NAMES.put("hotpink", new int[]{0xff, 0x69, 0xb4, 0xff}); + NAMES.put("deeppink", new int[]{0xff, 0x14, 0x93, 0xff}); + NAMES.put("mediumvioletred", new int[]{0xc7, 0x15, 0x85, 0xff}); + NAMES.put("palevioletred", new int[]{0xdb, 0x70, 0x93, 0xff}); + + //Orange color names + NAMES.put("coral", new int[]{0xff, 0x7f, 0x50, 0xff}); + NAMES.put("tomato", new int[]{0xff, 0x63, 0x47, 0xff}); + NAMES.put("orangered", new int[]{0xff, 0x45, 0x00, 0xff}); + NAMES.put("darkorange", new int[]{0xff, 0x8c, 0x00, 0xff}); + NAMES.put("orange", new int[]{0xff, 0xa5, 0x00, 0xff}); + + //Orange color names + NAMES.put("gold", new int[]{0xff, 0xd7, 0x00, 0xff}); + NAMES.put("yellow", new int[]{0xff, 0xff, 0x00, 0xff}); + NAMES.put("lightyellow", new int[]{0xff, 0xff, 0xefe, 0xff}); + NAMES.put("lemonchiffon", new int[]{0xff, 0xfa, 0xcd, 0xff}); + NAMES.put("lightgoldenrodyellow", new int[]{0xfa, 0xfa, 0xd2, 0xff}); + NAMES.put("papayawhip", new int[]{0xff, 0xef, 0xd5, 0xff}); + NAMES.put("moccasin", new int[]{0xff, 0xe4, 0xb5, 0xff}); + NAMES.put("peachpuff", new int[]{0xff, 0xda, 0xb9, 0xff}); + NAMES.put("palegoldenrod", new int[]{0xee, 0xe8, 0xaa, 0xff}); + NAMES.put("khaki", new int[]{0xf0, 0xe6, 0x8c, 0xff}); + NAMES.put("darkkhaki", new int[]{0xbd, 0xb7, 0x6b, 0xff}); + + //Purple color names + NAMES.put("lavender", new int[]{0xe6, 0xe6, 0xfa, 0xff}); + NAMES.put("thistle", new int[]{0xd8, 0xbf, 0xd8, 0xff}); + NAMES.put("plum", new int[]{0xdd, 0xa0, 0xdd, 0xff}); + NAMES.put("violet", new int[]{0xee, 0x82, 0xee, 0xff}); + NAMES.put("orchid", new int[]{0xda, 0x70, 0xd6, 0xff}); + NAMES.put("fuchsia", new int[]{0xff, 0x00, 0xff, 0xff}); + NAMES.put("magenta", new int[]{0xff, 0x00, 0xff, 0xff}); + NAMES.put("mediumorchid", new int[]{0xba, 0x55, 0xd3, 0xff}); + NAMES.put("mediumpurple", new int[]{0x93, 0x70, 0xdb, 0xff}); + NAMES.put("amethyst", new int[]{0x99, 0x66, 0xcc, 0xff}); + NAMES.put("blueviolet", new int[]{0x8a, 0x2b, 0xe2, 0xff}); + NAMES.put("darkviolet", new int[]{0x94, 0x00, 0xd3, 0xff}); + NAMES.put("darkorchid", new int[]{0x99, 0x32, 0xcc, 0xff}); + NAMES.put("darkmagenta", new int[]{0x8b, 0x00, 0x8b, 0xff}); + NAMES.put("purple", new int[]{0x80, 0x00, 0x80, 0xff}); + NAMES.put("indigo", new int[]{0x4b, 0x00, 0x82, 0xff}); + NAMES.put("slateblue", new int[]{0x6a, 0x5a, 0xcd, 0xff}); + NAMES.put("darkslateblue", new int[]{0x48, 0x3d, 0x8b, 0xff}); + NAMES.put("mediumslateblue", new int[]{0x7b, 0x68, 0xee, 0xff}); + + //Green color names + NAMES.put("greenyellow", new int[]{0xad, 0xff, 0x2f, 0xff}); + NAMES.put("chartreuse", new int[]{0x7f, 0xff, 0x00, 0xff}); + NAMES.put("lawngreen", new int[]{0x7c, 0xfc, 0x00, 0xff}); + NAMES.put("lime", new int[]{0x00, 0xff, 0x00, 0xff}); + NAMES.put("limegreen", new int[]{0x32, 0xcd, 0x32, 0xff}); + NAMES.put("palegreen", new int[]{0x98, 0xfb, 0x98, 0xff}); + NAMES.put("lightgreen", new int[]{0x90, 0xee, 0x90, 0xff}); + NAMES.put("mediumspringgreen", new int[]{0x00, 0xfa, 0x9a, 0xff}); + NAMES.put("springgreen", new int[]{0x00, 0xff, 0x7f, 0xff}); + NAMES.put("mediumseagreen", new int[]{0x3c, 0xb3, 0x71, 0xff}); + NAMES.put("seagreen", new int[]{0x2e, 0x8b, 0x57, 0xff}); + NAMES.put("forestgreen", new int[]{0x22, 0x8b, 0x22, 0xff}); + NAMES.put("green", new int[]{0x00, 0x80, 0x00, 0xff}); + NAMES.put("darkgreen", new int[]{0x00, 0x64, 0x00, 0xff}); + NAMES.put("yellowgreen", new int[]{0x9a, 0xcd, 0x32, 0xff}); + NAMES.put("olivedrab", new int[]{0x6b, 0x8e, 0x23, 0xff}); + NAMES.put("olive", new int[]{0x80, 0x80, 0x00, 0xff}); + NAMES.put("darkolivegreen", new int[]{0x55, 0x6b, 0x2f, 0xff}); + NAMES.put("mediumaquamarine", new int[]{0x66, 0xcd, 0xaa, 0xff}); + NAMES.put("darkseagreen", new int[]{0x8f, 0xbc, 0x8f, 0xff}); + NAMES.put("lightseagreen", new int[]{0x20, 0xb2, 0xaa, 0xff}); + NAMES.put("darkcyan", new int[]{0x00, 0x8b, 0x8b, 0xff}); + NAMES.put("teal", new int[]{0x00, 0x80, 0x80, 0xff}); + + //Blue color names + NAMES.put("aqua", new int[]{0x00, 0xff, 0xff, 0xff}); + NAMES.put("cyan", new int[]{0x00, 0xff, 0xff, 0xff}); + NAMES.put("lightcyan", new int[]{0xe0, 0xff, 0xff, 0xff}); + NAMES.put("paleturquoise", new int[]{0xaf, 0xee, 0xee, 0xff}); + NAMES.put("aquamarine", new int[]{0x7f, 0xff, 0xd4, 0xff}); + NAMES.put("turquoise", new int[]{0x40, 0xe0, 0xd0, 0xff}); + NAMES.put("mediumturquoise", new int[]{0x48, 0xd1, 0xcc, 0xff}); + NAMES.put("darkturquoise", new int[]{0x00, 0xce, 0xd1, 0xff}); + NAMES.put("cadetblue", new int[]{0x5f, 0x9e, 0xa0, 0xff}); + NAMES.put("steelblue", new int[]{0x46, 0x82, 0xb4, 0xff}); + NAMES.put("lightsteelblue", new int[]{0xb0, 0xc4, 0xde, 0xff}); + NAMES.put("powderblue", new int[]{0xb0, 0xe0, 0xe6, 0xff}); + NAMES.put("lightblue", new int[]{0xad, 0xd8, 0xe6, 0xff}); + NAMES.put("skyblue", new int[]{0x87, 0xce, 0xeb, 0xff}); + NAMES.put("lightskyblue", new int[]{0x87, 0xce, 0xfa, 0xff}); + NAMES.put("deepskyblue", new int[]{0x00, 0xbf, 0xff, 0xff}); + NAMES.put("dodgerblue", new int[]{0x1e, 0x90, 0xff, 0xff}); + NAMES.put("cornflowerblue", new int[]{0x64, 0x95, 0xed, 0xff}); + NAMES.put("royalblue", new int[]{0x41, 0x69, 0xe1, 0xff}); + NAMES.put("blue", new int[]{0x00, 0x00, 0xff, 0xff}); + NAMES.put("mediumblue", new int[]{0x00, 0x00, 0xcd, 0xff}); + NAMES.put("darkblue", new int[]{0x00, 0x00, 0x8b, 0xff}); + NAMES.put("navy", new int[]{0x00, 0x00, 0x80, 0xff}); + NAMES.put("midnightblue", new int[]{0x19, 0x19, 0x70, 0xff}); + + //Brown color names + NAMES.put("cornsilk", new int[]{0xff, 0xf8, 0xdc, 0xff}); + NAMES.put("blanchedalmond", new int[]{0xff, 0xeb, 0xcd, 0xff}); + NAMES.put("bisque", new int[]{0xff, 0xe4, 0xc4, 0xff}); + NAMES.put("navajowhite", new int[]{0xff, 0xde, 0xad, 0xff}); + NAMES.put("wheat", new int[]{0xf5, 0xde, 0xb3, 0xff}); + NAMES.put("burlywood", new int[]{0xde, 0xb8, 0x87, 0xff}); + NAMES.put("tan", new int[]{0xd2, 0xb4, 0x8c, 0xff}); + NAMES.put("rosybrown", new int[]{0xbc, 0x8f, 0x8f, 0xff}); + NAMES.put("sandybrown", new int[]{0xf4, 0xa4, 0x60, 0xff}); + NAMES.put("goldenrod", new int[]{0xda, 0xa5, 0x20, 0xff}); + NAMES.put("darkgoldenrod", new int[]{0xb8, 0x86, 0x0b, 0xff}); + NAMES.put("peru", new int[]{0xcd, 0x85, 0x3f, 0xff}); + NAMES.put("chocolate", new int[]{0xd2, 0x69, 0x1e, 0xff}); + NAMES.put("saddlebrown", new int[]{0x8b, 0x45, 0x13, 0xff}); + NAMES.put("sienna", new int[]{0xa0, 0x52, 0x2d, 0xff}); + NAMES.put("brown", new int[]{0xa5, 0x2a, 0x2a, 0xff}); + NAMES.put("maroon", new int[]{0x80, 0x00, 0x00, 0xff}); + + //White color names + NAMES.put("white", new int[]{0xff, 0xff, 0xff, 0xff}); + NAMES.put("snow", new int[]{0xff, 0xfa, 0xfa, 0xff}); + NAMES.put("honeydew", new int[]{0xf0, 0xff, 0xf0, 0xff}); + NAMES.put("mintcream", new int[]{0xf5, 0xff, 0xfa, 0xff}); + NAMES.put("azure", new int[]{0xf0, 0xff, 0xff, 0xff}); + NAMES.put("aliceblue", new int[]{0xf0, 0xf8, 0xff, 0xff}); + NAMES.put("ghostwhite", new int[]{0xf8, 0xf8, 0xff, 0xff}); + NAMES.put("whitesmoke", new int[]{0xf5, 0xf5, 0xf5, 0xff}); + NAMES.put("seashell", new int[]{0xff, 0xf5, 0xee, 0xff}); + NAMES.put("beige", new int[]{0xf5, 0xf5, 0xdc, 0xff}); + NAMES.put("oldlace", new int[]{0xfd, 0xf5, 0xe6, 0xff}); + NAMES.put("floralwhite", new int[]{0xff, 0xfa, 0xf0, 0xff}); + NAMES.put("ivory", new int[]{0xff, 0xff, 0xf0, 0xff}); + NAMES.put("antiquewhite", new int[]{0xfa, 0xeb, 0xd7, 0xff}); + NAMES.put("linen", new int[]{0xfa, 0xf0, 0xe6, 0xff}); + NAMES.put("lavenderblush", new int[]{0xff, 0xf0, 0xf5, 0xff}); + NAMES.put("mistyrose", new int[]{0xff, 0xe4, 0xe1, 0xff}); + + //Grey color names + NAMES.put("gainsboro", new int[]{0xdc, 0xdc, 0xdc, 0xff}); + NAMES.put("lightgrey", new int[]{0xd3, 0xd3, 0xd3, 0xff}); + NAMES.put("silver", new int[]{0xc0, 0xc0, 0xc0, 0xff}); + NAMES.put("darkgray", new int[]{0xa9, 0xa9, 0xa9, 0xff}); + NAMES.put("gray", new int[]{0x80, 0x80, 0x80, 0xff}); + NAMES.put("dimgray", new int[]{0x69, 0x69, 0x69, 0xff}); + NAMES.put("lightslategray", new int[]{0x77, 0x88, 0x99, 0xff}); + NAMES.put("slategray", new int[]{0x70, 0x80, 0x90, 0xff}); + NAMES.put("darkslategray", new int[]{0x2f, 0x4f, 0x4f, 0xff}); + NAMES.put("black", new int[]{0x00, 0x00, 0x00, 0xff}); + + //Transparent color names + NAMES.put("transparent", new int[]{0xff, 0xff, 0xff, 0x00}); } /** @@ -258,6 +281,6 @@ public class WebColors extends HashMap { throw new IllegalArgumentException("Color '" + name + "' not found."); c = (int[]) NAMES.get(name); - return new Color(c[0], c[1], c[2], 255); + return new Color(c[0], c[1], c[2], c[3]); } } \ No newline at end of file diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/HTMLWorker.java b/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/HTMLWorker.java index 5a4481ab7..4ccf4aaff 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/HTMLWorker.java +++ b/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; @@ -61,6 +62,7 @@ import java.util.HashMap; import java.util.Stack; import java.util.StringTokenizer; +import com.fr.third.v2.lowagie.text.Cell; import com.fr.third.v2.lowagie.text.DocumentException; import com.fr.third.v2.lowagie.text.Element; import com.fr.third.v2.lowagie.text.ExceptionConverter; @@ -72,6 +74,8 @@ import com.fr.third.v2.lowagie.text.Rectangle; import com.fr.third.v2.lowagie.text.TextElementArray; import com.fr.third.v2.lowagie.text.html.CSSUtils; import com.fr.third.v2.lowagie.text.html.HtmlTags; +import com.fr.third.v2.lowagie.text.pdf.PdfCell; +import com.fr.third.v2.lowagie.text.pdf.PdfPCell; import com.fr.third.v2.lowagie.text.pdf.draw.LineSeparator; import com.fr.third.v2.lowagie.text.xml.simpleparser.SimpleXMLDocHandler; import com.fr.third.v2.lowagie.text.html.Markup; @@ -154,6 +158,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); @@ -659,10 +667,13 @@ public class HTMLWorker implements SimpleXMLDocHandler, DocListener { cprops.removeChain("tr"); ArrayList cells = new ArrayList(); IncTable table = null; + float maxHeight = 0; while (true) { Object obj = stack.pop(); - if (obj instanceof IncCell) { - cells.add(((IncCell) obj).getCell()); + if (obj instanceof IncCell) { + PdfPCell cell = ((IncCell) obj).getCell(); + cells.add(cell); + maxHeight = Math.max(maxHeight, cell.getStyleHeight()); } if (obj instanceof IncTable) { table = (IncTable) obj; @@ -670,11 +681,11 @@ public class HTMLWorker implements SimpleXMLDocHandler, DocListener { } } float rowHeight = 0.0f; - if(rowHeightPx!=null){ + if (rowHeightPx != null) { rowHeight = CSSUtils.parseFloat(rowHeightPx); } table.addCols(cells); - table.endRow(rowHeight); + table.endRow(Math.max(rowHeight, maxHeight)); stack.push(table); skipText = true; @@ -802,10 +813,15 @@ public class HTMLWorker implements SimpleXMLDocHandler, DocListener { public static final HashMap tagsSupported = new HashMap(); + public static final HashMap tagsPrefixSupported = new HashMap(); + static { StringTokenizer tok = new StringTokenizer(tagsSupportedString); - while (tok.hasMoreTokens()) - tagsSupported.put(tok.nextToken(), null); + while (tok.hasMoreTokens()){ + String s = tok.nextToken(); + tagsSupported.put(s, null); + tagsPrefixSupported.put(s.charAt(0), null); + } } } diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java b/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java index 5da1eb4ca..9c99d6370 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java +++ b/fine-itext/src/com/fr/third/v2/lowagie/text/html/simpleparser/IncTable.java @@ -50,6 +50,7 @@ package com.fr.third.v2.lowagie.text.html.simpleparser; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import com.fr.third.v2.lowagie.text.html.CSSUtils; import com.fr.third.v2.lowagie.text.html.Markup; @@ -66,6 +67,7 @@ public class IncTable { private HashMap props = new HashMap(); private ArrayList rows = new ArrayList(); private ArrayList cols; + private List rowIndex4ZeroHeight = new ArrayList(); private ArrayList rowHeights = new ArrayList(); private ArrayList relativeColWidths = new ArrayList(); @@ -88,6 +90,9 @@ public class IncTable { } public void endRow(float rowHeight) { + if (rowHeight == 0) { + rowIndex4ZeroHeight.add(rowHeights.size()); + } rowHeights.add(rowHeight); if (cols != null) { Collections.reverse(cols); @@ -204,12 +209,53 @@ public class IncTable { } public void processRowHeight(PdfPTable table) { - Float height = CSSUtils.parseFloat((String) props.get("height")); - Float eachHeight = height / table.getRows().size(); + adjustRowHeight(CSSUtils.parseFloat((String) props.get("height"))); //调整行高 - for (int a = 0; a < rowHeights.size(); a++) { - table.getRow(a).setStyleHeight(Math.max(eachHeight, rowHeights.get(a))); + for (int i = 0; i < rowHeights.size(); i++) { + table.getRow(i).setStyleHeight(rowHeights.get(i)); + } + } + + /** + * 调整行高 + * 1、若 tableHeight < rowHeightSum , return ,每行扔取取指定的 height (该行的最大值) + * 2、若 tableHeight > rowHeightSum ,每行都有指定 height (该行的最大值),则按比例平分tableHeight + * 3、若 tableHeight > rowHeightSum ,有些行没有指定 height ,则将tableHeight - rowHeightSum ,平分给这些行 + * 最后,若计算出的内容高度大于上述计算出的行高,则取内容高度 + * + * @param tableHeight + */ + private void adjustRowHeight(Float tableHeight) { + if (0 > tableHeight) { + return; + } + float totalHeight = getRowHeightSum(); + if (tableHeight < totalHeight) { + return; + } + float extraHeight = tableHeight - totalHeight; + int size = rowIndex4ZeroHeight.size(); + //多出来的高度平分给没有设置高度的行 + if (size > 0) { + float eachHeight = extraHeight / size; + for (int i = 0; i < size; i++) { + rowHeights.set(rowIndex4ZeroHeight.get(i), eachHeight); + } + } + //按比例分 + else { + for (int i = 0; i < rowHeights.size(); i++) { + rowHeights.set(i, tableHeight * rowHeights.get(i) / totalHeight); + } + } + } + + private float getRowHeightSum() { + float sum = 0; + for (int i = 0; i < rowHeights.size(); i++) { + sum += rowHeights.get(i); } + return sum; } public TableProperties parseTableProperties(){ diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfChunk.java b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfChunk.java index f5b67439a..8d12c2a14 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfChunk.java +++ b/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; @@ -88,6 +89,14 @@ public class PdfChunk { private static final float FONT_SCALE = 100f; + private static final String BREAK = "\n"; + + private static final String BREAK_TAG = "
"; + + private final static char EMPTY_SYMBOL = ' '; + + private boolean breakTag = false; + public float getHeight() { return height; } @@ -135,16 +144,16 @@ public class PdfChunk { keysNoStroke.put(Chunk.TEXTRENDERMODE, null); } - + // membervariables /** The value of this object. */ protected String value = PdfObject.NOTHING; - + /** The encoding. */ protected String encoding = BaseFont.WINANSI; - - + + /** The font for this PdfChunk. */ protected PdfFont font; @@ -164,7 +173,7 @@ public class PdfChunk { * such as underline. */ protected HashMap attributes = new HashMap(); - + /** * Non metric attributes. *

@@ -172,16 +181,16 @@ public class PdfChunk { * such as Color. */ protected HashMap noStroke = new HashMap(); - + /** true if the chunk split was cause by a newline. */ protected boolean newlineSplit; - + /** The image in this PdfChunk, if it has one */ protected Image image; - + /** The offset in the x direction for the image */ protected float offsetX; - + /** The offset in the y direction for the image */ protected float offsetY; @@ -189,17 +198,18 @@ public class PdfChunk { protected boolean changeLeading = false; // constructors - + /** * Constructs a PdfChunk-object. * * @param string the content of the PdfChunk-object * @param other Chunk with the same style you want for the new Chunk */ - + PdfChunk(String string, PdfChunk other) { thisChunk[0] = this; value = string; + updateBreakTag(); this.font = other.font; this.attributes = other.attributes; this.noStroke = other.noStroke; @@ -217,18 +227,18 @@ public class PdfChunk { splitCharacter = DefaultSplitCharacter.DEFAULT; this.height = other.getHeight(); } - -/** + + /** * Constructs a PdfChunk-object. * * @param chunk the original Chunk-object * @param action the PdfAction if the Chunk comes from an Anchor */ - + public PdfChunk(Chunk chunk, PdfAction action) { thisChunk[0] = this; value = chunk.getContent(); - + updateBreakTag(); Font f = chunk.getFont(); float size = f.getSize(); if (size == Font.UNDEFINED) @@ -302,15 +312,14 @@ public class PdfChunk { if (splitCharacter == null) splitCharacter = DefaultSplitCharacter.DEFAULT; } - // methods - + /** Gets the Unicode equivalent to a CID. - * The (inexistent) CID is translated as '\n'. + * The (inexistent) CID is translated as '\n'. * It has only meaning with CJK fonts with Identity encoding. * @param c the CID code * @return the Unicode equivalent - */ + */ public int getUnicodeEquivalent(int c) { return c; } @@ -355,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; } @@ -379,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; } @@ -394,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 PdfChunk if it's too long for the given width. *

* Returns null if the PdfChunk wasn't truncated. @@ -407,7 +436,7 @@ public class PdfChunk { * @param width a given width * @return the PdfChunk that doesn't fit into the width. */ - + PdfChunk truncate(float width) { if (image != null) { if (image.getScaledWidth() + indent.getLeft() + indent.getRight() > width) { @@ -421,10 +450,10 @@ public class PdfChunk { else return null; } - + int currentPosition = 0; float currentWidth = indent.getLeft(); - + // it's no use trying to split if there isn't even enough place for a space if (width < font.width() + indent.getLeft() + indent.getRight()) { String returnValue = value.substring(1); @@ -432,7 +461,7 @@ public class PdfChunk { PdfChunk pc = new PdfChunk(returnValue, this); return pc; } - + // loop over all the characters of a string // or until the totalWidth is reached int length = value.length(); @@ -451,12 +480,12 @@ public class PdfChunk { currentPosition++; currentPosition++; } - + // if all the characters fit in the total width, null is returned (there is no overflow) if (currentPosition == length) { return null; } - + // otherwise, the string has to be truncated //currentPosition -= 2; // we have to chop off minimum 1 character from the chunk @@ -470,49 +499,49 @@ public class PdfChunk { PdfChunk pc = new PdfChunk(returnValue, this); return pc; } - + // methods to retrieve the membervariables - + /** * Returns the font of this Chunk. * * @return a PdfFont */ - + PdfFont font() { return font; } - + /** * Returns the color of this Chunk. * * @return a Color */ - + Color color() { return (Color)noStroke.get(Chunk.COLOR); } - + /** * Returns the width of this PdfChunk. * * @return a width */ - + public float width() { return font.width(value) + indent.getLeft() + indent.getRight(); } - + /** * Checks if the PdfChunk split was caused by a newline. * @return true if the PdfChunk split was caused by a newline. */ - + public boolean isNewlineSplit() { return newlineSplit; } - + /** * Gets the width of the PdfChunk taking into account the * extra character and word spacing. @@ -520,7 +549,7 @@ public class PdfChunk { * @param wordSpacing the extra word spacing * @return the calculated width */ - + public float getWidthCorrected(float charSpacing, float wordSpacing) { if (image != null) { @@ -532,7 +561,7 @@ public class PdfChunk { ++numberOfSpaces; return width() + (value.length() * charSpacing + numberOfSpaces * wordSpacing); } - + /** * Gets the text displacement relative to the baseline. * @return a displacement in points @@ -544,7 +573,7 @@ public class PdfChunk { } return 0.0f; } - + /** * Trims the last space. * @return the width of the space trimmed, otherwise 0 @@ -565,44 +594,44 @@ public class PdfChunk { } return 0; } - + /** * Gets an attribute. The search is made in attributes * and noStroke. * @param name the attribute key * @return the attribute value or null if not found */ - + public Object getAttribute(String name) { if (attributes.containsKey(name)) return attributes.get(name); return noStroke.get(name); } - + /** *Checks if the attribute exists. * @param name the attribute key * @return true if the attribute exists */ - + boolean isAttribute(String name) { if (attributes.containsKey(name)) return true; return noStroke.containsKey(name); } - + /** * Checks if this PdfChunk needs some special metrics handling. * @return true if this PdfChunk needs some special metrics handling. */ - + boolean isStroked() { return (!attributes.isEmpty()); } - + /** * Checks if this PdfChunk is a Separator Chunk. * @return true if this chunk is a separator. @@ -611,7 +640,7 @@ public class PdfChunk { boolean isSeparator() { return isAttribute(Chunk.SEPARATOR); } - + /** * Checks if this PdfChunk is a horizontal Separator Chunk. * @return true if this chunk is a horizontal separator. @@ -624,7 +653,7 @@ public class PdfChunk { } return false; } - + /** * Checks if this PdfChunk is a tab Chunk. * @return true if this chunk is a separator. @@ -633,7 +662,7 @@ public class PdfChunk { boolean isTab() { return isAttribute(Chunk.TAB); } - + /** * Correction for the tab position based on the left starting position. * @param newValue the new value for the left X. @@ -645,72 +674,72 @@ public class PdfChunk { attributes.put(Chunk.TAB, new Object[]{o[0], o[1], o[2], new Float(newValue)}); } } - + /** * Checks if there is an image in the PdfChunk. * @return true if an image is present */ - + public boolean isImage() { return image != null; } - + /** * Gets the image in the PdfChunk. * @return the image or null */ - + public Image getImage() { return image; } - + /** * Sets the image offset in the x direction * @param offsetX the image offset in the x direction */ - + void setImageOffsetX(float offsetX) { this.offsetX = offsetX; } - + /** * Gets the image offset in the x direction * @return the image offset in the x direction */ - + float getImageOffsetX() { return offsetX; } - + /** * Sets the image offset in the y direction * @param offsetY the image offset in the y direction */ - + void setImageOffsetY(float offsetY) { this.offsetY = offsetY; } - + /** * Gets the image offset in the y direction * @return Gets the image offset in the y direction */ - + float getImageOffsetY() { return offsetY; } - + /** * sets the value. * @param value content of the Chunk */ - + void setValue(String value) { this.value = value; @@ -727,17 +756,17 @@ public class PdfChunk { * Tells you if this string is in Chinese, Japanese, Korean or Identity-H. * @return true if the Chunk has a special encoding */ - + boolean isSpecialEncoding() { return encoding.equals(CJKFont.CJK_ENCODING) || encoding.equals(BaseFont.IDENTITY_H); } - + /** * Gets the encoding of this string. * * @return a String */ - + String getEncoding() { return encoding; } @@ -745,7 +774,7 @@ public class PdfChunk { int length() { return value.length(); } - + int lengthUtf32() { if (!BaseFont.IDENTITY_H.equals(encoding)) return value.length(); @@ -758,17 +787,17 @@ public class PdfChunk { } return total; } - + boolean isExtSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { return splitCharacter.isSplitCharacter(start, current, end, cc, ck); } - + /** * Removes all the ' ' and '-'-characters on the right of a String. *

* @param string the String that has to be trimmed. * @return the trimmed String - */ + */ String trim(String string) { while (string.endsWith(" ") || string.endsWith("\t")) { string = string.substring(0, string.length() - 1); @@ -779,7 +808,7 @@ public class PdfChunk { public boolean changeLeading() { return changeLeading; } - + float getCharWidth(int c) { if (noPrint(c)) return 0; @@ -798,7 +827,7 @@ public class PdfChunk { htmlString.append(""); - htmlString.append(value); + htmlString.append(breakTag ? BREAK_TAG : value); htmlString.append(""); return htmlString.toString(); } @@ -856,4 +885,12 @@ public class PdfChunk { return indent.getLeft(); } + private void updateBreakTag() { + breakTag = BREAK.equals(value); + } + + public boolean isBreakTag() { + return breakTag; + } + } diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfFont.java b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfFont.java index d81d3c878..31592eed7 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfFont.java +++ b/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(){ diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfLine.java b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfLine.java index 4752ffd8e..a4f980b3c 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfLine.java +++ b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfLine.java @@ -91,9 +91,11 @@ public class PdfLine { /** The original width. */ protected float originalWidth; - + protected boolean isRTL = false; + + public float getHeight() { return height; } @@ -155,9 +157,15 @@ public class PdfLine { public PdfChunk add(PdfChunk chunk) { // nothing happens if the chunk is null. if (chunk == null || chunk.toString().equals("")) { - return null; + return null; } - + // add to line if the chunk is break tag ("\n") + if (chunk.isBreakTag()) { + addToLine(chunk); + width = 0; + return null; + } + // we split the chunk to be added PdfChunk overflow = chunk.split(width); newlineSplit = (chunk.isNewlineSplit() || overflow == null); diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java index ed4a6b24a..466ee0df8 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java +++ b/fine-itext/src/com/fr/third/v2/lowagie/text/pdf/PdfPRow.java @@ -50,12 +50,19 @@ package com.fr.third.v2.lowagie.text.pdf; import java.awt.Color; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import com.fr.third.v2.lowagie.text.ExceptionConverter; import com.fr.third.v2.lowagie.text.DocumentException; import com.fr.third.v2.lowagie.text.Element; import com.fr.third.v2.lowagie.text.Image; +import com.fr.third.v2.lowagie.text.ListItem; +import com.fr.third.v2.lowagie.text.Paragraph; import com.fr.third.v2.lowagie.text.Rectangle; +import com.fr.third.v2.lowagie.text.html.CSS; /** * A row in a PdfPTable. @@ -155,10 +162,64 @@ public class PdfPRow { --k; cell.setRight(total); cell.setTop(0); + processColWidth(cell.getColumn().getCompositeElements(), cell.getWidth()); } return true; } + /** + * @param list + * @param width + */ + private void processColWidth(List list, float width) { + if (null == list) { + return; + } + String widthStr = String.valueOf(width); + //调整列宽,不然内容换行任取指定的width + for (int i = 0; i < list.size(); i++) { + setStyleWidth(list.get(i), widthStr); + } + } + + private void setStyleWidth(Element element, String width) { + if (null == element) { + return; + } + try { + switch (element.type()) { + case Element.PARAGRAPH: { + HashMap attr = ((Paragraph) element).getAttributes(); + attr.put(CSS.Property.WIDTH, width); + break; + } + case Element.LIST: { + com.fr.third.v2.lowagie.text.List list = (com.fr.third.v2.lowagie.text.List) element; + for (Iterator i = list.getList().iterator(); i.hasNext(); ) { + setStyleWidth((Element) i.next(), width); + } + break; + } + case Element.LISTITEM: { + ListItem listItem = (ListItem) element; + for (Iterator i = listItem.iterator(); i.hasNext(); ) { + setStyleWidth((Element) i.next(), width); + } + break; + } + case Element.PTABLE: { + PdfPTable table = (PdfPTable) element; + table.setTotalWidth(Float.parseFloat(width)); + break; + } + default: + return; + } + } catch (Exception e) { + throw new ExceptionConverter(e); + } + } + /** * Initializes the extra heights array. * @since 2.1.6 diff --git a/fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java b/fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java index 2a15f56ff..3e765d52e 100644 --- a/fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java +++ b/fine-itext/src/com/fr/third/v2/lowagie/text/xml/simpleparser/SimpleXMLParser.java @@ -75,6 +75,8 @@ */ package com.fr.third.v2.lowagie.text.xml.simpleparser; +import com.fr.third.v2.lowagie.text.html.simpleparser.HTMLWorker; + import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -229,16 +231,13 @@ public final class SimpleXMLParser { // we are in an unknown state before there's actual content case UNKNOWN: if(character == '<') { - saveState(TEXT); - state = TAG_ENCOUNTERED; + beginnOfTag((char) reader.read(), UNKNOWN); } break; // we can encounter any content case TEXT: if(character == '<') { - flush(); - saveState(state); - state = TAG_ENCOUNTERED; + beginnOfTag((char) reader.read(), TEXT); } else if(character == '&') { saveState(state); entity.setLength(0); @@ -335,6 +334,8 @@ public final class SimpleXMLParser { return; } state = restoreState(); + //防止 如
等标签后面的空格键生效 + nowhite = false; break; // we are processing CDATA @@ -377,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); + //防止如   等标签后面的空格无效 + nowhite = true; + } } else if ((character != '#' && (character < '0' || character > '9') && (character < 'a' || character > 'z') && (character < 'A' || character > 'Z')) || entity.length() >= 7) { state = restoreState(); @@ -481,6 +485,27 @@ public final class SimpleXMLParser { } } + + /** + * 处理标签的开头,若不在支持标签范围内,将<符号作为文本处理,例:<1111 (仿造浏览器的处理方式) + */ + public void beginnOfTag(char c, int type) { + previousCharacter = c; + if (c == -1) { + return; + } + if (c == '/' || HTMLWorker.tagsPrefixSupported.containsKey(c)) { + if (type == TEXT) { + flush(); + } + saveState(TEXT); + state = TAG_ENCOUNTERED; + return; + } + text.append((char) character); + nowhite = true; + } + /** * Gets a state from the stack * @return the previous state diff --git a/fine-j2v8/src/com/eclipsesource/v8/PlatformDetector.java b/fine-j2v8/src/com/eclipsesource/v8/PlatformDetector.java index 8fa7868d0..643f57c7c 100644 --- a/fine-j2v8/src/com/eclipsesource/v8/PlatformDetector.java +++ b/fine-j2v8/src/com/eclipsesource/v8/PlatformDetector.java @@ -127,7 +127,7 @@ public class PlatformDetector { //如果if条件全部不符合,就会陷入死循环,代码存在风险 //throw new UnsatisfiedLinkError("Unsupported vendor: " + getName()); - return ""; + return null; } private static String getLinuxOsReleaseId() { @@ -148,7 +148,7 @@ public class PlatformDetector { //linux系统下如果缺失/etc/os-release,/usr/lib/os-release,/etc/redhat-release三个文件,就会和getName方法就会一直互相调用 //throw new UnsatisfiedLinkError("Unsupported linux vendor: " + getName()); - return ""; + return null; } private static String parseLinuxOsReleaseFile(final File file) {