Latex 書籤中文亂碼解決方案
作者:playerc
本文連結:http://www.cnblogs.com/playerc/archive/2013/05/20/latex_utf8_bookmark_c.html
最近使用 pdflatex 寫文檔的時候,發現 utf8 書籤中文出現亂碼,網上搜尋,發現一個有價值的解決方案。
他使用一個 python 實現的轉碼方案。下文中簡稱 方案1
http://www.thinkemb.com/wordpress/?p=260
我就照著寫了個 c 語言的。程式的原理在 方案1 中說的很明白,就是 pdflatex 產生含有 書籤或目錄 的pdf檔案時,需要執行兩次,第一次先產生一些準備檔案,比如 *.out ,這個檔案就是儲存了書籤資訊。第二次再根據第一次產生的檔案產生 含有書籤或目錄的 pdf 檔案,也就是說,第一次執行時,產生的pdf檔案不包含書籤或目錄。
關於書籤亂碼的原因,就是當pdf閱讀器讀取書籤時,只能識別 UNICODE 編碼,當我們使用的tex文本環境是utf8或gbk 編碼時,產生的 *.out 也就使用了 utf8或gbk編碼,產生的pdf也同樣保留了編碼。所以pdf書籤中包含的非 ascii 字元就出現亂碼了。
這個 轉換工具 所做的工作,就是把 *.out 中書籤名字串由 utf8編碼轉換成unicode 編碼。需要用到 utf8 編碼知識,和 unicode編碼知識。
使用gcc 或 vs 編譯後,使用命令列,運行
utf82uni < src.out > dst .out
src.out 是準備轉換的檔案,dst.out是轉換後的檔案。
/** * utf82uni.c -- translate bookmark names in Latex's .out file,Utf8 encoded to Unicode;
* compile: cc -o utf82uni utf82uni.c */#include<stdio.h>#define UNICODE_PREFIX "\\376\\377"#define UTF8_MAX_BYTES (6)#define UTF8_THREE (14)void init_int_array(int * array, int length){ while(length>0){ *(array+(--length)) = 0; }}//eo init_int_arrayint main(int argc,char *argv[]){ int bi; //byte number int str[UTF8_MAX_BYTES]={0}; //all byte int gb[2]={0}; int i; int is_begin = 0; //is begin translate int count_brace = 0; int is_brace_begin = 0; int is_brace_end = 0; int is_line_end = 0; while(!feof(stdin)){ i=0; init_int_array(str,UTF8_MAX_BYTES); bi = fread(&str[0],1,1,stdin); is_brace_begin = ((str[0]&0x7f) == '{') ? 1:0; is_brace_end = (str[0]&0x7f) =='}' ? 1:0; is_line_end = (str[0]&0x7f)=='\n' ? 1:0; if(is_brace_begin||is_brace_end){ count_brace ++; }else if(is_line_end){ count_brace=0; } if((count_brace !=3) || is_brace_begin ||is_brace_end){ fwrite(&str[0],bi,1,stdout); is_begin = 0; continue; } // count_brace == 3 ,translate Utf8 code to Unicode with \ooo format; if(is_begin == 0){ printf(UNICODE_PREFIX); is_begin = 1; } if(((str[0]>>4)&0xff)== UTF8_THREE ){ bi = 3; for(i=1; (i< bi) && (!feof(stdin)); i++){ fread(&str[i], 1, 1, stdin); } init_int_array(gb, 2); /** * 1110xxxx , 10 xxxx xx , 10 xxxxxx */ gb[0] = ((str[0]<<4)&0xF0)|((str[1]>>2)&0x0F); gb[1] = ((str[1]<<6)& 0xF0) | ((str[2])& 0x3F); printf("\\%03o\\%03o",gb[0],gb[1]); }else{ printf("\\%03o\\%03o",0,(str[0])&0x7f); } }//eof while return 0;}//eof main