Вернуться к разделу "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). Все нижестоящие классы удаляются автоматически.