午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

初めて使ってみたStructure、構造体、文字の描画の文字間隔の調整その3の上

の続き
イメージ 1
前回はこれ、WAが離れていた
今回の結果
イメージ 2
まだ問題はあるけど、できた!
 
 
イメージ 3
「う」と「え」がくっつきすぎ
 
 
イメージ 4
これは期待通り
 
イメージ 5
前回は文字が収まるピッタリの四角形(緑枠)を元にしていたので
字間指定が0だと
イメージ 6
緑枠が隣り合う(間隔が0)こうなっていた
四角形で判定しているからこれ以上近づけないし
もしマイナスの値を指定したらWとAは良くなるけど
Vの右上とWの左上が交差してしまうことになる
 
イメージ 7
 
文字間0で期待するAの描画位置はこの状態の時Wの描画位置を(0,0)のとき
Aの描画位置(x,0)のxが知りたい
イメージ 8

 
Aの一つ前の文字Wの右端と同じ高さにある今から描画する文字Aの左空間と
Wの左端からの左空間を合計したもの(上がわの緑の横線の長さ)と
今から描画する文字Aの左端と同じ高さにある一個前の文字Wの右空間と
Aの左端からの左空間を合計したもの(下側の緑の横線の長さ)を
比較して短い方の距離分を使えば良さそうと思いついて
 
こうなって
イメージ 9
上が29で下が26、だから26を使う
Wの描画範囲(緑枠)の隣にAがあった時に
Aの描画位置をそこから左に26移動させればちょど良くなるはず
 
イメージ 10
こうなるから合っている
26はだいたいわかったからあとはWのとなりになるようなAの座標
これはWの緑枠の右上の座標だから
 
 
イメージ 11
Wの左空間は9だから文字間0指定なら左に9だから0-9で-9
Wの描画範囲(緑枠)の幅は56だから右上のx座標は
56-9=47
イメージ 12
(47,0)にAを描画したところ
ここから47からさっきの26引いて
47-26=21
これがAの描画位置
イメージ 13
(21,0)にAを描画したところ、あっている


イメージ 14
字間指定10で描画したところ
 
前回よりは良くなったけど
イメージ 15
ターンを字間指定0で描画
「タ」と「ー」がどう見ても離れすぎている
「ー」と「ン」は良さそうに見えて実際いいんだけど
予想ではもっと近づくはずだった
イメージ 16
ターンをそれぞれ1文字ごとに普通に描画した場合の描画範囲


イメージ 17
今回の方法で描画するとき使う数字
本当は0のところが「ー」の幅いっぱいの48になるように作ったつもりだったけど
0になっているみたい
だからタとーの場合だと9と11+10=21を比較して小さい方の9が選択されている
期待したのは9+48=57と11+10=21を比較して小さい方の21だった
でもこれは0だったら文字の幅を返せばいいからすぐ解決できるとして
でもそうすると
「ー」と「ン」の場合
今回は0+9=9と10+30=40で9を使っていたのが
48+9=57と10+30=40の比較になって40を使うことになる
イメージ 18
そうするとたぶんこうなる
で、解決方法が思いつかない
 
 
Public Structure DrawRange2描画範囲
    Public Property AllSize As Size
    Public Property TopX As List(Of Integer)
    Public Property TopY As Integer
    Public Property BottomX As List(Of Integer)
    Public Property BottomY As Integer
    Public Property LeftX As Integer
    Public Property LeftY As List(Of Integer)
    Public Property RightX As Integer
    Public Property RightY As List(Of Integer)

    Public Overrides Function ToString() As String
        Dim str As String
        str = "TopY=" & TopY & " BottomY=" & BottomY & " LeftX=" & LeftX & " RightX=" & RightX &
            " TopX_Count=" & TopX.Count & " BottomX_Count=" & BottomX.Count & " LeftY_Count=" & LeftY.Count & " RightY_Count=" & RightY.Count
        Return str
    End Function

    Public Function myString1() As String 'ToStringのかわり、上下左右の一番外側の位置
        Dim str As String = "TopY=" & TopY & " BottomY=" & BottomY & " LeftX=" & LeftX & " RightX=" & RightX & " Width=" & RightX - LeftX + 1 & " Height=" & BottomY - TopY + 1
        Return str
    End Function
    Public Function myString2() As String 'ToStringのかわり、上下左右のピクセルのカウント数
        Return " TopX_Count=" & TopX.Count & " BottomX_Count=" & BottomX.Count & " LeftY_Count=" & LeftY.Count & " RightY_Count=" & RightY.Count
    End Function
    Public Function DrawWidth() As Integer '文字の幅
        Return RightX - LeftX + 1
    End Function
    Public Function DrawHeight() As Integer '文字の高さ
        Return BottomY - TopY + 1
    End Function
    Public Function DrawSize() As Size '文字の幅と高さ
        Return New Size(DrawWidth, DrawHeight)
    End Function
    Public Function RightSpace() As Integer '右空白
        Return Me.AllSize.Width - RightX - 1
    End Function
End Structure
 
 

f:id:gogowaten:20191018095411p:plain

描画範囲の情報とか入れておく構造体のDrawRange2描画範囲
前回に付け足したのが文字描画全体のサイズ範囲を入れておくSize型のAllSizeと
右空間の距離分のピクセル数を返す関数
だけかな、ほとんど同じ

 
    Public Structure QuartetSpace上下左右の空白
        Dim Top As Integer
        Dim Bottom, Left, Right As Integer
    End Structure
イメージ 21
4つの整数を入れておくだけの構造体
数値を入れておくだけならPropertyじゃなくてDimでもいいみたい
しかも「,」で区切ってまとめて宣言してもいいみたい
間違っているかもしれないけど期待通りに動いている
これを使っているのは
 
11や7はDrawRange2描画範囲に入っている数字からすぐわかるけど
18と19は別の関数(LeftSpace指定座標の距離一覧)で探すことになるのでそれ用
TopとBottomは縦書の時に必要になりそう
↓が18とか19の場所を探す関数
 
Private Function LeftSpace指定座標の距離一覧(bmp As Bitmap, dr As DrawRange2描画範囲) As QuartetSpace上下左右の空白
    Dim reInte As QuartetSpace上下左右の空白

    Dim w As Integer = bmp.Width
    Dim h As Integer = bmp.Height
    Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
    Dim bmpData As BitmapData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat)
    Dim ptr As IntPtr = bmpData.Scan0 'Bitmapデータが在るメモリのアドレス?
    Dim data As Integer = bmpData.Stride * h - 1 '入れ物の大きさ、Strideはbmp.width*4になる?
    Dim pixels(data) As Byte '入れ物
    Runtime.InteropServices.Marshal.Copy(ptr, pixels, 0, pixels.Length) '入れ物にデータが入る、コピー
    Dim pos As Integer = 0 '入れ物のアドレス指定用
    Dim x, y As Integer
    Dim isFind As Boolean = False '上限、下限見つかったよフラグ

   ''上の行から順番に色があるピクセルを探す
   'For y = 0 To h - 1
   '   For x = 0 To w - 1
   '       pos = y * bmpData.Stride + x * 4
   '       If pixels(pos + 3) <> 0 Then 'アルファの値が0以上なら色があると判定、upperYに今の行位置を入れてループを抜ける
   '           If isFind = False Then
   '               isFind = True
   '               'reInte.TopY = y + 1 '+1しているのはBitmapのサイズは1からか始まるけどBitmapDataは0からで1ずれているからそれの修正、
   '               '例えば2行目で色付きピクセルを見つけても1が記録されるので+1している
   '               reInte.TopY = y '後で使うときには0から数えたほうが良さそうなので+1しないように変更した
   '           End If

   '           reInte.TopX.Add(x) '上限での横位置、縦書で使う
   '           '配列というかリストになる、例えば「-」という文字なら横一直線なので左端から右端まですべてのピクセルの座標が入ることになる

   '       End If

   '   Next

   '   If isFind Then Exit For

   'Next
   'isFind = False

   ''下の行から順番に色があるピクセルを探す
   'For y = h - 1 To 0 Step -1
   '   For x = 0 To w - 1
   '       pos = y * bmpData.Stride + x * 4
   '       If pixels(pos + 3) <> 0 Then
   '           If isFind = False Then
   '               isFind = True
   '               reInte.BottomY = y '+ 1 '下限

   '           End If
   '           reInte.BottomX.Add(x) '下限の横位置の配列

   '       End If
   '   Next
   '   If isFind Then Exit For
   'Next
   'isFind = False

   '左端
    For x = 0 To w - 1
        For y = dr.RightY(0) To dr.RightY(dr.RightY.Count - 1)
            pos = y * bmpData.Stride + x * 4
            If pixels(pos + 3) <> 0 Then
                If isFind = False Then
                    isFind = True
                    reInte.Left = x
                    Exit For
                End If

            End If
        Next
        If isFind Then Exit For
    Next
    isFind = False

   '右端探査
    For x = w - 1 To 0 Step -1
        For y = dr.LeftY(0) To dr.LeftY(dr.LeftY.Count - 1)
            pos = y * bmpData.Stride + x * 4
            If pixels(pos + 3) <> 0 Then
                If isFind = False Then
                    isFind = True
                    reInte.Right = w - x - 1
                    Exit For
                End If

            End If
        Next
        If isFind Then Exit For
    Next

    bmp.UnlockBits(bmpData)


    Return reInte
End Function
 

f:id:gogowaten:20191018095535p:plain

画像を渡して指定された座標の範囲の中から一番先に見つかった色付きの
ピクセルの座標を返す
横書きしか使っていないので左右しか使っていない
これは前回に書いた関数のDrawRange2描画範囲情報のコピペ改変




これ以上書いて投稿するとエラーになるから分割になった
続きは