Дата публикации статьи: 22.11.2006 19:57

Конвертация RTF в HTML

Автор: Дреманович Павел
[Пример 1] [Пример 2]
[Обсудить на форуме]

Как конвертировать RTF в HTML

    Когда-то давно я хотел сделать в своём текстовом редакторе функцию для конвертации из RTF в HTML, после долгих часов проведённых в Интернете я нашёл пример, но результат меня разочаровал. Та прога просто копировала текст и вставляла его между заголовками

<HTML>
<BODY>

</BODY>
</HTML>

    При этом всё форматирование терялось. И тогда я задумался над воросом: "А как сохранить форматирование?" Ответ напрашивался сам собой, необходимо создать функцию или несколько функций, которые бы анализировали форматирование текста и генерировали бы код для такого же форматировиния HTML - Документа.
    Сейчас я выложу код этих функций.

ПРЕДУПРЕЖДЕНИЕ: Данный код не универсальный т.е. могут быть ошибки при переводе.


Public Function RTFTOHTML(ObjectRTF As RichTextBox) As String
Dim i As Integer
Dim fcolor As String
Dim fName As String
Dim fSize As String
i = 1
Do Until i = Len(ObjectRTF.Text) + 1
If Asc(Mid(ObjectRTF.Text, i, 1)) = 13 Then RTFTOHTML = RTFTOHTML & "< BR>"
If i = 1 Then
ObjectRTF.SelStart = 1
ObjectRTF.SelLength = 0
RTFTOHTML = RTFTOHTML & "< FONT " & " FACE=" & Chr(34) & _
        ObjectRTF.SelFontName & Chr(34) & " Color=" & _
        TableConvertPallete(ObjectRTF.SelColor) & " Size=" _
        & ObjectRTF.SelFontSize / 3 & ">" & Mid(ObjectRTF.Text, 1, i)
fcolor = ObjectRTF.SelColor
fSize = ObjectRTF.SelFontSize
fName = ObjectRTF.SelFontName
i = i + 1
End If
'====================================================================================
ObjectRTF.SelStart = i
ObjectRTF.SelLength = 0
If Not (fcolor = ObjectRTF.SelColor) Or Not _
       (fSize = ObjectRTF.SelFontSize) Or Not _
       (fName = ObjectRTF.SelFontName) _
       Then 'если произошли изменения форматирования вывести
RTFTOHTML = RTFTOHTML & " < FONT " & " FACE=" & Chr(34) & _
        ObjectRTF.SelFontName & Chr(34) & " Color=" & _
        TableConvertPallete(ObjectRTF.SelColor) & " Size=" & _
        ObjectRTF.SelFontSize / 3 & ">" & Mid(ObjectRTF.Text, i, 1)
'-=================================================================================
Else 'Если изменений не произошло добавить символ к остальным
RTFTOHTML = RTFTOHTML & Mid(ObjectRTF.Text, i, 1)
End If
fcolor = ObjectRTF.SelColor
fSize = ObjectRTF.SelFontSize
fName = ObjectRTF.SelFontName
i = i + 1
Loop
End Function
Public Function TableConvertPallete(ColorNumber As String) As String
If ColorNumber = "255" Then TableConvertPallete = Chr(34) & "Red" & Chr(34)
If ColorNumber = "16711680" Then TableConvertPallete = Chr(34) & "Blue" & Chr(34)
If ColorNumber = "65535" Then TableConvertPallete = Chr(34) & "Yellow" & Chr(34)
If ColorNumber = "65280" Then TableConvertPallete = Chr(34) & "Green" & Chr(34)
If ColorNumber = "16777215" Then TableConvertPallete = Chr(34) & "White" & Chr(34)
If ColorNumber = "986895" Then TableConvertPallete = Chr(34) & "Black" & Chr(34)
If ColorNumber = "16711935" Then TableConvertPallete = "FF00CC"
If ColorNumber = "16776960" Then TableConvertPallete = "00FFFF"
If ColorNumber = "4227327" Then TableConvertPallete = "FF9900"
End Function

Вот всё что нам понадобится, теперь буду разъяснять что тут делалось. Кстати, код я прогнал через этот конвертировщик.
В переменной i будет хранится номер текущего символа, в fColor значение цвета предыдущего символа, в fName значение шрифта предыдущего символа, в fSize значение размера предыдущего символа. Указываем что считывать мы будем с первого символа. Затем входим в цикл и начинаем проверять каждый символ. Если в тексте встречаем символ перевода строки, то вставляем тэг < BR>. Если проверяется первый символ тогда, выделяем этот символ строками

ObjectRTF.SelStart = 1
ObjectRTF.SelLength = 0


    Добавляем разметку страницы: считываются значения размера, цвета, шрифта данного символа и генерируется соответсвующий тег < FONT>.Затем переменным fColor, fName и fSize присваивается значения цвета, шрифта и размера для первого символа, номер считываемого символа увеличим на 1. Выделяем следующий символ, если его параметры не изменились т.е. остались прежними цвет, шрифт, размер, то просто добавляем его к остальным символам. Если параметры изменились генерируется закрывающий тэг и новый тэг < FONT> c новыми параметрами. Ну и наконец присваиваем переменным fColor, fName и fSize значения цвета, шрифта и размера, дабы поддерживать их в актуальном состоянии и увеличиваем значение i на 1. Пока не забыл, аргументом у функции RTFTOHTML должно быть имя компонента RichTextBox. Здесь представлена только функция для конвертирования, но не сам конвертировщик, функция возвращает HTML код документа.

    Кстати говоря, давайте поговорим о минусах данного конвертировщика, ну чтоб жизнь малиной не казалась. Надеюсь все поняли что делает функция TableConvertPallete(), если кто не понял объясняю, т.к. значение возвращаемое ObjectRTF.SelColor является числом, да не просто числом ,а числом в десятичном формате, то приходится заменять его соответствующим цветом, формат которого поддерживается браузером, т.е. не все цвета будут восприниматся конвертировшиком.
Это первый момент, а теперь второй момент, Конвертировщик не поддерживает выравнивание и не распознаёт курсива, подчеркнутого и жирного шрифта. Это можно сделать, но пока я не буду расматривать это в качестве учебного примера. И третий момент, т.к. в браузере и в RTF редакторе единицы размера различаются т.е. если в браузере текст будет выведен размером 20 и 72, то выглядеть он будет одинаково, поэтому в строке & " Size=" & ObjectRTF.SelFontSize / 3 &, мы значение размера делим на 3, для поддержания относительности размера.
Ну собственно, как бы и всё, с разбором этого кода мы закончили, но если у вас всё-таки что-то не получилось или лень дописать код руками вы можете скачать пример конвертировщика.
Здесь лежит пример.

Дополнения

    Давайте (для тех кто не всё понял из первой статьи) я объясню алгоритм действия нашей функции. Функция как бы "прокатывается" по всем символам текста (и вы видите автоскроллинг) считывая с них параметры (цвет, имя шрифта, размер) и сравнивает эти значения со значениями предыдущего символа (они хранятся в переменных fName, fSize, fColor), если хоть одно значение отличается то закрывается старый тэг < FONT > и генерируется новый тэг < FONT > с новыми парамерами. Если символы не отличаются по оформлению то они записываются после открывающего тэга < FONT >. Вроде с этим разобрались, поехали дальше.
    Помните я говорил что пока не буду рассматривать "как сделать функцию чтобы она поддерживала жирное начертание, подчёркивание, курсив и выравнивание", всё это будет рассмотрено в этом дополнении. Вот код функций с дополнениями. Обратите внимание я добавил новую функцию(в принципе её можно и не добавлять).
    Ну какой тут можно дать комментарий, введены новые переменные из их названия вы и сами можете всё понять. Здесь введена дополнительная проверка изменения выравнивания и жирного, подчёркнотого, курсивного шрифта. Думаю понять можно?!
    Давайте поговорим об оптимизации кода. Что я подразумеваю под словом отимизация? Вот что, когда функция генерит код он должен быть максимально минимальным. Загнул, да?
    Ну вобщем чем меньше код тем лучше. Давайте рассмотрим оптимизацию кода, который генерит наша программа. Я долго выдумывал как ещё можно его оптимизировать, ничего в голову не пришло.
Итак многие визуальные средства разработки допускают следующие расточительсва которорые не допускаются нашей прогой:
1. Незакрытые тэги (очень тормозят загрузку проекта)
2. Излишнее злоупотребление тэгами FONT (Кстати наша программа всё равно не достаточно оптимизирует код, предлагаю вам подумать над этой проблемой, И... ещё над одной которую я так и не решил.)
    Программа сохранияет лишь относительность размеров но не размеры т.е. тег FONT не поддерживает размеры больше 8 т.е. для тега Font 8 самый большой размер, нам же нужно сохранить размеры 72, 12, 36 и т.д, но в броузере они будут отображатся одинаково. Вот такая у нас проблема, подумайте и пришлите мне сообщение на mapstudio@mail.ru.

Что тут можно сказать пользуйтесь на здоровье, модифицируйте код как вам заблагорассудится. Если будут новые идеи присылайте мне их по адресу который был указан выше.

P.S. Подобный алгоритм я использовал для написания программы для извлечения стилей из RTF - документа