flat assembler
Message board for the users of flat assembler.

Index > Tutorials and Examples > JPEG screenshot with GDI+

Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8357
Location: Kraków, Poland
Tomasz Grysztar 10 Jul 2009, 15:51
Today I have made a small snippet demonstrating how to make a screenshot and save it to JPEG file with the GDI+ library (available since XP, though you can get a redistributable for ealier versions of Windows, too).
It displays no error messages in case of any failure, however it does free the resources appropriately in each case, so it's easy to modify it to get the full and proper error handling.
Code:
format PE GUI 4.0

include 'win32w.inc'

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

struct ImageCodecInfo
  Clsid      db 16 dup ?
  FormatID       db 16 dup ?
  CodecName      dd ?
  DllName       dd ?
  FormatDescription dd ?
  FilenameExtension dd ?
  MimeType      dd ?
  Flags         dd ?
  Version       dd ?
  SigCount      dd ?
  SizeSize      dd ?
  SigPattern            dd ?
  SigMask       dd ?
ends

section '.text' code readable executable

entry $

       invoke  GdiplusStartup,token,input,NULL
     test    eax,eax
     jnz     exit

    invoke  GdipGetImageEncodersSize,encoders_count,encoders_size
       test    eax,eax
     jnz     gdiplus_shutdown
    invoke  VirtualAlloc,0,[encoders_size],MEM_COMMIT,PAGE_READWRITE
    test    eax,eax
     jz      gdiplus_shutdown
    mov     ebx,eax
     invoke  GdipGetImageEncoders,[encoders_count],[encoders_size],ebx
   test    eax,eax
     jnz     gdiplus_shutdown
    scan_encoders:
  mov     esi,[ebx+ImageCodecInfo.MimeType]
   mov     edi,encoder_mimetype
        mov     ecx,11
      repe    cmpsw
       je      encoder_found
       add     ebx,sizeof.ImageCodecInfo
   dec     [encoders_count]
    jnz     scan_encoders
       ; no encoder found
  jmp     gdiplus_shutdown
     encoder_found:
 lea     esi,[ebx+ImageCodecInfo.Clsid]
      mov     edi,encoder_clsid
   mov     ecx,4
       rep     movsd
       invoke  VirtualFree,ebx,0,MEM_RELEASE

   invoke  GetDC,HWND_DESKTOP
  test    eax,eax
     jz      gdiplus_shutdown
    mov     esi,eax
     invoke  GetSystemMetrics,SM_CYSCREEN
        mov     [screen_height],eax
 invoke  GetSystemMetrics,SM_CXSCREEN
        mov     [screen_width],eax
  invoke  CreateCompatibleBitmap,esi,[screen_width],[screen_height]
   test    eax,eax
     jz      release_desktop_dc
  mov     ebx,eax
     invoke  CreateCompatibleDC,esi
      test    eax,eax
     jz      delete_bitmap
       mov     edi,eax
     invoke  SelectObject,edi,ebx
        test    eax,eax
     jz      delete_dc
   invoke  BitBlt,edi,0,0,[screen_width],[screen_height],esi,0,0,SRCCOPY
       test    eax,eax
     jz      delete_dc

       invoke  GdipCreateBitmapFromHBITMAP,ebx,NULL,gdip_bitmap
    test    eax,eax
     jnz     delete_dc

       invoke  GdipSaveImageToFile,[gdip_bitmap],file_name,encoder_clsid,NULL

  invoke  GdipDisposeImage,[gdip_bitmap]
  delete_dc:
  invoke  DeleteObject,edi
  delete_bitmap:
    invoke  DeleteObject,ebx
  release_desktop_dc:
       invoke  ReleaseDC,HWND_DESKTOP,esi
  gdiplus_shutdown:
       invoke  GdiplusShutdown,[token]
  exit:
      invoke  ExitProcess,0


section '.data' data readable writeable

  file_name du 'test.jpg',0

  encoder_mimetype du 'image/jpeg',0
  encoder_clsid db 16 dup ?

  input GdiplusStartupInput 1
  token dd ?
  memdc dd ?
  gdip_bitmap dd ?

  encoders_count dd ?
  encoders_size dd ?

  screen_width dd ?
  screen_height dd ?

section '.rdata' data readable

data import

  library kernel32,'KERNEL32.DLL',\
      user32,'USER32.DLL',\
    gdi32,'GDI32.DLL',\
      gdiplus, 'GDIPLUS.DLL'

  include 'api\kernel32.inc'
  include 'api\user32.inc'
  include 'api\gdi32.inc'

  import  gdiplus,\
        GdiplusStartup,'GdiplusStartup',\
        GdiplusShutdown,'GdiplusShutdown',\
      GdipGetImageEncodersSize,'GdipGetImageEncodersSize',\
    GdipGetImageEncoders,'GdipGetImageEncoders',\
    GdipSaveImageToFile,'GdipSaveImageToFile',\
      GdipDisposeImage,'GdipDisposeImage',\
    GdipCreateBitmapFromHBITMAP,'GdipCreateBitmapFromHBITMAP'

end data    
Post 10 Jul 2009, 15:51
View user's profile Send private message Visit poster's website Reply with quote
pete



Joined: 20 Apr 2009
Posts: 110
pete 10 Jul 2009, 15:59
Thank you for the example!
Post 10 Jul 2009, 15:59
View user's profile Send private message Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22 10 Jul 2009, 18:20
Works on my WinXP64.

I'd suggest you add some comments to the code and have it placed in the FASM examples section.
Post 10 Jul 2009, 18:20
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
eskizo



Joined: 22 Nov 2005
Posts: 59
eskizo 10 Jul 2009, 19:11
perfect job! thankyou
Post 10 Jul 2009, 19:11
View user's profile Send private message Reply with quote
heizzpep



Joined: 03 Jul 2012
Posts: 4
heizzpep 09 Jul 2012, 06:22
works on my win7 x64 and x86.
very nice thx!
Post 09 Jul 2012, 06:22
View user's profile Send private message Reply with quote
hopcode



Joined: 04 Mar 2008
Posts: 563
Location: Germany
hopcode 09 Jul 2012, 07:51
mmmh, vista64 ok, i like open source that works! Wink
it should be packed in the main package.

_________________
⠓⠕⠏⠉⠕⠙⠑
Post 09 Jul 2012, 07:51
View user's profile Send private message Visit poster's website Reply with quote
bzdashek



Joined: 15 Feb 2012
Posts: 147
Location: Tolstokvashino, Russia
bzdashek 10 Jul 2012, 21:13
Cool story, no need in those libraries. Thanks
Post 10 Jul 2012, 21:13
View user's profile Send private message Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 12 Jul 2012, 11:01
Weird thing is that nothing else besides TIFF and JPEG are supported. What about BMP, PNG, GIF? Do we need to make anything special for that?
EDIT: Sorry, I already found the bug. Line 49 says: mov ecx,11, but instead should say mov ecx,(encoder_clsid-encoder_mimetype) shr 1 or something.
Post 12 Jul 2012, 11:01
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
wolf



Joined: 28 Sep 2003
Posts: 11
wolf 06 Feb 2013, 16:03
Thanks a lot! very useful code! I just tried it out.
The line ecx=11 should be ecx=strlen(encoder_mimetype)+1 -- image/tiff / jpeg is 11 then -- bmp /gif / png = 10

But 10 works for all possible mimetypes for the moment.
The MessageBox shows all 5 possible mimetypes when you define
encoder_mimetype du 'image/png', which is the last one or a non existing one like du 'image/abc'.

Code:
scan_encoders:
     mov esi,[ebx+ImageCodecInfo.MimeType]
     mov edi,encoder_mimetype

     invoke MessageBox,0,esi,0,0

     mov ecx,10
     repe cmpsw
     je .encoder_found
      
Post 06 Feb 2013, 16:03
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.