Так уж исторически сложилось, что я практически не работал с JasperReports. Конечно мне приходилось строить отчеты, но обычно хватало генерации HTML из Velocity-шаблонов. И на этой неделе судьба мне подкинула шанс устранить пробелы в моем опыте
Возникла проблема с генерацией pdf-отчетов: на одном компьютере все работало, а на другом отчет искажался. В итоге проблема была решена установкой шрифта: arial.ttf, в операционную систему.
Причем данная проблема напомнила следующую историю: у меня есть один друг, который когда-то посоветовал воткнуть два сетевых кабеля в сервер, с двумя сетевыми картами. По его мнению: так сеть на сервере стала бы работать в два раза быстрее
Мы после этого убили неделю, на поиски причин постоянного пропадания сети на данном сервер, а авторитет моего друга казался непререкаемым: у него был большой опыт администрирования сетей, а мы были студентами с 6 месячным опытом работы
Проблема тогда решилась банально и просто: я вытащил один сетевой кабель и все заработало
Но сейчас речь о JasperReports
Так вот, еще один мой друг сказал, что для генерации отчета JasperReports достаточно положить файл со шрифтом в CLASSPATH и прописать в отчете ссылку на данный файл. И все, этого достаточно
Но в итоге на одном компьютере итог генерации отчетов был один, а на другом другим (обрезались слова в генерируемых отчетов). Были совершены различные шаманские действия: обновлена версия Apache Tomcat, изменена версия Java; но результата не было. Гугление ничего не показало и тогда я решил проверить русское сообщество на знание данной проблемы тут и тут.
В итоге и сообщество не дало мне ответ на мой вопрос… …и тогда я решил отладить JasperReport и найти причину данной ошибки. Было написано тестовое приложение и была запущена удаленная отладка его на одном из серверов где наблюдалась проблема. Кстати про удаленную отладку можно прочитать здесь.
И после отладки и анализа простого исходного кода JasperReports был найден следующий код из класса net.sf.jasperreports.engine.fill.TextMeasurer:
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, FONT_RENDER_CONTEXT);
measuredState.textOffset = lastParagraphStart;
boolean rendered = true;
boolean renderedLine = false;
while (lineMeasurer.getPosition() < paragraph.getEndIndex() && rendered)
{
rendered = renderNextLine(lineMeasurer, paragraph);
renderedLine = renderedLine || rendered;
}
И также интересно немного кода из метода renderNextLine:
int lineStartPosition = lineMeasurer.getPosition();
TextLayout layout = lineMeasurer.nextLayout(formatWidth);
float newTextHeight = measuredState.textHeight + layout.getLeading() + lineSpacing * layout.getAscent();
А теперь я попытаюсь объяснить что это за код:) В первом куске кода создается замечательный объект java.awt.font.LineBreakMeasurer. Данный класс позволяет вычислить основные характеристики шрифта для отображаемого текста и разбить текст на сегменты. Кстати во втором куске кода, который вызывается из первого, мы видим два основных метода для получения характеристик шрифта. Более подробно про эти методы можно почитать в описании класса java.awt.font.TextLayout.
Получилось немного сумбурно, но вывод прост: JasperReports использует AWT для генерации отчетов, а AWT в свою очередь использует шрифты операционной системы, так как шрифт из CLASSPATH не передается в LineBreakMeasurer . И если вдруг такого шрифта в операционной системе нет, то используется первый подходящий шрифт. Например, у меня вышеприведенная проблема была связана с тем, что шрифта Arial не было в операционной системе, и брался наиболее подходящий шрифт – Arial Bold, а ширина букв в Arial Bold больше чем в Arial
Во-общем проверяйте авторитетные мнения, и ставьте шрифты для генерации отчетов в операционную систему
p/s
Кстати, тут есть цикл статей о JasperReports.
p/s/s
Картинка украдена с официального сайта JasperReports.

RSS Блога
Понторез хренов
без шрифта в класспасе тоже рихрена не работало бы.
intr13 Reply:
марта 22, 2009 at 21:04
А я разве возражаю:)