iTextで禁則処理を行おうとし、色々調べてみたが、なかなか情報がありませんでした。
なので、こちらとこちらを参考に禁則処理を行うことにしました。
禁則処理文字列は禁則処理…文字コード一覧を基準にして作りました。
isSplitCharacterは文字列を1文字ずつ読み取り、その文字は折り返し可能かどうかの判断をしています。
(true…折り返し可能 false…折り返し不可)
今回、FontSelectorを使っていたので、単純にisSplitCharacterのオーバーライドはできませんでした。
なので、FontSelectorを継承したクラスを作成し、そのクラスにisSplitCharacterをオーバーライドしました。
iText1.3と2.1.7だと微妙にsetter getterの名前が変わっているのでバージョンによってコメントアウトをする必要があります。(25~28行目あたり)
import com.lowagie.text.Font;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.FontSelector;
import com.lowagie.text.pdf.PdfChunk;
import com.lowagie.text.*;
import java.util.ArrayList;
public class FontSelectorHyphenation extends FontSelector {
public FontSelectorHyphenation() {
fonts = new ArrayList();
}
public void addFont(Font font) {
if (font.getBaseFont() != null) {
fonts.add(font);
return;
} else {
BaseFont basefont = font.getCalculatedBaseFont(true);
//itext1.3
// Font font1 = new Font(basefont, font.size(), font.getCalculatedStyle(), font.color());
//itext2.1.7
Font font1 = new Font(basefont, font.getSize(), font.getCalculatedStyle(), font.getColor());
fonts.add(font1);
return;
}
}
public Paragraph Hyphenationparagraph(String s) {
int i = fonts.size();
if (i == 0) throw new IndexOutOfBoundsException("No font is defined.");
char ac[] = s.toCharArray();
int j = ac.length;
StringBuffer stringbuffer = new StringBuffer();
Object obj = null;
int k = -1;
// Phrase phrase = new Phrase();
Paragraph paragraph = new Paragraph();
label0: for (int l = 0; l < j; l++) {
char c = ac[l];
if (c == '\n' || c == '\r') {
stringbuffer.append(c);
continue;
}
int i1 = 0;
do {
if (i1 >= i) continue label0;
Font font = (Font) fonts.get(i1);
if (font.getBaseFont().charExists(c)) {
if (k == i1) {
stringbuffer.append(c);
continue label0;
}
if (stringbuffer.length() > 0 && k != -1) {
Chunk chunk1 = new Chunk(stringbuffer.toString(), (Font) fonts.get(k));
SplitCharacter splitcharacter = setSplitCharacter();
chunk1.setSplitCharacter(splitcharacter);
paragraph.add(chunk1);
stringbuffer = new StringBuffer();
}
stringbuffer.append(c);
k = i1;
continue label0;
}
i1++;
} while (true);
}
if (stringbuffer.length() > 0) {
Chunk chunk = new Chunk(stringbuffer.toString(), (Font) fonts.get(k));
SplitCharacter splitcharacter = setSplitCharacter();
chunk.setSplitCharacter(splitcharacter);
//phase.add(chunk);
paragraph.add(chunk);
}
return paragraph;
}
private SplitCharacter setSplitCharacter() {
return new SplitCharacter() {
@Override
public boolean isSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) {
//初期設定
char c;
if (ck == null) c = cc[current];
else c = (char) ck[Math.min(current, ck.length - 1)].getUnicodeEquivalent(cc[current]);
char c2;
if (ck == null) c2 = cc[current];
else
if (ck[Math.min(current + 1, ck.length - 1)] != null) {
if (current + 1 < end) {
c2 = (char) ck[Math.min(current + 1, ck.length - 1)].getUnicodeEquivalent(cc[current + 1]);
} else {
c2 = ' ';
}
} else {
c2 = (char) ck[Math.min(current, ck.length - 1)].getUnicodeEquivalent(cc[current]);
}
char c3;
if (ck == null) c3 = cc[current];
else
if (ck[Math.min(current + 2, ck.length - 1)] != null) {
if (current + 2 < end) {
c3 = (char) ck[Math.min(current + 2, ck.length - 1)].getUnicodeEquivalent(cc[current + 2]);
} else {
c3 = ' ';
}
} else {
c3 = (char) ck[Math.min(current, ck.length - 1)].getUnicodeEquivalent(cc[current]);
}
char c11;
if (ck == null) c11 = cc[current];
else {
int current_t = 0;
if (current - 1 < 0) {
current_t = current;
} else {
current_t = current - 1;
}
if (ck[Math.min(current_t, ck.length - 1)] != null) {
c11 = (char) ck[Math.min(current_t, ck.length - 1)].getUnicodeEquivalent(cc[current_t]);
} else {
c11 = (char) ck[Math.min(current, ck.length - 1)].getUnicodeEquivalent(cc[current]);
}
}
//trueの場合は改行する。
//falseの場合は改行しない。
//一つ前の文字が英数字の場合の処理
if (c11 >= 0x20 && c11 <= 0x7e) { //!から~まで
if (c <= ' ' || c == '-') {
return true;
}
// if (c < 0x2e80)
return false;
}
if (c != c2 && c2 != c3) {
//行頭文字
switch (c) {
//終わり括弧類
case 0x002C: //,
return false;
case 0xFF0c: //,
return false;
case 0x0029: //)
return false;
case 0xFF09: //)
return false;
case 0x005D: //]
return false;
case 0xFF3D: //]
return false;
case 0xFF5D: //}
return false;
case 0x3001: //、
return false;
case 0x3015: //〕
return false;
case 0x3009: //〉
return false;
case 0x300B: //》
return false;
case 0x300D: //」
return false;
case 0x300F: //』
return false;
case 0x3011: //】
return false;
case 0x3019: //〙
return false;
case 0x3017: //〗
return false;
case 0x301F: //〟
return false;
case 0x2019: //'
return false;
case 0x201D: //"
return false;
case 0xFF60: //⦆
return false;
case 0x00BB: //»
return false;
//行頭禁則和字
case 0x30FD: //ヽ
return false;
case 0x30FE: //ヾ
return false;
case 0x30FC: //ー
return false;
case 0x30A1: //ァ
return false;
case 0x30A3: //ィ
return false;
case 0x30A5: //ゥ
return false;
case 0x30A7: //ェ
return false;
case 0x30A9: //ォ
return false;
case 0x30C3: //ッ
return false;
case 0x30E3: //ャ
return false;
case 0x30E5: //ュ
return false;
case 0x30E7: //ョ
return false;
case 0x30EE: //ヮ
return false;
case 0x30F5: //ヵ
return false;
case 0x30F6: //ヶ
return false;
case 0x3041: //ぁ
return false;
case 0x3043: //ぃ
return false;
case 0x3045: //ぅ
return false;
case 0x3047: //ぇ
return false;
case 0x3049: //ぉ
return false;
case 0x3063: //っ
return false;
case 0x3083: //ゃ
return false;
case 0x3085: //ゅ
return false;
case 0x3087: //ょ
return false;
case 0x308E: //ゎ
return false;
case 0x3095: //ゕ
return false;
case 0x3096: //ゖ
return false;
case 0x31F0: //ㇰ
return false;
case 0x31F1: //ㇱ
return false;
case 0x31F2: //ㇲ
return false;
case 0x31F3: //ㇳ
return false;
case 0x31F4: //ㇴ
return false;
case 0x31F5: //ㇵ
return false;
case 0x31F6: //ㇶ
return false;
case 0x31F7: //ㇷ
return false;
case 0x31F8: //ㇸ
return false;
case 0x31F9: //ㇹ
return false;
case 0x31FA: //ㇺ
return false;
case 0x31FB: //ㇻ
return false;
case 0x31FC: //ㇼ
return false;
case 0x31FD: //ㇽ
return false;
case 0x31FE: //ㇾ
return false;
case 0x31FF: //ㇿ
return false;
case 0x3005: //々
return false;
case 0x303B: //〻
return false;
//ハイフン類
case 0x2010: //‐
return false;
case 0x002D: //-
return false;
case 0x30A0: //゠
return false;
case 0x003D: //=
return false;
case 0xFF1D: //=
return false;
case 0x2013: //–
return false;
case 0x301C: //〜
return false;
case 0xFF5E: //~
return false;
//区切り約物
case 0x003F: //?
return false;
case 0xFF1F: //?
return false;
case 0x0021: //!
return false;
case 0xFF01: //!
return false;
case 0x203C: //‼
return false;
case 0x2047: //⁇
return false;
case 0x2048: //⁈
return false;
case 0x2049: //⁉
return false;
//中点類
case 0x30FB: //・
return false;
case 0x003A: //:
return false;
case 0xFF1A: //:
return false;
case 0x003B: //;
return false;
case 0xFF1B: //;
return false;
//句点類
case 0x3002: //。
return false;
case 0x002E: //.
return false;
case 0xFF0E: //.
return false;
}
switch (c2) {
//終わり括弧類
case 0x002C: //,
return false;
case 0xFF0c: //,
return false;
case 0x0029: //)
return false;
case 0xFF09: //)
return false;
case 0x005D: //]
return false;
case 0xFF3D: //]
return false;
case 0xFF5D: //}
return false;
case 0x3001: //、
return false;
case 0x3015: //〕
return false;
case 0x3009: //〉
return false;
case 0x300B: //》
return false;
case 0x300D: //」
return false;
case 0x300F: //』
return false;
case 0x3011: //】
return false;
case 0x3019: //〙
return false;
case 0x3017: //〗
return false;
case 0x301F: //〟
return false;
case 0x2019: //'
return false;
case 0x201D: //"
return false;
case 0xFF60: //⦆
return false;
case 0x00BB: //»
return false;
//行頭禁則和字
case 0x30FD: //ヽ
return false;
case 0x30FE: //ヾ
return false;
case 0x30FC: //ー
return false;
case 0x30A1: //ァ
return false;
case 0x30A3: //ィ
return false;
case 0x30A5: //ゥ
return false;
case 0x30A7: //ェ
return false;
case 0x30A9: //ォ
return false;
case 0x30C3: //ッ
return false;
case 0x30E3: //ャ
return false;
case 0x30E5: //ュ
return false;
case 0x30E7: //ョ
return false;
case 0x30EE: //ヮ
return false;
case 0x30F5: //ヵ
return false;
case 0x30F6: //ヶ
return false;
case 0x3041: //ぁ
return false;
case 0x3043: //ぃ
return false;
case 0x3045: //ぅ
return false;
case 0x3047: //ぇ
return false;
case 0x3049: //ぉ
return false;
case 0x3063: //っ
return false;
case 0x3083: //ゃ
return false;
case 0x3085: //ゅ
return false;
case 0x3087: //ょ
return false;
case 0x308E: //ゎ
return false;
case 0x3095: //ゕ
return false;
case 0x3096: //ゖ
return false;
case 0x31F0: //ㇰ
return false;
case 0x31F1: //ㇱ
return false;
case 0x31F2: //ㇲ
return false;
case 0x31F3: //ㇳ
return false;
case 0x31F4: //ㇴ
return false;
case 0x31F5: //ㇵ
return false;
case 0x31F6: //ㇶ
return false;
case 0x31F7: //ㇷ
return false;
case 0x31F8: //ㇸ
return false;
case 0x31F9: //ㇹ
return false;
case 0x31FA: //ㇺ
return false;
case 0x31FB: //ㇻ
return false;
case 0x31FC: //ㇼ
return false;
case 0x31FD: //ㇽ
return false;
case 0x31FE: //ㇾ
return false;
case 0x31FF: //ㇿ
return false;
case 0x3005: //々
return false;
case 0x303B: //〻
return false;
//ハイフン類
case 0x2010: //‐
return false;
case 0x002D: //-
return false;
case 0x30A0: //゠
return false;
case 0x003D: //=
return false;
case 0xFF1D: //=
return false;
case 0x2013: //–
return false;
case 0x301C: //〜
return false;
case 0xFF5E: //~
return false;
//区切り約物
case 0x003F: //?
return false;
case 0xFF1F: //?
return false;
case 0x0021: //!
return false;
case 0xFF01: //!
return false;
case 0x203C: //‼
return false;
case 0x2047: //⁇
return false;
case 0x2048: //⁈
return false;
case 0x2049: //⁉
return false;
//中点類
case 0x30FB: //・
return false;
case 0x003A: //:
return false;
case 0xFF1A: //:
return false;
case 0x003B: //;
return false;
case 0xFF1B: //;
return false;
//句点類
case 0x3002: //。
return false;
case 0x002E: //.
return false;
case 0xFF0E: //.
return false;
}
}
//行末禁則文字
switch (c) {
case 0x0028: //(
return false;
case 0xFF08: //(
return false;
case 0xFF3B: //[
return false;
case 0x005B: //[
return false;
case 0xFF5B: //{
return false;
case 0x3014: //〔
return false;
case 0x3008: //〈
return false;
case 0x300A: //《
return false;
case 0x300C: //「
return false;
case 0x300E: //『
return false;
case 0x3010: //【
return false;
case 0x3018: //〘
return false;
case 0x3016: //〖
return false;
case 0x301D: //〝
return false;
case 0x2018: //'
return false;
case 0x201C: //"
return false;
case 0xFF5F: //⦅
return false;
case 0x00AB: //«
}
switch (c11) {
case 0x0028: //(
return false;
case 0xFF08: //(
return false;
case 0xFF3B: //[
return false;
case 0x005B: //[
return false;
case 0xFF5B: //{
return false;
case 0x3014: //〔
return false;
case 0x3008: //〈
return false;
case 0x300A: //《
return false;
case 0x300C: //「
return false;
case 0x300E: //『
return false;
case 0x3010: //【
return false;
case 0x3018: //〘
return false;
case 0x3016: //〖
return false;
case 0x301D: //〝
return false;
case 0x2018: //'
return false;
case 0x201C: //"
return false;
case 0xFF5F: //⦅
return false;
case 0x00AB: //«
}
//分離禁則
if (c == c2) {
switch (c) {
case 0x2014: //—
return false;
case 0x2026: //…
return false;
case 0x2025: //‥
return false;
case 0x3033: //〳
return false;
case 0x3034: //〴
return false;
case 0x3035: //〵
return false;
}
}
if (c == c11) {
switch (c11) {
case 0x2014: //—
return false;
case 0x2026: //…
return false;
case 0x2025: //‥
return false;
case 0x3033: //〳
return false;
case 0x3034: //〴
return false;
case 0x3035: //〵
return false;
}
}
if (c2 == c3) {
switch (c2) {
case 0x2014: //—
return false;
case 0x2026: //…
return false;
case 0x2025: //‥
return false;
case 0x3033: //〳
return false;
case 0x3034: //〴
return false;
case 0x3035: //〵
return false;
}
}
// return ((c >= 0x2e80 && c < 0xd7a0)
// || (c >= 0xf900 && c < 0xfb00)
// || (c >= 0xfe30 && c < 0xfe50)
// || (c >= 0xff61 && c < 0xffa0));
return true;
// return false; //折り返しさせないように、falseを返す
}
};
}
protected ArrayList fonts;
}
paragraph関数をHyphenationparagraphに変更すれば使えると思います。
【、あ、あ、あ、あ】等になると微妙に折り返し処理がおかしくなるが、ほぼ思った通りの動作になったからよしとるすかな……