プログラマメモ2 - programmer no memo2

jasperreports 外字への道 その2 アイデア実証レベル 2008/02/21

この記事での、java.awt.font.TextAttribute.FAMILYの使い方まちがっていました!!!!!

JasperReportsです。
windowsのみでの話しです。

JasperReportsをつかってPDFを出力とかではなくて、JasperReportsを付属のviewerに表示するときとかの話です。

外字(EUDC)を表示するための実証コードです。

対象としているのは、JasperReports 2.0.4
使用しているjavassistのバージョンは、3.6.0.GA

どういうふうにやっているかといいますと、net.sf.jasperreports.engine.export.TextRendererのrenderParagraphメソッドで処理に手を加えることで、外字混在で表示させています。

メソッドの中身を下記のようにします。※変更箇所は色かえてます。

{
AttributedCharacterIterator paragraph = null;

if (lastParagraphText == null)
{
paragraph =
new AttributedString(
" ",
new AttributedString(
allParagraphs,
lastParagraphStart,
lastParagraphStart + 1
).getIterator().getAttributes()
).getIterator();
}
else
{
paragraph =
new AttributedString(
allParagraphs,
lastParagraphStart,
lastParagraphStart + lastParagraphText.length()
).getIterator();
}

LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, LINE_BREAK_FONT_RENDER_CONTEXT);//grx.getFontRenderContext()

while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached)
{
//eugene fix - start
int startIndex = lineMeasurer.getPosition();
//eugene fix - end

TextLayout layout = lineMeasurer.nextLayout(formatWidth);

if (isMinimizePrinterJobSize)
{
//eugene fix - start
AttributedString tmpText =
new AttributedString(
paragraph,
startIndex,
startIndex + layout.getCharacterCount()
);
java.util.Map map = new java.util.LinkedHashMap();
map.put(java.awt.font.TextAttribute.FAMILY, "MS ゴシック,EUDC");
tmpText.addAttributes(map, startIndex, startIndex + layout.getCharacterCount());

layout = new TextLayout(tmpText.getIterator(), grx.getFontRenderContext());
//eugene fix - end
}

float lineHeight = lineSpacingFactor *
maxFontSizeFinder.findMaxFontSize(
new AttributedString(
paragraph,
startIndex,
startIndex + layout.getCharacterCount()
).getIterator(),
fontSize
);

if (drawPosY + lineHeight <= textHeight)
{
drawPosY += lineHeight;

switch (horizontalAlignment)
{
case JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED :
{
if (layout.isLeftToRight())
{
drawPosX = 0;
}
else
{
drawPosX = formatWidth - layout.getAdvance();
}
if (lineMeasurer.getPosition() < paragraph.getEndIndex())
{
layout = layout.getJustifiedLayout(formatWidth);
}

break;
}
case JRAlignment.HORIZONTAL_ALIGN_RIGHT :
{
drawPosX = formatWidth - layout.getAdvance();
break;
}
case JRAlignment.HORIZONTAL_ALIGN_CENTER :
{
drawPosX = (formatWidth - layout.getAdvance()) / 2;
break;
}
case JRAlignment.HORIZONTAL_ALIGN_LEFT :;
default :
{
drawPosX = 0;
}
}

draw(layout);
}
else
{
isMaxHeightReached = true;
}
}
}


つぎにこのコードをJasperReportsのソースを変更せずにロジックだけ変更します。
ここでJavassistを使います。Javassistを使うと、バイトコードを変更することができます。すごい便利です。

大本のライブラリを、コンパイルしなおす必要がない、もしくはしたくないときとかに重宝します。


下記のコードをJasperReportsを使用するクラスとかに貼ります。staticなブロックにしています。
static {
ClassPool pool = ClassPool.getDefault();

CtClass myCtClass;
try {
myCtClass = pool.get("ja.TextRenderer");
CtMethod ctMethod = myCtClass.getDeclaredMethod("renderParagraph");

ctMethod.getMethodInfo2().setAccessFlags(AccessFlag.PUBLIC);

StringBuffer buffer = new StringBuffer();
buffer.append(" {");
buffer.append(" java.text.AttributedCharacterIterator paragraph = null;");
buffer.append(" ");
buffer.append(" if ($3 == null)");
buffer.append(" {");
buffer.append(" paragraph = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" \" \",");
buffer.append(" new java.text.AttributedString(");
buffer.append(" $1, ");
buffer.append(" $2, ");
buffer.append(" $2 + 1");
buffer.append(" ).getIterator().getAttributes()");
buffer.append(" ).getIterator();");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" paragraph = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" $1, ");
buffer.append(" $2, ");
buffer.append(" $2 + $3.length()");
buffer.append(" ).getIterator();");
buffer.append(" }");
buffer.append("");
buffer.append(" java.awt.font.LineBreakMeasurer lineMeasurer = new java.awt.font.LineBreakMeasurer(paragraph, net.sf.jasperreports.engine.export.TextRenderer.LINE_BREAK_FONT_RENDER_CONTEXT);");
buffer.append(" ");
buffer.append(" while (lineMeasurer.getPosition() < paragraph.getEndIndex() && !isMaxHeightReached)");
buffer.append(" {");
buffer.append(" ");
buffer.append(" int startIndex = lineMeasurer.getPosition();");
buffer.append(" ");
buffer.append("");
buffer.append(" java.awt.font.TextLayout layout = lineMeasurer.nextLayout(formatWidth);");
buffer.append("");
buffer.append(" if (isMinimizePrinterJobSize)");
buffer.append(" {");
buffer.append(" ");
buffer.append(" java.text.AttributedString tmpText = ");
buffer.append(" new java.text.AttributedString(");
buffer.append(" paragraph, ");
buffer.append(" startIndex, ");
buffer.append(" startIndex + layout.getCharacterCount()");
buffer.append(" );");
buffer.append(" java.util.Map map = new java.util.LinkedHashMap();");
buffer.append(" map.put(java.awt.font.TextAttribute.FAMILY, \"MS ゴシック,EUDC\");");
buffer.append(" tmpText.addAttributes(map, startIndex, startIndex + layout.getCharacterCount());");
buffer.append(" layout = new java.awt.font.TextLayout(tmpText.getIterator(), grx.getFontRenderContext());");
buffer.append(" ");
buffer.append(" }");
buffer.append("");
buffer.append(" float lineHeight = lineSpacingFactor * ");
buffer.append(" maxFontSizeFinder.findMaxFontSize(");
buffer.append(" new java.text.AttributedString(");
buffer.append(" paragraph, ");
buffer.append(" startIndex, ");
buffer.append(" startIndex + layout.getCharacterCount()");
buffer.append(" ).getIterator(),");
buffer.append(" fontSize");
buffer.append(" );");
buffer.append("");
buffer.append(" if (drawPosY + lineHeight <= textHeight)");
buffer.append(" {");
buffer.append(" drawPosY += lineHeight;");
buffer.append(" ");
buffer.append(" switch (horizontalAlignment)");
buffer.append(" {");
buffer.append(" case 4 :");
buffer.append(" {");
buffer.append(" if (layout.isLeftToRight())");
buffer.append(" {");
buffer.append(" drawPosX = 0;");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" drawPosX = formatWidth - layout.getAdvance();");
buffer.append(" }");
buffer.append(" if (lineMeasurer.getPosition() < paragraph.getEndIndex())");
buffer.append(" {");
buffer.append(" layout = layout.getJustifiedLayout(formatWidth);");
buffer.append(" }");
buffer.append("");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 3 :");
buffer.append(" {");
buffer.append(" drawPosX = formatWidth - layout.getAdvance();");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 2 :");
buffer.append(" {");
buffer.append(" drawPosX = (formatWidth - layout.getAdvance()) / 2;");
buffer.append(" break;");
buffer.append(" }");
buffer.append(" case 1 :;");
buffer.append(" default :");
buffer.append(" {");
buffer.append(" drawPosX = 0;");
buffer.append(" }");
buffer.append(" }");
buffer.append("");
buffer.append(" draw(layout);");
buffer.append(" }");
buffer.append(" else");
buffer.append(" {");
buffer.append(" isMaxHeightReached = true;");
buffer.append(" }");
buffer.append(" }");
buffer.append(" }");

ctMethod.setBody(new String(buffer));

myCtClass.toClass();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}

}

: