Created
September 14, 2024 08:39
-
-
Save CarsonSlovoka/b34e2c252ee63932e46fe2b387bdacf8 to your computer and use it in GitHub Desktop.
go draw_text eample: winapi.{TextOut, ExtTextOut}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module demo-draw-text | |
go 1.23.0 | |
require github.com/CarsonSlovoka/go-pkg/v2 v2.4.2-0.20240619074555-8d486f5913b0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main_test | |
import ( | |
"encoding/binary" | |
"fmt" | |
"github.com/CarsonSlovoka/go-pkg/v2/w32" | |
"os" | |
"unicode/utf16" | |
"unsafe" | |
) | |
const testFontPath = "./DFGoldenButterflyJP13N-W2.otf" // 👈 置換成你的字型檔路徑 | |
var ( | |
Gdi = w32.NewGdi32DLL() | |
User = w32.NewUser32DLL() | |
) | |
func ImportFont( | |
fontPath string, | |
fontFamily string, // 要解字型檔的name表格,這邊不解,需要自己查 | |
height int32, | |
) (w32.HFONT, error) { | |
numFont := Gdi.AddFontResource(fontPath) | |
if numFont == 0 { | |
return 0, fmt.Errorf("沒有任何字型被加載,請確定字型路徑是正確的") | |
} | |
// _ = User.PostMessage(w32.HWND_BROADCAST, w32.WM_FONTCHANGE, 0, 0) // 可選項 | |
return NewHFont(fontFamily, height), nil | |
} | |
func NewHFont(fontFamily string, height int32) w32.HFONT { | |
lf := w32.LogFont{ | |
Height: height, | |
Width: 0, | |
Escapement: 0, | |
Orientation: 0, | |
Weight: 400, | |
Italic: 0, | |
Underline: 0, | |
StrikeOut: 0, | |
CharSet: w32.DEFAULT_CHARSET, | |
OutPrecision: w32.OUT_TT_PRECIS, | |
ClipPrecision: w32.CLIP_DEFAULT_PRECIS, | |
Quality: w32.ANTIALIASED_QUALITY, | |
PitchAndFamily: w32.FF_DONTCARE, | |
} | |
return Gdi.CreateFont( | |
lf.Height, | |
lf.Width, | |
lf.Escapement, | |
lf.Orientation, | |
lf.Weight, | |
uint32(lf.Italic), | |
uint32(lf.Underline), | |
uint32(lf.StrikeOut), | |
uint32(lf.CharSet), | |
uint32(lf.OutPrecision), | |
uint32(lf.ClipPrecision), | |
uint32(lf.Quality), | |
uint32(lf.PitchAndFamily), | |
fontFamily, // fontFamilyName: nameID1; platformID, platformEncID, languageID // 系統要裝字, 或者用AddFontResource | |
) | |
} | |
func saveHBitmap(outputPath string, hdcMem w32.HDC, hBitmap w32.HBITMAP) error { | |
var bitmap w32.Bitmap | |
Gdi.GetObject(w32.HANDLE(hBitmap), int32(unsafe.Sizeof(bitmap)), uintptr(unsafe.Pointer(&bitmap))) | |
bitCount := uint16(32) | |
bmpSize := ((bitmap.Width*int32(bitCount) + 31) >> 5) * 4 * bitmap.Height | |
bmpData := make([]byte, bmpSize) | |
bitmapInfo := &w32.BitmapInfo{Header: w32.BitmapInfoHeader{ | |
Size: 40, | |
Width: bitmap.Width, Height: bitmap.Height, | |
Planes: 1, | |
BitCount: bitCount, | |
Compression: w32.BI_RGB, | |
}} | |
Gdi.GetDIBits( | |
hdcMem, hBitmap, 0, | |
uint32(bitmap.Height), | |
bmpData, // lpBitmap, // [out] | |
bitmapInfo, | |
w32.DIB_RGB_COLORS, | |
) | |
f, err := os.Create(outputPath) | |
if err != nil { | |
return err | |
} | |
defer func() { | |
_ = f.Close() | |
}() | |
_ = binary.Write(f, binary.LittleEndian, w32.BitmapFileHeader{ | |
Type: 0x4D42, | |
Size: 14 + 40 + uint32(bmpSize), // HEADER + INFO + DATA | |
OffsetBits: 14 + 40, | |
}) | |
_ = binary.Write(f, binary.LittleEndian, bitmapInfo.Header) | |
_, err = f.Write(bmpData) | |
return err | |
} | |
const bitmapHeight = 100 | |
const bitmapWidth = 600 | |
func init() { | |
if bitmapHeight == 0 || bitmapWidth == 0 { | |
panic("invalid size 0") | |
} | |
} | |
func Example_textOut() { | |
// init | |
hdcScreen := User.GetDC(0) | |
defer User.ReleaseDC(0, hdcScreen) | |
hFont, err := ImportFont(testFontPath, "DFGoldenButterfly JP13N W2", -72) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
defer func() { | |
for { | |
if Gdi.RemoveFontResource(testFontPath) == 0 { | |
break | |
} | |
} | |
}() | |
defer Gdi.DeleteObject(w32.HGDIOBJ(hFont)) | |
// hdc | |
hMemDC := Gdi.CreateCompatibleDC(hdcScreen) | |
defer Gdi.DeleteObject(w32.HGDIOBJ(hMemDC)) | |
// select bitmap | |
hBitmap := Gdi.CreateCompatibleBitmap(hdcScreen, bitmapWidth, bitmapHeight) | |
defer Gdi.DeleteObject(w32.HGDIOBJ(hBitmap)) | |
hObjOld := Gdi.SelectObject(hMemDC, w32.HGDIOBJ(hBitmap)) | |
defer Gdi.SelectObject(hMemDC, hObjOld) | |
// select font | |
oldFont := Gdi.SelectObject(hMemDC, w32.HGDIOBJ(hFont)) | |
defer Gdi.SelectObject(hMemDC, oldFont) | |
const text = "Hello 世界!" | |
textSize, _ := Gdi.GetTextExtentPoint32(hMemDC, text) | |
Gdi.TextOut(hMemDC, | |
(bitmapWidth-textSize.CX)/2, (bitmapHeight-textSize.CY)/2, | |
text, | |
) | |
if err = saveHBitmap("temp.textOut.png", hMemDC, hBitmap); err != nil { | |
fmt.Println(err) | |
} | |
// Output: | |
} | |
func Example_extTextOut() { | |
hdcScreen := User.GetDC(0) | |
defer User.ReleaseDC(0, hdcScreen) | |
hFont, err := ImportFont(testFontPath, "DFGoldenButterfly JP13N W2", -72) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
defer func() { | |
for { | |
if Gdi.RemoveFontResource(testFontPath) == 0 { | |
break | |
} | |
} | |
}() | |
defer Gdi.DeleteObject(w32.HGDIOBJ(hFont)) | |
for i, d := range []struct { | |
x, y int32 | |
options uint32 | |
pRECT *w32.RECT | |
u16s []uint16 | |
}{ | |
{ | |
x: 0, y: 0, | |
options: 0, // 不使用glyphID | |
pRECT: nil, // rect在ETO_OPAQUE或者ETO_CLIPPED才會有用 | |
u16s: utf16.Encode([]rune("Hi 中文")), | |
}, | |
// 範例二使用glyphID | |
{0, 0, | |
w32.ETO_GLYPH_INDEX, | |
nil, | |
[]uint16{41, 52}, // glyphID: 41, 52 | |
}, | |
} { | |
hMemDC := Gdi.CreateCompatibleDC(hdcScreen) | |
hBitmap := Gdi.CreateCompatibleBitmap(hdcScreen, bitmapWidth, bitmapHeight) | |
hObjOld := Gdi.SelectObject(hMemDC, w32.HGDIOBJ(hBitmap)) | |
oldFont := Gdi.SelectObject(hMemDC, w32.HGDIOBJ(hFont)) | |
Gdi.SetTextColor(hMemDC, w32.RGB(0xff, 0x00, 0x00)) | |
Gdi.SetBkMode(hMemDC, w32.TRANSPARENT) | |
Gdi.ExtTextOut(hMemDC, d.x, d.y, d.options, d.pRECT, d.u16s) | |
if err = saveHBitmap(fmt.Sprintf("temp.%02d.png", i), hMemDC, hBitmap); err != nil { | |
fmt.Println("error: ", err) | |
} | |
Gdi.SelectObject(hMemDC, hObjOld) | |
Gdi.SelectObject(hMemDC, oldFont) | |
Gdi.DeleteObject(w32.HGDIOBJ(hBitmap)) | |
Gdi.DeleteObject(w32.HGDIOBJ(hMemDC)) | |
} | |
// Output: | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment