Skip to content

Commit

Permalink
gdi32.GetBitmapBits, 新增TextOut範例 (#5)
Browse files Browse the repository at this point in the history
	將LOGFONT改名為LogFont
  • Loading branch information
CarsonSlovoka committed Jun 12, 2024
1 parent 864a900 commit 012cc1f
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 24 deletions.
15 changes: 8 additions & 7 deletions v2/w32/gdi32.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ const (
)

// Font output quality constants
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/9518fece-d2f2-4799-9df6-ba3db1d73371
const (
DEFAULT_QUALITY = 0
DRAFT_QUALITY = 1
Expand Down Expand Up @@ -633,7 +634,7 @@ const (
// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setbkmode#parameters
const (
TRANSPARENT = 1 // Background remains untouched.
OPAQUE = 2 // Background is filled with the current background color before the text, hatched brush, or pen is drawn.
OPAQUE = 2 // Background is filled with the current background color before the text, hatched brush, or pen is drawn.
)

// Ternary raster operations
Expand Down Expand Up @@ -810,8 +811,8 @@ type PIXELFORMATDESCRIPTOR struct {
DwDamageMask uint32
}

// LOGFONT https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw
type LOGFONT struct {
// LogFont https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfontw
type LogFont struct {
Height int32
Width int32
Escapement int32
Expand All @@ -828,19 +829,19 @@ type LOGFONT struct {
FaceName [LF_FACESIZE]uint16
}

func (f *LOGFONT) IsItalic() bool {
func (f *LogFont) IsItalic() bool {
return f.Italic == 1
}

func (f *LOGFONT) IsStrikeOut() bool {
func (f *LogFont) IsStrikeOut() bool {
return f.StrikeOut == 1
}

func (f *LOGFONT) IsUnderline() bool {
func (f *LogFont) IsUnderline() bool {
return f.Underline == 1
}

func (f *LOGFONT) GetFaceName() string {
func (f *LogFont) GetFaceName() string {
return syscall.UTF16ToString(f.FaceName[:])
}

Expand Down
29 changes: 23 additions & 6 deletions v2/w32/gdi32_func.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ const (

PNFillRgn ProcName = "FillRgn"

PNGetDIBits ProcName = "GetDIBits"
PNGetObject ProcName = "GetObjectW"
PNGetPixel ProcName = "GetPixel"
PNGetBitmapBits ProcName = "GetBitmapBits"
PNGetDIBits ProcName = "GetDIBits"
PNGetObject ProcName = "GetObjectW"
PNGetPixel ProcName = "GetPixel"

PNLineTo ProcName = "LineTo"

Expand Down Expand Up @@ -90,6 +91,7 @@ func NewGdi32DLL(procList ...ProcName) *Gdi32DLL {

PNFillRgn,

PNGetBitmapBits,
PNGetDIBits,
PNGetObject,
PNGetPixel,
Expand Down Expand Up @@ -331,7 +333,7 @@ func (dll *Gdi32DLL) CreateDIBSection(hdc HDC, bitmapInfo *BitmapInfo,

// CreateFontIndirect https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontindirectw
// If the function fails, the return value is NULL.
func (dll *Gdi32DLL) CreateFontIndirect(logFont *LOGFONT) HFONT {
func (dll *Gdi32DLL) CreateFontIndirect(logFont *LogFont) HFONT {
proc := dll.mustProc(PNCreateFontIndirect)
r1, _, _ := syscall.SyscallN(proc.Addr(),
uintptr(unsafe.Pointer(logFont)),
Expand Down Expand Up @@ -451,15 +453,15 @@ func (dll *Gdi32DLL) EnumFontFamilies(hdc HDC,
}

// EnumFonts https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-enumfontsw
// LOGFONT
// LogFont
// The return value is the last value returned by the callback function. Its meaning is defined by the application
func (dll *Gdi32DLL) EnumFonts(hdc HDC,
lpLogfont string, // If NULL => enumerates one font of "each" available typeface.
lpProc FONTENUMPROC, lParam LPARAM) int32 {
proc := dll.mustProc(PNEnumFonts)

// https://learn.microsoft.com/en-us/previous-versions/dd162623(v=vs.85)
lpProcCallback := syscall.NewCallback(func(logFont *LOGFONT, textMetric *TEXTMETRIC, fontType uint32, lpData LPARAM) uintptr {
lpProcCallback := syscall.NewCallback(func(logFont *LogFont, textMetric *TEXTMETRIC, fontType uint32, lpData LPARAM) uintptr {
ret := lpProc(logFont, textMetric, fontType, lpData)
return uintptr(ret)
})
Expand All @@ -484,6 +486,21 @@ func (dll *Gdi32DLL) FillRgn(hdc HDC, hrgn HRGN, hbr HBRUSH) bool {
return ret1 != 0
}

// GetBitmapBits https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getbitmapbits

func (dll *Gdi32DLL) GetBitmapBits(hBit HBITMAP,
cb int32, // The number of bytes to copy from the bitmap into the buffer.
lpbBits uintptr, // LPVOID // A pointer to a buffer to receive the bitmap bits. The bits are stored as an array of byte values.
) int32 {
proc := dll.mustProc(PNGetBitmapBits)
ret1, _, _ := syscall.SyscallN(proc.Addr(),
uintptr(hBit),
uintptr(cb),
lpbBits,
)
return int32(ret1)
}

// GetDIBits https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits
//
// retrieves the bits of the specified compatible bitmap and copies them into a buffer as a DIB(Device-Independent Bitmap) using the specified format.
Expand Down
119 changes: 116 additions & 3 deletions v2/w32/gdi32_func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"encoding/binary"
"fmt"
"github.com/CarsonSlovoka/go-pkg/v2/w32"
"image"
"image/color"
"image/png"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -741,7 +744,7 @@ func ExampleGdi32DLL_EnumFonts() {
gdi32dll := w32.NewGdi32DLL()
user32dll := w32.NewUser32DLL()
var fontEnumProc w32.FONTENUMPROC
fontEnumProc = func(lpLF *w32.LOGFONT, lpTM *w32.TEXTMETRIC, dwType uint32, lpData w32.LPARAM) int32 {
fontEnumProc = func(lpLF *w32.LogFont, lpTM *w32.TEXTMETRIC, dwType uint32, lpData w32.LPARAM) int32 {
log.Println(lpLF.GetFaceName())
return 1
}
Expand Down Expand Up @@ -822,10 +825,10 @@ func ExampleGdi32DLL_CreateFont() {

// hFont: Arial 使用CreateFontIndirect來建立
{
var logFont w32.LOGFONT
var logFont w32.LogFont
{
gdi32dll.EnumFonts(hdc, "Arial",
func(lpLF *w32.LOGFONT, lpTM *w32.TEXTMETRIC, dwType uint32, lpData w32.LPARAM) int32 {
func(lpLF *w32.LogFont, lpTM *w32.TEXTMETRIC, dwType uint32, lpData w32.LPARAM) int32 {
logFont = *lpLF
return 0 // DO NOT CONTINUE // 找到一個就停止
},
Expand Down Expand Up @@ -1272,3 +1275,113 @@ func ExampleGdi32DLL_MoveToEx() {
// {0 0}
// {100 200}
}

// 可以取得到HBITMAP的資料
func ExampleGdi32DLL_GetBitmapBits() {
hdcScreen := userDll.GetDC(0)
defer userDll.ReleaseDC(0, hdcScreen)

const width, height int32 = 600, 72
hBitmap := gdiDll.CreateCompatibleBitmap(hdcScreen, width, height)
defer gdiDll.DeleteObject(w32.HGDIOBJ(hBitmap))
bitmapBits := make([]byte, width*height*4) // 資料是用BGRA
gdiDll.GetBitmapBits(hBitmap, int32(len(bitmapBits)), uintptr(unsafe.Pointer(&bitmapBits[0])))
}

func TestGdi32DLL_TextOut(t *testing.T) {
hdcScreen := userDll.GetDC(0)
defer userDll.ReleaseDC(0, hdcScreen)
hMemDC := gdiDll.CreateCompatibleDC(hdcScreen)
defer gdiDll.DeleteObject(w32.HGDIOBJ(hMemDC))

const width, height int32 = 600, 72
hBitmap := gdiDll.CreateCompatibleBitmap(hdcScreen, width, height)
defer gdiDll.DeleteObject(w32.HGDIOBJ(hBitmap))

hObjOld := gdiDll.SelectObject(hMemDC, w32.HGDIOBJ(hBitmap))
defer gdiDll.SelectObject(hMemDC, hObjOld) // 不用之後可以考慮選回之前的物件

gdiDll.SetTextColor(hMemDC, w32.RGB(0, 1, 0)) // 全為0為黑色 // 我們故意把g改成1,來藉此判斷該元素需不需要被畫
gdiDll.SetBkColor(hMemDC, w32.RGB(0, 255, 255)) // 如果你的SetBkMode是TRANSPARENT,那麼這個顏色就看不出來了
// gdiDll.SetBkMode(hMemDC, w32.TRANSPARENT)

// 不一定要創建此結構,也可以直接把數值寫入到CreateFont
lf := w32.LogFont{
Height: -64,
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,
}
// copy(lf.FaceName[:], utf16.Encode([]rune("Arial"+"\x00")))

hFont := gdiDll.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),
"Arial", // 安裝到你電腦的字型 FontFamilyName, name.ID=1 都可以指定
)
defer gdiDll.DeleteObject(w32.HGDIOBJ(hFont))

oldFont := gdiDll.SelectObject(hMemDC, w32.HGDIOBJ(hFont))
defer gdiDll.SelectObject(hMemDC, oldFont)

text := "Hello! 世界"
gdiDll.TextOut(hMemDC, 5, 5, text, int32(len(text)))

bitmapBits := make([]byte, width*height*4)
gdiDll.GetBitmapBits(hBitmap, int32(len(bitmapBits)), uintptr(unsafe.Pointer(&bitmapBits[0])))

// Create an image from the bitmap bits
img := image.NewRGBA(image.Rect(0, 0, int(width), int(height)))
var alpha uint8
for y := int32(0); y < height; y++ {
for x := int32(0); x < width; x++ {
idx := (y*width + x) * 4
b, g, r := bitmapBits[idx], bitmapBits[idx+1], bitmapBits[idx+2]
// alpha = bitmapBits[idx+3] // 這個都會是0
if g == 1 {
alpha = uint8(255) // a為255表示不透明
g = 0
} else if g == 255 || b == 255 { // 我們訂的背景顏色
alpha = uint8(255)
} else {
alpha = 0
}
img.Set(int(x), int(y), color.RGBA{R: r, G: g, B: b, A: alpha})
// img.Set(int(x), int(y), color.RGBA{R: r, G: g, B: b, A: 255}) // 如果你要顯示背景顏色,要改這樣
}
}

if false {
file, err := os.Create("output.png")
if err != nil {
fmt.Println("Error creating file:", err)
return
}
defer func() {
_ = file.Close()
}()
if err = png.Encode(file, img); err != nil {
t.Fatal(err)
}
}
}
10 changes: 5 additions & 5 deletions v2/w32/user32.go
Original file line number Diff line number Diff line change
Expand Up @@ -1673,15 +1673,15 @@ type NONCLIENTMETRICS struct {
IScrollHeight int32
ICaptionWidth int32
ICaptionHeight int32
LfCaptionFont LOGFONT
LfCaptionFont LogFont
ISmCaptionWidth int32
ISmCaptionHeight int32
LfSmCaptionFont LOGFONT
LfSmCaptionFont LogFont
IMenuWidth int32
IMenuHeight int32
LfMenuFont LOGFONT
LfStatusFont LOGFONT
LfMessageFont LOGFONT
LfMenuFont LogFont
LfStatusFont LogFont
LfMessageFont LogFont
}

type MEASUREITEMSTRUCT struct {
Expand Down
6 changes: 3 additions & 3 deletions v2/w32/wingdi_h.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package w32
import "syscall"

// FONTENUMPROC https://learn.microsoft.com/en-us/previous-versions/dd162623(v=vs.85)
type FONTENUMPROC func(logFont *LOGFONT, textmetric *TEXTMETRIC, fontType uint32, lParam LPARAM) int32
type FONTENUMPROC func(logFont *LogFont, textmetric *TEXTMETRIC, fontType uint32, lParam LPARAM) int32

// EnumFontFamProc https://learn.microsoft.com/en-us/previous-versions/dd162621(v=vs.85)
type EnumFontFamProc func(logFont *ENUMLOGFONT, textmetric *TEXTMETRIC, fontType uint32, lparam LPARAM) int32

// ENUMLOGFONT https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-enumlogfontw?redirectedfrom=MSDN
type ENUMLOGFONT struct {
LogFont LOGFONT
LogFont LogFont
FullName [LF_FULLFACESIZE]uint16 // For example, ABCD Font Company TrueType Bold Italic Sans Serif. // NameID=4
Style [LF_FACESIZE]uint16 // For example, Bold Italic.
}
Expand All @@ -26,7 +26,7 @@ func (e *ENUMLOGFONT) GetStyle() string {
/*
// ENUMLOGFONTEX https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-enumlogfontexw
type ENUMLOGFONTEX struct {
LogFont LOGFONT
LogFont LogFont
FullName [LF_FULLFACESIZE]uint16
Style [LF_FACESIZE]uint16
Script [LF_FACESIZE]uint16 // The script, that is, the character set, of the font. For example, Cyrillic.
Expand Down

0 comments on commit 012cc1f

Please sign in to comment.