えムナウ Blog

えムナウ の なすがまま

目次

Blog 利用状況

ニュース


follow mnow at http://twitter.com


えムナウのプログラミングのページ

INETAJ

書庫

日記カテゴリ

ギャラリ

WPF の縦書き

WPF の縦書きで microsoft にお願いしていましたが聞き入れてもらえません。

https://connect.microsoft.com/VisualStudioJapan/feedback/details/420434/wpf-xps

自分でやってみました。

WPF の縦書きを表示することはできました。

image

こんな XAML を書きます。
msgothic で 特殊な文字を使わなければ Indices でグリフ変換するだけです。

<Window

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        x:Class="縦書きテスト.MainWindow"

        x:Name="Window"

        Title="MainWindow"

        Width="525" Height="320">

 

        <Grid x:Name="LayoutRoot">

        <Canvas RenderTransformOrigin="0.5,0.5">

            <Glyphs Name="a0" Fill="#FF000000"

                          FontUri="C:\Windows\Fonts\msgothic.ttc"

                          UnicodeString="私の名前はえムナウです。"

                          Indices="9918;21455;4001;3667;21456;21418;21559;21537;21501;21448;21435;21395"

                          IsSideways="true" Canvas.Left="505" FontRenderingEmSize="20">

                <Glyphs.RenderTransform>

                        <TransformGroup>

                                <ScaleTransform/>

                                <SkewTransform/>

                                <RotateTransform Angle="90"/>

                                <TranslateTransform/>

                        </TransformGroup>

                </Glyphs.RenderTransform>

            </Glyphs>

            <Glyphs Name="a1" Fill="#FF000000"

                          FontUri="C:\Windows\Fonts\msgothic.ttc"

                          UnicodeString="「1+1=2」、じゃーね。"

                          Indices="21400;21638;18439;21638;21649;21639;21401;21394;21434;21476;21582;21454;21395"

                          IsSideways="true" Canvas.Left="485" FontRenderingEmSize="20">

                <Glyphs.RenderTransform>

                        <TransformGroup>

                                <ScaleTransform/>

                                <SkewTransform/>

                                <RotateTransform Angle="90"/>

                                <TranslateTransform/>

                        </TransformGroup>

                </Glyphs.RenderTransform>

            </Glyphs>

_        </Canvas>

    </Grid>

</Window>

 

Indices を作るプログラムは C(C++) の DLL (uniscribe.dll)です。
usp10.dll > version 1.6 を呼んでいます。

 

extern "C" HRESULT PASCAL EXPORT UniscribeScriptItemizeOpenType(

        wchar_t* pwcInChars, int cInChars, SCRIPT_ITEM* pItems, OPENTYPE_TAG* pScriptTags, int* pcItems)

{

        HRESULT hr = ScriptItemizeOpenType(pwcInChars, cInChars, cInChars, 0, 0, pItems, pScriptTags, pcItems);

        return hr;

}

 

extern "C" HRESULT PASCAL EXPORT UniscribeScriptShapeOpenType(

        HWND hWnd, wchar_t* pwcFontName, int lfHeight, SCRIPT_CACHE* psc, SCRIPT_ANALYSIS* psa,

        OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,

        OPENTYPE_FEATURE_RECORD* potfRecords, int cotfRecords, int *rcRangeChars,

        wchar_t* pwcChars, int cChars, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProps,

        WORD* pwOutGlyphs, SCRIPT_GLYPHPROP* pOutGlyphProps, int* pcGlyphs)

{

        HDC hDC = GetDC(hWnd);

        LOGFONT logfont;

        memset(&logfont, 0, sizeof(logfont));

        logfont.lfCharSet = DEFAULT_CHARSET;

        logfont.lfHeight = lfHeight;

        wcscpy_s(logfont.lfFaceName, sizeof(logfont.lfFaceName)/sizeof(WCHAR), pwcFontName);

        HFONT hFont = CreateFontIndirect(&logfont);

        HGDIOBJ hOldFont = SelectObject(hDC, hFont);

 

        TEXTRANGE_PROPERTIES* rpRangeProperties = new ::TEXTRANGE_PROPERTIES[1];

        rpRangeProperties[0].potfRecords = potfRecords;

        rpRangeProperties[0].cotfRecords = cotfRecords;

 

        HRESULT hr = ScriptShapeOpenType(hDC, psc, psa, tagScript, tagLangSys, rcRangeChars, &rpRangeProperties, 1,

                pwcChars, cChars, cChars, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);

 

        delete[] rpRangeProperties;

        SelectObject(hDC, hOldFont);

        DeleteObject(hFont);

        ReleaseDC(hWnd, hDC);

        return hr;

}

 

C# から呼ぶには クラスを作ります。

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct SCRIPT_CACHE

    {

        public IntPtr cache;

    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct SCRIPT_ANALYSIS

    {

        public ushort flags;

        public ushort scriptState;

    }

 

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct SCRIPT_ITEM

    {

        public int iCharPos;

        public SCRIPT_ANALYSIS a;

    }

 

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct SCRIPT_CHARPROP

    {

        public ushort flags;

    }

 

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct OPENTYPE_TAG

    {

        public Byte b0;

        public Byte b1;

        public Byte b2;

        public Byte b3;

        public OPENTYPE_TAG(char b0, char b1, char b2, char b3)

        {

            this.b0 = (Byte)b0;

            this.b1 = (Byte)b1;

            this.b2 = (Byte)b2;

            this.b3 = (Byte)b3;

        }

        public override string ToString()

        {

            if (b0 == 0)

            {

                return "<null>";

            }

            StringBuilder sb = new StringBuilder();

            sb.Append((char)b0);

            sb.Append((char)b1);

            sb.Append((char)b2);

            sb.Append((char)b3);

            return sb.ToString();

        }

    }

 

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct OPENTYPE_FEATURE_RECORD

    {

        public OPENTYPE_TAG tagFeature;

        public uint lParameter;

    }

 

    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    public struct SCRIPT_GLYPHPROP

    {

        public ushort sva;

        public ushort reserved;

    }

    public static class Uniscribe

    {

        [DllImport("uniscribe.dll", CharSet = CharSet.Unicode)]

        public static extern int UniscribeScriptItemizeOpenType(

            string pwcInChars,

            int cInChars,

            [In, Out] SCRIPT_ITEM[] pItems,

            [In, Out] OPENTYPE_TAG[] pScriptTags,

            ref int pcItems

        );

        [DllImport("uniscribe.dll", CharSet = CharSet.Unicode)]

        public static extern int UniscribeScriptShapeOpenType(

            IntPtr hwnd,

            string pwcFontName,

            int lfHeight,

            ref SCRIPT_CACHE psc,

            ref SCRIPT_ANALYSIS psa,

            OPENTYPE_TAG tagScript,

            OPENTYPE_TAG tagLangSys,

            [In, Out] OPENTYPE_FEATURE_RECORD[] potfRecords,

            int cotfRecords,

            [In, Out] int[] rcRangeChars,

            string pwcChars,

            int cChars,

            [In, Out] ushort[] pwLogClust,

            [In, Out] SCRIPT_CHARPROP[] pCharProps,

            [In, Out] ushort[] pwOutGlyphs,

            [In, Out] SCRIPT_GLYPHPROP[] pOutGlyphProps,

            ref int pcGlyphs

        );

    }

 

呼ぶほうはこんな風に呼びます。

            //string pwcInChars = "私の名前はえムナウです。";

            string pwcInChars = "「1+1=2」、じゃーね。";

            int cInChars = pwcInChars.Length;

            SCRIPT_ITEM[] pItems = new SCRIPT_ITEM[cInChars];

            OPENTYPE_TAG[] pScriptTags = new OPENTYPE_TAG[cInChars];

            for (int index = 0; index < cInChars; index++)

            {

                pItems[index] = new SCRIPT_ITEM();

                pScriptTags[index] = new OPENTYPE_TAG('\u0000', '\u0000', '\u0000', '\u0000');

            }

            int pcItems = 0;

            int hresult = Uniscribe.UniscribeScriptItemizeOpenType(

                pwcInChars, cInChars, pItems, pScriptTags, ref pcItems);

 

            WindowInteropHelper helper = new WindowInteropHelper(App.Current.MainWindow);

            SCRIPT_CACHE psc = new SCRIPT_CACHE();

            for (int itemIndex = 0; itemIndex < pcItems; itemIndex++)

            {

                SCRIPT_ANALYSIS psa = pItems[itemIndex].a;

                int cChars = pItems[itemIndex+1].iCharPos - pItems[itemIndex].iCharPos;

                string pwcChars = pwcInChars.Substring(pItems[itemIndex].iCharPos, cChars);

                OPENTYPE_TAG tagScript = pScriptTags[itemIndex];

                OPENTYPE_TAG tagLangSys = new OPENTYPE_TAG('\u0000', '\u0000', '\u0000', '\u0000');

                OPENTYPE_FEATURE_RECORD[] potfRecords = new OPENTYPE_FEATURE_RECORD[1];

                potfRecords[0] = new OPENTYPE_FEATURE_RECORD();

                potfRecords[0].tagFeature = new OPENTYPE_TAG('v', 'e', 'r', 't');

                potfRecords[0].lParameter = 1;

                int[] rcRangeChars = new int[] { cChars };

                ushort[] pwLogClust = new ushort[cChars];

                SCRIPT_CHARPROP[] pCharProps = new SCRIPT_CHARPROP[cChars];

                ushort[] pwOutGlyphs = new ushort[cInChars];

                SCRIPT_GLYPHPROP[] pOutGlyphProps = new SCRIPT_GLYPHPROP[cChars];

                for (int index = 0; index < cChars; index++)

                {

                    pOutGlyphProps[index] = new SCRIPT_GLYPHPROP();

                    pwLogClust[index] = 0;

                    pCharProps[index] = new SCRIPT_CHARPROP();

                    pwOutGlyphs[index] = 0;

                }

                int pcGlyphs = 0;

 

                System.Diagnostics.Debug.Print("pwcChars={0}, cChars={1} tagScript={2:x}", pwcChars, cChars, tagScript);

 

                int hresult2 = Uniscribe.UniscribeScriptShapeOpenType(

                    helper.Handle, "msgothic", 200, ref psc, ref psa, tagScript, tagLangSys,

                    potfRecords, 1, rcRangeChars, pwcChars, cChars,

                    pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, ref pcGlyphs);

 

                System.Diagnostics.Debug.Print("Gryphs={0}", pcGlyphs);

                for (int gryphIndex = 0; gryphIndex < pcGlyphs; gryphIndex++)

                {

                    System.Diagnostics.Debug.Print(

                        "Gryph pwLogClust={0}, pCharProps={1}, pwOutGlyphs={2}, pOutGlyphProps={3}",

                        pwLogClust[gryphIndex], pCharProps[gryphIndex].flags, pwOutGlyphs[gryphIndex], pOutGlyphProps[gryphIndex].sva);

                }

            }

 

結果の pwOutGlyphs を加工すれば一番最初の XAML にできます。

pwcChars=「, cChars=1 tagScript=hani
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21400, pOutGlyphProps=274
pwcChars=1, cChars=1 tagScript=<null>
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21638, pOutGlyphProps=274
pwcChars=+, cChars=1 tagScript=hani
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=18439, pOutGlyphProps=274
pwcChars=1, cChars=1 tagScript=<null>
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21638, pOutGlyphProps=274
pwcChars==, cChars=1 tagScript=hani
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21649, pOutGlyphProps=274
pwcChars=2, cChars=1 tagScript=<null>
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21639, pOutGlyphProps=274
pwcChars=」、, cChars=2 tagScript=hani
Gryphs=2
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21401, pOutGlyphProps=274
Gryph pwLogClust=1, pCharProps=0, pwOutGlyphs=21394, pOutGlyphProps=274
pwcChars=じゃーね, cChars=4 tagScript=kana
Gryphs=4
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21434, pOutGlyphProps=274
Gryph pwLogClust=1, pCharProps=0, pwOutGlyphs=21476, pOutGlyphProps=274
Gryph pwLogClust=2, pCharProps=0, pwOutGlyphs=21582, pOutGlyphProps=274
Gryph pwLogClust=3, pCharProps=0, pwOutGlyphs=21454, pOutGlyphProps=274
pwcChars=。, cChars=1 tagScript=hani
Gryphs=1
Gryph pwLogClust=0, pCharProps=0, pwOutGlyphs=21395, pOutGlyphProps=274

WPF の縦書きに一筋の光明が見えてきました。

投稿日時 : 2010年10月30日 18:19