News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Has anyone done any work in GDI+ recently ?

Started by hutch--, October 16, 2016, 10:13:35 AM

Previous topic - Next topic

hutch--

Yes, that makes sense, thanks for the confirmation.

mabdelouahab

hutch--
Full Example: Crystal ball from resource without creating a temp file:crystal-ball.zip * It could not be included in the attachments because it is larger than 512

hutch--


jj2007

I took another road, work in progress (still severe memory leaks) but so far it looks OK, i.e. the exe runs on XP and Win7-64 alike. Grateful for tests with other OS versions :icon14:

It requires a hilarious workaround, though, to remain compatible with XP:
QuotePrior to Windows Vista, SHCreateMemStream was not included in the public Shlwapi.h file, nor was it exported by name from Shlwapi.dll. To use it on earlier systems, you must call it directly from the Shlwapi.dll file as ordinal 12.

The original bmp file is 922270 bytes, the exe has 270kB.

GuruSR

Just a thought, though have you looked on...  SourceForge for the FreeImage library?

GuruSR.
Learned 68k Motorola Asm instruction set in 30 minutes on the way to an Amiga Developer's Forum meeting.
Following week wrote a kernel level memory pool manager in 68k assembler for fun.

FORTRANS

Hi,

Quote from: jj2007 on October 20, 2016, 01:18:43 PM
I took another road, work in progress (still severe memory leaks) but so far it looks OK, i.e. the exe runs on XP and Win7-64 alike. Grateful for tests with other OS versions

   Windows XP and 8.1.  There was an error message in the console
output on XP.  Output attached.  Didn't like my P-III as always. <g>

Regards,

Steve N.

HSE

Hi JJ!! 7-32

Not skat.zip for recompilation.
Equations in Assembly: SmplMath

hutch--

I am actually happy enough with the technique of storing the PNG file as a resource, writing it as a file then loading the file with the GDI+ function. I have used the technique in the past and what makes it viable is the OS disk cache and the time lag between writing the file, reading it with the GDI+function then deleting the file is so short that it never reaches the disk, its a purely in memory operation that is easily fast enough.

jj2007

Quote from: GuruSR on October 20, 2016, 02:03:07 PM
Just a thought, though have you looked on...  SourceForge for the FreeImage library?

A DLL with 5.5MB :dazzled:

I feel already ashamed for the 20k overhead of a MasmBasic hello world :redface:

@HSE+FORTRANS: Thanks for testing. I have to investigate into the SelectObject failure. Does the image show properly?

@Hutch: Correct but still, if you can avoid writing to a file, it would be even better. Zipping a BMP has about the same compression as converting to PNG, sometimes more, sometimes less. So unzipping to bmp in memory is a valid option imho. However, GdipCreateBitmapFromStream as used by mabdelouahab seems even better - compliments :t

@mabdelouahab: How (or rather: why) does this line work?
.invoke GdipCreateBitmapFromScan0,rect.right,rect.bottom,0,PixelFormat32bppPARGB,0,&bitmap

According to the docs, the 0 should be a pointer to the pixels ::)

FORTRANS

Hi,

Quote from: jj2007 on October 21, 2016, 02:10:13 AM
@HSE+FORTRANS: Thanks for testing. I have to investigate into the SelectObject failure. Does the image show properly?

   I think so.  On the XP machine there was a lot of flickering when
the window was moved.  But it is a slower machine.

HTH,

Steve N.

HSE

JJ : image look good. I can't see As column. It's no posible to increase window size beyond Kings.
Equations in Assembly: SmplMath

jj2007

Thanks. The images show, so it's working in principle. I've spent some time on a weird problem:  if 1 ; ##### no leak but bmp doesn't work, and jpg fails often #####
push rv(SizeofResource, 0, esi)
push rv(LoadResource, 0, esi) ; src
mov hGlobal, rv(GlobalAlloc, GMEM_MOVEABLE, stack[4]) ; dest
invoke GlobalLock, eax
push eax
call MbCopy ; invoke MbCopy, dest, src, bytes
invoke GlobalUnlock, hGlobal
invoke CreateStreamOnHGlobal, hGlobal, 0, addr iStream
invoke GdipCreateBitmapFromStream, iStream, ebx ; addr hBitmap; GdipBitmapLockBits?
invoke GlobalFree, hGlobal
  else ; ##### bmp works, but leaks approx size of bitmaps #####
push rv(SizeofResource, 0, esi) ; invoke ShlWapi:SHCreateMemStream, pBuffer, bytes
push rv(LoadResource, 0, esi)
call GdiSI.jjMemStream ; get *IStream; use global GdiSI because ebx points to bitmap
invoke GdipCreateBitmapFromStream, eax, ebx ; addr hBitmap; GdipBitmapLockBits
  endif


The upper version works fine with png, and it doesn't leak, but it fails always with bmp and sometimes with jpg.
The lower version works great, but to prevent leaking, the stream needs to be released in the right moment (MS Social):
QuoteUnfortunately GDI+ does tend to hold files open for images for the duration of the image.  This is because GDI+ lazy decompresses the image (i.e. it doesn't actually decompress the image until the DrawImage call), which means it keeps your stream open.

There is a related post by Siekmanski that inspired me :t

Siekmanski

iStream pointer must be empty before use.
I use some kind of a SAFE_RELEASE,

.if iStream != 0
mov   ecx,iStream
push  ecx
mov   eax,[ecx]
call  DWORD PTR [eax + 8] ; IUnknown::Release
mov   iStream,0
.endif
.
Creative coders use backward thinking techniques as a strategy.

jj2007

Yes, that did the trick. Just tested it on my XP VM, and noticed that in one occasion, SelectObject oldpen returns 0, which was flagged by my debugging routine. GetLastError reveals that there was no error, though (meaning XP has initially no pen selected). So I got curious and found this in Raymond Chen's What are the dire consequences of not selecting objects out of my DC?:
QuoteGDI will sometimes (not always) lie and say, "Sure, I deleted your object." It didn't actually delete it, because it's still selected into a DC, but it also ties a string around its finger, and when the object is finally deselected, GDI will say, "Oh, wait, I was supposed to delete this object," and perform the deletion.
::)

Vortex

Here is my GdipCreateBitmapFromStream example. It displays a PNG image loaded from file into memory :

    .IF uMsg==WM_CREATE

        invoke  GlobalAlloc,GMEM_MOVEABLE,PNG_IMG_SIZE
        mov     hMem,eax

        invoke  GlobalLock,eax
        mov     pMem,eax

        invoke  ReadFileToMem,ADDR filename,eax

        mov     eax,OFFSET StartupInfo
        mov     GdiplusStartupInput.GdiplusVersion[eax],1
        mov     GdiplusStatus,eax

        invoke  GdiplusStartup,ADDR token,ADDR StartupInfo,0
        invoke  CreateStreamOnHGlobal,hMem,FALSE,ADDR pStream
        invoke  GdipCreateBitmapFromStream,pStream,ADDR BmpImage

        invoke  GdipCreateHBITMAPFromBitmap,BmpImage,ADDR hBitmap,0