Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 6, 2007 12:35:49

Teddy Bear
От:
Зарегистрирован: 2007-03-02
Сообщения: 53
Репутация: +  0  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Продолжаю свои поиски генераторов отчетов. На этот раз разговор пойдет о PyRTF. Это не значит, что ReportLab забыт, просто сегодня у меня такое настороение ;).

PyRTF – библиотека для создания RTF (Rich Text Format) файлов средствами языка Python.
Краткое описание:
PyRTF – это библиотека для создания RTF документов непосредственно из Python скриптов. У библиотеки нет внешних зависимостей (написана на чистом Python), в тестах разработчиков она показала себя вполне стабильным и быстрым инструментом.
PyRTF была протестирована на следующих ОС: W2K, WinXP, GNU/Linux, OpenBSD, FreeBSD и на следующих текстовых редакторах: OpenOffice, Word95, Word97, Word2000, WordXP и MacWord.

Функционал:

- Стили:
Предоставляется стандартный набор стилей, но допускается создание произвольных наборов стилей, что позволяет генерировать комплекты документов, которые соответствуют нормативам оформления для конкретного предприятия.
Стили могут быть переопределены практически на любом уровне, таким образом базовая структура документа может быть привязана к некоторому набору стилей, а переопределение стилей производится только в необходимых местах. Например жирное начертание, курсив, подчеркивание и т.д. могут быть применены лишь к тем элементам, которые того требуют.

- Разделы документа:
Документы могут содержать многочисленные разделы, каждый раздел может обладать своим собственным размером страницы, набором стилей, верхним и нижним колонтитулом. Поддерживаются и колонтитулы, которые применяются только к первой странице раздела.
- Таблицы:
Имеется всесторонняя поддержка таблиц, в PyRTF реализованы практически все особенности оформления таблиц входящие в спецификацию формата RTF. Таблицы конструируются из базовых “строительных блоков”, таким образом, если вы ознакомились с основами, то таблицы относительно легки в обхождении.
- Изображения:
Поддерживается встраивание как растровых изображений (форматов PNG и JPG), так и векторных (EMF).

PDF формат идеально подходит для кроссплатформенной печати, но если пользователю необходимо оперативно внести коррективы в сгенерированный документ, то тут возникают проблемы. И в данном случае чуть ли не единственным выбором становится формат RTF - редакторы под все платформы имеются в избытке, спецификация формата открытая, возможности, конечно не такие богатые как в PDF, да и гарантий, что он будет выглядеть “один-в-один” на разных платформах тоже никто не даст. Ну, всегда приходится чем-то жертвовать.

Итак, PyRTF. Несмотря на заброшенность проекта (последние изменения датируются началом 2006 года) и “зеленый” номер версии (0.46), возможности у неё, в целом, очень даже зрелые, да и в плане стабильности особо не придерешься. Самый большой недостаток - это практически полное отсутствие документации - в наличии имеется лишь подборка из примеров, демонстрирующих основные возможности. Еще одна неприятная мелочь - отсутствие поддержки юникода. Из возможностей мне остро недостает только так называемой “text box” - это такие фреймы в которые можно помещать текст и располагать их в любом месте листа хоть поверх друг друга (если дойдут руки, то попробую самостоятельно реализовать этот элемент).

Пришлось потратить некоторое время на “русификацию” PyRTF, чтобы в RTF файлах отображалась кириллица вместо кракозябр. Вот что для этого нужно сделать:
1) В модуле pyRTF/PropertySets.py находим класс Font:

class Font :
def __init__( self, name, family, character_set = 0, pitch = None, panose = None, alternate = None ) :
и заменяем в этой строке character_set = 0 на character_set = 204

2) В модуле pyRTF/Elements.py находим строки идущие подряд (всего 28 штук):
StandardFonts.append( Font( 'Arial', 'swiss' , 0, 2, '020b0604020202020204' ) )
...
...
StandardFonts.append( Font( 'Verdana', 'swiss' , 0, 2, '020b0604030504040204' ) )
И в них всех (кроме единственной StandardFonts.append( Font( ‘Symbol’, ‘roman’ , 2, 2, ‘05050102010706020507’ ) )) заменяем третий аргумент - 0(ноль) идущий после ‘swiss’ меняем на 204.

3) В модуле pyRTF/Constants.py находим класс Languages и атрибут DEFAULT=EnglishAustralian меняем на DEFAULT=Russian

4) В модуле pyRTF/Renderer.py находим класс Renderer, у него ищем метод _WriteDocument( self ) и в нем в строчке
self._write( "{\\rtf1\\ansi\\ansicpg1252\\deff0%s\n" % settings )
меняем ansicpg1252 на ansicpg1251.
Ну вот, собственно, и все по русификации.



Отредактировано (Сен. 6, 2007 12:37:16)

Офлайн

#2 Сен. 6, 2007 12:42:14

balu
От:
Зарегистрирован: 2006-05-24
Сообщения: 521
Репутация: +  0  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Teddy Bear
Продолжаю свои поиски генераторов отчетов.
Посмотри на pyExcelerator Лучшего пока не знаю.



Офлайн

#3 Сен. 6, 2007 13:15:18

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

А теперь PyRTF...

ИМХО, такие руссификации – это неловкий хак. Лучше бы доработать уже до полной интернационализации, чтобы любой язык можно было юзать. Что эти замены 0 на 204 значат? Как вы их подобрали?



Офлайн

#4 Сен. 7, 2007 08:18:21

Teddy Bear
От:
Зарегистрирован: 2007-03-02
Сообщения: 53
Репутация: +  0  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Спору нет, иначе как грязным хаком это не назовешь, но полноценный перевод PyRTF на юникод занял бы как минимум в 10 раз больше времени, поэтому не обессудьте.

По поводу замены '0' на '204':
В спецификации формата RTF указано, что "тег \fcharset определяет набор символов в таблице шрифта (т.е. кодовую страницу), а значения которые он может принимать можно отыскать в заголовочных файлах Windows и в файле RTFDEFS.H, входящем в комплект данной спецификации".
Я не обнаружил его в комплекте спецификации, но в интернете нашел майкрософтовский заголовочный файл wingdi.h в котором, в частности, есть следующие строки:

//****** CHARSETS *******

#define ANSI_CHARSET 0
#define DEFAULT_CHARSET 1
#define SYMBOL_CHARSET 2
#define SHIFTJIS_CHARSET 128
#define HANGEUL_CHARSET 129
#define GB2312_CHARSET 134
#define CHINESEBIG5_CHARSET 136
#define OEM_CHARSET 255
#if(WINVER >= 0x0400)
#define JOHAB_CHARSET 130
#define HEBREW_CHARSET 177
#define ARABIC_CHARSET 178
#define GREEK_CHARSET 161
#define TURKISH_CHARSET 162
#define THAI_CHARSET 222
#define EASTEUROPE_CHARSET 238
#define RUSSIAN_CHARSET 204

#define MAC_CHARSET 77
#define BALTIC_CHARSET 186

//***********************
То есть, меняя '0' на '204' мы, соответственно, задаем RUSSIAN_CHARSET для выводимого текста (а это, видимо, по умолчанию cp1251 для кириллицы - ведь rtf - формат майкрософтовский).
Отсюда можно предположить, что, например кодировка KOI-8 вряд ли поддерживается в rtf. Что же касается других национальных кодировок (украинской, например) то мне затруднительно что-либо предполагать, поскольку у меня нет под рукой ни украинских локализованных windows+msoffice (а желательно и linux+ooffice), ни шрифтов. Если кто-нибудь возьмется поэкспериментировать - будет весьма кстати. Нужно будет создать в word rtf-документ с украинским текстом и открыть его блокнотом (ну или кто чем пользуется) и посмотреть что там значится в теге \fcharset (хотя, возможно, этого окажется недостаточно).



Офлайн

#5 Сен. 7, 2007 10:01:43

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

А теперь PyRTF...

а что говорит спецификация формата по поводу unicode?



Офлайн

#6 Сен. 7, 2007 10:04:55

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Вот что получилось с украинским текстом:

{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fswiss\fcharset204{\*\fname Arial;}Arial CYR;}}
\viewkind4\uc1\pard\lang1058\f0\fs20\'cf\'f0\'e8\'e2\'b3\'f2, \'f6\'e5 \'ef\'f0\'e8\'ea\'eb\'e0\'e4 \'f3\'ea\'f0\'e0\'bf\'ed\'f1\'fc\'ea\'ee\'e3\'ee \'f2\'e5\'ea\'f1\'f2\'f3\lang1049\par
}
Кодировка cp1251 содержит в себе все украинские буквы (и белорусские тоже), так что ваш подход работает и здесь.



Офлайн

#7 Сен. 7, 2007 10:08:40

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Кстати по поводу интересного тега \lang в теле RTF


>>> import locale
>>> locale.windows_locale
'ru_RU'
>>> locale.windows_locale
'uk_UA'



Офлайн

#8 Сен. 7, 2007 13:04:28

proDiva
От:
Зарегистрирован: 2007-02-15
Сообщения: 244
Репутация: +  0  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Teddy Bear
Хочу выразить благодарность за такие подробности в исследовании нового для меня модуля))



Офлайн

#9 Сен. 8, 2007 11:14:20

Teddy Bear
От:
Зарегистрирован: 2007-03-02
Сообщения: 53
Репутация: +  0  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Изучение спецификации RTF и мои эксперименты показали, что теги \deflang и \lang не имеют отношения к кракозябрам в RTF-файлах. Эти теги лишь указывают текстовому редактору язык для проверки грамматики и орфографии (т.е. если задать их неправильно, то, например, все слова, даже правильно написанные, в word'е будут подчеркнуты красной волнистой линией).
При настройке PyRTF на русский язык, мы косвенно устанавливали эти теги в п.3 : если посмотреть модуль pyRTF/Constants.py в котором мы меняли атрибут DEFAULT=EnglishAustralian на DEFAULT=Russian, то увидим там строки

class Languages : 
    NoLanguage            = 1024
    Albanian              = 1052
    Arabic                = 1025
    Bahasa                = 1057
    BelgianDutch          = 2067
    BelgianFrench         = 2060
    BrazilianPortuguese   = 1046
    Bulgarian             = 1026
    Catalan               = 1027
    CroatoSerbianLatin    = 1050
    Czech                 = 1029
    Danish                = 1030
    Dutch                 = 1043
    EnglishAustralian     = 3081
    EnglishUK             = 2057
    EnglishUS             = 1033
    Finnish               = 1035
    French                = 1036
    FrenchCanadian        = 3084
    German                = 1031
    Greek                 = 1032
    Hebrew                = 1037
    Hungarian             = 1038
    Icelandic             = 1039
    Italian               = 1040
    Japanese              = 1041
    Korean                = 1042
    NorwegianBokmal       = 1044
    NorwegianNynorsk      = 2068
    Polish                = 1045
    Portuguese            = 2070
    RhaetoRomanic         = 1047
    Romanian              = 1048
    Russian               = 1049
    SerboCroatianCyrillic = 2074
    SimplifiedChinese     = 2052
    Slovak                = 1051
    SpanishCastilian      = 1034
    SpanishMexican        = 2058
    Swedish               = 1053
    SwissFrench           = 4108
    SwissGerman           = 2055
    SwissItalian          = 2064
    Thai                  = 1054
    TraditionalChinese    = 1028
    Turkish               = 1055
    Urdu                  = 1056
    SesothoSotho          = 1072
    Afrikaans             = 1078
    Zulu                  = 1077
    Xhosa                 = 1076
    Venda                 = 1075
    Tswana                = 1074
    Tsonga                = 1073
    FarsiPersian          = 1065
Они и имеют отношение к выставлению значения тегов \deflang и \lang. Видимо, если добавить сюда строку Ukrainian = 1058, а затем DEFAULT=Ukrainian, то word не будет подчеркивать красным украинские слова (но это надо проверить!).



Отредактировано (Сен. 8, 2007 11:19:56)

Офлайн

#10 Авг. 25, 2008 09:27:58

j2a
От:
Зарегистрирован: 2006-06-29
Сообщения: 869
Репутация: +  1  -
Профиль   Отправить e-mail  

А теперь PyRTF...

Поскольку так править исходники не труъ, то я написал мелкую обертку вокруг PyRTF: PyRuRTF, два доп.класса: RussianDocument и RussianRenderer, используются соответственно вместо Document и Renderer. Всё остальное остается as is.

http://dumpz.org/2017/

пример: http://dumpz.org/2014/

upd: http://hg.pyobject.ru/pyrurtf/ (с поддержкой юникода)



Отредактировано (Авг. 26, 2008 10:20:21)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version