CJK TrueType mappings and aliases for Windows installer
"Russell Lang" <[email protected]> Fri, 22 Oct 2004 19:27:15 +1000
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <41795F13.22558.F515BEB@localhost> |
This is applicable to 8.15 and HEAD. Log Message: Change MS-Windows installer to update lib/cidfmap with the CJK fonts found in the Windows font directory. DETAILS: Ghostscript does not ship with CJK fonts. If support for Chinese, Japanese or Korean is added to MS-Windows, CJK TrueType fonts and font collections are added to the MS-Windows fonts directory. These can be used by ghostscript by specifying mapping and aliases in the lib/cidfmap file. This patch looks in the MS-Windows fonts directory for known CJK fonts, and if present it appends appropriate mappings or aliases to the lib/cidfmap file. The font names and aliases are currently fixed. At present aliases are disabled due to bug #687776. Russell Lang [email protected] Ghostgum Software Pty Ltd http://www.ghostgum.com.au/ diff -u l:/cvs/gs/src/dwsetup.cpp src/dwsetup.cpp --- l:/cvs/gs/src/dwsetup.cpp Sat Apr 12 22:04:21 2003 +++ src/dwsetup.cpp Wed Oct 06 08:45:51 2004 @@ -139,6 +139,7 @@ BOOL install_prog(); BOOL install_fonts(); BOOL make_filelist(int argc, char *argv[]); +BOOL write_cidfmap(const char *path); ////////////////////////////////////////////////////////////////////// @@ -694,6 +695,7 @@ char szArguments[MAXSTR]; char szDescription[MAXSTR]; char szDotVersion[MAXSTR]; + char szCIDFmap[MAXSTR]; if (g_bQuit) return FALSE; @@ -726,6 +728,21 @@ if (g_bQuit) return FALSE; + + /* Create lib/cidfmap */ + gs_addmess("Updating cidfmap\n "); + strcpy(szCIDFmap, g_szTargetDir); + strcat(szCIDFmap, "\\"); + strcat(szCIDFmap, cinst.GetMainDir()); + strcat(szCIDFmap, "\\lib\\cidfmap"); + gs_addmess(szCIDFmap); + gs_addmess("\n"); + if (!write_cidfmap(szCIDFmap)) { + gs_addmess("Failed to update \042"); + gs_addmess(szCIDFmap); + gs_addmess("\042\n"); + return FALSE; + } // write registry entries gs_addmess("Updating Registry\n"); @@ -871,6 +888,465 @@ return TRUE; } +////////////////////////////////////////////////////////////////////// +// File and directory enumeration +////////////////////////////////////////////////////////////////////// + +typedef struct enum_file_s { + HANDLE find_handle; + WIN32_FIND_DATA find_data; + char name[256]; + char base[256]; +} enum_file_t; + +/* Prepare to enumerate files */ +/* name should include a wildcard if you want to find more than one file */ +enum_file_t * +enum_file_init(const char *name) +{ + char *p; + int i; + int baselen; + int len; + enum_file_t *pfe = (enum_file_t *)malloc(sizeof(enum_file_t)); + if (pfe != NULL) { + memset(pfe, 0, sizeof(pfe)); + strncpy(pfe->name, name, sizeof(pfe->name)-1); + pfe->find_handle = INVALID_HANDLE_VALUE; + len = strlen(pfe->name); + baselen = 0; + for (i = 0; i < len; i++) { + if (pfe->name[i] == '\\') + pfe->name[i] = '/'; + if ((pfe->name[i] == '/') || (pfe->name[i] == ':')) + baselen = i+1; + } + memcpy(pfe->base, pfe->name, baselen); + pfe->base[baselen] = '\0'; + } + return pfe; +} + +/* Return name of next file. *dir is set non-zero if a directory */ +int +enum_file_next(enum_file_t *pfe, char *buf, unsigned int buflen, int *dir) +{ + BOOL found = FALSE; + char *p; + if (pfe->find_handle == INVALID_HANDLE_VALUE) { + pfe->find_handle = FindFirstFile(pfe->name, &pfe->find_data); + if (pfe->find_handle == INVALID_HANDLE_VALUE) + found = TRUE; + } + else + found = FindNextFile(pfe->find_handle, &pfe->find_data); + if (found) { + strncpy(buf, pfe->base, buflen-1); + strncat(buf, pfe->find_data.cFileName, strlen(buf)-buflen-1); + *dir = pfe->find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; + for (p=buf; *p; p++) + if (*p == '\\') + *p = '/'; + } + if ((strcmp(pfe->find_data.cFileName, ".") == 0) || + (strcmp(pfe->find_data.cFileName, "..") == 0)) + found = enum_file_next(pfe, buf, buflen, dir); /* have another go */ + return found; +} + +void +enum_file_close(enum_file_t *pfe) +{ + FindClose(pfe->find_handle); + free(pfe); +} + +////////////////////////////////////////////////////////////////////// +// Create lib/cidfmap based on installed fonts +////////////////////////////////////////////////////////////////////// + + +typedef enum font_order_e { + JAPAN1 = 0, + KOREA1 = 1, + GB1 = 2, + CNS1 = 3 +} font_order; + +const char *order_string[4] = { + "Japan1", + "Korea1", + "GB1", + "CNS1" +}; + +typedef struct cjk_font_s { + const char *name; + int subfontid; + font_order order; + int supplement; + const char *fontname; +} cjk_font_t; + +typedef struct font_alias_s { + const char *substituted; + const char *original; +} font_alias_t; + +typedef struct font_list_s font_list_t; +struct font_list_s { + int cjk_index; + char *fontname; + font_list_t *next; +}; + +typedef struct alias_list_s alias_list_t; +struct alias_list_s { + const char *fontname; + font_list_t *font; + alias_list_t *next; +}; + + +/* The real fonts */ +/* serif = light font */ +/* gothic = san serif = heavy font */ +cjk_font_t cjk_fonts[] = { +{"MS-Mincho", 1, JAPAN1, 3, "msmincho.ttc"}, /* Japanese serif */ +{"MS-PMincho", 2, JAPAN1, 3, "msmincho.ttc"}, /* Japanese serif */ +{"MS-Gothic", 1, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */ +{"MS-PGothic", 2, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */ +{"MS-UI-Gothic", 3, JAPAN1, 3, "msgothic.ttc"}, /* Japanese gothic */ + +{"MingLiu", 1, CNS1, 2, "mingliu.ttc"}, /* Traditional Chinese serif */ +{"PMingLiu", 2, CNS1, 2, "mingliu.ttc"}, /* Traditional Chinese serif */ +{"Arial-Unicode-MS", 1, CNS1, 2, "arialuni.ttc"},/*Traditional Chinese gothic*/ + +{"SimSun", 1, GB1, 2, "simsun.ttc"}, /* Simplified Chinese serif */ +{"NSimSun", 2, GB1, 2, "simsun.ttc"}, /* Simplified Chinese serif */ +{"SimHei", 0, GB1, 2, "simhei.ttf"}, /* Simplified Chinese gothic */ + +{"Batang", 1, KOREA1, 3, "batang.ttc"}, /* Korean serif */ +{"BatangChe", 2, KOREA1, 3, "batang.ttc"}, /* Korean serif */ +{"Gungsuh", 3, KOREA1, 3, "batang.ttc"}, /* Korean serif */ +{"GungsuhChe", 4, KOREA1, 3, "batang.ttc"}, /* Korean serif */ +{"Gulim", 1, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */ +{"GulimChe", 2, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */ +{"Dotum", 3, KOREA1, 3, "gulim.ttc"}, /* Korean gothic */ +{"DotumChe", 4, KOREA1, 3, "gulim.ttc"} /* Korean gothic */ +}; + +/* The aliases. + * Note that we can list multiple substitutions. + * The first substitution that matches a found original font will be used. + */ +font_alias_t font_aliases[] = { + /* Japanese */ + {"Ryumin-Light", "MS-Mincho"}, + {"GothicBBB-Medium", "MS-Gothic"}, + {"HeiseiMi-W3", "MS-Mincho"}, + {"HeiseiKakuGo", "MS-Gothic"}, + + /* Traditional Chinese (CNS1) */ +/* Sung, Hei and Kai are different styles */ + {"MSung-Light", "MingLiu"}, + {"MSung-Medium", "MingLiu"}, + {"MHei-Medium", "MingLiu"}, + {"MKai-Medium", "Arial-Unicode-MS"}, + {"MKai-Medium", "MingLiu"}, + + /* Simplified Chinese (GB1) */ + {"STSong-Light", "SimSun"}, + {"STFangsong-Light", "SimSun"}, + {"STHeiti-Regular", "SimHei"}, + {"STKaiti-Regular", "SimHei"}, + + /* Korean */ + {"HYSMyeongJo-Medium", "Batang"}, + {"HYRGoThic-Medium", "Gulim"}, + {"HYGoThic-Medium", "Dotum"} +}; + + +/* Get the path to enumerate for fonts */ +int +get_font_path(char *path, unsigned int pathlen) +{ + int i; + int len = GetWindowsDirectory(path, pathlen); + if (len == 0) + return -1; + if (pathlen - strlen(path) < 10) + return -1; + strncat(path, "/fonts/*", pathlen - strlen(path) - 9); + for (i = strlen(path)-1; i >= 0; i--) + if (path[i] == '\\') + path[i] = '/'; + return len; +} + +/* Get the name of the cidfmap used by ghostscript */ +/* This implementation assumes that this program is + * .../bin/wincid.exe and that we should write .../lib/cidfmap + */ +int +get_cid_path(char *path, unsigned int pathlen) +{ + int i; + char *p; + char *basepath; + char *basename; + int len = GetModuleFileName(NULL, path, pathlen); + if (len == 0) + return -1; + if (pathlen - strlen(path) < 10) + return -1; + for (i = strlen(path)-1; i >= 0; i--) + if (path[i] == '\\') + path[i] = '/'; + /* find last '// */ + basepath = basename = path; + for (p = path; *p; p++) { + if (*p == '/') { + basepath = basename; + basename = p+1; + } + } + /* append lib/cidfname */ + *basepath = '\0'; + if (pathlen - strlen(path) < 12) + return -1; + strncat(path, "lib/cidfmap", pathlen - strlen(path) - 12); + return len; +} + + +int +find_font_files(font_list_t **fflist, const char *path) +{ + enum_file_t *pfe; + char fname[256]; + char *p; + char *basename; + int i; + int len; + int code = 0; + font_list_t *flistp = *fflist; + int isdir; + while (flistp && flistp->next) + flistp = flistp->next; + + memset(fname, 0, sizeof(fname)); + pfe = enum_file_init(path); + if (pfe == NULL) + return -1; + while (enum_file_next(pfe, fname, sizeof(fname)-1, &isdir)) { + len = strlen(fname); + basename = fname; + for (p = fname; *p; p++) + if (*p == '/') + basename = p+1; + /* Check to see if known font */ + for (i = 0; i < sizeof(cjk_fonts) / sizeof(cjk_fonts[0]); i++) { + if (stricmp(cjk_fonts[i].fontname, basename) == 0) { + if (flistp == NULL) + *fflist = flistp = (font_list_t *) + malloc(sizeof(font_list_t)); + else { + flistp->next = (font_list_t *) + malloc(sizeof(font_list_t)); + flistp = flistp->next; + } + if (flistp == NULL) { + code = -1; + break; + } + flistp->next = NULL; + flistp->cjk_index = i; + flistp->fontname = (char *)malloc(len+1); + if (flistp->fontname == 0) { + code = -1; + break; + } + memcpy(flistp->fontname, fname, len+1); + } + } + } + enum_file_close(pfe); + return code; +} + +/* Return 1 if alias already known, 0 if not found */ +int find_alias(alias_list_t *falist, const char *name) +{ + alias_list_t *alistp = falist; + while (alistp) { + if (strcmp(alistp->fontname, name) == 0) + return 1; + alistp = alistp->next; + } + return 0; +} + +font_list_t * +find_font(font_list_t *fflist, const char *name) +{ + font_list_t *flistp = fflist; + while (flistp) { + if (strcmp(cjk_fonts[flistp->cjk_index].name, name) == 0) + return flistp; + flistp = flistp->next; + } + return NULL; +} + +int +build_font_aliases(alias_list_t **falist, font_list_t *fflist) +{ + font_list_t *flistp = fflist; + alias_list_t *alistp = *falist; + int i; + int code = 0; + if (flistp == NULL) + return 0; + + while (alistp && alistp->next) + alistp = alistp->next; + + /* Add the substitutions */ + for (i=0; i<sizeof(font_aliases)/sizeof(font_aliases[0]); i++) { + if ( !find_alias(*falist, font_aliases[i].substituted) && + !find_font(fflist, font_aliases[i].substituted) && + ((flistp = find_font(fflist, font_aliases[i].original)) + != NULL) ) { + if (alistp == NULL) + *falist = alistp = (alias_list_t *)malloc(sizeof(alias_list_t)); + else { + alistp->next = (alias_list_t *) malloc(sizeof(alias_list_t)); + alistp = alistp->next; + } + if (alistp == NULL) { + code = -1; + break; + } + alistp->next = NULL; + alistp->fontname = font_aliases[i].substituted; + alistp->font = flistp; + } + } + return code; +} + +void +write_cidfmap_fonts(FILE *f, font_list_t *fflist) +{ + font_list_t *listp; + cjk_font_t *cjk; + for (listp = fflist; listp; listp = listp->next) { + cjk = &cjk_fonts[listp->cjk_index]; + fprintf(f, "/%s\n", cjk->name); + fprintf(f, "<<\n"); + fprintf(f, " /FileType /TrueType\n"); + fprintf(f, " /Path (%s)\n", listp->fontname);; + fprintf(f, " /SubfontID %d\n", cjk->subfontid); + fprintf(f, " /CSI [(%s) %d]\n", order_string[cjk->order], + cjk->supplement); + fprintf(f, ">> ;\n\n"); + } +} + +void +write_cidfmap_aliases(FILE *f, alias_list_t *falist) +{ + alias_list_t *listp; + cjk_font_t *cjk; + for (listp = falist; listp; listp = listp->next) { + cjk = &cjk_fonts[listp->font->cjk_index]; +#ifdef USE_ALIASES + /* These don't work in GS 8.32 or earlier */ + fprintf(f, "/%s /%s ;\n", listp->fontname, cjk->name); +#else + fprintf(f, "/%s\n", listp->fontname); + fprintf(f, "<<\n"); + fprintf(f, " /FileType /TrueType\n"); + fprintf(f, " /Path (%s)\n", listp->font->fontname);; + fprintf(f, " /SubfontID %d\n", cjk->subfontid); + fprintf(f, " /CSI [(%s) %d]\n", order_string[cjk->order], + cjk->supplement); + fprintf(f, ">> ;\n\n"); +#endif + } +} + +void +cleanup(font_list_t *fflist, alias_list_t *falist) +{ + alias_list_t *ap, *apnext; + font_list_t *fp, *fpnext; + + ap = falist; + while (ap) { + apnext = ap->next; + free(ap); + ap = apnext; + } + + fp = fflist; + while (fp) { + fpnext = fp->next; + free(fp->fontname); + free(fp); + fp = fpnext; + } +} + +int +build_cidfmap(font_list_t **ffhead, alias_list_t **fahead) +{ + char fontpath[256]; + + /* Current we only support searching a single font path */ + if (get_font_path(fontpath, sizeof(fontpath)-1) < 0) + return -1; + if (find_font_files(ffhead, fontpath) < 0) + return -1; + + if (build_font_aliases(fahead, *ffhead) < 0) + return -1; + + return 0; +} + +BOOL write_cidfmap(const char *cidpath) +{ + FILE *f; + font_list_t *ffhead = NULL; + alias_list_t *fahead = NULL; + int code = 0; + + if (build_cidfmap(&ffhead, &fahead) < 0) { + code = 1; + gs_addmess("Failed to build cidfmap\n"); + } + else { + f = fopen(cidpath, "a"); + if (f == NULL) { + gs_addmess("Failed to update cidfmap \042"); + gs_addmess(cidpath); + gs_addmess("\042\n"); + code = 1; + } + else { + fprintf(f, "\n%% entries below here were generated by ghostscript\n"); + fprintf(f, "%% installer from fonts present on this computer\n\n"); + write_cidfmap_fonts(f, ffhead); + write_cidfmap_aliases(f, fahead); + fprintf(f, "\n"); + fclose(f); + } + } + return (code == 0); +} ////////////////////////////////////////////////////////////////////// _______________________________________________ gs-code-review mailing list [email protected] http://www.ghostscript.com/mailman/listinfo/gs-code-review