flat assembler
Message board for the users of flat assembler.
Index
> Windows > Createfont save to png. |
| Author |
|
|
Ali.Z 19 Dec 2025, 05:57
render to memory device context, get the pixels, save as bmp, finally use image editor to convert bmp to png.
_________________ Asm For Wise Humans |
|||
|
|
bitRAKE 19 Dec 2025, 07:36
Since GDI+ is the easiest way to save a PNG, we also use it for font rendering:
Code: ; fasm2 fontgrid.asm format PE GUI 4.0 entry start include 'win32a.inc' ; Structs for GDI+ struct GdiplusStartupInput GdiplusVersion dd ? DebugEventCallback dd ? SuppressBackgroundThread dd ? SuppressExternalCodecs dd ? ends ; ============================================================= ; Data Section: Configuration and Variables ; ============================================================= section '.data' data readable writeable ; --------------------------------------------------------- ; USER CONFIGURATION BLOCK ; --------------------------------------------------------- config_data: dd 48, 64 ; [0] Width, Height of each cell (pixels) dd 3, 4 ; [8] Grid Width, Height (characters) ; Rows of characters (null-terminated strings) db '123',0 db '456',0 db '789',0 db ' 0 ',0 db 0 ; Terminator for safety ; --------------------------------------------------------- ; Internal Variables ; --------------------------------------------------------- _filename du 'output.png',0 _font_family du 'Consolas',0 ; Unicode for GDI+ _mime_png du 'image/png',0 token dd ? gdiplusInput GdiplusStartupInput encoderClsid rd 4 ; GUID pBitmap dd ? pGraphics dd ? pFamily dd ? pFont dd ? pBrushText dd ? pBrushBg dd ? ; Rendering vars cell_w dd ? cell_h dd ? cols dd ? rows dd ? curr_x dd ? curr_y dd ? ; RectF structure for drawing (X, Y, Width, Height) draw_rect dd 0.0, 0.0, 0.0, 0.0 ; ============================================================= ; Code Section ; ============================================================= section '.text' code readable executable ; ============================================================= ; Helper: Get Encoder CLSID for MimeType ; ============================================================= proc GetEncoderClsid uses ebx esi edi, _format, clsid locals numEncoders dd ? size dd ? pImageCodecInfo dd ? endl invoke GdipGetImageEncodersSize, addr numEncoders, addr size test eax, eax jnz .fail invoke GlobalAlloc, 0x40, [size] ; GPTR mov [pImageCodecInfo], eax invoke GdipGetImageEncoders, [numEncoders], [size], [pImageCodecInfo] mov ecx, [numEncoders] mov esi, [pImageCodecInfo] .scan: push ecx push esi mov eax, [esi + 48] ; MimeType is at offset 48 mov ebx, [_format] ; Simple string compare (WideChar) .strcmp: mov dx, [eax] cmp dx, [ebx] jne .next_encoder test dx, dx jz .found add eax, 2 add ebx, 2 jmp .strcmp .next_encoder: pop esi pop ecx add esi, 76 ; Size of ImageCodecInfo structure dec ecx jnz .scan .fail: invoke GlobalFree, [pImageCodecInfo] mov eax, -1 ret .found: pop esi ; restore current codec info pointer pop ecx ; balance stack ; Copy CLSID (offset 0) to destination mov edi, [clsid] mov ecx, 4 ; 16 bytes = 4 dwords rep movsd invoke GlobalFree, [pImageCodecInfo] xor eax, eax ; Success ret endp start: ; 1. Initialize GDI+ mov [gdiplusInput.GdiplusVersion], 1 invoke GdiplusStartup, token, gdiplusInput, NULL test eax, eax jnz .exit ; 2. Parse Config Data mov esi, config_data lodsd mov [cell_w], eax lodsd mov [cell_h], eax lodsd mov [cols], eax lodsd mov [rows], eax ; ESI now points to the first string ; Calculate total image size mov eax, [cell_w] imul eax, [cols] mov ebx, [cell_h] imul ebx, [rows] ; 3. Create Bitmap (Canvas) ; PixelFormat24bppRGB = 0x21808 (defined in headers or magic number) invoke GdipCreateBitmapFromScan0, eax, ebx, 0, 0x21808, NULL, pBitmap invoke GdipGetImageGraphicsContext, [pBitmap], pGraphics ; 4. Setup Graphics (Font, Brush, Clear) invoke GdipGraphicsClear, [pGraphics], 0xFFFFFFFF ; White background ; Create Font: Consolas, Size 32 (approx), Regular Style (0), UnitPixel (2) invoke GdipCreateFontFamilyFromName, _font_family, NULL, pFamily invoke GdipCreateFont, [pFamily], 32.0, 0, 2, pFont invoke GdipCreateSolidFill, 0xFF000000, pBrushText ; Black text ; 5. Rendering Loop mov edi, 0 ; Row counter xor ecx, ecx mov [curr_y], ecx .row_loop: cmp edi, [rows] jge .save_image mov [curr_x], 0 mov ebx, 0 ; Col counter .col_loop: cmp ebx, [cols] jge .next_row_prep ; Check for null terminator in string mov al, [esi] test al, al jz .next_row_prep ; End of string line ; Setup RectF for this character fild [curr_x] fstp [draw_rect] fild [curr_y] fstp [draw_rect+4] fild [cell_w] fstp [draw_rect+8] fild [cell_h] fstp [draw_rect+12] ; Draw the single character (ESI points to it) ; -1 length indicates null terminated, but we want 1 char. ; Convert char to Unicode? GdipDrawString expects WCHAR. ; Quick hack: We use GdipDrawString which needs WCHAR. ; We will convert ASCII char to WCHAR buffer on stack. xor eax, eax mov al, [esi] push 0 ; Null terminator high byte push ax ; Char + Null mov edx, esp ; Pointer to temporary WCHAR string invoke GdipDrawString, [pGraphics], edx, -1, [pFont], draw_rect, NULL, [pBrushText] add esp, 4 ; Restore stack ; Advance inc esi inc ebx mov eax, [curr_x] add eax, [cell_w] mov [curr_x], eax jmp .col_loop .next_row_prep: ; Skip to the next null terminator in ESI if we exited loop early .skip_null: cmp byte [esi], 0 je .found_null inc esi jmp .skip_null .found_null: inc esi ; Skip the null itself inc edi mov eax, [curr_y] add eax, [cell_h] mov [curr_y], eax jmp .row_loop ; 6. Save to PNG .save_image: ; Find PNG Encoder CLSID stdcall GetEncoderClsid, _mime_png, encoderClsid test eax, eax js .cleanup ; Failed (-1) invoke GdipSaveImageToFile, [pBitmap], _filename, encoderClsid, NULL .cleanup: invoke GdipDeleteBrush, [pBrushText] invoke GdipDeleteFont, [pFont] invoke GdipDeleteFontFamily, [pFamily] invoke GdipDeleteGraphics, [pGraphics] invoke GdipDisposeImage, [pBitmap] invoke GdiplusShutdown, [token] .exit: invoke ExitProcess, 0 ; ============================================================= ; Imports ; ============================================================= section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\ gdiplus,'gdiplus.dll' include 'api/kernel32.inc' import gdiplus,\ GdiplusStartup,'GdiplusStartup',\ GdiplusShutdown,'GdiplusShutdown',\ GdipCreateBitmapFromScan0,'GdipCreateBitmapFromScan0',\ GdipGetImageGraphicsContext,'GdipGetImageGraphicsContext',\ GdipGraphicsClear,'GdipGraphicsClear',\ GdipCreateFontFamilyFromName,'GdipCreateFontFamilyFromName',\ GdipCreateFont,'GdipCreateFont',\ GdipDrawString,'GdipDrawString',\ GdipCreateSolidFill,'GdipCreateSolidFill',\ GdipDeleteBrush,'GdipDeleteBrush',\ GdipDeleteFont,'GdipDeleteFont',\ GdipDeleteFontFamily,'GdipDeleteFontFamily',\ GdipDeleteGraphics,'GdipDeleteGraphics',\ GdipDisposeImage,'GdipDisposeImage',\ GdipSaveImageToFile,'GdipSaveImageToFile',\ GdipGetImageEncodersSize,'GdipGetImageEncodersSize',\ GdipGetImageEncoders,'GdipGetImageEncoders' _________________ ¯\(°_o)/¯ AI may [not] have aided with the above reply. |
|||
|
|
Roman 19 Dec 2025, 11:07
bitRAKE crash.
in Code: proc GetEncoderClsid uses ebx esi edi, _format, clsid locals numEncoders dd ? size dd ? pImageCodecInfo dd ? endl invoke GdipGetImageEncodersSize, [numEncoders], [size] ;this crash memory 0xFFFFFFFF can't be read |
|||
|
|
bitRAKE 19 Dec 2025, 12:00
I've pushed both the x86/x64 versions of the program to:
https://github.com/bitRAKE/odd_tests/tree/main/fontgrid I don't know why you're getting errors, but you could try the executables I've had success with. (Not that this will solve your problem.) _________________ ¯\(°_o)/¯ AI may [not] have aided with the above reply. |
|||
|
|
bitRAKE 19 Dec 2025, 12:10
Roman wrote:
_________________ ¯\(°_o)/¯ AI may [not] have aided with the above reply. |
|||
|
|
Roman 19 Dec 2025, 12:20
program not compiled with addr.
I remove addr. Code: proc GetEncoderClsid uses ebx esi edi, _format, clsid locals numEncoders dd ? size dd ? pImageCodecInfo dd ? endl invoke GdipGetImageEncodersSize, addr numEncoders, addr size Now working fine. And I get in one png 6 digits images. Code: lea eax,[numEncoders] lea ecx,[size] invoke GdipGetImageEncodersSize, eax,ecx But how save each text symbol to each png files ? If I want 10 symbols, I needed get 10 png files. |
|||
|
|
bitRAKE 19 Dec 2025, 12:31
Oh, you're trying to build with fasm. It might work:
Code: lea eax, [numEncoders] lea edx, [size] invoke GdipGetImageEncodersSize,eax,edx Edit: you solved it already. Roman wrote: But how save each text symbol to each png files ? Put the save after the GdipDrawString and update the file name. You can delete all the grid code and have a simple string iterator. |
|||
|
|
Tomasz Grysztar 19 Dec 2025, 12:51
bitRAKE wrote: perhaps there is much to change. Nothing stands out, but I am poor with compatibility skill. With this simple change the source is compatible with both. |
|||
|
|
Roman 19 Dec 2025, 13:29
bitRAKE I am trying do GdipSetStringFormatAlign, but not work.
I want alignment symbol to center. |
|||
|
|
bitRAKE 19 Dec 2025, 14:01
You've probably worked through it, but here is the centering:
Code: invoke GdipCreateStringFormat, 0, 0, addr pFormat ; pointer/handle sized location to receive creation test eax, eax jnz .fail ; horizontal invoke GdipSetStringFormatAlign, [pFormat], 1 ; StringAlignmentCenter ; vertical invoke GdipSetStringFormatLineAlign, [pFormat], 1 ; use format object in draw call invoke GdipDrawString, [pGraphics], addr char_buf, -1, \ [pFont], addr draw_rect, [pFormat], [pBrushText] invoke GdipDeleteStringFormat, [pFormat] (GdipMeasureString for more custom work. Flat API reference.) Fixed: parameter order correction. Last edited by bitRAKE on 19 Dec 2025, 16:07; edited 1 time in total |
|||
|
|
Roman 19 Dec 2025, 14:18
Thanks. Alignment now work.
But png not have transparent background Color. I want get whyte symbol on transparent background. When I open symbol in photoshop background Color white, but not transparent. I do GdipGraphicsClear, [Graphics], 0 But it not helped. |
|||
|
|
Roman 20 Dec 2025, 08:56
I found
Do this invoke GdipCreateBitmapFromScan0, eax, ebx, 0, 0x26200A, 0, pBitmap PixelFormat32bppARGB = 0x26200A For transparent background Color do Invoke GdipGraphicsClear, [Graphics], 0 |
|||
|
|
Roman 20 Dec 2025, 10:51
Oh, how do antialiasing for draw Text?
I found. invoke GdipSetTextRenderingHint, [Graphics], 1 or 4 |
|||
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.