emfファイルのフォントサイズ変更

解決


yoro  2009-04-28 17:20:25  No: 101681  IP: 192.*.*.*

散布図で各プロットに対応する文字が表示されています。
それらの文字は全て同一です。
他にも、軸ラベルなどがあります。

このemf(或いはwmfでも可)ファイルをVBから編集することで
フォントサイズを全て一定の比率・・例えば1.5倍とか0.7倍
などに変更することは可能でしょうか?

よろしくお願いします。

編集 削除
オショウ  2009-04-28 17:37:22  No: 101682  IP: 192.*.*.*

(拡張)メタファイルは、拡大縮小に対応していますので、この場合
文字フォントの大きさのみを変更したいと言うことでしょうか?

一応、機能的には可能です。

ただ大昔にやったので、どうやったか覚えてません・・・
DXF => MetaFile 変換やりました。後にMetaFileの表示でレイヤ的な
部分や文字情報の変更とか加工処理を別途行いましたから可能なはず
です。(あくまではず・・・)

以上。

編集 削除
yoro  2009-04-28 17:52:16  No: 101683  IP: 192.*.*.*

オショウさん、早速のレスありがとうございます。

上の質問がチョット判りにくいですね。
> 散布図で各プロットに対応する文字が表示されています。
> それらの文字は全て同一です。
文字は異なっていますが、サイズは同一です。

詳しく言えば、統計解析システム R で散布図を作成しemfで出力しています。
http://www.okada.jp.org/RWiki/?RjpWiki

データ数が大きいので、emfファイルをVBで作った簡易ビューアで拡大表示
させています。

その際に、文字サイズも同時に拡大しますので、例えばグラフが2倍に
なったら、文字サイズは1/2にして、拡大表示させたときの文字サイズを
一定にさせたかったのです。

> ただ大昔にやったので、どうやったか覚えてません・・・

残念です!
ただ、可能性がありそうなことが判っただけでも嬉しいです。

今、MSのENHMET.HLP(仕様書?)を読んでいますが、よく判りません(汗

引き続き、皆様の情報をお待ちしています。

宜しくお願いします。

編集 削除
オショウ  2009-04-28 20:46:58  No: 101684  IP: 192.*.*.*

EnumEnhMetaFile
GetEnhMetaFileBits

これらを使って・・・
レコードを列挙・抽出を行い、別の加工後のメタファイルに
出力させながら、該当の要素を修正してやれば、欲しい機能
が実現できるはずです。結構力技かも・・・です。

※  要素の抽出と言う方法がミソ!

※  1992〜1993年に作ったソースコードを偶然引っ張りだせ
    ましたので・・・ヒーコラ・・・

    DXF ファイルから要素を列挙・抽出して、MetaFile向け
    のGDI命令に変更して変換を実現していましたので、方法
    としては、実現できるはずです。

※  要素の抽出の際、文字列情報が、どんなIDになっている
    のか、調べる必要があると思います。
    ちょっともう調べるのが面倒・・・すいません・・・

以上。がんばって下さい!

編集 削除
K.J.K.  2009-04-28 20:48:38  No: 101685  IP: 192.*.*.*

片方で EnumEnhMetaFile で列挙しながら、もう片方で EnhMetaDC に
PlayEnhMetaFileRecord で記録することにして、列挙側では Font の
設定に関係ありそうな EMR、例えば EMREXTCREATEFONTINDIRECTW など
を監視して、もし該当するのが来たら、その時だけ加工した EMR を
記録側に送るとか。

編集 削除
yoro  2009-04-30 13:01:09  No: 101686  IP: 192.*.*.*

オショウ様、K.J.K.様  コメントありがとうございます。

聞けば聞くほど壁がはっきりし、簡単には出来そうにない予感が・・・

別なアプローチで、フォントサイズを変更した2つのemfファイルを
比較したりもしているのですが、ファイルサイズ自体も変化しています。

現時点では、Rに適当なタイミングで、都度emfファイルを出力させる
ことで逃げる仕様にしました。

とりあえず、この話題は閉めることとさせていただきます。

編集 削除
yoro  2009-05-08 07:39:12  No: 101687  IP: 192.*.*.*

オショウ様、K.J.K.様のアドバイスを元に連休中に少しトライしてみました。

⇒ 下記を参考にフォント高さを変更することには成功しました。
http://nienie.com/~masapico/api_GetEnhMetaFileBits.html
http://park7.wakwak.com/~efc21/cgi-bin/exqalounge.cgi?print+200708/07080129.txt

◆ しかし、文字の長さ(矩形表示領域?)が変更されず、文字高さを小さくすると
文字と文字の間隔が広くなり、逆に大きくすると文字が重なりだします。

Type EMREXTTEXTOUT
    pEmr        As EMR
    rclBounds   As RECTL
    iGraphicsMode As Long
    exScale     As Double
    eyScale     As Double
    emrtext     As emrtext
End Type

Type EXTLOGFONT
    elfLogFont      As LOGFONT
    elfFullName(LF_FULLFACESIZE) As Byte
    elfStyle(LF_FACESIZE) As Byte
    elfVersion      As Long
    elfStyleSize    As Long
    elfMatch        As Long
    elfReserved     As Long
    elfVendorId(ELF_VENDOR_SIZE) As Byte
    elfCulture      As Long
    elfPanose       As PANOSE
End Type

Type EMREXTCREATEFONTINDIRECT
    pEmr            As EMR
    ihFont          As Long
    elfw            As EXTLOGFONT
End Type

Const EMR_EXTCREATEFONTINDIRECTW = 82
Const EMR_EXTTEXTOUTW = 84

While SrcIdx < BufSize
  'レコードのヘッダを取得
  MoveMemory RecordHeader, SrcData(SrcIdx), Len(RecordHeader)
  
  If RecordHeader.iType = EMR_EXTCREATEFONTINDIRECTW Then
      MoveMemory E_CREATEFONTINDIRECT, SrcData(SrcIdx), Len(E_CREATEFONTINDIRECT)
      'フォント高さを半減
      E_CREATEFONTINDIRECT.elfw.elfLogFont.lfHeight = E_CREATEFONTINDIRECT.elfw.elfLogFont.lfHeight * sScale
     'E_CREATEFONTINDIRECT.elfw.elfLogFont.lfWidth ・・ は個々の文字幅!
      '新規メタファイル用バッファに設定
      MoveMemory DestData(DestIdx), E_CREATEFONTINDIRECT, Len(E_CREATEFONTINDIRECT)
      DestIdx = DestIdx + RecordHeader.nSize
  ElseIf RecordHeader.iType = EMR_EXTTEXTOUTW Then
      MoveMemory E_TEXTOUT, SrcData(SrcIdx), RecordHeader.nSize  'Len(E_TEXTOUT)ではカタカナが1文字長さで固まる
      With E_TEXTOUT.rclBounds
          Debug.Print .Left, .Top, .Right, .Bottom    '0  0   -1  -1 のみ
      End With
      '新規メタファイル用バッファに設定
      MoveMemory DestData(DestIdx), E_TEXTOUT, RecordHeader.nSize  'Len(E_TEXTOUT)ではカタカナが1文字長さで固まる
      DestIdx = DestIdx + RecordHeader.nSize
  '文字描画レコードでない場合  →  そのまま複製
  Else
      MoveMemory DestData(DestIdx), SrcData(SrcIdx), RecordHeader.nSize
      DestIdx = DestIdx + RecordHeader.nSize
  End If
  SrcIdx = SrcIdx + RecordHeader.nSize
Wend

◆ 矩形領域はEMREXTTEXTOUTW構造体のrclBoundsかなとも思ったのですが、入っているデータは
      With E_TEXTOUT.rclBounds
          Debug.Print .Left, .Top, .Right, .Bottom    '0  0   -1  -1 のみ
      End With
でした。

また、上にもコメント入れていますがEMR_EXTTEXTOUTWの際には、
MoveMemory E_TEXTOUT, SrcData(SrcIdx), Len(E_TEXTOUT)  ではカタカナが1文字長さの矩形領域に
重なって表示されます。
→漢字は正しく表示されます。

APIの扱いがよく判っていない為だと思いますが、お気づきの点がありましたらご教授頂ければ幸いです。

編集 削除
K.J.K.  2009-05-08 10:28:36  No: 101688  IP: 192.*.*.*

EMREXTTEXTOUT.emrtext.rcl や EXTLOGFONT.elfLogFont.lfWidth の値などを
換えてみるとどうなりますか?

編集 削除
yoro  2009-05-08 10:56:33  No: 101689  IP: 192.*.*.*

K.J.K.様  お世話になります。

> EMREXTTEXTOUT.emrtext.rcl や EXTLOGFONT.elfLogFont.lfWidth の値などを
> 換えてみるとどうなりますか?

EMREXTTEXTOUT.emrtext.rclは
Debug.Print .Left, .Top, .Right, .Bottom  で全て
  0 , 0 ,  -1 , -1 のみ返します。

EXTLOGFONT.elfLogFont.lfWidth はフォント自体(1文字?)の幅でしょうか?
→ 値は 0 となっています。省略値?

個人的には、何か上位オブジェクトの矩形領域などを参照している気がします。
⇒あまり関係ないでしょうが、下記のDrawTextでソースの雰囲気からです。

http://www.f3.dion.ne.jp/~element/msaccess/clgdiplusdoc.html#VI-F

Public Function DrawText(pText As String, pSize As Long, Optional pFontName As String, _
                         Optional pX1 As Long, Optional pY1 As Long, Optional pX2 As Long = -1, Optional pY2 As Long = -1, _
                         Optional pAlignHoriz As Long = 1, Optional pAlignVert As Long = 1, _
                         Optional pPenColor As Long = 0, Optional pPenAlpha As Integer = 255, _
                         Optional pBackColor As Long = -1, Optional pBackAlpha As Integer = 255, _
                         Optional pItalic As Boolean, Optional pBold As Boolean, _
                         Optional pUnderline As Boolean, Optional pStrikeout As Boolean, _
                         Optional pAntialiase As Boolean = False, Optional pOnlyGetSize As Boolean = False) As Boolean
' Conversion si controle de reference
    If Not gCtrlRef Is Nothing Then
        pX1 = CtrlToImgX(pX1, gCtrlRef, True)
        pY1 = CtrlToImgY(pY1, gCtrlRef, True)
        pX2 = CtrlToImgX(pX2, gCtrlRef, True)
        pY2 = CtrlToImgY(pY2, gCtrlRef, True)
    End If
    DrawText = PrivDrawText(pText, pSize, pFontName, pX1, pY1, pX2, pY2, _
                            pAlignHoriz, pAlignVert, pPenColor, pPenAlpha, pBackColor, pBackAlpha, _
                            pItalic, pBold, pUnderline, pStrikeout, pAntialiase, pOnlyGetSize)
End Function

Private Function PrivDrawText(pText As String, pSize As Long, Optional ByVal pFontName As String, _
                              Optional pX1 As Long, Optional pY1 As Long, Optional pX2 As Long = -1, Optional pY2 As Long = -1, _
                              Optional ByVal pAlignHoriz As Long = 1, Optional ByVal pAlignVert As Long = 1, _
                              Optional pPenColor As Long = 0, Optional pPenAlpha As Integer = 255, _
                              Optional pBackColor As Long = -1, Optional pBackAlpha As Integer = 255, _
                              Optional pItalic As Boolean, Optional pBold As Boolean, _
                              Optional pUnderline As Boolean, Optional pStrikeout As Boolean, _
                              Optional pAntialiase As Boolean = False, Optional pOnlyGetSize As Boolean = False, _
                              Optional pImage As String = "") As Boolean
    Dim lGraphics As Long
    Dim lFontFamily As Long, lFont As Long
    Dim lTextBrush As Long, lBackBrush As Long
    Dim lTextRect As RECTF
    Dim lCalcRect As RECTF
    Dim lStrFormat As Long
    Dim lBitmap As Long
    Dim lwidth As Single, lheight As Single
    Dim lCenter As Boolean
    Dim lStyle As Long
    On Error GoTo gestion_erreurs
    If pImage = "" Then
        ConvertTo32Bits gBitmapWork
        lBitmap = gBitmapWork
    Else
        lBitmap = gImgList(pImage)
    End If
    ' Rectangle de positionnement du texte
    ' Dimensions de l'image
    GdipGetImageDimension lBitmap, lwidth, lheight
    If pX2 = -1 And pY2 = -1 Then
        lCenter = True
    End If
    If pX2 = -1 Then pX2 = lwidth
    If pY2 = -1 Then pY2 = lheight
    lTextRect.Left = pX1
    lTextRect.Top = pY1
    lTextRect.Right = pX2 - pX1
    lTextRect.Bottom = pY2 - pY1
以下省略します。

よろしくお願いします。

編集 削除
K.J.K.  2009-05-08 11:47:50  No: 101690  IP: 192.*.*.*

GetEnhMetaFileBits を用いずに、動的に EnumEnhMetaFile + PlayEnhMetaFileRecord
で行うとどうなりますか?

編集 削除
yorp  2009-05-13 09:08:52  No: 101691  IP: 192.*.*.*

K.J.K.様
> GetEnhMetaFileBits を用いずに、動的に EnumEnhMetaFile + PlayEnhMetaFileRecord
> で行うとどうなりますか?

http://nienie.com/~masapico/api_sample_metafile03_vb.html

上記ののサンプルを見ながらトライしていましたが、最初は
  RtlMoveMemory VarPtr(eh), pRecord, Len(eh) が上手く機能しないのか
eh.iTypeが全て0となり、海外のサイトを参考にしながら

EnumEnhMetaFile + PlayEnhMetaFileRecordでiTypeを確認しながら単純再生は
出きるようになりました。

しかし、パラメータの変更など、MoveMemoryが上手くできず?
挫折しました。

その後、下記の記載を見つけました。

http://msdn.microsoft.com/en-us/library/dd162591(VS.85).aspx
http://msdn.microsoft.com/en-us/library/cc230576(PROT.10).aspx

offDx 
Offset to intercharacter spacing array.

これを如何に使うかがヒントかと思い下記の情報も得ました。
http://social.microsoft.com/Forums/ja-JP/os_windowsprotocols/thread/85805191-98f2-4087-a829-5e65cc3bd21e

しかし、結局どう使って良いのかわからず、試しに

emrtext.offDx = 0

としたところ、上手く文字間隔が詰まりました。
→  emrtext.offDx = 0  とすることで指定条件が解除され、標準的な配置に
されたのでしょうか?

とりあえず、これで様子見ですが上記HPなどの情報を含め、何かお気づきの
点がありましたらご教授願います。

編集 削除
K.J.K.  2009-05-13 12:14:30  No: 101692  IP: 192.*.*.*

offDx = 0 でいけるというのは面白いですね。
本来そこには影響を与えていないようにも思えますが、
やはり何かしらのリセット効果があるのかも知れません。

編集 削除