高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

TX09 - Postscript フォントファイル名の翻訳

(97 年 11 月 17 日)

Q: どうすればフォント名を Postscript フォントファイルの名前に翻訳できますか。

A: Postscript フォントの名前は FOND リソース内部に格納されている情報を使って決定されます。この情報は、スタイルマッピングテーブルの中に格納されています。このテーブルの詳細については、『Inside Macintosh: Text』の 4-99 ページから 4-105 ページを参照してください。基本的な手順としては、FOND とスタイル情報を取り出して、有効な Postscript 名を構築します。

Postscript フォントファイルの名前が必要な場合は、Postscript 名を縮めてファイルの名前にすることができます。フォント名の先頭 5 文字はそのまま使用し、それ以降はダッシュで区切られたブロックの先頭 3 文字を順に追加していくというのが規則です。たとえば、次のような Helvetica 系のフォントでは、

Helvetica-Bold-Oblique-Condensed

フォントファイルの名前は次のようになります。

HelveBolOblCon

フォントファイル名を取得できれば、対応するファイルを検索できます。ファイルタイプは 'LWFN' で、クリエータは 'ASPF' です。フォントは複数のスーツケースに格納されている可能性があります。

* “フォント”フォルダ
* “機能拡張”フォルダ (7.0 には“フォント”フォルダがなかったため)
* システムフォルダ (6.x では、ここが Postscript ファイルの格納場所だったため)
* FOND リソースを保持するファイルと同じフォルダ (スーツケースを使用すると、Postscript フォントをシステムフォルダの外にも格納できるため)

もう一度繰り返しますが、フォントは複数のスーツケースに格納されている可能性があります。このため、上のステップを最後までたどる場合は、そのフォントに対する使用可能な FOND リソースをすべて検索する必要があります。

次に 2 つのサンプルコードを示します。1 つは、『Inside Macintosh: Text』で紹介されているスタイルマッピングコードを C 言語に書き換えたものです。もう 1 つは、FOND リソースのリストを見て回るために日ごろ私が使っているコードです。なお、MoreFiles は、複数のディレクトリを検索して目的のファイルを見つけ出す必要がある場合に役立つコンパクトなサンプルコードです。

----------------------------------------------------------------------------

#include <fonts.h>
#include <Strings.h>

typedef short int16;
typedef long int32;
typedef FamRec **FamRecHdl;
typedef StyleTable *StyleTablePtr;

#define MIN(a,b) ((a)<(b)?(a):(b))

void main (void);
void GetPrinterFontName (Str255 screenName, Str255 printerName);
int32 MyCompressStyle(Style aStyle);
void MyNthStyleName(int32 index, Ptr q, Str255 s);
void MyPSFontName(FamRec **fh, Style aStyle, Str255 PSName);

void ConcatPStrings (Str255 targetStr, ConstStr255Param appendStr);

void ConcatPStrings (Str255 targetStr, ConstStr255Param appendStr)
{
    short appendLen;

    /* コピーするバイト数を計算する。最大 255 まで */

    appendLen = MIN(appendStr[0], 255 - targetStr[0]);
    if (appendLen > 0) {
        BlockMoveData(appendStr+1, targetStr+targetStr[0]+1, (long) appendLen);
        targetStr[0] += appendLen;
    }
}

void main (void)
{
        Str255 printer;

// 標準的な Mac の初期化を実行する
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();

    MaxApplZone();
    MoreMasters();
    MoreMasters();
    MoreMasters();

    GetPrinterFontName ("\pTimes", printer);
    Debugger();
}

void GetPrinterFontName(Str255 screenName, Str255 printerName)
{
    int16           fontNum;
    FMetricRec  theMetrics;
    WidthTable  **wTabHan;

    GetFNum( screenName, &fontNum);
    TextFont( fontNum );
    TextFace (bold + italic);
    FontMetrics( &theMetrics );
    wTabHan = (WidthTable **) theMetrics.wTabHandle;
    MyPSFontName((FamRecHdl) (**wTabHan).fHand, bold+italic, printerName);
    return;
}

int32 MyCompressStyle(Style aStyle)
    // 短縮と伸張が相互に排他的であると仮定して、
    // "StyleItem のセット" は [0..47] の中にマップされる
{
    int32 styleCode;

    styleCode = 0;
    if (bold & aStyle)
        styleCode = styleCode + 1;
    if (italic & aStyle)
        styleCode = styleCode + 2;
    if (outline & aStyle)
        styleCode = styleCode + 4;
    if (shadow & aStyle)
        styleCode = styleCode + 8;

    if (condense & aStyle)
        styleCode = styleCode + 16;
    else if (extend & aStyle)
        styleCode = styleCode + 32;

    return( styleCode );
}

void MyNthStyleName(int32 index, Ptr q, Str255 s)
{
    while (index > 1) {
        q = (Ptr) (q + *q + 1);
        // q^ = stringlength < 128 ... と仮定する
        index -= 1;
    }
    BlockMove(q, &s[0], *q + 1);
    // q^ = stringlength < 127 ... と仮定する
    return;
}

void MyPSFontName(FamRec **fh, Style aStyle, Str255 PSName)
{
    StyleTablePtr stp;
    Ptr     q;              // スタイル名テーブルへのポインタ
    Str255  styleName, suffixIndices;
    int32   i, nbOfStrings, offset, whichIndex;

    PSName[0] = '0';
    offset = (**fh).ffStylOff;
    if (offset > 0) {
        q = ((Ptr) *fh) + offset;
        stp = (StyleTablePtr) q;
        q += sizeof (StyleTable);

            // スタイル名テーブルはスタイルマッピングテーブルに従う
        nbOfStrings = *(SInt16 *) q;
            // チェックを行う範囲
        q += sizeof (SInt16);
            // これでフォントのベース名をポイントする
        BlockMove(q, (Ptr) PSName, *q + 1);
            // フォントのベース名。length < 128 と仮定する
        whichIndex = stp->indexes[MyCompressStyle(aStyle)];
        if (whichIndex > 1  &&  whichIndex <= nbOfStrings) {
            MyNthStyleName(whichIndex, q, suffixIndices);
            for (i=1;i <= suffixIndices[0];++i) {
                MyNthStyleName(suffixIndices[i], q, styleName);
                ConcatPStrings( PSName, styleName);
            }
        }
    }
        //ELSE  FOND が壊れている
    //else // FOND にスタイルマッピングテーブルがない
        //return( PSName );
}

----------------------------------------------------------------------------

#define _SanityCheck_ 1

#ifndef _SanityCheck_
    #define _SanityCheck_ 1
#endif

// これらのコードでは何らかのエラー変数を設定していません。
// 一般に、OSErr を通知するルーチンでは、適切に設定されているルーチンの内部に
// 変数を持つようにしてください。そうすれば、そのルーチンがすでに noErr に
// 設定されていないとき、"デフォルト" のエラーコードが返されます

#if _SanityCheck_
    #define FAIL_NIL(y,msg)         {if (y == NULL) {DebugStr(msg); goto error;}}
    #define FAIL_OSERR(y,msg)       {if (y != noErr) {DebugStr(msg); goto error;}}
    #define FAIL_FALSE(y,msg)       {if (!y) {DebugStr(msg); goto error;}}
    #define SIGNAL_ERROR(msg)       {DebugStr(msg); goto error;}
#else
    #define FAIL_NIL(y,msg)         {if (y == NULL) {goto error;}}
    #define FAIL_OSERR(y,msg)       {if (y != noErr) { goto error;}}
    #define FAIL_FALSE(y,msg)       {if (!y) {goto error;}}
    #define SIGNAL_ERROR(msg)       {goto error;}
#endif

void main (void);

// このルーチンは、渡されたフォントを含む、最初に使用可能なインストール済みファイルを返す
// また、このルーチンは目的のフォントを含むその他のファイルを検索するために使用できる魔法のクッキーを返す。

OSErr   FontNameToFSSpec (ConstStr31Param inFont, FSSpec *outFile, long *outCookie);
OSErr   NextFontToFSSpec (long *inOutCookie, FSSpec *outFile);

// 扱いが容易なため、次のルーチンは MoreFiles から借用している
/*****************************************************************************/

pascal  OSErr   GetFileLocation(short refNum,
                                short *vRefNum,
                                long *dirID,
                                StringPtr fileName);
/*  オープンファイルの保存場所を取得する
    GetFileLocation 関数はオープンファイルの保存場所 (ボリューム参照番号、ディレクトリ ID、および fileName) を取得する。

    refNum      input:  オープンファイルのファイル参照番号
    vRefNum     output: ボリューム参照番号
    dirID       output: 親ディレクトリ ID
    fileName    input:  ファイル名が返されるバッファ (最小限 Str63) へのポインタ、または nil でなければらない
                output: ファイル名

    結果コード
        noErr               0       正常終了
        nsvErr              -35     指定されたボリュームが存在しない
        fnOpnErr            -38     ファイルがオープンされていない
        rfNumErr            -51     参照番号が存在しないアクセスパスを指定している

    __________

    関連項目:   FSpGetFileLocation
*/

/*****************************************************************************/

pascal  OSErr   FSpGetFileLocation(short refNum,
                                   FSSpec *spec);
/*  FSSpec レコードに含まれるオープンファイルの保存場所を取得する

    refNum      input:  オープンファイルのファイル参照番号
    spec        output: ファイル名と保存場所を含む FSSpec レコード

    結果コード
        noErr               0       正常終了
        nsvErr              -35     指定されたボリュームが存在しない
        fnOpnErr            -38     ファイルがオープンされていない
        rfNumErr            -51     参照番号が存在しないアクセスパスを指定している

    __________

    関連項目:   GetFileLocation
*/

/*****************************************************************************/

pascal  OSErr   GetFileLocation(short refNum,
                                short *vRefNum,
                                long *dirID,
                                StringPtr fileName)
{
    FCBPBRec pb;
    OSErr error;

    pb.ioNamePtr = fileName;
    pb.ioVRefNum = 0;
    pb.ioRefNum = refNum;
    pb.ioFCBIndx = 0;
    error = PBGetFCBInfoSync(&pb);
    *vRefNum = pb.ioFCBVRefNum;
    *dirID = pb.ioFCBParID;
    return ( error );
}

/*****************************************************************************/

pascal  OSErr   FSpGetFileLocation(short refNum,
                                   FSSpec *spec)
{
    return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) );
}

OSErr   FontNameToFSSpec (ConstStr31Param inFont, FSSpec *outFile, long *outCookie)
{
    OSErr theErr= noErr;
    short homeFile;

    Handle fond;
    *outCookie = NULL;

    fond = GetNamedResource('FOND', inFont);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find any installed font file with that font name")
    FAIL_NIL (fond, "\p Failed to find any installed font file with that font name")

    homeFile = HomeResFile (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find the resource's home")

    theErr = FSpGetFileLocation(homeFile, outFile);
    FAIL_OSERR (theErr, "\p couldn't convert the reference to a file spec")

    // 処理成功。クッキーをセットして戻る
    *outCookie = (long) fond;

    return noErr;

    error:
    if (theErr != noErr)
        theErr = paramErr;
    *outCookie = NULL;
    return theErr;
}

OSErr   NextFontToFSSpec (long *inOutCookie, FSSpec *outFile)
{
    OSErr theErr= noErr;
    short homeFile;

    Handle fond = (Handle) *inOutCookie;

    if (fond == NULL) return paramErr;

    fond = GetNextFOND (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p No more fonds left with that name")
    FAIL_NIL (fond, "\p No more fonds left with that name")

    homeFile = HomeResFile (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find the resource's home")

    theErr = FSpGetFileLocation(homeFile, outFile);
    FAIL_OSERR (theErr, "\p couldn't convert the reference to a file spec")

    // 処理成功。クッキーをセットして戻る
    *inOutCookie = (long) fond;

    return noErr;

    error:
    if (theErr != noErr)
        theErr = paramErr;
    *inOutCookie = NULL;
    return theErr;
}

void main (void)
{
    long oreo;
    FSSpec  fontFile;
    OSErr   theErr;

    // ここでデバッガに入り、返された FSSpecs を通知する

    theErr = FontNameToFSSpec("\pPalatino", &fontFile, &oreo);
    Debugger();
    while (oreo != 0)
    {
        theErr = NextFontToFSSpec (&oreo, &fontFile);
        Debugger();
    }

}



                        -- Tim Carroll
                        devsupport@apple.com