Вернуться к разделу "OpenOCR".


Описание библиотеки CED - контейнера для работы с ed файлами

Библиотека выполнена в виде dll файла(ced.dll), заголовочные файлы ced_struc.h 
или ced.h. ced_struc.h следует включать в программы на C++, он содержит описатели
классов, рассматриваемых ниже. ced.h - несколько урезанная версия
для включения в C-код, не содержит описателей классов, но содержит С-функции,
работающие с Handl'ами, позволяющие работать с деревом(впрочем эти функции 
есть и в ced_struct). Не следует включать эти два хедера одновременно.

Для работы требует наличия и предварительной инициализации модуля CFIO.

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

Все желающие могут ознакомиться с бинарным ed-форматом, он описан в файле
ed-diskr.txt. По всем вопросам обращаться dukei@com2com.ru 

                                                     7.12.98  Артем Боженов

		Интерфейс высокого уровня.

Для того, чтобы записать/читать файл, используется довольно хитрая
(но очевидная, на мой взгляд) иерархическая структура. Она несет в 
себе всю информацию по форматированию текста, которая может быть записана 
в рамках стандартного набора команд ed. Также в ней заложена возможность
читать и сохранять прочую информацию, которую пользователь библиотеки
сочтет нужной. Структура в своих узлах имеет представителей следующих С-классов:
CEDPage - описатель страницы, CEDSection - описатель раздела(секции),
CEDParagraph - описатель параграфа, CEDLine - строки, CEDChar - символа.
В настоящий момент в ed-файле может находиться на более 1й страницы, так
что и класс CEDPage присутствует здесь в единственном экземпляре.
Под разделом понимается то же сомое, что и при рассотрении rtf формата,
т.е. горизонтальный сегмент текста, имеющий собственное количество
колонок и свои отступы от краев бумаги.
Взаимоотношения между представителями классов изображены на диаграмме:

                CEDPage
                 ¦                  
     -------T----+--------T-------------T------¬     
     v      v             v             v      v  
CEDSection0-CEDSection1-CEDSection2-CEDSection3-CEDSection4     
       ¦     ¦                                           ¦
       ¦     L--------------¬                            ¦ 
       v                    v                            v  
CEDParagraph0-CEDParagraph1-CEDParagraph2-CEDParagraph3-CEDParagraph4    
              ¦                                          ¦
    -----------                                    -------      
    v                                              v
CEDLine0-CEDLine1-CEDLine2-CEDLine3-CEDLine4-CEDLine5     
    ¦        ¦                                     ¦
    ¦        L-----------------¬                   L----¬
    v                          v                        v
CEDChar0-CEDChar1-CEDChar2-CEDChar3-CEDChar4-CEDChar5-CEDChar6-CEDChar7       


Преобразованый к привычному формату, данные из диаграмы выглядят так:
------------Начало страницы-------------------
                (раздел0)
  (абзац0) (пустой)
  (абзац1)
(строка0)(символы0,1,2)
(строка1)(символы3,4,5)
(строка2)(пустая)
(строка3)(пустая)
(строка4)(пустая)
----------------разрыв раздела----------------
                 (раздел1)
(абзац2) (пустой)
(абзац3) (пустой)
----------------разрыв раздела----------------
              (раздел2) (пустой)
----------------разрыв раздела----------------
              (раздел3) (пустой)
----------------разрыв раздела----------------
              (раздел4) 
  (абзац4) 
(строка5)(символы6,7)

По этой диаграмме можно путешествовать как сверху вниз, так и по горизонтали.
Для путешествий по горизонтали в классе CEDPage есть ф-ции 
CEDSection * GetSection(int _num);
CEDParagraph * GetParagraph(int _num);
CEDLine * GetLine(int _num);
CEDChar * GetChar(int _num);
которые возвращают указатель на соответствующий элемент. _num - сквозной номер
элемента(та цифра, которая нарисована на картинке вверху).

В каждом узле хранится т.н. текущий элемент более низкого уровня.
Все операции в структуре происходят относительно него. 
Каждый из вышеперечисленных классов(за исключением CEDChar) имеет ф-ции работы с
текущим эл-том. 
Номер или адрес текущего 
элемента можно получить с помощью функций GetNumOfCur... и GetCur..., где под ... подразумевается элемент 
нижестоящего класса. 
Всё это сделано для
того, чтобы можно было хранить один глобальный указатель на CEDPage, а
для доступа к содержимому дерева из различных функций использовать
конструкции вида 
myPage->GetCurSection()->GetCurParagraph()->userNumber=0;

При создании объекта текущий эл-т устанавливается равным 0, после добавления
объекта более низкого уровня - начинает указывать на него.

Текущий элемент можно изменить 
непосредственным присаиванием, либо заданием его порядкового номера 
с помощью функций SetCur...
В качестве порядкового номера здесь выступает не сквозной номер, а номер
в текущем узле. На картинке:абзац0 можно получить так:
section0->SetCurParagraph(0);
абзац2 так:
section1->SetCurParagraph(0);
абзац3:
section1->SetCurParagraph(1);
и т.п.

Также существуют ф-ции Next...(Bool32 _goThroughSect)  и 
Prev...(Bool32 _goThroughSect), которые 
возвращают соответственно 
следующий или предыдущий элементы относительно текущего. Аргмент указывает,
что возвращать, если следующий элемент более низкого уровня имеет другого
родителя, чем текущий. Если аргумент - FALSE, то возвращается 0, иначе возвращается 
элемент. Напр. (картинка) если в разделе1 текущим является абзац3, то
section1->NextParagraph(FALSE)==0;
section1->NextParagraph(TRUE)==paragraph4.

Существует еще один способ изменить текущий элемент - это ф-ции
Bool32	GoToNextSection();
Bool32	GoToNextParagraph();
Bool32	GoToNextLine();
Bool32	GoToNextChar();
определенные в классе CEDPage.
Рассмотрим, к примеру GoToNextLine. Она берет текущую секцию, там - текущий
абзац, там - текущую строку и делает текущей строку, идущую следом. Если
эта новая строка находится в следующем абзаце, то сменяется и текущий абзац
и т.д. Фактически, конструкция 
myPage->GetCurSection()->GetCurParagraph()->GetCurLine() начинает указывать
на следующую строку. Ф-ции возвращают TRUE, если текущий элемент был
успешно изменен, и FALSE в противном случае. FALSE означает, что текущий
эл-т является последним на данном уровне дерева либо что на одном из
уровней дерева текущий эл-т не имеет детей. Напр, на рисунке, это будет
в случае GoToNextParagraph(), если текущими являются секция4 и абзац4. Или
GoToNextLine(), если текущие секция1 и абзац2 (нет детей)

Добавить элемент в дерево можно при помощи ф-ций Insert... Вставится он
сразу после текущего. Ф-ции Insert... возвращают 
указатель на вновь вставленный эл-т, и делают этот новый эл-т текущим.
 Напр. если в CEDSection три абзаца и текущим
является 2й, то комада mySection->InsertParagraph() вставит новый абзац 
на 3е место, старый абзац номер3 станет четвёртым, текущим станет абзац3,
указатель на который будет возвращен.

Ф-ции из CEDPage
int	GetNumberOfSections();
int	GetNumberOfParagraphs();
int	GetNumberOfLines();
int	GetNumberOfChars();
возвращают количество соответствующих элементов в дереве

 Каждый из CED классов имеет поля extData и extDataLen(длина в байтах).
Туда помещается та информация, которая была или должна быть записана
в ed файле сразу вслед за информацией, взятой из класса. В качестве этой
информации должны выступать исключительно структуры расширенного ed 
(edExtension). Информация по ситаксису таких структур лежит в ed-discr.txt.

			Иерархическая структура

На самом верху мы имеем CEDPage. Этот класс хранит данные о всей странице
в целом. Это:

EDSIZE	sizeOfImage		//Размеры исходной картинки в пикселях
EDSIZE	dpi;			//Разрешение сканера для этой картинки
int	turn;			//Тангенс угла поворота картинки относительно вертикали*2048
char*	imageName;		//Имя файла изображения. Если путь не указан, ищется в одном 
				//каталоге с ed файлом

int	pageNumber;		//Номер страницы(=0 не в пакетном режиме)
EDSIZE	pageSizeInTwips;	//Ширина страницы в твипах(1дюйм=1440твипов) для текстового редактора


Далее следуют классы CEDSection. Каждый из них может сожержать
несколько абзатцев. Информация по форматированию (где начинать колонки,
где - таблицы и картини) хранится в заголовках соответствующих абзатцев.
Класс содержит:
int		numberOfColumns;	//Количество колонок в секции(n штук)
EDRECT	borders;			//отступы от края бумаги

поле borders аналогично полю в rtf. В нем сожержится информация по 
левому и правому отступах от края бумаги, относительно которых будут
выравниваться абзацы(см. серая зона на Линейке Word'a). Верхний и нижний
отступы учитываются лишь в том случае, если абзац первый(соответственно 
последний) на странице.

На следующем уровне мы встречаем CEDParagraph. Этот класс описывает абзацы.

int	type;					//Тип абзаца
int	alligment;				//Выравнивание абзатца
EDRECT	ident;					//Отступы: left=левый, right=ширина,top=красн.строка(в твипах)
int	userNumber;				//Номер, данный пользователем на этапе фрагментации
int	border;					//Рамка вокруг абзатца
EDSIZE	interval;				//cx-верхний отступ, cy- нижний
edBox	layout;					//Расположение абзаца на странице
void * descriptor;			//Указатель на расширенный описатель специальных структур

Самые интересные поля здесь - type  и descriptor. Каждому типу абзаца 
соответстует свой описатель, либо не соответствует никакой(=0). Стили
могут комбинироваться оператором '|'.
Рассмотрим различные варианты форматирования:

колонки - для того, чтобы описать колонки, следует в заголовке секции указать
их число, каждую колонку начинать фиктивным абзатцем с типом
COLUMN_BEGIN и descriptor=EDCOLDISCR,где width=ширине колонки, spacing=расстоянию
до следующей,next - указатель на начало следующей колонки(если колонка
последняя- то 0).В конце последней
колонки присвоить фиктивному абзацу тип LAST_IN_COLUMN,
descriptor=0

Для всего этого можно использовать ф-цию из CEDSection
CEDParagraph * CreateColumn();
которая создает обрамляющие абзацы, увеличивает на 1 счетчик колонок, 
текущим делает первый фиктивный абзац. Возвращается указатель, который
можно передавать ф-ции из CEDSection
CEDParagraph * CreateParagraph(CEDParagraph * hObject,int align, EDRECT indent, int UserNum,int FlagBorder,
			       EDSIZE interval, edBox layout, int  color, int  shading, int spaceBetweenLines, 
			       char spcBtwLnsMult, char  keep);
(см. ниже)

фрейм(рамка) - Все фреймы должны лежать после колонок. Каждый фрейм начинать 
фиктивным абзатцем с типом
FRAME_BEGIN и descriptor=EDFRAMEDISCR, указывающий на структуру, содержащую 
координаты в твипах фрейма относительно страницы и ее размер,где 
 rec-размер,next - указатель на начало следующго фрейма(если фрейм
последний- то 0).В конце последнго
фрейма присвоить фиктивному абзацу тип FRAME_END,
descriptor=0 
Для всего этого можно использовать ф-цию из CEDSection
CEDParagraph * CreateFrame(CEDParagraph* hObject, edBox rect, char position=-1, DWORD borderSpace=-1, 
			   DWORD dxfrtextx=-1, DWORD dxfrtexty=-1)
которая создает обрамляющие абзацы, 
текущим делает первый фиктивный абзац. Возвращается указатель, который
можно передавать ф-ции из CEDSection
CEDParagraph * CreateParagraph(CEDParagraph * hObject,int align, EDRECT indent, int UserNum,int FlagBorder,
			       EDSIZE interval, edBox layout, int  color, int  shading, int spaceBetweenLines, 
			       char spcBtwLnsMult, char  keep);

(см. ниже)


картинка - тип PICTURE,
descriptor = ctp_pic_hdr*. Описание структуры- см. ed-discr.txt

таблица - таблица начинается фиктивным абзацем, который имеет тип TAB_BEGIN,
descriptor= указатель на структуру edTabDescr. Далее идет фиктивный абзац,
описывающий строку таблицы с типом TAB_ROW_BEGIN, descriptor=указатель на структуру edRowDescr
далее идет фиктивный абзац, описывающий ячейку с типом TAB_CELL_BEGIN и соотв. дискриптором,
ячейка, еще один и.т.д., потом снова TAB_ROW_BEGIN и в самом конце - TAB_END, descriptor=0.


Других типов абзацев на данный момент не существует. 

Следующий уровень - строки - CEDLine.
Класс не обладает никакой содержательной информацией, служит лишь
для разбиения сиволов внутри абзацев

И, наконец, CEDChar

edRect		layout;			//Размещение символа на исходном изображении(в пикселях)
int		fontHeight,fontAttribs;	//параметры шрифта
letter * alternatives;	//Массив альтернатив


			Чтение ed-файлов

Для чтения файлов в подобную структуру, библиотека имеет экспортируемую функцию
CEDPage * CED_FormattedLoad (char * file,Bool32 readFromFile, Word32 bufLen);

Если readFromFile=TRUE, то file должен содержать имя файла, bufLen - игнорируется
Если readFromFile=FALSE, то file - указатель на область в памяти, где лежит ed, 
                         BufLen - размер этого буфера

, возвращающую указатель на CEDPage. Полученный указатель 
можно, после необходимых вам преобразований в структуре передать в функию 
CED_FormattedWrite. По окончанию работы со стуктурой, следует вызвать для 
нее 
void CED_DeleteTree(CEDPage * pg). Все нижестоящие 
классы удаляются автоматически.




Hosted by uCoz