E-Book (читалка книг)

Проблема обрезания последних символов в строках


В MiniOS есть встроенная читалка книг E-Book, но при первом взгляде видно, что она обрезает на каждой строчке около 6-10 символов в конце. Корни этой проблемы не совсем понятны, но временное решение "в лоб" может быть таким:

В файле /mtv_50/ebook/ebook.c в функции ebDrawFrameText() заменить строку
 
DrawText(pbmp, rect, font_id, p->text, nFrameWidthOfAsc, x, y,
  pstEbAttr->nAscGap, pstEbAttr->nCjkGap, text_color, 0);

На:

DrawText(pbmp, rect, font_id, p->text, nFrameWidthOfAsc+20, x, y,
  pstEbAttr->nAscGap, pstEbAttr->nCjkGap, text_color, 0);

То есть теперь к nFrameWidthOfAsc будет прибавляться 20. Честно говоря, код читалки, мягко говоря, не читаем совсем и понять почему так происходит лично мне просто лениво. Так же не известно, были ли изначально задуманы переносы или хотя-бы правильное форматирование текста. Выглядит читалка после этого изменения так:

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

Встраивание кодировки Windows cp1251

Можно читать книги на русском языке в UTF или UNICODE кодировке, а можно и встроить поддержку cp1251. Я делал это так:

В файле /mtv_50/ebook/ebook_menus.c в фукции ebMenuMain() добавляем после строк

case CHAR_SET_Windows_1258:
MenuAddItem(ID_IMG_EB_ICON_CHAR_SET, 0, 0, string, str_len, _T("Windows 1258"), 13, TRUE, NULL);
break;
строки
case CHAR_SET_Windows_1251:
MenuAddItem(ID_IMG_EB_ICON_CHAR_SET, 0, 0, string, str_len, _T("Windows 1251"), 13, TRUE, NULL);
break;

В функции ebMenuCodeType() после строки

MenuAddItem(0, 0, 0, _T("Windows_1258"), 13, NULL, 0, FALSE, (void*)CHAR_SET_Windows_1258);
добавляем строку
MenuAddItem(0, 0, 0, _T("Windows_1251"), 13, NULL, 0, FALSE, (void*)CHAR_SET_Windows_1251);

В файле /mtv_50/gui_lib/inc/detect.h после

CHAR_SET_Windows_1258,
добавляем
CHAR_SET_Windows_1251,

В файле /mtv_50/gui_lib/inc/converts.h в описании функции InitContextTableID после параметра
   
RESID id_windows_1258_to_unicode_tbl
Добавляем новый параметр
RESID id_windows_1251_to_unicode_tbl
Чтобы получилось так:
RESID id_windows_1258_to_unicode_tbl,
RESID id_windows_1251_to_unicode_tbl);

Так же в этом файле добавляем новый дефайн:
#define CONVERTS_WINDOWS_1251_UNICODE 0X00001000

Далее в файле /mtv_50/gui_lib/src/boot.c в описании функции SetConvertParam после параметра
RESID* id_windows_1258_to_unicode_tbl
добавляем параметр
RESID* id_windows_1251_to_unicode_tbl
чтобы получилось так:
RESID* id_windows_1258_to_unicode_tbl,
RESID* id_windows_1251_to_unicode_tbl);

В функции sys_boot() после строки
RESID id_windows_1258_to_unicode_tbl;
добавляем строку   
RESID id_windows_1251_to_unicode_tbl;
Сразу за этими строками при вызыве функции SetConvertParam после
&id_windows_1258_to_unicode_tbl
добавляем новый параметр
&id_windows_1251_to_unicode_tbl
чтобы получилось так:
&id_windows_1258_to_unicode_tbl,
&id_windows_1251_to_unicode_tbl);

Сразу за этими строками при вызове функции InitContextTableID после
id_windows_1258_to_unicode_tbl
вставляем новый параметр
id_windows_1251_to_unicode_tbl
чтобы получилось так:
id_windows_1258_to_unicode_tbl,
id_windows_1251_to_unicode_tbl);

Затем в файле /mtv_50/gui_lib/src/converts.c после строки
static RESID id_windows_1258_unicode_tbl;
добавляем строку
static RESID id_windows_1251_unicode_tbl;

после строки 
static WORD* windows_1258_unicode_tbl;
добавляем строку
static WORD* windows_1251_unicode_tbl;

Создаем новый дефайн
#define SIZE_WINDOWS_1251_UNICODE_TBL sizeof(WORD)*128*2

В функции InitContextTableID() после параметра
RESID id_windows_1258_to_unicode_tbl
добавляем новый параметр
RESID id_windows_1251_to_unicode_tbl
чтобы получилось так:
RESID id_windows_1258_to_unicode_tbl,
RESID id_windows_1251_to_unicode_tbl)

В этой же функции после строки
id_windows_1258_unicode_tbl = id_windows_1258_to_unicode_tbl;
добавляем строку
id_windows_1251_unicode_tbl = id_windows_1251_to_unicode_tbl;

В функции ConvertsInit() после строки
windows_1258_unicode_tbl = NULL;
добавляем строку
windows_1251_unicode_tbl = NULL;

Там же после условной конструкции
if((param & CONVERTS_WINDOWS_1258_UNICODE) && NULL == windows_1258_unicode_tbl){
if(0 == GetExBin(id_windows_1258_unicode_tbl,
(BYTE**)&windows_1258_unicode_tbl,
SIZE_WINDOWS_1258_UNICODE_TBL))
{
RES_ERROR(id_windows_1258_unicode_tbl);
return 0;
}
}
добавляем конструкцию:
if((param & CONVERTS_WINDOWS_1251_UNICODE) && NULL == windows_1251_unicode_tbl){
if(0 == GetExBin(id_windows_1251_unicode_tbl,
(BYTE**)&windows_1251_unicode_tbl,
SIZE_WINDOWS_1251_UNICODE_TBL))
{
RES_ERROR(id_windows_1251_unicode_tbl);
return 0;
}
}

В функции ConvertsFini() после условной конструкции

if(NULL != windows_1258_unicode_tbl){
res_free(windows_1258_unicode_tbl);
windows_1258_unicode_tbl = NULL;
}
добавляем конструкцию вида:
if(NULL != windows_1251_unicode_tbl){
res_free(windows_1251_unicode_tbl);
windows_1251_unicode_tbl = NULL;
}

Далее создаем новую функцию:
UNC Windows_1251_to_unicode(BYTE* src)
{
int n;
BOOL find = FALSE;
UNC dest;

for (n=0; n<128; n++)
{
if( *(windows_1251_unicode_tbl+n*2) == *src )
{
printf("*src = 0x%02x\n", *src);
dest = (UNC)(*(windows_1251_unicode_tbl+n*2+1));
printf("dest = 0x%04x\n", dest);
find = TRUE;
break;
}
}

if (find)
{
;
}
else
{
printf("*src = 0x%02x\n", *src);
dest = (UNC)(*src);
printf("dest = 0x%04x\n", dest);
}

return dest;
}



В файле /mtv_50/gui_lib/src/Scanners.c после строки
static UNC ScannerWindows_1258(BYTE* psBuffer, int* pnLen);
добавляем строку
static UNC ScannerWindows_1251(BYTE* psBuffer, int* pnLen);

После строки
static UNC ScannerWindows_1258Ex(BYTE* buffer, int* scan_len, PFN_BUFFER_POS_VALID fn, int* error);
добавляем строку
static UNC ScannerWindows_1251Ex(BYTE* buffer, int* scan_len, PFN_BUFFER_POS_VALID fn, int* error);

В функции Scanner() после строки
case CHAR_SET_Windows_1258: return ScannerWindows_1258(psBuffer, pnLen);
добавляем строку
case CHAR_SET_Windows_1251: return ScannerWindows_1251(psBuffer, pnLen);

В функии ScannerEx() после строки
case CHAR_SET_Windows_1258: return ScannerWindows_1258Ex(buffer, scan_len, fn, error);
добавляем строку
case CHAR_SET_Windows_1251: return ScannerWindows_1251Ex(buffer, scan_len, fn, error);

Создаем новую функцию:

static UNC ScannerWindows_1251(BYTE* psBuffer, int* pnLen)
{
*pnLen = 1;
return Windows_1251_to_unicode(psBuffer);
}

и функцию

static UNC ScannerWindows_1251Ex(BYTE* buffer, int* scan_len, PFN_BUFFER_POS_VALID fn, int* error)
{
if(!fn(1, error)){
*scan_len = 0;
return 0xFFFF;
}
*scan_len = 1;
*error = SYSTEM_SCANNER_NO_ERROR;
return Windows_1251_to_unicode(buffer);
}

Далее в файле /mtv_50/common/boot_options.c в функции SetConvertParam после параметра
RESID* id_windows_1258_to_unicode_tbl
добавляем новый параметр
RESID* id_windows_1251_to_unicode_tbl
чтобы получилось так:
RESID* id_windows_1258_to_unicode_tbl,
RESID* id_windows_1251_to_unicode_tbl
)

В этой же функции после строки
*id_windows_1258_to_unicode_tbl = ID_WINDOWS_1258_UNICODE_TBL;
добавляем строку
*id_windows_1251_to_unicode_tbl = ID_WINDOWS_1251_UNICODE_TBL;

С файлами вроде все, теперь остается создать новую таблицу перекодировки и запихнуть ее в ресурсы (res.bin).

Итак, находим табличку перекодировки cp1251 в юникод. Я воспользовался этой: http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT По ней видно, что символы от 0 до 0x7f у cp1251 и юникода одинаковые, а соответственно и в таблицу их пихать смысла нет. Всего у нас получается 0xff-0x80=128 символов в таблице. Быстро пишем на чем угодно программу, которая преобразует таблицу в бинарный вид (код символа cp1251(word), код символа unicode(word) ) Получаем бинарный файл размером 512 байт. Можно скачать готовый здесь: http://night-gryphon.ru/Vogue/Windows_1251_unicode_tbl.bin

Его нужно назвать windows_1251_unicode_tbl.bin и положить в папку \other ,после чего запустить батник auto_delete.bat и затем программу PkgMaker. На выходе, получив новый ResID.h, скопировать его в /mtv_50/common, а файл res.bin прошить в устройство.

После чего полностью пересобрать MiniOS:

make cleanall
make build

Comments