Author Topic: How to load non-bitmap (.bmp) files from the disk (.jpg, .png, .gif, and etc)  (Read 2437 times)

assembler

  • Guest
When I:

Code: [Select]
include \masm32\include\windows.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

I can either invoke or call either LoadImageA or LoadImageW procedure/routine, but the problem with these both procedures/routines is that they allow me load only .bmp, .ico, .cur and .ani files.

I know but only about the Gdiplus flat api, i.e. when I:

Code: [Select]
include \masm32\include\gdiplus.inc
includelib \masm32\lib\gdiplus.lib

But I want to know about more APIs and libraries to do this task/mission, because Gdiplus is for desktop apps only, I get troubles with it and some people and MSDN not recommending it. It is also said that it is unsupported.

Vortex

  • Member
  • *****
  • Posts: 1850
Hello,

There is nothing wrong with GDI+ Here are two examples, one of them is using the GDI+ functions.

assembler

  • Guest
Sorry that I didn't say this before, but I want to get the data of the image I load from disk, i.e. all bytes in one buffer, plus the image dimensions, i.e. width and height.

jj2007

  • Member
  • *****
  • Posts: 8773
  • Assembler is fun ;-)
    • MasmBasic
As Vortex wrote, Gdi+ is OK, and knowing Microsoft, it will be supported in the next millennium :P

Here is the source of a simple image viewer:

include \masm32\MasmBasic\Res\MbGui.asm      ; part of MasmBasic
Event Paint
  GuiImage CL$(), fit      ; drag e.g. a jpg or an animated gif over the exe
GuiEnd


Full project attached.

Sorry that I didn't say this before, but I want to get the data of the image I load from disk, i.e. all bytes in one buffer, plus the image dimensions, i.e. width and height.

Insert this under the include line in my example above:
  GuiImage CL$(), info
  deb 1, "Info:", GdiSI.jjWidth, GdiSI.jjHeight
  Let esi=FileRead$(CL$())
  deb 1, "Contents:", $esi:400

assembler

  • Guest
Thanks for the tips.

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 5831
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
assembler,

GDI+ has been around for a while and is very stable, it is available in both Win32 and Win64. It is reasonably complex to use and very poorly documented but it is reliable and works well. The best easily available documentation is a CHM help file by Jose Roca and if you can get an old enough SDK from Microsoft it also has GDI+ documentation. We do have a number of people here who are experienced in GDI+ so if you have an example that you need info on, ask and someone may be able to help you.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :biggrin:

assembler

  • Guest
I thank you very much, actually I am trying to use gdiplus right now, but I have a problem, that GdipCreateBitmapFromFile returns not null, but GdipCreateHBITMAPFromBitmap returns null, and I don't know what's wrong. Here is the code:

Code: [Select]
.386
.model flat, stdcall
option casemap: none

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\gdiplus.lib
includelib \masm32\lib\msvcrt.lib

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\gdiplus.inc

CreateWindowExA proto :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword, :dword
GetMessageA proto :dword, :dword, :dword, :dword
TranslateMessage proto :dword
DispatchMessageA proto :dword
SetWindowLongA proto :dword, :dword, :dword
DefWindowProcA proto :dword, :dword, :dword, :dword
RtlZeroMemory proto :dword, :dword
CreateMenu proto
GetOpenFileNameW proto :dword
printf proto c :vararg

.data

string_mdiclient db "mdiclient",0
class db "classic",0
string_load_and_display_any_image db "load and display any image",0
string_load_image db "load image",0
image_path db MAX_PATH dup (0)
ofn OPENFILENAMEW <0,sizeof OPENFILENAMEW>
hBitmap dword 0
bitmap_hDC dd 0
;bitmapdata BITMAP <0,sizeof BITMAP>
image_width dd 0
image_height dd 0
dword_zero dd 0
string_error_occurred db "error occurred",0
string_eax_is_zero_after_GdipCreateBitmapFromFile db "eax is zero after GdipCreateBitmapFromFile",0
string_pBitmap_is_null db "pBitmap is null",0
string_eax_is_zero_after_GdipCreateHBITMAPFromBitmap db "eax is zero after GdipCreateHBITMAPFromBitmap",0
string_hBitmap_is_null db "hBitmap is null",0
pd_pdnl db "%d %d",10,0

.code

alert_error_occurred_and_exit:
invoke MessageBoxA, 0, offset string_error_occurred, offset string_error_occurred, MB_ICONERROR or MB_OK
invoke ExitProcess, 0

alert_eax_is_zero_after_GdipCreateBitmapFromFile_and_exit:
invoke MessageBoxA, 0, offset string_eax_is_zero_after_GdipCreateBitmapFromFile,
                       offset string_eax_is_zero_after_GdipCreateBitmapFromFile, MB_ICONERROR or MB_OK
invoke ExitProcess, 0

alert_pBitmap_is_null_and_exit:
invoke MessageBoxA, 0, offset string_pBitmap_is_null, offset string_pBitmap_is_null, MB_ICONERROR or MB_OK
invoke ExitProcess, 0

alert_eax_is_zero_after_GdipCreateHBITMAPFromBitmap_and_exit:
invoke MessageBoxA, 0, offset string_eax_is_zero_after_GdipCreateHBITMAPFromBitmap,
                       offset string_eax_is_zero_after_GdipCreateHBITMAPFromBitmap, MB_ICONERROR or MB_OK
invoke ExitProcess, 0

alert_hBitmap_is_null_and_exit:
invoke MessageBoxA, 0, offset string_hBitmap_is_null,
                       offset string_hBitmap_is_null, MB_ICONERROR or MB_OK
invoke ExitProcess, 0

MessageProcedure proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
local LOwParam:word
local HIwParam:word
local LOlParam:word
local HIlParam:word
local ps:PAINTSTRUCT
local pBitmap:dword
local bitmapdata:BITMAP
mov eax,wParam
mov LOwParam,ax
shr eax,16
mov HIwParam,ax
mov eax,lParam
mov LOlParam,ax
shr eax,16
mov HIlParam,ax
cmp uMsg,WM_CLOSE
je case_WM_CLOSE
cmp uMsg,WM_DESTROY
je case_WM_DESTROY
cmp uMsg,WM_COMMAND
je case_WM_COMMAND
jne invoke_DefWindowProcA
case_WM_CLOSE:
invoke DestroyWindow, hWnd
invoke ExitProcess,0
;xor eax,eax
;ret
case_WM_DESTROY:
invoke PostQuitMessage,NULL
invoke ExitProcess,0
;xor eax,eax
;ret
case_WM_COMMAND:
cmp HIwParam,0
jne invoke_DefWindowProcA
cmp LOwParam,0
jne invoke_DefWindowProcA
invoke GetOpenFileNameW, offset ofn
invoke MessageBoxW, hWnd, offset image_path, NULL, MB_ICONEXCLAMATION or MB_OK
invoke GdipCreateBitmapFromFile, offset image_path, addr pBitmap
cmp eax,0
jz alert_eax_is_zero_after_GdipCreateBitmapFromFile_and_exit
cmp pBitmap,0
jz alert_pBitmap_is_null_and_exit
invoke GdipCreateHBITMAPFromBitmap, pBitmap, offset hBitmap, 00000000h ;offset dword_zero
cmp eax,0
jz alert_eax_is_zero_after_GdipCreateHBITMAPFromBitmap_and_exit
cmp hBitmap,0
jz alert_hBitmap_is_null_and_exit
invoke SelectObject, bitmap_hDC, hBitmap
;invoke GdipCreateImageFromBitmap, pBitmap, offset pImage
invoke GdipGetImageWidth, pBitmap, offset image_width
invoke GdipGetImageHeight, pBitmap, offset image_height
;invoke GetObject, hBitmap, sizeof BITMAP, addr bitmapdata
;push bitmapdata.bmWidth
;pop image_width
;push bitmapdata.bmHeight
;pop image_height
invoke printf, offset pd_pdnl, image_width, image_height
;invoke printf, offset pd_pdnl, bitmapdata.bmWidth, bitmapdata.bmHeight
xor eax,eax
ret
case_WM_PAINT:
invoke BeginPaint, hWnd, addr ps
invoke BitBlt, eax, 0, 0, image_width, image_height, bitmap_hDC, 0, 0, SRCCOPY
invoke EndPaint, hWnd, addr ps
xor eax,eax
ret
invoke_DefWindowProcA:
invoke DefWindowProcA, hWnd, uMsg, wParam, lParam
;xor eax,eax
ret
MessageProcedure endp

;WinMainCRTStartup proc hInstance:HINSTANCE, hPrevInstance:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
mainCRTStartup proc hInstance:HINSTANCE, hPrevInstance:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
local gsi:GdiplusStartupInput
local token:dword
;local wc:WNDCLASSEX
local hWnd:HWND
local msg:MSG
local hMenu:HMENU
invoke GdiplusStartup, addr token, addr gsi, NULL
invoke CreateCompatibleDC, NULL
mov bitmap_hDC, eax
;mov wc.cbSize,sizeof WNDCLASSEX
;mov wc.style, CS_HREDRAW or CS_VREDRAW
;mov wc.lpfnWndProc, offset MessageProcedure
;mov wc.cbClsExtra,NULL
;mov wc.cbWndExtra,NULL
;push hInstance
;pop wc.hInstance
;mov wc.hbrBackground,COLOR_WINDOW+1
;mov wc.lpszMenuName,NULL
;mov wc.lpszClassName,offset class
;invoke LoadIconA,NULL,IDI_APPLICATION
;mov wc.hIcon,eax
;mov wc.hIconSm,eax
;invoke LoadCursorA,NULL,IDC_ARROW
;mov wc.hCursor,eax
;invoke RegisterClassExA,addr wc
;cmp eax,0
;jz the_end
mov ofn.lStructSize,sizeof OPENFILENAMEW
mov ofn.lpstrFile,offset image_path
mov ofn.nMaxFile,sizeof image_path
call CreateMenu
mov hMenu,eax
invoke AppendMenuA, eax, MF_STRING, 0, offset string_load_image
;invoke RtlZeroMemory, addr msg, sizeof msg
invoke CreateWindowExA, 0, offset string_mdiclient, offset string_load_and_display_any_image,
WS_OVERLAPPEDWINDOW or WS_VISIBLE, 100, 100, 640, 480, NULL, hMenu, NULL, NULL
mov hWnd, eax
invoke SetWindowLongA, eax, GWLP_WNDPROC, offset MessageProcedure
MessageLoop:
invoke IsWindow, hWnd
cmp eax,0
jz the_end
invoke IsWindowVisible, hWnd
cmp eax,0
jz the_end
invoke GetMessageA, addr msg, hWnd, 0, 0
invoke TranslateMessage, addr msg
invoke DispatchMessageA, addr msg
jmp MessageLoop
the_end:
ret
;WinMainCRTStartup endp
mainCRTStartup endp
end

assembler

  • Guest
Found the issue: The local variable "gsi" of type GdiplusStartupInput defined in WinMain procedure was uninitialized properly. I initialized it properly and now everything is working. I can finally see the image, that I browse from my computer, on the window.

Siekmanski

  • Member
  • *****
  • Posts: 1671
Hi assembler,

Quote
but I want to get the data of the image I load from disk, i.e. all bytes in one buffer, plus the image dimensions, i.e. width and height.

I think this is what you want...

You can do this with the "GdipBitmapLockBits" function call,

Code: [Select]
    include    gdiplus.inc
    includelib gdiplus.lib


.const

ImageLockModeRead               equ 1
ImageLockModeWrite              equ 2
ImageLockModeReadWrite          equ 3
ImageLockModeUserInputBuf       equ 4

PixelFormat1bppIndexed          equ 30101h
PixelFormat4bppIndexed          equ 30402h
PixelFormat8bppIndexed          equ 30803h
PixelFormat16bppGreyScale       equ 101004h
PixelFormat16bppRGB555          equ 21005h
PixelFormat16bppRGB565          equ 21006h
PixelFormat16bppARGB1555        equ 61007h
PixelFormat24bppRGB             equ 21808h
PixelFormat32bppRGB             equ 22009h
PixelFormat32bppARGB            equ 26200Ah
PixelFormat32bppPARGB           equ 0E200Bh

GdiplusStartupInput struct
    GdiplusVersion              dd ?
    DebugEventCallback          dd ?
    SuppressBackgroundThread    dd ?
    SuppressExternalCodecs      dd ?
GdiplusStartupInput ends

GdiplusSInput   GdiplusStartupInput <1,NULL,FALSE,FALSE>

BitmapData struct                         
    dwWidth      dd ?   
    dwHeight     dd ?   
    Stride       dd ?   
    PixelFormat  dd ?   
    Scan0        dd ?   
    Reserved     dd ?
BitmapData ends

.data?

GdiplusToken dd ?
GDIplusBitmapData BitmapData <?>
FilenameW   dw  MAX_PATH dup (?)

.data

pImage       dd NULL
PictureName  db "CoolPicture.png",0

.code

; code to load image ( without error checking )
 invoke  GdiplusStartup,addr GdiplusToken,addr GdiplusSInput,NULL

 invoke  MultiByteToWideChar,CP_ACP,0,addr PictureName,-1,addr FilenameW,MAX_PATH-1
 invoke  GdipCreateBitmapFromFile,addr FilenameW,addr pImage

 invoke  GdipBitmapLockBits,pImage,NULL,ImageLockModeRead,PixelFormat32bppARGB,addr GDIplusBitmapData

 mov     esi,GDIplusBitmapData.Scan0     ; pointer to the bitmap data
 mov     eax,GDIplusBitmapData.Stride    ; total length in bytes of 1 horizontal line in the bitmapdata
 mov     ecx,GDIplusBitmapData.dwHeight
 mov     edx,GDIplusBitmapData.dwWidth

; Now you have full access to the bitmap data

 invoke  GdipBitmapUnlockBits,pImage,addr GDIplusBitmapData

 invoke  GdipDisposeImage,pImage

 invoke  GdiplusShutdown,GdiplusToken
 ret


EDIT: PixelFormat32bppRGB             equ 22009h ( "h" after 22009 was missing...)
« Last Edit: December 28, 2016, 05:59:52 PM by Siekmanski »
Creative coders use backward thinking techniques as a strategy.

assembler

  • Guest
Thanks very much for the tips!

LordAdef

  • Member
  • ****
  • Posts: 590
Hello,

There is nothing wrong with GDI+ Here are two examples, one of them is using the GDI+ functions.
Hi guys, I've downloaded and was studying Vortex's examples and after almost commiting a japonese Arakiri, I gave up and am asking for rescue  :dazzled:
The code in question is GdipCreateBitmapFromFile, from Vortex (a couple of posts above):http://masm32.com/board/index.php?topic=5893.msg62649#msg62649

It's all cool and clear, builds ok and so forth...
But when I tried to literally copy his code within mine, nothing happens...(I tried some variations and as they didn't work, I tried a literal copy, just saying for the record).
I don't even need to post mine. The only differences are:
#1. He is using ml, and I UASM.
#2. he is on .386 and I .686p.
#3. A interesting thing: If I change this line of his from:
Quote
invoke  GdipCreateBitmapFromFile, ADDR filename, ADDR UnicodeFileName
to
Quote
invoke  GdipCreateBitmapFromFile, "logo.png", ADDR UnicodeFileName
It runs alright on his version. On mine, I get an error.
Any clear suspects (apart from obviously myself)?Humble appreciation for any possible help

jj2007

  • Member
  • *****
  • Posts: 8773
  • Assembler is fun ;-)
    • MasmBasic
Check the order of args:
Code: [Select]
GpStatus WINGDIPAPI GdipCreateBitmapFromFile(
   GDIPCONST WCHAR* filename,
   GpBitmap **bitmap
):

The call needs a Unicode filename, and a pointer to a DWORD variable. Typically, that looks like
Code: [Select]
push eax  ; create a DWORD variable
invoke GdipCreateBitmapFromFile, wChr$("MyFile.bmp"), esp
pop edx   ; voilĂ , a bitmap (if eax is zero...)

dedndave

  • Member
  • *****
  • Posts: 8808
  • Still using Abacus 2.0
    • DednDave
these images may also be loaded using IImgCtx (COM)
COM is a little messy, and involves a bit of a learning curve

you mentioned in your original post, "Gdiplus is for desktop apps only"
i am guessing you are referring to portable devices, and i can't really comment on which methods are supported

LordAdef

  • Member
  • ****
  • Posts: 590
these images may also be loaded using IImgCtx (COM)
COM is a little messy, and involves a bit of a learning curve

you mentioned in your original post, "Gdiplus is for desktop apps only"
i am guessing you are referring to portable devices, and i can't really comment on which methods are supported
Hi Dave, the original post is not actually mine!

LordAdef

  • Member
  • ****
  • Posts: 590
Check the order of args:
Code: [Select]
GpStatus WINGDIPAPI GdipCreateBitmapFromFile(
   GDIPCONST WCHAR* filename,
   GpBitmap **bitmap
):

The call needs a Unicode filename, and a pointer to a DWORD variable. Typically, that looks like
Code: [Select]
push eax  ; create a DWORD variable
invoke GdipCreateBitmapFromFile, wChr$("MyFile.bmp"), esp
pop edx   ; voilĂ , a bitmap (if eax is zero...)
Thanks Jochen, I'll have a look. Although unless Vortex changed the calling convention in his code, this stuff should work