Hi,

I implemented a patch which supports CJK fonts in the postscript output device and on Windows platforms in general. It consists mainly of three parts:

1. Adapt bug fix for bug 11413 to the postscript device
2. A small bug fix when locateFont doesn't find a suitable font and returns a null pointer
3. CJK substitute implementation on WIndows platforms.

to 1.:
Adapting the implementation of the bug fix for splash and cairo to the postscript device was quite easy. But my first proofs of the output with ghostscript 8.71 shows some regressions where the CJK chars have a smaller height than the default square of the font. But the "48" in the output of bug-poppler11413.pdf which is set in a "normal" font but rotated was at the right position. Then I stepped to ghostscript 9.04, and now the CJK chars were shown correctly, but the 48 was positioned wrong. But because of these different tests I think that it is still a problem in ghostscript when using a mix of CJK fonts and "normal" fonts. BTW, also Acrobat X distiller has problems with the position of the "48"!

to 2.:
On my first tests with PDF which uses non embedded CJK fonts on Windows I got crashes. Reason for it was that GlobalParamWin returns Helvetica, which is not a CID font, but locateFont accepts here only CID fonts and therefore returns a NULL pointer. I first fixed that and then decided to return as default MS Mincho if a CID font is expected.

to 3.:
When You install ghostscript on WIndows You're able to switch on CJK support. This will create a cidfmap file in the gs-lib directory. The ps file which creates it (mkcidfm.ps) runs over the windows font directory and tries to create a suitable substitution table for missing CJK fonts. The cidfmap file is more or less PDF like, so it's quite easy to parse it with our parser and create a substitution table in GlobalParamsWin and use that table. But I expect it in the poppler data dir instead of searching for ghostscript installation. If it is not there, it always returns the default CID font of point 2. You can either copy it from the gs lib directory or create it with the ghostscript tool calling

gswin32c -q -dBATCH -sFONTDIR=<windows font directory> -sCIDFMAP=<popper data dir>/cidfmap mkcidfm.ps

To clearify the format of cidfmap I attach the file produced on my installation. Keep care: I have not a default windows installation with windows on c:/windows, my windows installation is on drive f!

Cheers,
Thomas
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index 72448bf..53aaebe 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -550,6 +550,7 @@ GlobalParams::GlobalParams(const char *customPopplerDataDir)
 #ifdef _WIN32
   // baseDir will be set by a call to setBaseDir
   baseDir = new GooString();
+  substFiles = new GooHash(gTrue);
 #else
   baseDir = appendToPath(getHomeDir(), ".xpdf");
 #endif
@@ -787,6 +788,9 @@ GlobalParams::~GlobalParams() {
   deleteGooHash(fontFiles, GooString);
   deleteGooList(fontDirs, GooString);
   deleteGooHash(ccFontFiles, GooString);
+#ifdef _WIN32
+  deleteGooHash(substFiles, GooString);
+#endif
   delete sysFonts;
   if (psFile) {
     delete psFile;
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index 7e23cff..dbefae3 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -289,6 +289,7 @@ private:
   GooList *toUnicodeDirs;              // list of ToUnicode CMap dirs 
[GooString]
 #ifdef _WIN32
   GBool baseFontsInitialized;
+  GooHash *substFiles; // windows font substitutes (for CID fonts)
 #endif
   GooHash *fontFiles;          // font files: font name mapped to path
                                //   [GString]
diff --git a/poppler/GlobalParamsWin.cc b/poppler/GlobalParamsWin.cc
index c62e2cd..3a454ab 100644
--- a/poppler/GlobalParamsWin.cc
+++ b/poppler/GlobalParamsWin.cc
@@ -40,6 +40,11 @@ description for all fonts available in Windows. That's how 
MuPDF works.
 #include "FontEncodingTables.h"
 #include "GlobalParams.h"
 #include "GfxFont.h"
+#include <sys/stat.h>
+#include "Object.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
 
 #if MULTITHREADED
 #  define lockGlobalParams            gLockMutex(&mutex)
@@ -58,6 +63,7 @@ description for all fonts available in Windows. That's how 
MuPDF works.
 #endif
 
 #define DEFAULT_SUBSTITUTE_FONT "Helvetica"
+#define DEFAULT_CID_FONT "MS-Mincho"
 
 static struct {
     const char *name;
@@ -147,7 +153,8 @@ static struct {
     {"Georgia-Bold", NULL, "georgiab.ttf"},
     {"Georgia-Italic", NULL, "georgiai.ttf"},
     {"Georgia-BoldItalic", NULL, "georgiaz.ttf"},
-
+    // default CID font:
+    {"MS-Mincho", NULL, "msmincho.ttf"},
     {NULL}
 };
 
@@ -346,6 +353,12 @@ SysFontInfo *SysFontList::makeWindowsFont(char *name, int 
fontNum,
 
 void GlobalParams::setupBaseFonts(char * dir)
 {
+       const char *dataRoot = popplerDataDir ? popplerDataDir : 
POPPLER_DATADIR;
+       GooString *fileName = NULL;
+       struct stat buf;
+       FILE *file;
+       int size = 0;
+
     if (baseFontsInitialized)
         return;
     baseFontsInitialized = true;
@@ -381,20 +394,85 @@ void GlobalParams::setupBaseFonts(char * dir)
     if (winFontDir[0]) {
       sysFonts->scanWindowsFonts(new GooString(winFontDir));
     }
+
+       fileName = new GooString(dataRoot);
+       fileName->append("/cidfmap");
+       if (stat(fileName->getCString(), &buf) == 0) {
+               size = buf.st_size;
+       }
+       // try to open file
+#ifdef VMS
+       file = fopen(fileName->getCString(), "rb", "ctx=stm");
+#else
+       file = fopen(fileName->getCString(), "rb");
+#endif
+
+       if (file != NULL) {
+               Parser *parser;
+               Object obj1, obj2;
+
+               obj1.initNull();
+               parser = new Parser(NULL,
+                       new Lexer(NULL,
+                       new FileStream(file, 0, gFalse, size, &obj1)),
+                       gTrue);
+               obj1.free();
+               parser->getObj(&obj1);
+               while (!obj1.isEOF()) {
+                       parser->getObj(&obj2);
+                       if (obj1.isName()) {
+                               // Substitutions
+                               if (obj2.isDict()) {
+                                       Object obj3;
+                                       obj2.getDict()->lookup("Path", &obj3);
+                                       if (obj3.isString())
+                                               addFontFile(new 
GooString(obj1.getName()), obj3.getString()->copy());
+                                       obj3.free();
+                               // Aliases
+                               } else if (obj2.isName()) {
+                                       substFiles->add(new 
GooString(obj1.getName()), new GooString(obj2.getName()));
+                               }
+                       }
+                       obj2.free();
+                       obj1.free();
+                       parser->getObj(&obj1);
+                       // skip trailing ';'
+                       while (obj1.isCmd(";")) {
+                               obj1.free();
+                               parser->getObj(&obj1);
+                       }
+               }
+               fclose(file);
+               delete parser;
+       }
 }
 
-static char *findSubstituteName(const char *origName)
+static char *findSubstituteName(GfxFont *font, GooHash *substFiles, const char 
*origName)
 {
     assert(origName);
     if (!origName) return NULL;
+       GooString *name2 = new GooString(origName);
+       int n = strlen(origName);
+       // remove trailing "-Identity-H"
+       if (n > 11 && !strcmp(name2->getCString() + n - 11, "-Identity-H")) {
+               name2->del(n - 11, 11);
+               n -= 11;
+       }
+       GooString *substName = (GooString *)substFiles->lookup(name2);
+       if (substName != NULL) {
+               delete name2;
+               return substName->getCString();
+       }
+
     /* TODO: try to at least guess bold/italic/bolditalic from the name */
-    return DEFAULT_SUBSTITUTE_FONT;
+       delete name2;
+       return (font->isCIDFont()) ? DEFAULT_CID_FONT: DEFAULT_SUBSTITUTE_FONT;
 }
 
 /* Windows implementation of external font matching code */
 GooString *GlobalParams::findSystemFontFile(GfxFont *font,
                                          SysFontType *type,
-                                         int *fontNum, GooString * 
/*substituteFontName*/) {
+                                         int *fontNum, GooString 
*substituteFontName) {
   SysFontInfo *fi;
   GooString *path = NULL;
   GooString *fontName = font->getName();
@@ -406,14 +484,21 @@ GooString *GlobalParams::findSystemFontFile(GfxFont *font,
     *type = fi->type;
     *fontNum = fi->fontNum;
   } else {
-    GooString *substFontName = new 
GooString(findSubstituteName(fontName->getCString()));
+    GooString *substFontName = new GooString(findSubstituteName(font, 
substFiles, fontName->getCString()));
+         GooString *path2 = NULL;
     error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is 
'{1:t}'", fontName, substFontName);
-    if ((fi = sysFonts->find(substFontName, gFalse))) {
-      path = fi->path->copy();
-      *type = fi->type;
-      *fontNum = fi->fontNum;
-    }
-  }      
+         if ((path2 = (GooString *)fontFiles->lookup(substFontName))) {
+           path = new GooString(path2);
+           if (substituteFontName)
+                   substituteFontName->Set(path->getCString());
+           if (!strcasecmp(path->getCString() + path->getLength() - 4, 
".ttc")) {
+                   *type = sysFontTTC;
+           } else {
+                   *type = sysFontTTF;
+           }
+           *fontNum = 0;
+         }
+  }
   unlockGlobalParams;
   return path;
 }
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 0c48b5a..1d0f7f2 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1816,6 +1816,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict 
*parentResDict) {
     setupType3Font(font, psName, parentResDict);
   } else {
     fontLoc = font->locateFont(xref, gTrue);
+  if (fontLoc != NULL) {
     switch (fontLoc->locType) {
     case gfxFontLocEmbedded:
       switch (fontLoc->fontType) {
@@ -1887,6 +1888,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict 
*parentResDict) {
       psName = fontLoc->path->copy();
       break;
     }
+  }
 
     if (!psName) {
       if (font->isCIDFont()) {
@@ -2364,9 +2366,6 @@ void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont 
*font,
   FoFiTrueType *ffTT;
   int *codeToGID;
   int codeToGIDLen;
-  CharCodeToUnicode *ctu;
-  Unicode *uBuf;
-  int cmap, code;
 
   // beginning comment
   writePSFmt("%%BeginResource: font {0:t}\n", psName);
@@ -2381,54 +2380,37 @@ void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont 
*font,
     // check for embedding permission
     if (ffTT->getEmbeddingRights() >= 1) {
 
-      // create a CID-to-GID mapping, via Unicode
-      if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) {
-       // look for a Unicode cmap
-       for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) {
-         if ((ffTT->getCmapPlatform(cmap) == 3 &&
-              ffTT->getCmapEncoding(cmap) == 1) ||
-             ffTT->getCmapPlatform(cmap) == 0) {
-           break;
-         }
-       }
-       if (cmap < ffTT->getNumCmaps()) {
-         // map CID -> Unicode -> GID
-         codeToGIDLen = ctu->getLength();
-         codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int));
-         for (code = 0; code < codeToGIDLen; ++code) {
-           int n = ctu->mapToUnicode(code, &uBuf);
-           if (n > 0) {
-             codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]);
-           } else {
-             codeToGID[code] = 0;
-           }
-         }
-          if (ffTT->isOpenTypeCFF()) {
-           ffTT->convertToCIDType0(psName->getCString(),
-                                codeToGID, codeToGIDLen,
-                                outputFunc, outputStream);
-          } else if (globalParams->getPSLevel() >= psLevel3) {
-           // Level 3: use a CID font
-           ffTT->convertToCIDType2(psName->getCString(),
-                                   codeToGID, codeToGIDLen,
-                                   needVerticalMetrics,
-                                   outputFunc, outputStream);
-         } else {
-           // otherwise: use a non-CID composite font
-           ffTT->convertToType0(psName->getCString(),
-                                codeToGID, codeToGIDLen,
-                                needVerticalMetrics,
-                                outputFunc, outputStream);
-         }
-         gfree(codeToGID);
-       }
-       ctu->decRefCnt();
-      } else {
-       error(errSyntaxError, -1,
-             "Couldn't find a mapping to Unicode for font '{0:s}'",
-             font->getName() ? font->getName()->getCString() : "(unnamed)");
-      }
-    } else {
+                 codeToGID = NULL;
+                 codeToGIDLen = 0;
+                 if (((GfxCIDFont *)font)->getCIDToGID()) {
+                         codeToGIDLen = ((GfxCIDFont *)font)->getCIDToGIDLen();
+                         if (codeToGIDLen) {
+                                 codeToGID = (int *)gmallocn(codeToGIDLen, 
sizeof(int));
+                                 memcpy(codeToGID, ((GfxCIDFont 
*)font)->getCIDToGID(),
+                                         codeToGIDLen * sizeof(int));
+                         }
+                 } else {
+                         codeToGID = ((GfxCIDFont 
*)font)->getCodeToGIDMap(ffTT, &codeToGIDLen);
+                 }
+                 if (ffTT->isOpenTypeCFF()) {
+                         ffTT->convertToCIDType0(psName->getCString(),
+                                 codeToGID, codeToGIDLen,
+                                 outputFunc, outputStream);
+                 } else if (globalParams->getPSLevel() >= psLevel3) {
+                         // Level 3: use a CID font
+                         ffTT->convertToCIDType2(psName->getCString(),
+                                 codeToGID, codeToGIDLen,
+                                 needVerticalMetrics,
+                                 outputFunc, outputStream);
+                 } else {
+                         // otherwise: use a non-CID composite font
+                         ffTT->convertToType0(psName->getCString(),
+                                 codeToGID, codeToGIDLen,
+                                 needVerticalMetrics,
+                                 outputFunc, outputStream);
+                 }
+                 gfree(codeToGID);
+       } else {
       error(errSyntaxError, -1,
            "TrueType font '%s' does not allow embedding",
            font->getName() ? font->getName()->getCString() : "(unnamed)");
%!
% cidfmap generated automatically by mkcidfm.ps from fonts found in
%   F:/WINDOWS/Fonts

% Substitutions
/ArialUnicodeMS-CNS << /SubfontID 0 /CSI [(CNS1) 2] /Path 
(F:/WINDOWS/Fonts/arialuni.ttf) /FileType /TrueType >> ;
/ArialUnicodeMS-KR << /SubfontID 0 /CSI [(Korea1) 3] /Path 
(F:/WINDOWS/Fonts/arialuni.ttf) /FileType /TrueType >> ;
/ArialUnicodeMS-GB << /SubfontID 0 /CSI [(GB1) 2] /Path 
(F:/WINDOWS/Fonts/arialuni.ttf) /FileType /TrueType >> ;
/MS-Mincho-oldttf << /SubfontID 0 /CSI [(Japan1) 3] /Path 
(F:/WINDOWS/Fonts/msmincho.ttf) /FileType /TrueType >> ;
/ArialUnicodeMS-JP << /SubfontID 0 /CSI [(Japan1) 3] /Path 
(F:/WINDOWS/Fonts/arialuni.ttf) /FileType /TrueType >> ;

% Aliases
/Ryumin-Medium /ArialUnicodeMS-JP ;
/AdobeHeitiStd-Regular /ArialUnicodeMS-GB ;
/HeiseiKakuGo-W5 /ArialUnicodeMS-JP ;
/AdobeMingStd-Light /ArialUnicodeMS-CNS ;
/MKai-Medium /ArialUnicodeMS-CNS ;
/MHei-Medium /ArialUnicodeMS-CNS ;
/MSung-Light /ArialUnicodeMS-CNS ;
/HYRGoThic-Medium /ArialUnicodeMS-KR ;
/GothicBBB-Medium /ArialUnicodeMS-JP ;
/AdobeSongStd-Light /ArialUnicodeMS-GB ;
/AdobeMyungjoStd-Medium /ArialUnicodeMS-KR ;
/HYSMyeongJo-Medium /ArialUnicodeMS-KR ;
/HYGoThic-Medium /ArialUnicodeMS-KR ;
/STSong-Light /ArialUnicodeMS-GB ;
/STKaiti-Regular /ArialUnicodeMS-GB ;
/KozMinPr6N-Regular /ArialUnicodeMS-JP ;
/STHeiti-Regular /ArialUnicodeMS-GB ;
/STFangsong-Light /ArialUnicodeMS-GB ;
/MSung-Medium /ArialUnicodeMS-CNS ;
/Ryumin-Light /ArialUnicodeMS-JP ;
/HeiseiMin-W3 /ArialUnicodeMS-JP ;
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to