Continuing on with my graphics related code... my first time writing gdiplus code that was not already pre-canned into a procedure by someone else. It took me a hot minute to figure out that I needed a unicode string for the image path... :rofl:
Tests opening an image and displaying using gdiplus.
Using StretchBlt also, to fill the client area with the image, even when resized.
Image is a cropped version of hutchs "downtown Sydney Australia" banner from the forum.
Have tested this program using *.jpg, *.png, and non-animated *.gif files.
include \masm32\include\masm32rt.inc
include \masm32\include\gdiplus.inc
includelib \masm32\lib\gdiplus.lib
DlgProc proto :dword, :dword, :dword, :dword
writefilex proto :dword, :dword, :dword
cwidth equ 1024 ; desired client area width
cheight equ 576 ; desired client area height
.data
gdipBmp dd 0 ; image object
hBmpgdip dd 0 ; image HBITMAP
picname db "sydney.jpg", 0 ; image filename in ascii
upicname db 128 dup (0) ; image file name in unicode
.data?
gdii GdiplusStartupInput <?>
GDIPtoken dd ?
.code
start proc
local hInstance:dword
invoke GetModuleHandle, NULL
mov hInstance, eax
;--------------------- GdiPlus Startup code -------
mov gdii.GdiplusVersion, 1
mov gdii.DebugEventCallback, 0
mov gdii.SuppressBackgroundThread, 0
mov gdii.SuppressExternalCodecs, 0
invoke GdiplusStartup, addr GDIPtoken, addr gdii, 0
;----------------------------------------------------
invoke MultiByteToWideChar, CP_ACP, 0, addr picname, -1, addr upicname, 128 ; convert ascii to unicode
fn GdipCreateBitmapFromFile, addr upicname, addr gdipBmp ; open image file, create image object
invoke GdipCreateHBITMAPFromBitmap, gdipBmp, addr hBmpgdip, 0 ; get HBITMAP, from image object
invoke GdipDisposeImage, gdipBmp ; dispose image object
invoke DialogBoxParam, hInstance, 100, 0, addr DlgProc, 0 ;; create dialog box, from resource dilalog
;-------------------- GdiPlus Shutdown code -------
invoke GdiplusShutdown, GDIPtoken
;----------------------------------------------------
invoke ExitProcess, eax
start endp
DlgProc proc hWin:dword, uMsg:dword, wParam:dword, lParam:dword
local hDC:dword, ps:PAINTSTRUCT, rct:RECT, hBrush:dword, hBrush_old:dword
local mDC:dword, hBmp:dword, hBmp_old:dword, hPen:dword, hPen_old:dword
local x:dword, y:dword, wwid:dword, whgt:dword, cwid:dword, chgt:dword
.if uMsg == WM_INITDIALOG
;; resizing Client Area to exact dimensions, specified by cwidth and cheight
invoke GetWindowRect, hWin, addr rct ;; get window current dimensions.
mov eax, rct.right ;; obtain current window width by subtracting left boundary
sub eax, rct.left ;; from the right boundary
mov wwid, eax ;; store current window width
mov eax, rct.bottom ;; obtain current window height by subtracting top boundary
sub eax, rct.top ;; from the bottom boundary
mov whgt, eax ;; store current window height
invoke GetClientRect, hWin, addr rct ;; get client area current dimensions.
mov eax, rct.right ;; obtain current client width by subtracting left boundary
sub eax, rct.left ;; from the right boundary
mov cwid, eax ;; store current client area width
mov eax, rct.bottom ;; obtain current client height by subtracting top boundary
sub eax, rct.top ;; from the bottom boundary
mov chgt, eax ;; store client area height
;; calculate the difference between desired client area width and current client area width
mov eax, cwidth
sub eax, cwid
;; adjust the window width according to the difference calculated above
add wwid, eax
;; calculate the difference between desired client area height and current client area height
mov eax, cheight
sub eax, chgt
;; adjust the window height according to the difference calculated height
add whgt, eax
;; center the main window
;; obtain client area of the desktop, not including the task bar
invoke SystemParametersInfoA, SPI_GETWORKAREA, 0, addr rct, 0
;; center window width
mov eax, rct.right
sub eax, wwid
sar eax, 1
mov x, eax
;; center window height
mov eax, rct.bottom
sub eax, whgt
sar eax, 1
mov y, eax
;; implement the centering of the resized main window
invoke MoveWindow, hWin, x, y, wwid, whgt, TRUE
.elseif uMsg == WM_SIZE
invoke InvalidateRect, hWin, 0, 0
.elseif uMsg == WM_PAINT
invoke BeginPaint, hWin, addr ps
mov hDC, eax ; window client area DC
;; get client area rectangle
invoke GetClientRect, hWin, addr rct
invoke CreateCompatibleDC, hDC
mov mDC, eax ; memory DC
invoke SelectObject, mDC, hBmpgdip ; select image HBITMAP
invoke StretchBlt, hDC, 0, 0, rct.right, rct.bottom, mDC, 0, 0, 276, 213, SRCCOPY
invoke DeleteDC, mDC
invoke EndPaint, hWin, addr ps
.elseif uMsg == WM_CLOSE
invoke EndDialog, hWin, 0
.endif
xor eax, eax
ret
DlgProc endp
writefilex proc lpName:dword, lpData:dword, fl:dword
local hOutput:dword
local bw :dword
invoke CreateFile, lpName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0
cmp eax, -1
jne @F
fn MessageBox, 0, lpName, "Couldn't read File!", MB_OK
xor eax, eax
xor ecx, ecx
jmp xit
@@:
mov hOutput, eax
invoke WriteFile, hOutput, lpData, fl, addr bw, NULL
invoke CloseHandle, hOutput
mov eax, 1
xit:
ret
writefilex endp
end
(https://i.postimg.cc/dtJkLmy1/untitled.png)
I think everything here is proper in regards to the gdiplus code.
What about using gdiplus code in WM_PAINT?? I have zero clue myself.
Using StretchBlt on a large image, when resizing smaller the results are not very appealing.
If nothing else, I have a way now to load and use .jpg, .png or .gif files in my programs, without relying on others work. *except as research material, into trying to understand gdi+. :smiley:
Here's your WM_PAINT handler for GDI+, good buddy:
.data
GDIhBitmap DD ? ;Global GDI+ bitmap handle
;=================================
; Open image before WM_PAINT runs:
; Note: "ImageFilename" must be Unicode
;=================================
INVOKE GdipLoadImageFromFile, OFFSET ImageFilename, OFFSET GDIhBitmap
;==================
; WM_PAINT handler:
;==================
LOCAL gdiHgraphics:DWORD
do_paint:
INVOKE BeginPaint, hWin, ADDR ps
MOV hDC, EAX
; Get graphics "object" from DC handle:
INVOKE GdipCreateFromHDC, hDC, ADDR gdiHgraphics
; Display image at (X,Y) with dimensions (W,H):
Invoke GdipDrawImageRectI, gdiHgraphics, GDIhBitmap, X, Y, W, H
INVOKE EndPaint, hWin, ADDR ps
XOR EAX, EAX
RET
You've already done the first part (opening the image with GdipLoadImageFromFile(); that gets done outside of the WM_PAINT handler.
Many thanks to "mabdelouahab" of this forum who provided these magic incantations ...
Quote from: NoCforMe on March 12, 2025, 04:28:03 AMHere's your WM_PAINT handler for GDI+, good buddy
; Display image at (X,Y) with dimensions (W,H):
Invoke GdipDrawImageRectI, gdiHgraphics, GDIhBitmap, X, Y, W, H
Thanks chum. :tongue:
And mabdelouahab, for the
Quote from: NoCforMe on March 12, 2025, 04:28:03 AMmagic incantations ...
:thumbsup:
I new there had to be a gdi+ way to draw the image ... back to more experimentation...
The MS documentation is weird when searching for gdiplus functions
"Creates a Graphics::Graphics object that is associated with a specified device context." ... like that tells ME something. lol
In a "real" program I would probably put the gdi+ startup code in either WM_INITDIALOG, or WM_CREATE depending on the GUI design, and the gdi+ shutdown call in WM_CLOSE.
Yes, documentation. Ugh.
This Micro$oft Learn page (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-graphics-flat) has a table of all the "flat" GDI+ functions--that is, the functions removed from their C++ "wrapper" and exposed for us non-C++ programmers. It's a little clunky, but search for the function you want info on and it'll show the parameters and other good stuff if you click on it.
Quote from: NoCforMe on March 12, 2025, 05:00:17 AMYes, documentation. Ugh.
This Micro$oft Learn page (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-graphics-flat) has a table of all the "flat" GDI+ functions--that is, the functions removed from their C++ "wrapper" and exposed for us non-C++ programmers. It's a little clunky, but search for the function you want info on and it'll show the parameters and other good stuff if you click on it.
Thanks for the tip, and no thanks to Microsoft. :biggrin:
I like the win32.hlp method of presenting information. Too bad gdi+, and some others never made it in there.
Do we need GdipDeleteGraphics after GdipCreateFromHDC ?
Quote from: TimoVJL on March 12, 2025, 05:56:27 AMDo we need GdipDeleteGraphics after GdipCreateFromHDC ?
I dunno, I am still learning about gdi+, and why I am asking questions here. :azn:
I just downloaded from MS, windows-win32-gdiplus.pdf for my research... :eusa_dance:
gdi+ reference (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-class-gdi-reference)
Button on the left of that page to Download PDF.
... whoops. :eusa_boohoo:
AGAIN! Quoted the above post, meaning to modify it. :greensml:
Quote from: TimoVJL on March 12, 2025, 05:56:27 AMDo we need GdipDeleteGraphics after GdipCreateFromHDC ?
Maybe, to prevent resource leaks.
Although the "graphics" object might be automagically deleted by Windows on program exit.
QuoteDo we need GdipDeleteGraphics after GdipCreateFromHDC ?
Yes. GDIhBitmap also needs GdipDisposeImage-ing
Quote from: adeyblue on March 12, 2025, 12:03:52 PMQuoteDo we need GdipDeleteGraphics after GdipCreateFromHDC ?
Yes. GDIhBitmap also needs GdipDisposeImage-ing
Thanks adeyblue. I am still doing research on gdi+ stuff.
Haven't seen you around here in a hot minute... :smiley:
Quote from: adeyblue on March 12, 2025, 12:03:52 PMQuoteDo we need GdipDeleteGraphics after GdipCreateFromHDC ?
Yes. GDIhBitmap also needs GdipDisposeImage-ing
OK, I looked that up in my GDI+ help file; it says
QuoteDisposes the specified Image object.
Hmm, that's not very helpful.
So what, exactly, does it mean to "dispose" [of?] an image object?
I know delete and destroy, but not dispose ...
Man, all this C++/"object" sophistry ...
Quote from: NoCforMe on March 12, 2025, 12:43:19 PMSo what, exactly, does it mean to "dispose" [of?] an image object?
I gunna try to find out...
I am going to try it where I would normally delete any gdi objects, either before EndPaint, or in WM_CLOSE.
Or maybe better, just before calling the gdiplus shutdown api.
I would have to see an example of how/when it is used. Or at least a more detailed description of the order of execution, i.e., where in the gdiplus chain of events this needs to be called. If that makes any sense. I'm tired and need sleep. :tongue:
Quote from: NoCforMe on March 12, 2025, 12:43:19 PMSo what, exactly, does it mean to "dispose" [of?] an image object?
I gunna try to find out...
I am going to try it where I would normally delete any gdi objects, either before EndPaint, or in WM_CLOSE.
Or maybe better, just before calling the gdiplus shutdown api.
I would have to see an example of how/when it is used. Or at least a more detailed description of the order of execution, i.e., where in the gdiplus chain of events this
needs to be called, if that makes any sense.
I'm tired and need sleep. :tongue:
When object goes out of scope in OOP language, it will be destroyed after that.
So if object is created with GdipCreateFromHDC() in WM_PAINT, it should be destroyed with GdipDeleteGraphics() after it isn't needed anymore.
Quote from: TimoVJL on March 12, 2025, 01:34:34 PMWhen object goes out of scope in OOP language, it will be destroyed after that.
So if object is created with GdipCreateFromHDC() in WM_PAINT, it should be destroyed with GdipDeleteGraphics() after it isn't needed anymore.
After the drawing has taken place, I would assume. Thanks Timo. Some things in MS documentation aren't always very clear.
Later:
Bbbbut wait a minute, I am not using GdipCreateFromHDC... did you look at my source code in post #1? I was following various gdiplus examples with bits and pieces from here and there... until I got everything working....
Quote from: zedd151 on March 12, 2025, 01:42:48 PMLater:
Bbbbut wait a minute, I am not using GdipCreateFromHDC... did you look at my source code in post #1? I was following various gdiplus examples with bits and pieces from here and there... until I got everything working....
That GdipCreateFromHDC thing started at post #2
Quote from: TimoVJL on March 12, 2025, 02:23:31 PMThat GdipCreateFromHDC thing started at post #2
Ah, okay. That was meant for NoCforMe.... you should have been more specific. :smiley:
Since you posted right after one of my posts, it appeared to me that your post was meant for me.
Quote from: TimoVJL on March 12, 2025, 01:34:34 PMWhen object goes out of scope in OOP language, it will be destroyed after that.
So if object is created with GdipCreateFromHDC() in WM_PAINT, it should be destroyed with GdipDeleteGraphics() after it isn't needed anymore.
OK. But what about this other function,
GdipDisposeImage(): when (and why) is it needed?
What does it mean to "dispose" [of] an image?
Well, a partial answer, anyhow, from good old Stack Overflow (https://stackoverflow.com/questions/30004391/how-to-release-an-object-created-from-gdipcreatebitmapfromhbitmap):
QuoteThat being said, GdipCreateBitmapFromHBITMAP() returns a pointer to a GpBitmap object (which is wrapped by the Bitmap class in C++). GdipDisposeImage() is the correct way to release that object (which is called by the Image destructor in C++).
So it may not be needed here, since we're not creating a
GpBitmap object using
GdipCreateBitmapFromHBITMAP().
God damn, this shit be complicated ... too complicated ...
Quote from: NoCforMe on March 12, 2025, 02:40:12 PMOK. But what about this other function, GdipDisposeImage(): when (and why) is it needed?
I think it has to do with how HBITMAP is created. Heres mine.
fn GdipCreateBitmapFromFile, addr upicname, addr gdipBmp ; open image file, create image object
invoke GdipCreateHBITMAPFromBitmap, gdipBmp, addr hBmpgdip, 0 ; get HBITMAP, from image object
invoke GdipDisposeImage, gdipBmp ; dispose image object
I use hBmpgdip (HBITMAP) from here in WM_PAINT to blit the image to DC with
Not sure still if I need to call GdipDeleteGraphics() by what Timo says...
It seems there are many ways to do very similar things with gdi+, and I understand none of them. Yet. :eusa_boohoo:
Yeah, it'd be nice to find some kind of tutorial or at least a better explanation of how all that shit works that's better than Micro$oft's documentation.
Too lazy to look for it at the moment ...
Quote from: NoCforMe on March 12, 2025, 02:58:13 PMYeah, it'd be nice to find some kind of tutorial...
Too lazy to look for it at the moment ...
I just did a quick forum search for both gdi+ and gdip... Shoulda done that even before starting this topic. :eusa_dance:
Seems there are a lot of topics covering gdi+/gdiplus..
Should be some good examples (hopefully not buggy code) somewhere here already. :biggrin:
Maybe tomorrow, its late here.
How to release an object created from GdipCreateBitmapFromHBITMAP? (https://stackoverflow.com/questions/30004391/how-to-release-an-object-created-from-gdipcreatebitmapfromhbitmap)
QuoteThat being said, GdipCreateBitmapFromHBITMAP() returns a pointer to a GpBitmap object (which is wrapped by the Bitmap class in C++). GdipDisposeImage() is the correct way to release that object (which is called by the Image destructor in C++).
I would imagine it's like an interface - you ask for an object and it gives you a reference.
Once you've finished with it you release it.
It might just be easier to take the approach that hutch did in masm64 SDK examples. Load the .jpg or other image file and set it into a static control, rather than using WM_PAINT explicitly to draw/blit/stretch it to DC. :tongue:
I don't know if his code regarding gdiplus is totally kosher now, after all I have been reading about gdi+ throughout the day. I don't see any Delete apis called there for gdip objects, unless I missed it.
And I will say it before NoCforMe does... Classes schmlasses. :biggrin:
They don't make things easy for an assembly programmer.
This might have some items of interest
https://github.com/VFPX/Win32API/tree/master/libraries/gdiplus (https://github.com/VFPX/Win32API/tree/master/libraries/gdiplus)
Yes, I have seen that while doing some research today. Thanks.
It's just that there seems to be several different paths to open and display .jpg, .png, .gif images. But nothing I have read yet, tells me which api should follow another in the code flow if that makes any sense.
The code I posted in the first post works, but I don't know if the gdiplus code flow is complete.
It's not like plain old gdi, where you can check Task Manager for gdi leaks, if I am not mistaken. Gdiplus might be leaking like a sieve.
I am very tired now. I'll get back to this tomorrow.
avcaballero made an example for GDIPlus
https://board.flatassembler.net/topic.php?p=193082 (https://board.flatassembler.net/topic.php?p=193082)
Quote from: sinsi on March 12, 2025, 04:00:44 PMThis might have some items of interest
https://github.com/VFPX/Win32API/tree/master/libraries/gdiplus (https://github.com/VFPX/Win32API/tree/master/libraries/gdiplus)
Sorry, not sorry: that really doesn't help.
It's the same documentation of the GDI+ flat functions that I already have in a Windows help (.chm) file. All it does is give the function parameters and return values: it doesn't really explain what the function does in any detail. That's what we need here.
Quote from: NoCforMe on March 12, 2025, 07:23:49 PMSorry, not sorry: that really doesn't help.
Did you look at any?
You asked the question earlier
Quote from: NoCforMe on March 12, 2025, 02:40:12 PMOK. But what about this other function, GdipDisposeImage(): when (and why) is it needed?
The link gives an answer as to why
QuoteDECLARE INTEGER GdipDisposeImage IN gdiplus;
INTEGER img
Parameters:
img [in] Identifies the Image created by GdipLoadImageFromFile, GdipLoadImageFromStream and other Image constructors.
Quote from: sinsi on March 12, 2025, 07:52:34 PMThe link gives an answer as to why
QuoteDECLARE INTEGER GdipDisposeImage IN gdiplus;
INTEGER img
Parameters:
img [in] Identifies the Image created by GdipLoadImageFromFile, GdipLoadImageFromStream and other Image constructors.
No it doesn't!How is that in any way an explanation of what it does?
What does it mean to "dispose" [of] an image?
Since this is a different verb from "delete" or "destroy", it leads one to believe that it does something different from those actions. But what?
And when do we need to use this? with what types of "objects"?
Do you see how a real explanation of how this stuff works is what's needed (for us who don't know yet)?
Jeez man, ever heard of a synonym?
To me, it's self-explanatory.
You create/load/bring into being an image from a file/stream/etc.
You dispose of/delete/destroy/kill it when you're finished using it.
That's a bit more information than MS give you.
Have to understand OOP principles.
Every COM object have method Release and OOP object delete or ~
and other are just synonyms for same purpose.
I haven't found any good simple info for GDIPlusFlat API, that is for non-OOP languages.
Name GdipDisposeImage() quite is logical, it don't delete nor destroy that image, just release it's object and it's resources from memory.
Quote from: sinsi on March 12, 2025, 08:38:38 PMJeez man, ever heard of a synonym?
To me, it's self-explanatory.
You create/load/bring into being an image from a file/stream/etc.
You dispose of/delete/destroy/kill it when you're finished using it.
That's a bit more information than MS give you.
Is it, though? MS does say
QuoteReleases resources used by the Image object.
Which may seem obvious, but it's nice to at least have a hint, a clue as to what a function does ...
I've reached a conclusion about using the GDI+ "flat" API:
The best way to figure out how to use this stuff (600+ functions) is, to use that internet abbreviation,
FAFO
Quote from: NoCforMe on March 12, 2025, 09:10:22 PMI've reached a conclusion about using the GDI+ "flat" API:
The best way to figure out how to use this stuff (600+ functions) is, to use that internet abbreviation,
FAFO
I had to look that up. :joking: :rofl:
It went right over my head.
Either that, or "fake it until you make it". :tongue:
I guess I'll just stick to drawing lines, pixels, ellipses and rectangles, and more importantly polygons! :biggrin: :biggrin:
Calls used in my ImgPaintP proc (tested, no leaks); GdipDisposeImage and GdipDeleteGraphics are indeed the last actions required.
invGdip GdipCreateBitmapFromHBITMAP, eax, 0, esp
invGdip GdipCreateBitmapFromStream, #
invGdip GdipCreateBitmapFromHBITMAP, eax, 0, esp
invGdip GdipCreateHBITMAPFromBitmap, gsi.jjImgObject, addr gdiFil
invGdip GdipCreateFromHDC, ecx, addr gsi.jjGraphicsObj
invGdip GdipImageGetFrameDimensionsList, giImage, addr Dimensio
invGdip GdipImageGetFrameCount, giImage, addr DimensionIDs, add
invGdip GdipImageSelectActiveFrame, giImage, addr DimensionIDs
invGdip GdipGetPropertyItemSize, giImage, PropertyTagFrameDelay
invGdip GdipGetPropertyItem, giImage, PropertyTagFrameDelay, prop
invGdip GdipGetPropertyItemSize, giImage, PropertyTagDocumentName
invGdip GdipGetPropertyItem, giImage, PropertyTagDocumentName, pr
invGdip GdipGetPropertyItemSize, giImage, PropertyTagLoopCount, a
invGdip GdipGetPropertyItem, giImage, PropertyTagLoopCount, propS
invGdip GdipScaleWorldTransform, gsi.jjGraphicsObj, FP4(4.0)
invGdip GdipGetImageWidth, gsi.jjImgObject, esp
invGdip GdipGetImageHeight, gsi.jjImgObject, esp
invGdip GdipImageRotateFlip, gsi.jjImgObject, [edi.GuiImageZOOM].
invGdip GdipRotateWorldTransform, gsi.jjImgObject, FP4(45.0), Mat
invGdip GdipSaveImageToFile, giImage, ecx, eax, offset imgQuali
invGdip GdipDisposeImage, ebx
invGdip GdipDeleteGraphics, gsi.jjGraphicsObj
Quote from: jj2007 on March 12, 2025, 09:53:08 PMCalls used in my ImgPaintP proc (tested, no leaks); GdipDisposeImage and GdipDeleteGraphics are indeed the last actions required.
From what was posted here, I understand that
GdipDeleteGraphics is
definitely needed if
GdipCreateFromHDC is called.
Which, in my exapmle in #1 I do not use
GdipCreateFromHDC .
Are there other gdip apis that would need
GdipDeleteGraphics also?
When is
GdipDeleteGraphics actually
needed? Or is it a standard function that should
always be called kinda like EndPaint?
I do call
GdipDisposeImage, though. I think in the right place, too.
Listing 20+ apis, doesnt tell us what is definitely neeeded for a simple example as I posted in the original post here, jj2007.
I just want to know for now, if the code in that example is complete (
as far as the gdip stuff) or is there an api call that is missing???
I am using gdi StretchBlt to do the actual drawing to the DC.
My experience of memory leak in gdi, was long ago it worked a little while until all create pen and brush stopped working and program started to draw black and white
That why delete objects are important
"fake it until you make it". :tongue:
It's so true in demo/game graphics development from slowest x86 faking it with luts and cheat like pseudo 3d and pre rendered 3d objects and light to new gaming computers making it with real time rendering with pixelshaders
GdipCreateHBITMAPFromBitmap just create GDI bitmap, not object.
GdipDeleteGraphics is only for Graphics object.
GdipCreateBitmapFromFile create GpBitmap object, that you delete with GdipDisposeImage.
So a your GdipDisposeImage was in right place.
Quote from: daydreamer on March 12, 2025, 10:19:27 PMMy experience of memory leak in gdi, was long ago it worked a little while until all create pen and brush stopped working and program started to draw black and white
That why delete objects are important
"fake it until you make it". :tongue:
It's so true in demo/game graphics development from slowest x86 faking it with luts and cheat like pseudo 3d and pre rendered 3d objects and light to new gaming computers making it with real time rendering with pixelshaders
Um. Okay. How does that answer a single question about GDI+?
GDI leaks are easily seen in Task Manager cause by not deleting the usual object (pens, brushes), and possibly not deleting memory DC. Or would that one be a memory leak??
I don't think that applies to GDI+ and it's apis.
There are no GDI leaks in my example, btw.
Quote from: TimoVJL on March 12, 2025, 10:22:15 PMGdipCreateHBITMAPFromBitmap just create GDI bitmap, not object.
GdipDeleteGraphics is only for Graphics object.
GdipCreateBitmapFromFile create GpBitmap object, that you delete with GdipDisposeImage.
So a your GdipDisposeImage was in right place.
Thank you for taking the time to look at my code. :azn:
Do I need to call GdipDeleteGraphics?
I am a bit mystified with this gdi+ stuff.
I had thought I had done enough research before posting the example. And I believe everything I need is already in the code.
No with #1 code, as Graphic object wasn't created in that code
Quote from: TimoVJL on March 12, 2025, 10:32:29 PMNo with #1 code, as Graphic object wasn't created in that code
Thank you. That is all I needed to know at this time.
Now
everybody...See,
this is what happens when you throw around
function names that are
not relevant to the topic at hand (meaning
my example in post #1).
It causes major confusion to those trying to learn something new. In this case, ME. And NoCforMe as well.
Case closed for me, problem non existent, carry on.
Sheesh! Over 14 hours to finally get the answers that really mattered regarding my posted code.
Thread Closed!Just kidding about that last one :skrewy:
I am satisfied using BitBlt or StretchBlt to draw it to the DC. I ain't gunna try doing it with gdiplus at this time. :smiley:
But to be clear, Timo.. if I do use a gdi+ API to draw to the DC, will I then need to use GdipDeleteGraphics?
Quoteto be clear, Timo.. if I do use a gdi+ API to draw to the DC, will I then need to use GdipDeleteGraphics?
Just in case, that you use GdipCreateFromHDC or similar function
Quote from: TimoVJL on March 12, 2025, 10:50:04 PMQuoteto be clear, Timo.. if I do use a gdi+ API to draw to the DC, will I then need to use GdipDeleteGraphics?
Just in case, that you use GdipCreateFromHDC or similar function
Okay, now I think I got it. Thanks man!
:biggrin:
I'll tinker some more with gdi+ in the future.
For now, this is enough for me to begin using smaller (in kb) images instead of huge 24 bit bitmaps. I will polish up the code, and post it as a "proper example" for others to possibly learn from, away from the distractions here in this WIP thread.
Thanks to all that posted helpful information, and to those that had good (possibly misguided) intentions.
And thank you once again Timo, your help has been invaluable.
Do you have any gdi+ examples in C that you could share, Timo?
I am not adverse to learning from C example code. (As long as it will compile with gcc that is) :smiley:
... if you don't have anything already written, that's ok.
Quote from: zedd151 on March 12, 2025, 10:00:33 PMAre there other gdip apis that would need GdipDeleteGraphics also?
In my code it's GdipCreateFromHDC that creates the graphics object to be deleted later.
That's what I understood from earlier. Thx for the confirmation. :thumbsup:
Quote from: TimoVJL on March 12, 2025, 01:34:34 PMif object is created with GdipCreateFromHDC() in WM_PAINT, it should be destroyed with GdipDeleteGraphics() after it isn't needed anymore.
@Zedd: to lessen the confusion here, you should realize that since there are several types of "objects" here, you need to use the relevant function (
not an API: the whole schmear is the API) to release/delete/destroy/dispose that object:
So if you create a bitmap, then you wouldn't use
GdipDeleteGraphics(), because that applies to a different class of objects (graphics vs. bitmaps). (Unless you create a graphic object
from a bitmap, in which case you would use that function.)
I've been able to figure at least that much out so far ...
All I know is my little example is fine as far as the gdi+ code goes. And I'm happy as a camper to be done with gdi+. Yuck. What a big mess. :biggrin:
Quote from: zedd151 on March 13, 2025, 09:36:57 AMYuck. What a big mess. :biggrin:
Agreed :badgrin:
include \masm32\MasmBasic\Res\MbGui.asm
Event Paint
GuiImage CL$(), fit
GuiEnd
P.S.: Drag tweety over the exe, then size the window :smiley:
I second that emotion.
So Zedd: any motivation on your part to look into DirectDraw? Since you've been taking the Magical Mystery Tour of Win32 Graphics Techniques?
Quote from: NoCforMe on March 13, 2025, 09:55:46 AMI second that emotion.
So Zedd: any motivation on your part to look into DirectDraw? Since you've been taking the Magical Mystery Tour of Win32 Graphics Techniques?
Hell no. After this fiasco. (Not really a fiasco, my code was okay in the end, but the confusion after - definite fiasco)
I think DirectDraw would break my brain.
Quote from: jj2007 on March 13, 2025, 09:53:10 AMP.S.: Drag tweety over the exe, then size the window :smiley:
"GdiPlusEasy.exe"... Easy my ass! 49 gdiplus functions/apis??? :dazzled: (whatever the hell you'd call 'em, David)
But it was a cute feature. :azn: animate on resizing
Bug report: Menu items do not work on click. :biggrin:
Yves (https://i.postimg.cc/PJg3q2tr/yves.gif) Yours (https://i.postimg.cc/nLpW7RqX/Tweetie.gif)
Free Yves! Let him go... can't you see he is flapping his wings faster while in captivity trying to escape?
Quote from: zedd151 on March 13, 2025, 10:03:01 AM"GdiPlusEasy.exe"... Easy my ass! 49 gdiplus functions/apis??? :dazzled: (whatever the hell you'd call 'em, David)
I remember when JJ would be posting in astonishment at the prospect of such a simple task needing to import 10 dlls and nearly 300 functions. What happened to that guy? Looks like he's gotten into bed with the bloat industry *idk what the smiley codes are, imagine there's one here*
Sound about right. :joking:
Point taken.
In fairness to JJ, though, everything he does, all that pain he goes through with those 10 DLLs and 300 functions, ends up in his baby, his project, MasmBasic. Where it then becomes available to its users (I'm not one of them, BTW) as a very easy-to-use facility, often accomplishing in a single line of code what it takes the rest of us 10 or 100 times that. Which is a pretty good piece of work if you ask me.
Regarding terminology: since when did "functions" become aggrandized to "APIs"? An API ("application programming interface") is the entire collection of things--functions, structures, enumerations, etc.--that accomplish certain tasks. GDI+ is an API; GdipDeleteGraphics() is just a function within that API.
I notice this undue promotion of meaning occurs in lots of other places online, not just here. But let's nip it in the bud, shall we?
Yes, Professor. :biggrin:
That's "Perfessor" to you.
Quote from: NoCforMe on March 13, 2025, 02:51:51 PMRegarding terminology: since when did "functions" become aggrandized to "APIs"? An API ("application programming interface") is the entire collection of things--functions, structures, enumerations, etc.--that accomplish certain tasks. GDI+ is an API; GdipDeleteGraphics() is just a function within that API.
To nitpick further, traditionally a "function" was a procedure you called and got a result back.
Not all Windows procedures return a result, so not all Windows procedures are functions.
Perhaps we could use the term "Windows API call"?
:biggrin:
Quote from: zedd151 on March 13, 2025, 10:03:01 AMBut it was a cute feature. :azn: animate on resizing
Well, not really a feature :badgrin:
Some trigger is needed to animate a GIF: a timer, resizing, mousemove...
GuiParas equ "An image, hooray!!!!", w300, h300, icon Butterfly
include \masm32\MasmBasic\Res\MbGui.asm
Event Message
If_ uMsg_==WM_MOUSEMOVE Then GuiCls
Event Paint
GuiImage CL$(), fit
GuiEnd
Quote from: adeyblue on March 13, 2025, 02:31:36 PMI remember when JJ would be posting in astonishment at the prospect of such a simple task needing to import 10 dlls and nearly 300 functions. What happened to that guy? Looks like he's gotten into bed with the bloat industry
A Hello World in MasmBasic weighs in at 32kBytes. That is bloat in Masm terms, I agree - but it's still tiny in comparison to a QT Hello World at several MB.
If you choose
Say (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1366) "Hello World" instead of Print, that adds only 512 bytes: no external libs, just a call to a built-in Windows feature.
The animated GIF in seven lines (https://masm32.com/board/index.php?topic=12605.msg137000#msg137000) of source code costs 57kBytes. Serious bloat, of course :bgrin:
It's a compromise: some bloat, yes, but in turn you get comfortable graphics, string handling, file io (e.g. GetFiles (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1056)) and much more. Hutch managed to keep all modules of Masm32 separate, they don't depend on each other, and therefore you can indeed produce a 1024 byte Hello World. But you have to add a lot of work for even simple things. MasmBasic has a core block of over 200 functions that costs around 32kBytes, and they do depend on each other, so no way to keep them as tiny as pure Masm32. I can live with that :cool:
I attach another example. Here is the source:
include \masm32\MasmBasic\MasmBasic.inc
Init
Say FileRead$(uCL$())
EndOfCode
The text in the file passed via the commandline (e.g. by dragging over the exe) must be UTF-16. I'd like to know whether it works for those of you who have an OS in Russian, Chinese or Arabic. I get an Italian voice ;-)
Don't drag TheHolyBible.txt over the exe, it might choke :bgrin:
Quote from: jj2007 on March 13, 2025, 07:31:39 PMQuote from: zedd151 on March 13, 2025, 10:03:01 AMBut it was a cute feature. :azn: animate on resizing
Well, not really a feature :badgrin:
Do you realize how many mistakes, accidents, or otherwise 'not by design' inventions there are, that are multimillion dollar industries today? :biggrin:
My attempt at GDI+ GIF animation.
I've tried to make it MASM32 compatible :biggrin:
No comments though :eusa_boohoo:
@sinsi:
Seems a little off. I opened the .gif in ImageReady and the animation displays properly there, RoadRunner runs.
But in your example, looks like RoadRunner has the shakes or is shivering, rather than running.
At least it shows the concept of getting the individual .gif frames. And working with multi frame gifs in general.
Used this your gif with jochens example from #59, and it animates better with his, but still not perfect.
Carry on with your gdiplus tests, guys. The more the merrier. :eusa_dance:
It's on a timer, changing the delay helps a little.
The main problem is that the background doesn't get erased.
It was a quick test to see the steps involved in actually getting it to animate.
The next step is smoothing it out.
Not too bad for ~10 lines of gdiplus code and an hour of frustration on google :biggrin:
Quote from: sinsi on March 14, 2025, 04:15:28 AMIt's on a timer, changing the delay helps a little.
tried that, to no great improvement
QuoteThe main problem is that the background doesn't get erased.
Sounds like a likely possible cause
QuoteIt was a quick test to see the steps involved in actually getting it to animate.
The next step is smoothing it out.
okay, so it really is experimental test code
QuoteNot too bad for ~10 lines of gdiplus code and an hour of frustration on google :biggrin:
:biggrin:
Updated. Now double buffered and resizable (looks crap when embiggened).
Might try a bigger GIF with more frames next.
Thats better. You're getting there.
btw I had to, in both cases, complete the path to "gdiplus.lib":
to --> "includelib \masm32\lib\gdiplus.lib"
otherwise no problem assembling and linking
Quote from: zedd151 on March 14, 2025, 04:55:09 AMThats better. You're getting there.
Gee, thanks grandpa
Quote from: zedd151 on March 14, 2025, 04:55:09 AMbtw I had to, in both cases, complete the path to "gdiplus.lib":
to --> "includelib \masm32\lib\gdiplus.lib"
Yeah, I use a VS batch file and the Windows SDK libraries and binaries.
Quote from: sinsi on March 14, 2025, 05:00:58 AMQuote from: zedd151 on March 14, 2025, 04:55:09 AMThats better. You're getting there.
Gee, thanks grandpa
Quote from: zedd151 on March 14, 2025, 04:55:09 AMbtw I had to, in both cases, complete the path to "gdiplus.lib":
to --> "includelib \masm32\lib\gdiplus.lib"
Yeah, I use a VS batch file and the Windows SDK libraries and binaries.
Ok, that's fine. It wasn't a major job to fix it.
You young whippersnappers... :biggrin:
Quote from: sinsi on March 13, 2025, 05:20:59 PMQuote from: NoCforMe on March 13, 2025, 02:51:51 PMRegarding terminology: since when did "functions" become aggrandized to "APIs"? An API ("application programming interface") is the entire collection of things--functions, structures, enumerations, etc.--that accomplish certain tasks. GDI+ is an API; GdipDeleteGraphics() is just a function within that API.
To nitpick further, traditionally a "function" was a procedure you called and got a result back.
Not all Windows procedures return a result, so not all Windows procedures are functions.
Perhaps we could use the term "Windows API call"?
:biggrin:
Welll, to expand on the pedantry just a bit more, technically speaking a "function" is, in mathematical terms, a black box (formula, etc.) that for each input value (
x) produces a single output value (
y) (so a parabola is a function while an ellipse is not).
However, as you point out, not all Win32, ahem, things that you call behave this way; some produce no output, while others produce more than a single value. So mathematically speaking they ain't functions.
But we need to call these things something, right? (My instinct is to call them "subroutines".) So Micro$oft, and practically everyone else out there has chosen to call them "functions". Which pretty much works for me; no need for hairsplitting here, even if it's not mathematically correct.
I just came up with another name: why don't we call them "Flamzingers"? That oughta settle it for good. (Somehow, though, I don't really see this catching on ...)
Hello,
Here is a GdipCreateBitmapFromGdiDib example. This demo reads a bitmap file from disc and retrieves the handle of the image with help of GdiPlus function :
.IF uMsg==WM_CREATE
mov eax,OFFSET StartupInfo
mov GdiplusStartupInput.GdiplusVersion[eax],1
mov GdiplusStatus,eax
invoke GdiplusStartup,ADDR token,ADDR StartupInfo,0
invoke ReadFileToMem,ADDR filename,ADDR pMem,\
ADDR pBytesRead
mov eax,pMem
mov ecx,BITMAPFILEHEADER.bfOffBits[eax]
lea edx,[eax+ecx] ; points the array of bytes that contains the pixel data
add eax,SIZEOF BITMAPFILEHEADER ; points the BITMAPINFO structure
invoke GdipCreateBitmapFromGdiDib,eax,edx,\
ADDR BmpImage
; creates a Bitmap object based on a BITMAPINFO structure and
; an array of pixel data
invoke GdipCreateHBITMAPFromBitmap,BmpImage,\
ADDR hBitmap,0
invoke VirtualFree,pMem,0,MEM_RELEASE
@: NoCforMe
How about if we just call it a thingy. :tongue:
If I or anyone else calls it an api, function, or anything else while also mentioning it by name, I am 100% certain that you or anyone else here that reads it will know exactly what I am talking about. Semantics, pedantics or any other kind of antics aside.
Stop being a buzzkill. :skrewy:
@Vortex:
Nice example, Vortex.
We are testing using gdiplus functions, for some of us, using gdiplus for the first time. Most of what is posted here is experimental or test code, not fully debugged examples. Thanks for your excellent contribution, it is appreciated.
Quote from: sinsi on March 14, 2025, 04:48:14 AMUpdated
You might use a lighter background. The animated-looney-toons-image-0017.gif is transparent (tweetie isn't)
Quote from: jj2007 on March 14, 2025, 07:42:07 AMis transparent (tweetie isn't)
I'm working on one that will be. :tongue:
https://en.m.wikipedia.org/wiki/Function_(computer_programming) (https://en.m.wikipedia.org/wiki/Function_(computer_programming))
Quote from: zedd151 on March 14, 2025, 08:24:39 AMQuote from: jj2007 on March 14, 2025, 07:42:07 AMis transparent (tweetie isn't)
I'm working on one that will be. :tongue:
Scratch that idea.
It had been so long that I had used ImageReady or Gimp to make transparent animated .gifs, I had forgotten much of what I once knew. Maybe some time in the future. A shame though, I have a 500 pixel wide clean copy of tweety in .gif with transparency. I fubarred my first several attempts so far. I might simply be missing a setting. They all had a white background. :rolleyes:
(https://i.postimg.cc/SKM5jTRY/Tweety-Large.gif)
from https://officialpsds.com/tweety-fun-gif-rvyz32
Needs sound: "I tawt I taw a putty tat!".
Here is my latest, a few minor needed changes based on example in #1. No animations here though, Sorry guys.
First I put the gdip startup code into a procedure, is called from WM_INITDIALOG
Also, put the image loading code into a procedure, is called from WM_INITDIALOG as well
Added a routine using GetOpenFileName, to choose an image file upon program starup, rather than using a hard coded image name. Gets called after loading the image.
I added code to get the image size. The client area will now be automatically sized exactly to the image size. rather than using hard coded image dimensions.
Some issues linger regarding image size. :rolleyes: if too large or small... (larger than screen dimensions, smaller than minimized window client)
For the larger images, I *could* use scrollbars on the main window, with all the phun that it entails. :toothy:
A few other errata also to attend to, before it's ready for prime time.
Another thing, this program does not handle images with transparency.
Interesting hybrid: you're using GDI+ to load image files and create handles to the bitmaps, but then you're using GDI (StretchBlt()) to actually display the image.
Was that intentional? does it work better for you that way?
Quote from: NoCforMe on March 14, 2025, 04:16:01 PMInteresting hybrid: you're using GDI+ to load image files and create handles to the bitmaps, but then you're using GDI (StretchBlt()) to actually display the image.
Was that intentional? does it work better for you that way?
At the time I first created it, I didn't know how to use gdi+ to do that. It worked fine like that, so I kept it.
Besides, I only really needed gdiplus only to load jpg,png,gif.etc. files. (Anything other than bmp's)
Why complicate simplicity?
Quote from: zedd151 on March 14, 2025, 04:36:56 PMQuote from: NoCforMe on March 14, 2025, 04:16:01 PMInteresting hybrid: you're using GDI+ to load image files and create handles to the bitmaps, but then you're using GDI (StretchBlt()) to actually display the image.
Was that intentional? does it work better for you that way?
At the time I first created it, I didn't know how to use gdi+ to do that. It worked fine like that, so I kept it.
Besides, I only really needed gdiplus only to load jpg,png,gif.etc. files. (Anything other than bmp's)
Why complicate simplicity?
thats very helpful jpg,png directly used smaller files than uncompressed .bmp photos and no extra manually work convert files to .bmp's and gifs for cartoon and animations :thumbsup:
Quote from: zedd151 on March 14, 2025, 04:36:56 PMQuote from: NoCforMe on March 14, 2025, 04:16:01 PMInteresting hybrid: you're using GDI+ to load image files and create handles to the bitmaps, but then you're using GDI (StretchBlt()) to actually display the image.
Was that intentional? does it work better for you that way?
At the time I first created it, I didn't know how to use gdi+ to do that. It worked fine like that, so I kept it.
Besides, I only really needed gdiplus only to load jpg,png,gif.etc. files. (Anything other than bmp's)
Why complicate simplicity?
Why indeed?
It turns out that your choice of hybrid processing may be the easier one.
You could use GDI+ to display the image (at a fixed size) after opening it from a file, using
GdipDrawImageRectI() in your WM_PAINT handler instead of
StretchBlt(). In that case, 6 of one, half a dozen of the other.
However, if you wanted to also resize the image dynamically (in the WM_PAINT handler), then it'd take an extra step for GDI+; you'd need to use something like
GdipScaleWorldTransform() first, then use
GdipDrawImageRectI(), whereas with GDI you can use
StretchBlt() to resize and display the image.
Good to know you can mix & match stuff here.
Quote from: NoCforMe on March 15, 2025, 07:40:41 AMGood to know you can mix & match stuff here.
Yes. Before I first tried that, I wasn't certain that it would work. But alas, it did. :biggrin:
One thing that I am not sure about. Would a gdi
plus leak show up in task manager as a
gdi leak? Or some form of
memory leak? Or neither (something else)??
Excellent question.
Wish I could answer it.
Process Explorer?
Quote from: NoCforMe on March 15, 2025, 07:54:31 AMExcellent question.
Wish I could answer it.
Process Explorer?
I might purposely not delete or dispose of any gdiplus related handles, to find out... then wait for a possible crash. All while watching task manager.
Then run the program in olly, if it had crashed in the previous run, to see if and where any exceptions occur. Some basic troubleshooting of a self inflicted injury. :cool: I'll report my findings.
Um, I don't think you're going to get a crash as a consequence of not releasing a few GDI/GDI+ objects. It's going to take a lot more than that to get to any kind of exception or crash due to resource depletion. I suppose you could do something in a loop that consumes lots of handles or other "objects".
Why not do that--not delete stuff--and then just use Task Manager to see how many GDI objects you have each time you run the app?
Quote from: zedd151 on March 15, 2025, 08:09:42 AMI'll report my findings.
Okay, after commenting out the call here
mov eax, lp_gdipBmp
mov eax, [eax] ;; get gdipBmp into eax (from lp_gdipBmp)
; invoke GdipDisposeImage, eax ; dispose gdipBmp
No noticeable difference in gdi objects, no matter if minimized, maximized, or hidden behind other windows.
Arbitrary difference in memory usage. Or I should say either one could be a few hundred kb +- the other version. The version without that call, could be either a few kb more than the version with it, or vice versa. Without any rhyme or reason. Go figure. :rolleyes:
Results of that test inconclusive. Also, no crashes.
Quote from: NoCforMe on March 14, 2025, 04:16:01 PMthen you're using GDI (StretchBlt()) to actually display the image
GuiImage (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1404) "\Masm32\examples\exampl04\car\car.jpg", fit ; uses GdipDrawImageRectI, which stretches the image as desired
Quote from: NoCforMe on March 15, 2025, 07:40:41 AMGood to know you can mix & match stuff here.
I've always thought that Gdi+ handles are different from Gdi handles, but it seems they aren't. Good to know indeed.
Quote from: jj2007 on March 15, 2025, 07:32:37 PMQuote from: NoCforMe on March 15, 2025, 07:40:41 AMGood to know you can mix & match stuff here.
I've always thought that Gdi+ handles are different from Gdi handles, but it seems they aren't. Good to know indeed.
So did a lot of members. There is not a lot of info about that on the forum. Most example code uses either plain gdi or uses gdiplus.
I just tried it as an experiment. Voila! It worked. :azn:
Quote from: jj2007 on March 15, 2025, 07:32:37 PM"\Masm32\examples\exampl04\car\car.jpg", fit ; uses GdipDrawImageRectI, which stretches the image as desired
I didn't see that anywhere in the import names in olly for the 'car' example in the Masm32 SDK, I looked:
Names in car
Address Section Type ( Name Comment
00402000 .rdata Import ( gdi32.CreateCompatibleBitmap
00402004 .rdata Import ( gdi32.CreateCompatibleDC
00402008 .rdata Import ( gdi32.DeleteDC
0040200C .rdata Import ( gdi32.SelectObject
00402010 .rdata Import ( gdi32.BitBlt
00402014 .rdata Import ( gdi32.DeleteObject
00402018 .rdata Import ( gdi32.GetDeviceCaps
00402020 .rdata Import ( kernel32.MulDiv
00402024 .rdata Import ( kernel32.SizeofResource
00402028 .rdata Import ( kernel32.SetLastError
0040202C .rdata Import ( kernel32.LockResource
00402030 .rdata Import ( kernel32.LoadResource
00402034 .rdata Import ( kernel32.FindResourceA
00402038 .rdata Import ( kernel32.GetModuleHandleA
0040203C .rdata Import ( kernel32.GetCommandLineA
00402040 .rdata Import ( kernel32.ExitProcess
00402048 .rdata Import ole32.CoTaskMemFree
0040204C .rdata Import ole32.CoTaskMemAlloc
00402050 .rdata Import ole32.CreateStreamOnHGlobal
00402054 .rdata Import ole32.CoUninitialize
00402058 .rdata Import ole32.CoInitialize
00402060 .rdata Import oleaut32.OleLoadPicture
00402068 .rdata Import ( user32.LoadCursorA
0040206C .rdata Import ( user32.GetSystemMetrics
00402070 .rdata Import ( user32.RegisterClassExA
00402074 .rdata Import ( user32.LoadIconA
00402078 .rdata Import ( user32.GetDC
0040207C .rdata Import ( user32.DefWindowProcA
00402080 .rdata Import ( user32.CreateWindowExA
00402084 .rdata Import ( user32.BeginPaint
00402088 .rdata Import ( user32.UpdateWindow
0040208C .rdata Import ( user32.MessageBoxA
00402090 .rdata Import ( user32.DispatchMessageA
00402094 .rdata Import ( user32.GetMessageA
00402098 .rdata Import ( user32.PostQuitMessage
0040209C .rdata Import ( user32.EndPaint
004020A0 .rdata Import ( user32.ShowWindow
004020A4 .rdata Import ( user32.TranslateMessage
Nor any other gdiplus functions, unless OleLoadPicture does it internally.
That is one of the first examples I had looked at when looking for code to load images other than bitmaps. Seemed like a rather clunky way to load a jpg file, imo.
OK; so now we come to the matter of image quality. Does GDI or GDI+ yield the better image quality? Especially if the image is stretched?
I know that some rendering techniques result in really crappy images, but I can't remember exactly which ones those were.
I have noticed that shrinking a large image with StretchBlt results in crappy quality for some images. There would be black lines at some intervals upon resizing the window smaller (using the size borders). Ill run some tests with screenshots when I get the chance.
I would like to think that gdiplus functions would yield better results, being more modern than the legacy gdi functions. Testing that will also come at some later time.
Here is a quick one using StretchBlt. Original image size 1024x768
shrunk dynamically using the sizing border. (window edge) Not black lines for this image, but... looks like crap.
(https://i.postimg.cc/fT87cSTv/untitled.png)
original zipped and attached
Can you maybe do some side-by-side comparisons? like GDI in one window and GDI+ in the other?
Quote from: NoCforMe on March 16, 2025, 08:51:28 AMCan you maybe do some side-by-side comparisons? like GDI in one window and GDI+ in the other?
Yes, but that will take a little time to get the gdiplus code 'just right'. Time that I don't have today. Maybe in a couple days. Remind me if I don't post something here by Monday or Tuesday regarding quality in gdiplus. I forget a lot of things here lately.
Quote from: sinsi on March 14, 2025, 04:48:14 AMMight try a bigger GIF with more frames next.
I played around with your program today, sinsi.
The gif I used here is not Transparent, I just wanted to see how well it displayed.
Is there any way to correlate the delay per frame in the code, to what the frame delay is in the gif file rather than a 'one size fits all' timer delay?
What I mean is, is there any way to get the information from the gif file, for the delay for each frame? As you might have noticed, I have only a slight clue about gdiplus functions. The MS documentation isn't a great help, either.
Screenshot of program
(https://i.postimg.cc/8kHVJvfz/untitled.png)
Original gif file... I had made this years ago, for use as an avatar on another forum.
(https://i.postimg.cc/Yq9Tvswd/pacman-final.gif)
Is it possible make old moonlander game,but with rotating a image of moonlander,instead of original vectorgraohics ?
Old atari game from 1970"s running on 6502 1.8 mhz
Quote from: daydreamer on March 21, 2025, 06:48:50 AMIs it possible make old moonlander game,but with rotating a image of moonlander,instead of original vectorgraohics ?
If you can get screenshots, sure. Maybe using DosBox or similar?
1. Just make all of the graphics elements into seperate bitmaps {taken from screenshot(s)}
2. Using mspaint or other similar tool to create each frame using the graphics elements created in step 1, incuding the background.
3. Use ImageReady, Gimp or similar program to create the animated .gif file from the indidual bitmaps (created in step 2) that represent the animation frames. There are undoubtedly other tools out now, that can do similar tasks. Even possibly do all of these within the same program.
Similar steps were used in creating the pacman gif file above.
Quote from: zedd151 on March 21, 2025, 04:00:47 AMIs there any way to correlate the delay per frame in the code, to what the frame delay is in the gif file rather than a 'one size fits all' timer delay?
What I mean is, is there any way to get the information from the gif file, for the delay for each frame? As you might have noticed, I have only a slight clue about gdiplus functions. The MS documentation isn't a great help, either.
I started to look into it but lost interest...
invoke GdipGetPropertyItemSize,GpImage,PropertyTagFrameDelay,addr delaysize
invoke GdipGetPropertyItem,GpImage,PropertyTagFrameDelay,delaysize,addr delay
PropertyTagFrameDelay (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions#propertytagframedelay) has more information, among other interesting stuff :biggrin:
Quote from: sinsi on March 21, 2025, 07:15:06 AMI started to look into it but lost interest...
invoke GdipGetPropertyItemSize,GpImage,PropertyTagFrameDelay,addr delaysize
invoke GdipGetPropertyItem,GpImage,PropertyTagFrameDelay,delaysize,addr delay
Thanks sinsi, I'll look into that... eventually. :smiley:
It's not an urgent need, but it might be useful in the future.
Quote from: sinsi on March 21, 2025, 07:15:06 AMPropertyTagFrameDelay (https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions#propertytagframedelay) has more information, among other interesting stuff :biggrin:
Looks vaguely familiar (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1407) :cool:
(https://i.postimg.cc/0bmNWgCb/Gdip-Get-Property-Item-Size.png) (https://postimg.cc/0bmNWgCb)
Quote from: zedd151 on March 21, 2025, 07:06:52 AMQuote from: daydreamer on March 21, 2025, 06:48:50 AMIs it possible make old moonlander game,but with rotating a image of moonlander,instead of original vectorgraohics ?
1. Just make all of the graphics elements into seperate bitmaps {taken from screenshot(s)}
https://nasa3d.arc.nasa.gov/search/lunar (https://nasa3d.arc.nasa.gov/search/lunar)
I have several 3d programs,so i can make old 3d pre-rendered graphics from 3d models, like baldurs gate
If you look thru 3d models, background could be made from one of landing sites
If it is your own programs daydreamer (that you have the source code for), the simplest way for you would be to output .bmp files at certain intervals rather than the method I mentioned earlier. Then work with those .bmp files to compile your gif animation from.
That would effectively remove at least some of the work to be done manually.
Keep in mind that even compressed (optimized) .gif animations can get large (in file size) very fast.
Generally the frame rate should be between 10-15 frames per second. Along with any optimizations, this should help keep the file size down to an acceptable level.
Huge (in pixel dimensions) .gif animations tend to take much longer to display, and use up much more memory when doing so. (I have at some point, tested using full screen sized .gif animations; 640x480, 800x600, etc.)
The results are much slower animations regardless of desired frame rate. At least that has been my experience in the past. (Almost 20 years ago)
Have fun! :biggrin:
Later:
With today's faster processors and computers with tons of memory, results these days might be better, as far as using and displaying .gif animations with large dimensions and file sizes.