255 lines
8.8 KiB
Java
255 lines
8.8 KiB
Java
|
/**
|
|||
|
* Text.java
|
|||
|
*
|
|||
|
Copyright (c) 2018, Innovatics Inc.
|
|||
|
All rights reserved.
|
|||
|
|
|||
|
Redistribution and use in source and binary forms, with or without modification,
|
|||
|
are permitted provided that the following conditions are met:
|
|||
|
|
|||
|
* Redistributions of source code must retain the above copyright notice,
|
|||
|
this list of conditions and the following disclaimer.
|
|||
|
|
|||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|||
|
this list of conditions and the following disclaimer in the documentation
|
|||
|
and / or other materials provided with the distribution.
|
|||
|
|
|||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
*/
|
|||
|
|
|||
|
package com.pdfjet;
|
|||
|
|
|||
|
import java.util.*;
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* Please see Example_45
|
|||
|
*/
|
|||
|
public class Text {
|
|||
|
|
|||
|
private List<Paragraph> paragraphs;
|
|||
|
private Font font;
|
|||
|
private Font fallbackFont;
|
|||
|
private float x;
|
|||
|
private float y;
|
|||
|
private float w;
|
|||
|
private float x_text;
|
|||
|
private float y_text;
|
|||
|
private float leading;
|
|||
|
private float paragraphLeading;
|
|||
|
private List<float[]> beginParagraphPoints;
|
|||
|
private List<float[]> endParagraphPoints;
|
|||
|
private float spaceBetweenTextLines;
|
|||
|
|
|||
|
|
|||
|
public Text(List<Paragraph> paragraphs) throws Exception {
|
|||
|
this.paragraphs = paragraphs;
|
|||
|
this.font = paragraphs.get(0).list.get(0).getFont();
|
|||
|
this.fallbackFont = paragraphs.get(0).list.get(0).getFallbackFont();
|
|||
|
this.leading = font.getBodyHeight();
|
|||
|
this.paragraphLeading = 2*leading;
|
|||
|
this.beginParagraphPoints = new ArrayList<float[]>();
|
|||
|
this.endParagraphPoints = new ArrayList<float[]>();
|
|||
|
this.spaceBetweenTextLines = font.stringWidth(fallbackFont, Single.space);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public Text setLocation(float x, float y) {
|
|||
|
this.x = x;
|
|||
|
this.y = y;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public Text setWidth(float w) {
|
|||
|
this.w = w;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public Text setLeading(float leading) {
|
|||
|
this.leading = leading;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public Text setParagraphLeading(float paragraphLeading) {
|
|||
|
this.paragraphLeading = paragraphLeading;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public List<float[]> getBeginParagraphPoints() {
|
|||
|
return this.beginParagraphPoints;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public List<float[]> getEndParagraphPoints() {
|
|||
|
return this.endParagraphPoints;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public Text setSpaceBetweenTextLines(float spaceBetweenTextLines) {
|
|||
|
this.spaceBetweenTextLines = spaceBetweenTextLines;
|
|||
|
return this;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public float[] drawOn(Page page) throws Exception {
|
|||
|
return drawOn(page, true);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public float[] drawOn(Page page, boolean draw) throws Exception {
|
|||
|
this.x_text = x;
|
|||
|
this.y_text = y + font.getAscent();
|
|||
|
for (Paragraph paragraph : paragraphs) {
|
|||
|
int numberOfTextLines = paragraph.list.size();
|
|||
|
StringBuilder buf = new StringBuilder();
|
|||
|
for (int i = 0; i < numberOfTextLines; i++) {
|
|||
|
TextLine textLine = paragraph.list.get(i);
|
|||
|
buf.append(textLine.getText());
|
|||
|
}
|
|||
|
for (int i = 0; i < numberOfTextLines; i++) {
|
|||
|
TextLine textLine = paragraph.list.get(i);
|
|||
|
if (i == 0) {
|
|||
|
beginParagraphPoints.add(new float[] { x_text, y_text });
|
|||
|
}
|
|||
|
textLine.setAltDescription((i == 0) ? buf.toString() : Single.space);
|
|||
|
textLine.setActualText((i == 0) ? buf.toString() : Single.space);
|
|||
|
float[] point = drawTextLine(
|
|||
|
page, x_text, y_text, textLine, draw);
|
|||
|
if (i == (numberOfTextLines - 1)) {
|
|||
|
endParagraphPoints.add(new float[] { point[0], point[1] });
|
|||
|
}
|
|||
|
x_text = point[0];
|
|||
|
if (textLine.getTrailingSpace()) {
|
|||
|
x_text += spaceBetweenTextLines;
|
|||
|
}
|
|||
|
y_text = point[1];
|
|||
|
}
|
|||
|
x_text = x;
|
|||
|
y_text += paragraphLeading;
|
|||
|
}
|
|||
|
return new float[] { x_text, y_text + font.getDescent() };
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public float[] drawTextLine(
|
|||
|
Page page,
|
|||
|
float x_text,
|
|||
|
float y_text,
|
|||
|
TextLine textLine,
|
|||
|
boolean draw) throws Exception {
|
|||
|
|
|||
|
Font font = textLine.getFont();
|
|||
|
Font fallbackFont = textLine.getFallbackFont();
|
|||
|
int color = textLine.getColor();
|
|||
|
|
|||
|
String[] tokens = null;
|
|||
|
String str = textLine.getText();
|
|||
|
if (stringIsCJK(str)) {
|
|||
|
tokens = tokenizeCJK(str, this.w);
|
|||
|
}
|
|||
|
else {
|
|||
|
tokens = str.split("\\s+");
|
|||
|
}
|
|||
|
|
|||
|
StringBuilder buf = new StringBuilder();
|
|||
|
boolean firstTextSegment = true;
|
|||
|
for (int i = 0; i < tokens.length; i++) {
|
|||
|
String token = (i == 0) ? tokens[i] : (Single.space + tokens[i]);
|
|||
|
if (font.stringWidth(fallbackFont, token) < (this.w - (x_text - x))) {
|
|||
|
buf.append(token);
|
|||
|
x_text += font.stringWidth(fallbackFont, token);
|
|||
|
}
|
|||
|
else {
|
|||
|
if (draw) {
|
|||
|
new TextLine(font, buf.toString())
|
|||
|
.setFallbackFont(fallbackFont)
|
|||
|
.setLocation(x_text - font.stringWidth(fallbackFont, buf.toString()),
|
|||
|
y_text + textLine.getVerticalOffset())
|
|||
|
.setColor(color)
|
|||
|
.setUnderline(textLine.getUnderline())
|
|||
|
.setStrikeout(textLine.getStrikeout())
|
|||
|
.setLanguage(textLine.getLanguage())
|
|||
|
.setAltDescription(firstTextSegment ? textLine.getAltDescription() : Single.space)
|
|||
|
.setActualText(firstTextSegment ? textLine.getActualText() : Single.space)
|
|||
|
.drawOn(page);
|
|||
|
firstTextSegment = false;
|
|||
|
}
|
|||
|
x_text = x + font.stringWidth(fallbackFont, tokens[i]);
|
|||
|
y_text += leading;
|
|||
|
buf.setLength(0);
|
|||
|
buf.append(tokens[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
if (draw) {
|
|||
|
new TextLine(font, buf.toString())
|
|||
|
.setFallbackFont(fallbackFont)
|
|||
|
.setLocation(x_text - font.stringWidth(fallbackFont, buf.toString()),
|
|||
|
y_text + textLine.getVerticalOffset())
|
|||
|
.setColor(color)
|
|||
|
.setUnderline(textLine.getUnderline())
|
|||
|
.setStrikeout(textLine.getStrikeout())
|
|||
|
.setLanguage(textLine.getLanguage())
|
|||
|
.setAltDescription(firstTextSegment ? textLine.getAltDescription() : Single.space)
|
|||
|
.setActualText(firstTextSegment ? textLine.getActualText() : Single.space)
|
|||
|
.drawOn(page);
|
|||
|
firstTextSegment = false;
|
|||
|
}
|
|||
|
|
|||
|
return new float[] { x_text, y_text };
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private boolean stringIsCJK(String str) {
|
|||
|
// CJK Unified Ideographs Range: 4E00–9FD5
|
|||
|
// Hiragana Range: 3040–309F
|
|||
|
// Katakana Range: 30A0–30FF
|
|||
|
// Hangul Jamo Range: 1100–11FF
|
|||
|
int numOfCJK = 0;
|
|||
|
for (int i = 0; i < str.length(); i++) {
|
|||
|
char ch = str.charAt(i);
|
|||
|
if ((ch >= 0x4E00 && ch <= 0x9FD5) ||
|
|||
|
(ch >= 0x3040 && ch <= 0x309F) ||
|
|||
|
(ch >= 0x30A0 && ch <= 0x30FF) ||
|
|||
|
(ch >= 0x1100 && ch <= 0x11FF)) {
|
|||
|
numOfCJK += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return (numOfCJK > (str.length() / 2));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private String[] tokenizeCJK(String str, float textWidth) {
|
|||
|
List<String> list = new ArrayList<String>();
|
|||
|
StringBuilder buf = new StringBuilder();
|
|||
|
for (int i = 0; i < str.length(); i++) {
|
|||
|
char ch = str.charAt(i);
|
|||
|
if (font.stringWidth(fallbackFont, buf.toString()) < textWidth) {
|
|||
|
buf.append(ch);
|
|||
|
}
|
|||
|
else {
|
|||
|
list.add(buf.toString());
|
|||
|
buf.setLength(0);
|
|||
|
}
|
|||
|
}
|
|||
|
if (buf.toString().length() > 0) {
|
|||
|
list.add(buf.toString());
|
|||
|
}
|
|||
|
return list.toArray(new String[list.size()]);
|
|||
|
}
|
|||
|
|
|||
|
} // End of Text.java
|