when converting files with gs 8.50 bold text is printed many times with slight offsets. this happend with korean fonts, and messes up text searching. adobe distiller does not do this.
Created attachment 1281 [details] test file with korean bold text
This file uses an PostScript procedure 'xsB' to create the 'bold' effect. The fix for this would probably involve an Idiom to replace the xsB with something that only emits the text once. This happens with MS PSCRIPT5.DLL when the font doesn't have a 'Bold' flavor and the request is for Bold (such as Impact)
In fact there are several procedures that would need to be zapped with Idioms (for the various 'show' variants). The relevant ProcSet is: %%BeginResource: file Pscript_TextBold 5.0 0 /sB{1 copy 2 copy : sBdx 0 -M S ; : 0 sBdx -M S ; : sBdx sBdx -M S ; S}b /asB{3 copy 3 copy 3 copy : sBdx 0 -M A ; : 0 sBdx -M A ; : sBdx sBdx -M A ; A}b /wsB{4 copy 4 copy 4 copy : sBdx 0 -M W ; : 0 sBdx -M W ; : sBdx sBdx -M W ; W}b /awsB {6 copy 6 copy 6 copy : sBdx 0 -M D ; : 0 sBdx -M D ; : sBdx sBdx -M D ; D}b /xsB{ 2 copy 2 copy 2 copy : sBdx 0 -M xS ; : 0 sBdx -M xS ; : sBdx sBdx -M xS ; xS}b /zsB{2 copy 2 copy 2 copy : sBdx 0 -M zS ; : 0 sBdx -M zS ; : sBdx sBdx -M zS ; zS}b /ysB{2 copy 2 copy 2 copy : sBdx 0 -M yS ; : 0 sBdx -M yS ; : sBdx sBdx -M yS ; yS}b %%EndResource Note: Adobe Distiller changes the xsB operation to doing the text once with "2 Tr" (fill and stroke) to do the bold. Sort of HAIRY to derive the stroke width from the sBdx value used in the Pscript_TextBold ProcSet. In order to determine if Adobe Distiller is using an Idiom, I zapped the ProcSet in a test file and see what results (inserting "1 pop" in it). This turned the original: 2 Tr 0 -1.13 TD 0.0107 Tc [(Impa) 4.6 (c) 5.3 (t) 5.4 ( ) ] TJ into: 0.02 -1.13 TD 0.0107 Tc [(Impa) 4.6 (c) 5.3 (t) ] TJ -0.02 -0.02 TD [(Impa) 4.6 (c) 5.3 (t) ] TJ 0.02 0 TD [(Impa) 4.6 (c) 5.3 (t) ] TJ -0.02 0.02 TD [(Impa) 4.6 (c) 5.3 (t) -14.6 ( ) ] TJ which confirms that Adobe Distiller is using Idiom replacement "magic"
Passing to Alex who is our best specialist on idioms.
Passing to mpsuzuki, because we suspect he can bring a better solution from gs- cjk.
A few of Ghostscript developers expressed concerns that installation of IdiomSet resources will greatly reduce Ghostscript performance. I've run the whole regression suite on peeves with nullpage device with 10 IdiomSet resources installed. Any effect is below the natural variation between run times. ( < 0.1%).
Bug 689310 "Offset between text and outline in pdfwrite.dev" shows a similar problem, which may be addressed as an idiom recognition. Feel free to pass this bug to ken.sharp@artifex.com .
In following, I use the term "style synthesis" to call the glyphs transformed by text graphic frameworks, like "Bold", "Italic", "Outline", "Shadow" etc etc. I think this bug is NOT CJK-specific issue in technical viewpoint. The remarkable difficulty in this issue is that the font object nor text drawing procedure in pswrite/pdfwrite don't have internal switches for style synthesis. In PDF, the style synthesis for bolding is implemented by changing the graphical parameters: "w" (setlinewidth) and "Tr" (PaintType). In the case of PDF, style synthesis is executed in graphics level, not in text/font level. Once the parameters are reflected on the output device, changing current font is insufficient to reset the style synthesis parameters. Such method is dependent on the output device (it is very possible that such graphical parameters cannot affect the text rendering on some PDL).
There are 2 approaches to fix the issue: how to optimize embolden text for PDF, to avoid repeating the text which makes the text informations ugly. A1) Simplification by pre-synthesized Type3/CIDFontType1. By Idiom substitution, the procedures to draw synthesized style is substituted by the combination of simple "show" families and Type3 or CIDFontType1 fonts whose BuildGlyph procedure executes the style synthesis per glyph. By using such font with simple "show" families, repeating of text drawing can be avoided. advantage: this approarch is almost independent with output device, and it's easy to proof the expected optimization. disadvantage: the handling of CIDFontType1 in current ghostscript pdfwrite is very primitive. The text drawn by Type3 font can be searched, but the text drawn by CIDFontType1 is not. The current implementation collects the bitmap images from glyph cache, pack them into Type3 fonts per 256 images. Thus, the text information is lost. The straight-forward embedding of CIDFontType1 is not supported. Making CJK text drawn by Type3 or CIDFontType1 font is long awaiting feature since gs5.5x, it may be worthful, but it will be long way. A2) Introduction of lazy style synthesis marking (LSS-mark) for output device driver By Idiom substitution, the procedure to draw synthesized style is substituted by the procedure marking the current font as "requested to be style synthesized" and let the output device driver to handle the marked font object. By using marked font with smiple "show" families, repeating of text drawing can be avoided. advantage: this approach can utilize existing Type1/Type42/ CIDFontType0/CIDFontType1 embedding features. disadvantage: the style synthesis result depends on the device. We cannot proof how the embolding in pdfwrite works via X11 device.
Created attachment 3381 [details] concept of approarch A1 A proof of concept in approarch A1. Here's no Idiom substitution, but 3 fundamental procedures are implemented. A1-a) /.synth_bold_basefont is a procedure to make a Type3 or CIDFontType1 for given Type1/3/42 and CIDFontType0/1/2. A1-b) /.decompose_cmapped_font is a procedure to decompose FMapType9-Type0 font and stack the scalematrix and CMap dict and basefont. A1-c) /.recompose_cmapped_font is a procedure to recompose Type0 font from stacked scalematrix, CMap dict and CIDFont. To execute this sample implementation, Courier must be Type1 font (not TrueType emulation), and WadaMaruGo-Regular must be CIDFontType0 (not cidfmap emulation). In this example, TrueType based Type3 is very slow.
Created attachment 3382 [details] concept of approarch A2 (patch) Here is a sample implementation of device-dependent style synthesis. If the difference of the style synthesis parameter is regarded as so critical and the font should be registered as unique resource (e.g. registering the marked font as /Impact,Bold, which is different from original /Impact, although the contents of font dicts are completely same), there will be a few problems: the appropriate naming convention (e.g. can we guarantee the source PS document does not define /Impact,Bold by itself?) and the divided font cache (e.g. pdfwrite will embed 2 font objects: /Impact and /Impact,Bold, although their contents are completely same). As an experiment to avoid the font resource management issue, I deal the LSS-mark as a scaling matrix parameter. Thus, we don't have to define/undefine new font resource per each style synthesis. As we can do as "currentfont 36 scalefont setfont", I designed LSS-mark can be set without definition of font resource. In addition, the LSS-mark should not be used by normal PostScript rendering, but the LSS-mark should be visible and variable from PostScript space (to work with Idiom substitution). A2-a) gs_font structure is extended to have additional LSS parameters for style synthesis. This bug report mentions only embolding feature, but I introduced all the switches described in MacOS QuickDraw (I think it's most rich), for future completion of similar problems related to style synthesis. Index: src/gxfont.h =================================================================== --- src/gxfont.h (revision 8217) +++ src/gxfont.h (working copy) @@ -365,6 +365,52 @@ uint size; } gs_font_name; +/* The style synthesis flag handled by output device */+typedef byte gs_lazy_stylebit_t; +#define GS_LAZY_BOLD 0x01 /* MacOS QuickDraw style code */ +#define GS_LAZY_ITALIC 0x02 /* ditto */ +#define GS_LAZY_UNDERLINE 0x04 /* ditto */ +#define GS_LAZY_OUTLINE 0x08 /* ditto */ +#define GS_LAZY_SHADOW 0x10 /* ditto */ +#define GS_LAZY_CONDENSE 0x20 /* ditto */ +#define GS_LAZY_EXTEND 0x40 /* ditto */ +#define GS_LAZY_RESERVED 0x80 /* ditto */ +typedef struct gs_lazy_stylesynth_s { + gs_lazy_stylebit_t stylebit; + float BoldWidth; + float ItalicAngle; + float UnderlineGap, UnderlineWidth; + float OutlineWidth; + float ShadowGap, ShadowWidth; + float CondenseWidth; + float ExtendWidth; +} gs_lazy_stylesynth_t; +#define cmplazyBold( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_BOLD ) ? (a).BoldWidth == (b).BoldWidth : 1 ) +#define cmplazyItalic( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_ITALIC ) ? (a).ItalicAngle == (b).ItalicAngle : 1 ) +#define cmplazyUnderline( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_UNDERLINE ) ? ( (a).UnderlineGap == (b).UnderlineGap && \ + (a).UnderlineWidth == (b).UnderlineWidth ) : 1 ) +#define cmplazyOutline( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_OUTLINE ) ? (a).OutlineWidth == (b).OutlineWidth : 1 ) +#define cmplazyShadow( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_SHADOW ) ? ( (a).ShadowGap == (b).ShadowGap && \ + (a).ShadowWidth == (b).ShadowWidth ) : 1 ) +#define cmplazyCondense( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_CONDENSE ) ? (a).CondenseWidth == (b).CondenseWidth : 1 ) +#define cmplazyExtend( a, b ) \ + ( 0 < ( (a).stylebit & GS_LAZY_EXTEND ) ? (a).ExtendWidth == (b).ExtendWidth : 1 ) +#define cmplazystyle( a, b ) \ + ( (a).stylebit == (b).stylebit && \ + cmplazyBold( a, b ) && \ + cmplazyItalic( a, b ) && \ + cmplazyUnderline( a, b ) && \ + cmplazyOutline( a, b ) && \ + cmplazyShadow( a, b ) && \ + cmplazyCondense( a, b ) && \ + cmplazyExtend( a, b ) ) + /* * Define a generic font. We include PaintType and StrokeWidth here because * they affect rendering algorithms outside the Type 1 font machinery. @@ -379,6 +425,7 @@ gs_memory_t *memory; /* allocator for this font */\ gs_font_dir *dir; /* directory where registered */\ bool is_resource;\ + gs_lazy_stylesynth_t lazystyle; /* device dependent style synthesis */\ gs_notify_list_t notify_list; /* clients to notify when freeing */\ gs_id id; /* internal ID (no relation to UID) */\ gs_font *base; /* original (unscaled) base font */\ A2-b) /DefineResource in gs_res.ps & gs_cidfn.ps, /.composefont in gs_cmap.ps are extended to insert /.LazyStyleSynth dict which is an interface between PostScript space and LSS-mark in gs_font. Index: lib/gs_res.ps =================================================================== --- lib/gs_res.ps (revision 8217) +++ lib/gs_res.ps (working copy) @@ -955,7 +955,19 @@ /InstanceType /dicttype /DefineResource - { 2 copy //definefont exch pop + { + dup /.LazyStyleSynth known not { + dup /.LazyStyleSynth 16 dict + dup /useBold false .growput dup /BoldWidth 0 .growput + dup /useItalic false .growput dup /ItalicAngle 0 .growput + dup /useUnderline false .growput dup /UnderlineGap 0 .growput dup /UnderlineWidth 0 .growput + dup /useOutline false .growput dup /OutlineWidth 0 .growput + dup /useShadow false .growput dup /ShadowGap 0 .growput dup /ShadowWidth 0 .growput + dup /useCondense false .growput dup /CondenseWidth 0 .growput + dup /useExtend false .growput dup /ExtendWidth 0 .growput + .growput + } if + 2 copy //definefont exch pop /Generic /Category findresource /DefineResource get exec } bind /UndefineResource Index: lib/gs_cidfn.ps =================================================================== --- lib/gs_cidfn.ps (revision 8217) +++ lib/gs_cidfn.ps (working copy) @@ -349,6 +349,20 @@ dup /PaintType known not { dup /PaintType 0 .growput % CPSI does it. Adding just for CET 33_all.PS conformity. } if + dup /.LazyStyleSynth known not { + currentglobal exch + true setglobal + dup /.LazyStyleSynth 16 dict + dup /useBold false .growput dup /BoldWidth 0 .growput + dup /useItalic false .growput dup /ItalicAngle 0 .growput + dup /useUnderline false .growput dup /UnderlineGap 0 .growput dup /UnderlineWidth 0 .growput + dup /useOutline false .growput dup /OutlineWidth 0 .growput + dup /useShadow false .growput dup /ShadowGap 0 .growput dup /ShadowWidth 0 .growput + dup /useCondense false .growput dup /CondenseWidth 0 .growput + dup /useExtend false .growput dup /ExtendWidth 0 .growput + .growput + exch setglobal + } if /Generic /Category findresource /DefineResource get exec } put % CIDFonts may be defined in CFF OpenType files. Index: lib/gs_cmap.ps =================================================================== --- lib/gs_cmap.ps (revision 8217) +++ lib/gs_cmap.ps (working copy) @@ -73,6 +73,7 @@ /FontMatrix matrix def /FontName 3 index def CMap /WMode .knownget { /WMode exch def } if + FDepVector { /.LazyStyleSynth .knownget { /.LazyStyleSynth exch def exit } if } forall /FontType 0 def pop pop currentdict end } bind odef @@ -81,6 +82,7 @@ % the "PostScript Language Reference Manual Supplement". /composefont { % <name> <cmap|cmapname> <fonts> composefont <font> .composefontdict /Font defineresource + dup /.LazyStyleSynth .knownget { { .setlazystyleparam } forall } if } bind def % ---------------- CMap operators ---------------- % A2-c) New operator ".setlazystyleparam" is introduced to control /.LazyStyleSynth dict and update the internal LSS-mark in gs_font. Index: src/zfont.c =================================================================== --- src/zfont.c (revision 8217) +++ src/zfont.c (working copy) @@ -25,8 +25,10 @@ #include "iddict.h" #include "igstate.h" #include "iname.h" /* for name_mark_index */ +#include "inamedef.h" #include "isave.h" #include "store.h" +#include "string_.h" #include "ivmspace.h" #include "gscencs.h" @@ -209,6 +211,109 @@ } +private int +sync_lazystyleparam(gs_font *pfont, const ref *lazystyleparam) +{ + int code; + ref *pvalue; + +#define SET_LAZY_STYLE_BIT( keyname, bitmacro ) \ + code = dict_find_string(lazystyleparam, (keyname), &pvalue); \ + if (code < 0) \ + return code; \ + else if (t_boolean == r_type(pvalue) && pvalue->value.boolval) \ + pfont->lazystyle.stylebit |= (bitmacro); \ + else \ + pfont->lazystyle.stylebit &= ~(bitmacro); + + SET_LAZY_STYLE_BIT( "useBold", GS_LAZY_BOLD ); + SET_LAZY_STYLE_BIT( "useItalic", GS_LAZY_ITALIC ); + SET_LAZY_STYLE_BIT( "useUnderline", GS_LAZY_UNDERLINE ); + SET_LAZY_STYLE_BIT( "useOutline", GS_LAZY_OUTLINE ); + SET_LAZY_STYLE_BIT( "useShadow", GS_LAZY_SHADOW ); + SET_LAZY_STYLE_BIT( "useCondense", GS_LAZY_CONDENSE ); + SET_LAZY_STYLE_BIT( "useExtend", GS_LAZY_EXTEND ); + +#undef SET_LAZY_STYLE_BIT + +#define SET_LAZY_STYLE_FLOAT_MEMBER( keyname, fmember ) \ + code = dict_find_string(lazystyleparam, (keyname), &pvalue); \ + if (code < 0) \ + return code; \ + else if (t_real == r_type(pvalue)) \ + pfont->lazystyle.fmember = pvalue->value.realval; \ + else \ + pfont->lazystyle.fmember = 0; + + SET_LAZY_STYLE_FLOAT_MEMBER( "BoldWidth", BoldWidth ); + SET_LAZY_STYLE_FLOAT_MEMBER( "ItalicAngle", ItalicAngle ); + SET_LAZY_STYLE_FLOAT_MEMBER( "UnderlineGap", UnderlineGap ); + SET_LAZY_STYLE_FLOAT_MEMBER( "UnderlineWidth", UnderlineWidth ); + SET_LAZY_STYLE_FLOAT_MEMBER( "ShadowGap", ShadowGap ); + SET_LAZY_STYLE_FLOAT_MEMBER( "ShadowWidth", ShadowWidth ); + SET_LAZY_STYLE_FLOAT_MEMBER( "CondenseWidth", CondenseWidth ); + SET_LAZY_STYLE_FLOAT_MEMBER( "ExtendWidth", ExtendWidth ); + +#undef SET_LAZY_STYLE_FLOAT_MEMBER + + return 0; +} + +/* <font> <key> <val> .setlazystyleparam <font> */ +private int +zsetlazystyleparam(i_ctx_t *i_ctx_p) +{ + os_ptr op_value = osp; + os_ptr op_key = op_value - 1; + os_ptr op_font = op_key - 1; + gs_font *pfont; + ref *lazystyleparam, *pvalue; + bool is_boolean_key; + int code; + + code = font_param(op_font, &pfont); + if (code < 0) + return code; + + if (dict_find_string(op_font, ".LazyStyleSynth", &lazystyleparam) <= 0) + return e_invalidfont; + + if (t_name != r_type(op_key)) + return e_typecheck; + + code = dict_find(lazystyleparam, op_key, &pvalue); + if (code < 0) + return code; + + /* "/useXXX" is assumed to be boolean, others are numericals */ + name_string_ref(imemory, op_key, op_key); + if (0 == strncmp(op_key->value.const_bytes, "use", 3)) + is_boolean_key = true; + else + is_boolean_key = false; + name_from_string(imemory, op_key, op_key); + + /* value should be boolean or integer or real */ + if (is_boolean_key) { + if (t_boolean != r_type(op_value)) + return e_typecheck; + } else if (t_integer == r_type(op_value)) + make_real(op_value, (float)op_value->value.intval); + else if (t_real != r_type(op_value)) + return e_typecheck; + + code = dict_put(lazystyleparam, op_key, op_value, NULL); + if (code < 0) + return code; ++ code = sync_lazystyleparam(pfont, lazystyleparam); + if (code < 0) + return code; + + pop(2); + return 0; +} + /* <Decoding> .setupUnicodeDecoder - */ private int zsetupUnicodeDecoder(i_ctx_t *i_ctx_p) @@ -237,6 +342,7 @@ {"1setcacheparams", zsetcacheparams}, {"0currentcacheparams", zcurrentcacheparams}, {"1.registerfont", zregisterfont}, + {"3.setlazystyleparam", zsetlazystyleparam}, {"1.setupUnicodeDecoder", zsetupUnicodeDecoder}, op_def_end(zfont_init) }; A2-d) The font caching system is changed to care the difference of LSS-mark. If it doesn't care, the cached image of normal font is reused for the LSS-marked font. Index: src/gsfont.c =================================================================== --- src/gsfont.c (revision 8217) +++ src/gsfont.c (working copy) @@ -486,6 +486,7 @@ for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next) if (pf_out->FontType == pfont->FontType && pf_out->base == pfont->base && + cmplazystyle(pf_out->lazystyle, pfont->lazystyle) && pf_out->FontMatrix.xx == newmat.xx && pf_out->FontMatrix.xy == newmat.xy && pf_out->FontMatrix.yx == newmat.yx && A2-e) If the font has the LSS-mark for bolding, pdfwrite insert setlinewidth and PaintType operator. Index: src/gdevpdts.h =================================================================== --- src/gdevpdts.h (revision 8217) +++ src/gdevpdts.h (working copy) @@ -36,6 +36,9 @@ * (and, in the case of text positioning, how) to emit PDF commands to * set them in the output. */ +typedef struct pdf_text_state_values_stylesynth_s { + float linewidth;+} pdf_text_state_values_stylesynth_t; typedef struct pdf_text_state_values_s { float character_spacing; /* Tc */ pdf_font_resource_t *pdfont; /* for Tf */ @@ -49,6 +52,8 @@ gs_matrix matrix; /* Tm et al */ int render_mode; /* Tr */ float word_spacing; /* Tw */ + /* The parameters for style synthesis: line width etc */ + pdf_text_state_values_stylesynth_t stylesynth_params; } pdf_text_state_values_t; #define TEXT_STATE_VALUES_DEFAULT\ 0, /* character_spacing */\ Index: src/gdevpdtt.c =================================================================== --- src/gdevpdtt.c (revision 8217) +++ src/gdevpdtt.c (working copy) @@ -1986,6 +1986,13 @@ ppts->values.word_spacing = w_s; ppts->font = font; + ppts->values.stylesynth_params.linewidth = 0; + /* under non-default rendering mode, the computation of appropriate render_mode is difficult */ + if (0 == ppts->values.render_mode && 0 != (GS_LAZY_BOLD & penum->current_font->lazystyle.stylebit)) { + ppts->values.render_mode = 2; + ppts->values.stylesynth_params.linewidth = penum->current_font->lazystyle.BoldWidth * size; + } + code = pdf_set_text_process_state(pdev, (const gs_text_enum_t *)penum, ppts); return (code < 0 ? code : mask); Index: src/gdevpdts.c =================================================================== --- src/gdevpdts.c (revision 8217) +++ src/gdevpdts.c (working copy) @@ -472,6 +472,10 @@ return code; } + if (0 != pts->in.render_mode && 0 < pts->in.stylesynth_params.linewidth) { + pprintg1(s, "%g w 1 M\n", pts->in.stylesynth_params.linewidth); + } + if (pts->out.render_mode != pts->in.render_mode) { pprintg1(s, "%g Tr\n", pts->in.render_mode); pts->out.render_mode = pts->in.render_mode;
Created attachment 3383 [details] concept of approarch A2 (demo document) Sample program using LSS-mark implemented by previous patch
Created attachment 3384 [details] current PDF result of approarch A1. current PDF result of approarch A1. Roman text is drawn once, but CJK text is drawn as graphics. q 0.1 0 0 0.1 0 0 cm /R7 gs 0 G 0 g q 10 0 0 10 0 0 cm BT /R8 32 Tf 1 0 0 1 10 700 Tm (this is normal /Courier)Tj /R27 1 Tf 40 TL (this is /Courier,Bold)' /R28 32 Tf 60 TL (<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF>)' ET Q 32 w 280.48 5554.72 m 280.48 5540.64 292 5529.12 306.398 5529.12 c 353.762 5529.12 l ...
Created attachment 3385 [details] current PDF result of approarch A2. current PDF result of approarch A2 is better for trivial & healthy input. q 0.1 0 0 0.1 0 0 cm /R7 gs 0 G 0 g q 10 0 0 10 0 0 cm BT 0 w /R8 20 Tf 1 0 0 1 10 400 Tm (Courier)Tj 25 TL 1 w 1 M 2 Tr (Courier,Bold)' /R12 20 Tf 75 TL 0 Tr (<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF>)' 25 TL 1 w 1 M 2 Tr (<E5><92><8C><E7><94><B0><E7><A0><94><E4><B8><B8><E3><82><B4><E3><82><B7><E3><83><83><E3><82><AF><EF><BC><8C><EF><BC><A2><EF><BD><8F><EF> <BD><8C><EF><BD><84>)' ET Q Q
Left issues of approach A2 patch: when pdfwrite receives a failure in rendering a text and regard the text cannot be embed as a combination of normal font & coded text, pdfwrite falls back to "default" rendering which drawing a text by Type3 font of cached images (if font cache is available) or draw vector graphics of extracted glyph paths (if font cache is unavailable). The LSS-mark should be reflected in such case. Yet I've not finished that. In the case of bitmap Type3 fallback, it's difficult to embold the glyph by setlinewidth and PaintType, because the glyph data is bitmap which setlinewidth/PaintType does not affect. Some embolding hook should be inserted into /BuildGlyph procedure of original font to obtain embolden glyph cache, but it's not easy. In the case of vector graphics fallback, the setlinewidth/PaintType may work.
Wow, a sudden flurry of activity :-) I have been exchanging email with Igor over this one, and I think a better approach is the one taken by Adobe. This is a two step refinement, and depends in part on other work which I am already implementing for a different issue. From Ray's original investigation, and examination of the behaviour of Acrobat, what Distiller seems to do is: 1) Convert the multiple 'show' operations into a single step, using Idiom recognition. This single step does the equivalent of '(text) show (text) charpath x setlinewidth stroke. 2) Internally convert the sequence show/charpath/stroke or charpath/fill/stroke into a '2 Tr (text) show' operation. '2 Tr' means stroke *and* fill the text. The emboldening is done by stroking the charpath with a wider line width, this seems (from Ray's work) to be done by an idiom. Since Adobe clearly feel this is adequate, I think we should follow their lead and do the same. conversion of charpath/stroke is an issue I'm already looking at, for bug #689310. In this case the stroke is not co-incident with the text, so we need to do this heuristic conversion to a 'show' with a different PDF text rendering rule. If we idiom recognise the Microsoft artificial bold operators, replace them with charpath stroke, and put that together with the work I'm already doing, then we should see a good result, I believe. This should (eventually) lead to just one set of text in the output, the same as the Adobe result. We don't have to mess about with type 3 fonts and custom BuildGlyph procedures, and we don't have to rely on the device to take special action.
Ken and me agree that this issue is not related to CJK and must be passed to Ken. Dear mpsuzuki please change the assignment if you have no objection. If you have an objection, please let us know.
Ken and me discussed it more and we believe it should be passed to Alex for writing an idiom with applying a stroked font. I mean fill the normal text and then stroke it with appropriate linewidth for enbolding. Converting it to 2 .settextrenderingmode should be a next step for high level devices only, which to be addressed to bug 689310 assigned to Ken. Dear mpsuzuki please let us know if you've got an objection for unassigning this bug from you.
Created attachment 3390 [details] sample to substitute PScript idioms Here's IdiomRecognition sample. /sB [ { % original PScript idiom 1 copy 2 copy gsave sBdx 0 rmoveto show grestore gsave 0 sBdx rmoveto show grestore gsave sBdx sBdx rmoveto show grestore show } bind { % idiom to substitute (known idiom /sB /sBdx=) print sBdx == flush gsave 0.18 sBdx mul setlinewidth show grestore } bind ] Please change "0.18 sBdx mul setlinewidth" phrase to appropriate procedure for embolding.
Yet I've not accepted this bug, so I have no objection to reassign this bug to other experts. I expect the preparation of a room to enhance for outline/shadow style synthesis. Now I pass this bug to Alex.
This is no longer a customer bug, since the reporter is no longer a customer.
commmit 34e2ae40bff4d288da83dcd739e50287bf7c3c2e fixes this for me.