The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Farabi on June 10, 2010, 09:18:29 PM

Title: My Code does not work anymore
Post by: Farabi on June 10, 2010, 09:18:29 PM

include gdiplus.inc
includelib gdiplus.lib

   GdiplusStartupInput STRUCT
      GdiplusVersion           DWORD ?
      DebugEventCallback       DWORD ?
      SuppressBackgroundThread DWORD ?
      SuppressExternalCodecs   DWORD ?
    GdiplusStartupInput ENDS

    ImageCodecInfo STRUCT
      ClassID           CLSID <>
      FormatID          GUID <>
      CodecName         DWORD ?
      DllName           DWORD ?
      FormatDescription DWORD ?
      FilenameExtension DWORD ?
      MimeType          DWORD ?
      Flags             DWORD ?
      Version           DWORD ?
      SigCount          DWORD ?
      SigSize           DWORD ?
      SigPattern        DWORD ?
      SigMask           DWORD ?
    ImageCodecInfo ENDS
.data
ALIGN 16
Sprite_Simd_Mask_RVB_unpck_1 DWORD 000010001h,000000001h
Sprite_Simd_Mask_RVB_unpck_255 DWORD 000FF00FFh,0000000FFh
   
.data?
      token               dd 0
      image               dd 0
      numEncoders         dd 0
      sizeImageCodecInfo  dd 0
      pImageCodecInfo     dd 0
      gdipsi              GdiplusStartupInput <1>  ; version must be 1

.code
fPicSaveToFileAsJpg proc uses esi edi lpFileName:dword
   LOCAL str_len,tmp_esi:dword
   LOCAL buff[256],buff2[256],buff3[256]:dword
   
   invoke exist,lpFileName
   .if eax==0
      invoke MessageBox,0,0,0,0
      ret
   .endif
   
   invoke GdiplusStartup, ADDR token, ADDR gdipsi, NULL
      invoke MultiByteToWideChar,0,0,lpFileName,-1,addr buff3,1024
      invoke GdipLoadImageFromFile, addr buff3, ADDR image
      invoke GdipGetImageEncodersSize, ADDR numEncoders,ADDR sizeImageCodecInfo
      invoke mAlloc,sizeImageCodecInfo
      .if eax==0
         invoke MessageBox,0,CADD("Not Enough memory/Memori tidak cukup"),0,0
         jmp error
      .endif
      mov pImageCodecInfo,eax
      invoke GdipGetImageEncoders, numEncoders, sizeImageCodecInfo,pImageCodecInfo
            invoke lstrlen,lpFileName
            mov str_len,eax
            sub str_len,2
            invoke lstrcpyn,addr buff,lpFileName,str_len
            invoke lstrcat,addr buff,CADD("jpg")
           
            assume esi:ptr ImageCodecInfo
               mov ecx,numEncoders
               mov esi,pImageCodecInfo
               @@:
               push ecx
               push esi
               mov tmp_esi,esi
               invoke WideCharToMultiByte,0,0,[esi].MimeType,-1,addr buff2,1024,0,0
               invoke lstrcmp,addr buff2,CADD("image/jpeg")
               .if eax==0
                  invoke MultiByteToWideChar,0,0,addr buff,-1,addr buff3,1024
                  invoke GdipSaveImageToFile, image, addr buff3,tmp_esi, NULL
                  pop esi
                  pop ecx
                  jmp error
               .endif
               pop esi
               add esi, SIZEOF ImageCodecInfo
               pop ecx
               dec ecx
               jnz @b
            assume esi:nothing
     
      error:     
   invoke GdipDisposeImage, image
   invoke GdiplusShutdown, token
   invoke GlobalFree,pImageCodecInfo
   
   ret
fPicSaveToFileAsJpg endp


It worked before, but now when it hit  invoke GdipLoadImageFromFile, addr buff3, ADDR image it crashed. Why?

How I used to use

invoke fPicSaveToFileAsJpg,CADD("Test.bmp")


It will generate a file named test.jpg
Title: Re: My Code does not work anymore
Post by: baltoro on June 11, 2010, 12:03:51 AM
MultiByteToWideChar just preceeding GdipLoadImageFromFile.
A simple mistake, you must have copied and pasted the code, because you do the same thing later.   
Just out of curiosity, what's the advantage of doing this in Assembly? You'd have better type checking, and the code for checking return values would be easier in C++.
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 12:09:41 AM
Quote from: baltoro on June 11, 2010, 12:03:51 AM
Just out of curiosity, what's the advantage of doing this in Assembly? You'd have better type checking, and the code for checking return values would be easier in C++.

Because that is the only thing I can do.

So MultiByteToWideChar is the main problem?
Title: Re: My Code does not work anymore
Post by: baltoro on June 11, 2010, 12:18:35 AM
If you read the documentation: MultiByteToWideChar (http://msdn.microsoft.com/en-us/library/dd319072(VS.85).aspx), that last parameter, if it is not the size of your buffer, the function fails. Hell, I've done it myself numerous times. That's why checking return values before you make the graphics call will keep you from crashing.   
Lately, I have been using DirectX, and so, am unfamiliar with the GDI+ APIs.
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 12:22:41 AM
So the problem is not on GdipLoadImageFromFile?
That is weird, it worked before.
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 01:33:53 AM
Vortex, I need you here  :green
Title: Re: My Code does not work anymore
Post by: aker on June 11, 2010, 01:39:53 AM
Why is Vortex?
Title: Re: My Code does not work anymore
Post by: MichaelW on June 11, 2010, 07:21:42 AM
Onan,

Your code works for me under Windows 2000. I did change mAlloc to crt_malloc and GlobalFree to crt_free, because I didn't have time to determine what mAlloc is. When GdipLoadImageFromFile "crashes" what is the return status? See the Status enumeration  here (http://com.it-berater.org/gdiplus/noframes/GdiPlus_enumerations.htm).

Title: Re: My Code does not work anymore
Post by: donkey on June 11, 2010, 09:39:08 AM
Hi,

I'm not completely sure why you are searching the codecs for JPEG, it is always found on Windows and has a fixed GUID:

From GdiPlusImaging.h in the GoAsm header project:
#define GUID_ImageEncoderBMP <0x557cf400, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderJPEG <0x557cf401, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderGIF <0x557cf402, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderEMF <0x557cf403, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderWMF <0x557cf404, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderTIFF <0x557cf405, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderPNG <0x557cf406, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>
#define GUID_ImageEncoderICON <0x557cf407, 0x1a04, 0x11d3, <0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e>>


You'll find that your proggy is working hard just to yield a predefined GUID.

Edgar
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 12:09:06 PM
Quote from: MichaelW on June 11, 2010, 07:21:42 AM
Onan,

Your code works for me under Windows 2000. I did change mAlloc to crt_malloc and GlobalFree to crt_free, because I didn't have time to determine what mAlloc is. When GdipLoadImageFromFile "crashes" what is the return status? See the Status enumeration  here (http://com.it-berater.org/gdiplus/noframes/GdiPlus_enumerations.htm).



There is no return status, because it doesnot execute  GdipLoadImageFromFile completely. On the debugger the ebx point to 0 memory address and it tried to access the value from it. Since the debugger stopped on 0x07000000 address or something I guess the dll tried to access a wrong address. Dont know what is my mistake. Can you upload your .lib file for the Win2000?
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 12:51:28 PM
Okay I got the return code from the GDIStart function
Quote
UnsupportedGdiplusVersion   = 17,


What should I do?
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 01:00:09 PM
Okay I got where is my mistake is, craps.  :red

Quote
fPicSaveToFileAsJpg proc uses esi edi lpFileName:dword
   LOCAL str_len,tmp_esi:dword
   LOCAL buff[256],buff2[256]
   LOCAL  buff3[256]:dword
   
   invoke exist,lpFileName
   .if eax==0
      invoke MessageBox,0,0,0,0
      ret
   .endif
   
   invoke MultiByteToWideChar,0,0,lpFileName,-1,addr buff3,512
  mov      eax,OFFSET gdipsi
   mov      GdiplusStartupInput.GdiplusVersion[eax],1
   invoke GdiplusStartup, ADDR token, eax, NULL

  ; mov ecx,eax
  ; invoke dw2a,ecx,addr buff
;  invoke MessageBox,0,addr buff,0,0
;   ret
      invoke GdipLoadImageFromFile, addr buff3, ADDR image
      invoke GdipGetImageEncodersSize, ADDR numEncoders,ADDR sizeImageCodecInfo
      invoke mAlloc,sizeImageCodecInfo
      .if eax==0
         invoke MessageBox,0,CADD("Not Enough memory/Memori tidak cukup"),0,0
         jmp error
      .endif
      mov pImageCodecInfo,eax
      invoke GdipGetImageEncoders, numEncoders, sizeImageCodecInfo,pImageCodecInfo
            invoke lstrlen,lpFileName
            mov str_len,eax
            sub str_len,2
            invoke lstrcpyn,addr buff,lpFileName,str_len
            invoke lstrcat,addr buff,CADD("jpg")
           
            assume esi:ptr ImageCodecInfo
               mov ecx,numEncoders
               mov esi,pImageCodecInfo
               @@:
               push ecx
               push esi
               mov tmp_esi,esi
               invoke WideCharToMultiByte,0,0,[esi].MimeType,-1,addr buff2,1024,0,0
               invoke lstrcmp,addr buff2,CADD("image/jpeg")
               .if eax==0
                  invoke MultiByteToWideChar,0,0,addr buff,-1,addr buff3,1024
                  invoke GdipSaveImageToFile, image, addr buff3,tmp_esi, NULL
                  pop esi
                  pop ecx
                  jmp error
               .endif
               pop esi
               add esi, SIZEOF ImageCodecInfo
               pop ecx
               dec ecx
               jnz @b
            assume esi:nothing
     
      error:     
   invoke GdipDisposeImage, image
   invoke GdiplusShutdown, token
   invoke GlobalFree,pImageCodecInfo
   
   ret
fPicSaveToFileAsJpg endp
Title: Re: My Code does not work anymore
Post by: baltoro on June 11, 2010, 03:49:19 PM
...Oops,...   
...I need brain surgery,...
...Sorry, Onan.
Thank god Edgar solved the problem.
Title: Re: My Code does not work anymore
Post by: clive on June 11, 2010, 04:36:36 PM
Now you just have to handle the error paths a little better.<G> My code would be a lot more clean/compact if I could really ignore them.
Title: Re: My Code does not work anymore
Post by: dedndave on June 11, 2010, 06:25:24 PM
Onan, does that routine give you the opportunity to set the "quality" and "smoothing" values for JFIF compression ?
Title: Re: My Code does not work anymore
Post by: Farabi on June 11, 2010, 11:01:47 PM
Quote from: dedndave on June 11, 2010, 06:25:24 PM
Onan, does that routine give you the opportunity to set the "quality" and "smoothing" values for JFIF compression ?

No, not yet.
Title: Re: My Code does not work anymore
Post by: donkey on June 11, 2010, 11:07:24 PM
Hi Onan,

There really is no need whatsoever to search the codecs, it is a predefined CLSID for JPEG. Also you are doing a lot of unicode conversion which can be painfully slow, the shlwapi API can replace a bit of it. This should work in MASM though I have not tried it:

.CONST
sCLSID_JPEG textequ <{557cf401H, 1a04H, 11d3H,{09aH, 073H, 000H, 000H, 0f8H, 01eH, 0f3H, 02eH}}>

.DATA
CLSIDImageEncoderJPEG GUID sCLSID_JPEG
JPEGExt DB ".",0,"J",0,"P",0,"G",0,0,0

.CODE
; ...
invoke MultiByteToWideChar,0,0,lpFileName,-1,addr buff3,512
; no need to dereference this, it is the first member of the structure
mov    DWORD PTR gdipsi, 1
; start GDIPlus
invoke GdiplusStartup, ADDR token, offset gdipsi, NULL

; Load the image
invoke GdipLoadImageFromFile, addr buff3, ADDR image

; rename the extension
invoke PathRenameExtensionW, ADDR buff3,offset JPEGExt

; Save the image
invoke GdipSaveImageToFile, image, addr buff3,offset CLSIDImageEncoderJPEG, NULL

; Free the image
invoke GdipDisposeImage, image
; Release GDIPlus
invoke GdiplusShutdown, token
Title: Re: My Code does not work anymore
Post by: Vortex on June 12, 2010, 09:30:36 AM
Hi Onan,

Sorry for being late. OK, here is my code converting a bitmap image in memory to .jpg :


include    GDIpBmpToJPG.inc

.data
jpegFile            db 'test.jpg',0
ImgType             db 'image/jpeg',0
message             db 'BMP file converted to JPG',0
caption             db 'GDI+ demo',0
ImgQuality          dd  90
_EncoderQuality     GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,05h,0e7h,0ebh>>

.data?
StartupInfo         GdiplusStartupInput <?>
buffer              db 32 dup(?)
pImageCodecInfo     dd ?
token               dd ?
BmpImage            dd ?
eps                 EncoderParameters <?>

.code

start:

    mov         eax,OFFSET StartupInfo
    mov         GdiplusStartupInput.GdiplusVersion[eax],1
                                                 ; must be always seto to 1
    invoke      GdiplusStartup,ADDR token,ADDR StartupInfo,0

    mov         eax,OFFSET pImage
    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     UnicodeStr,ADDR jpegFile,ADDR buffer
    mov        esi,OFFSET eps
    mov        EncoderParameters.Count[esi],1
    lea        ecx,[esi+EncoderParameters.Parameter.pGUID]
    invoke     MemCopy,ADDR _EncoderQuality,ecx,16    ; copy the GUID ot the correct address
    mov        EncoderParameters.Parameter.vType[esi],EncoderParameterValueTypeLong
    mov        EncoderParameters.Parameter.NumberOfValues[esi],1
                                                ; we have only one EncoderParameter structure
    mov        EncoderParameters.Parameter.value[esi],OFFSET ImgQuality
                                                ; set the JPEG compression level
    invoke     GetEncoderClsid,ADDR ImgType,ADDR pImageCodecInfo
                                                ; get the class identifier (CLSID) of the encoder
                                                ; The encoder can be bmp,jpeg,gif,tiff or png

    invoke     GdipSaveImageToFile,BmpImage,ADDR buffer,eax,ADDR eps
                                                ; save the image file

    invoke     VirtualFree,pImageCodecInfo,0,MEM_RELEASE

    invoke     GdipDisposeImage,BmpImage        ; release the image
    invoke     GdiplusShutdown,token            ; shutdown the GDI+ system
    invoke     MessageBox,0,ADDR message,ADDR caption,MB_OK
    invoke     ExitProcess,0

GetEncoderClsid PROC USES ebx edi sMimeType:DWORD,pMem:DWORD

LOCAL numEncoders:DWORD
LOCAL nSize:DWORD
LOCAL _buffer[32]:BYTE

    invoke     GdipGetImageEncodersSize,ADDR numEncoders,ADDR nSize
    invoke     VirtualAlloc,0,nSize,MEM_COMMIT,PAGE_READWRITE
    mov        edi,eax
    mov        eax,pMem                             ; = pImageCodecInfo
    mov        DWORD PTR [eax],edi
    invoke     GdipGetImageEncoders,numEncoders,nSize,edi
    invoke     UnicodeStr,sMimeType,ADDR _buffer
    mov        ebx,numEncoders
@@:
    invoke     StrCmpW,ADDR _buffer,ImageCodecInfo.MimeType[edi]
    test       eax,eax
    jnz        @f
    sub        ebx,1
    add        edi,SIZEOF ImageCodecInfo
    jmp        @b
@@:
    mov        eax,edi                              ; = lea    eax,[edi+ImageCodecInfo.Clsid]
    ret

GetEncoderClsid ENDP

END start

Title: Re: My Code does not work anymore
Post by: Vortex on June 12, 2010, 09:40:48 AM
Hi Onan,

My code can set the convertion quality of the .jpg but donkey's code is preferable as it's easier to maintain and use. Coding the codecs part of my application was not an easy task.
Title: Re: My Code does not work anymore
Post by: donkey on June 12, 2010, 12:37:16 PM
Hi Vortex,

Nice code, have you thought about allowing for a change in color depth as well ? I do it in some of my GDIP proggies. Here's the appropriate code segment for changing it (in GoAsm syntax - sorry). Allowable values for bitdepth are 8, 16,24, 32, 48 and 64 as well as -1 for no conversion, some depths are only available to bitmaps see the comments for details.

// The largest palette size is 1024 bytes so we allocate that
invoke GdipAlloc,1024 + SIZEOF ColorPalette
mov [pPal],eax

cmp D[bitdepth],-1
je >>.NoConvert

cmp D[bitdepth],8
jne >
// Since this is an indexed type use a large palette to find the closest colors
// it will be reduced to 256 colors by the conversion function
mov D[PalType],PaletteTypeFixedHalftone27
mov D[ImgFmt],PixelFormat8bppIndexed
jmp >>.Convert
:
cmp D[bitdepth],24
jne >
mov D[PalType],PaletteTypeFixedHalftone27
mov D[ImgFmt],PixelFormat24bppRGB
jmp >>.Convert
:
cmp D[bitdepth],32
jne >
mov D[PalType],PaletteTypeFixedHalftone256
mov D[ImgFmt],PixelFormat32bppRGB
jmp >>.Convert
:

cmp D[format],GDIP_IMAGE_BMP
jne >>.NoConvert
// Bitmap only color depths
cmp D[bitdepth],16
jne >
// There is no standard 16Bpp palette so we use a 24 Bpp. It's not optimal but easier.
mov D[PalType],PaletteTypeFixedHalftone27
mov D[ImgFmt],PixelFormat16bppRGB555
jmp >>.Convert
:
cmp D[bitdepth],48
jne >
mov D[PalType],PaletteTypeFixedHalftone256
mov D[ImgFmt],PixelFormat48bppRGB
:
cmp D[bitdepth],64
jne >.NoConvert
mov D[PalType],PaletteTypeFixedHalftone256
mov D[ImgFmt],PixelFormat64bppARGB

.Convert
invoke GdipInitializePalette,[pPal], [PalType], 0, TRUE, NULL

invoke GdipBitmapConvertFormat,[pImage],[ImgFmt], DitherTypeNone,[PalType],[pPal],50.0

.NoConvert


The PalletteType enumeration is found in GdiplusPixelFormats.h of the header project include gdiplus.h. This segment requires GDIP version 1.1.

Edgar
Title: Re: My Code does not work anymore
Post by: Vortex on June 12, 2010, 08:37:14 PM
Hi donkey,

Thanks for your code. The color depth is another important parameter and GDI+ can set this value. No problem with the syntax, it's fine :U
Title: Re: My Code does not work anymore
Post by: Farabi on June 13, 2010, 09:45:44 PM
Well I guess I will put all of this into one function named "fSaveFileAs".
It can save from one format to another format.