News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Bare Minimum GDIplus code to save different Image Types.

Started by Siekmanski, April 21, 2020, 06:08:10 AM

Previous topic - Next topic

nidud

#15
deleted

Siekmanski

I think the JPG quality encoder parameters for 64 bit are organized in an other way as in 32 bit code?
Creative coders use backward thinking techniques as a strategy.

nidud

#17
deleted

Siekmanski

This is my first work in 64 bit coding.  :biggrin:
Did the same direct approach as in my 32 bit GdiPlus examples but it failed.
Don't know if the EncoderParameters object is different in 64 bit.
I'm not sure if I did the addressing of the pointer to the JpgQualityLevel parameter value correctly....

   mov   JpgQualityLevel,10
   lea   eax,JpgQualityLevel
   mov   Qptr,eax      

It saves a jpg file but the Encoder Quality has no effect.
Tried all kind of alignments for the EncoderParameters object.

@nidud
Could you make a memory dump of the ( filled ) EncoderParameters object of your working example?
So I can compare the values and alignments.
Creative coders use backward thinking techniques as a strategy.

nidud

#19
deleted

hutch--

I tried a whole collection of variations on the JPG code in 64 bit but could not get the extra parameters to work. This is the library format that I got to work but no extra parameters for the last argument,

    invoke GdipSaveImageToFile,hGdip,L(filename),pCLSID,NULL

Algo

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

SaveAsJPGx proc bmHandle:QWORD,filename:QWORD

    LOCAL hGdip  :QWORD
    LOCAL pCLSID :QWORD

  .data
    CLSID_ImageType1 GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>>
  .code

    mov pCLSID, ptr$(CLSID_ImageType1)

    invoke GdipCreateBitmapFromHBITMAP,bmHandle,0,ptr$(hGdip)
    invoke GdipSaveImageToFile,hGdip,L(filename),pCLSID,NULL
    invoke GdipDisposeImage,hGdip

    ret

SaveAsJPGx endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

Siekmanski

nidud, thank you very much for the list dump.  :thumbsup:
It made things clear to me and now I did succeed to do the direct approach in 64 bit as well.

@Hutch, problem solved.  :biggrin:

EDIT: source code update


    include \masm32\include64\masm64rt.inc

.data?
pImage                  dq ?
JpgQualityLevel         dd ?
FilenameW               dw  MAX_PATH dup (?)

.data
CLSID_ImageType         GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>> ; JPG image type
JPG_EncoderParameters   dq 1    ; Number of parameters in this structure
CLSID_EncoderQuality    GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>
                        dd 1    ; Number of the parameter values
                        dd 4    ; ValueTypeLong
                        dq offset JpgQualityLevel

szWomanImage            db "Woman.bmp",0
szWoman                 db "Woman.jpg",0
   
.code
entry_point proc

    conout lf,"  64bit GDIplus Jpg Quality Encoder",lf,lf

    GdiPlusBegin                    ; initialise GDIPlus

    invoke  MultiByteToWideChar,CP_ACP,0,addr szWomanImage,-1,addr FilenameW,MAX_PATH-1
    invoke  GdipCreateBitmapFromFile,addr FilenameW,addr pImage
    test    rax,rax
    jnz     Done
   
    mov     JpgQualityLevel,50      ; 0 to 100

    invoke  MultiByteToWideChar,CP_ACP,0,addr szWoman,-1,addr FilenameW,MAX_PATH-1
    invoke  GdipSaveImageToFile,pImage,addr FilenameW,addr CLSID_ImageType,addr JPG_EncoderParameters

    invoke  GdipDisposeImage,pImage
Done:

    waitkey "  Press any key to continue ..."

    GdiPlusEnd                      ; GdiPlus cleanup

    invoke  ExitProcess,0
    ret

entry_point endp

end
Creative coders use backward thinking techniques as a strategy.

hutch--

Great, it works well, I have tested it from 10% to 75% and the results are perfect.

hutch--

Made the code into module format, works fine.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

SaveImgAsJpg proc BmpHndl:QWORD,filename:QWORD,quality:QWORD

    LOCAL pImage :QWORD

  ; ------------------------------------------------------------------------

  .data?
    QualityLevel@@@@@@@@   dd ?    ; mangle to avoid accidental duplicates

  .data
    CLSID_ImageType1 GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h, \
                           000h,0F8h,01Eh,0F3h,02Eh>> ; JPG image type

    JPG_EncoderParameters  dd 1    ; Number of parameters in this structure
                           dd 0    ; alignment !
    CLSID_EncoderQuality   GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh, \
                                 05dh,0b3h,051h,005h,0e7h,0ebh>>
                           dd 1    ; Number of the parameter values
                           dd 4    ; ValueTypeLong
    JpgQualityParameterPTR dq offset QualityLevel@@@@@@@@

  .code

  ; ------------------------------------------------------------------------

    cmp quality, 100
    ja default
    jmp next

  default:
    mov quality, 75                                             ; default for quality error

  next:
    rcall GdipCreateBitmapFromHBITMAP,BmpHndl,0,ptr$(pImage)    ; convert BMP handle
    mov rax, quality                                            ; set the quality level
    mov QualityLevel@@@@@@@@, eax                               ; 100 = highest, 0 = lowest
    invoke GdipSaveImageToFile,pImage,L(filename), \
           ADDR CLSID_ImageType1,ADDR JPG_EncoderParameters     ; write JPG image to file
    rcall GdipDisposeImage,pImage                               ; delete GDIP handle

    ret

SaveImgAsJpg endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤


I should mangle all of the names to ensure no accidents.

Siekmanski

Cool.  :cool:

Finally started exploring 64bit coding.
Working my way thru MACROS and addressing modes, still have a lot to learn...

Made my first Routine in 64bit.

    include \masm32\include64\masm64rt.inc

.const
Image_BMP       equ 0
Image_JPG       equ 1
Image_GIF       equ 2
Image_TIF       equ 5
Image_PNG       equ 6

.data?
pImage                  dq ?
pImageTemp              dq ?
JpgQualityLevel         dd ?

.data
CLSID_ImageTypes        GUID <0557CF400h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>> ; For all image types
JPG_EncoderParameters   dq 1    ; Number of parameters in this structure
CLSID_EncoderQuality    GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>
                        dd 1    ; Number of the parameter values
                        dd 4    ; ValueTypeLong
                        dq offset JpgQualityLevel
.code

SaveJpgQualityImage proc pGdiPlusImage:QWORD,pFilename:QWORD,Image_Quality:DWORD

    invoke  GdipCloneImage,pGdiPlusImage,addr pImageTemp ; make a copy of the image to work with.

    mov     eax,Image_Quality
    mov     JpgQualityLevel,eax
    mov     byte ptr [CLSID_ImageTypes],Image_JPG
   
    invoke  GdipSaveImageToFile,pImageTemp,L(pFilename),addr CLSID_ImageTypes,addr JPG_EncoderParameters
    invoke  GdipDisposeImage,pImageTemp
    ret
SaveJpgQualityImage endp
   
entry_point proc

    conout lf,"  64bit GDIplus Jpg Quality Encoder",lf,lf

    GdiPlusBegin                    ; initialise GDIPlus

; Load a test Image
    invoke  GdipCreateBitmapFromFile,L("Woman.bmp"),addr pImage
    test    rax,rax
    jnz     Done

    invoke  SaveJpgQualityImage,pImage,"Woman.jpg",50

    invoke  GdipDisposeImage,pImage
Done:

    waitkey "  Press any key to continue ..."

    GdiPlusEnd                      ; GdiPlus cleanup

    invoke  ExitProcess,0
    ret

entry_point endp

end
Creative coders use backward thinking techniques as a strategy.

hutch--

Once you get a feel for it, its great stuff, lots more registers, massive amounts of memory and without having to keep making prototypes, you can code very fast with practice.

Siekmanski

@Hutch
Having fun already, prepare for some questions later.  :biggrin:

Bare Minimum 64 bit GDIplus code to save different Image Types, PixelFormat and colorconversions.
Only 1 GUID used for all the Image Types.
Now you can find a balance between Image quality and file size.

You need to replace the old 64bit "gdiplus.lib" with a newer version.
The lib is included in the Lib folder, it's from the Microsoft SDK Windows v7.1A.

Hope I didn't violate the 64 bit coding rules, else let me know......
Creative coders use backward thinking techniques as a strategy.

Vortex

Hello Siekmanski,

I was able to build your example GDIplus64_color_conversions with Pelle's 64-bit import library. An alternative to SDK Windows v7 :

\PellesC\lib\Win64\gdiplus.lib

Siekmanski

Nice that it works.
Still have to find my way in 64 bit coding, maybe the code can be improved?
Creative coders use backward thinking techniques as a strategy.

jj2007

A little bit off topic: I am trying (successfully) to implement...

GdipDrawImageRectRectI(*graphics, GpImage *image, INT dstx, INT dsty, INT dstwidth, INT dstheight, INT srcx, INT srcy, INT srcwidth, INT srcheight, GpUnit srcUnit, GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData)

... to zoom into a picture. It works fine. Then I want to save the image using GdipSaveImageToFile

GdipSaveImageToFile(GpImage *image, WCHAR* filename, CLSID* clsidEncoder, EncoderParameters* encoderParams)

That works fine, too, but it saves the original image, not the zoomed one. Does Draw write to the bitmap/the image?

My understanding was that graphics is the equivalent of a DC in "normal" GDI, while image is the bitmap. Since GdipSaveImageToFile saves the bitmap, I expected to see the zoomed version. What's wrong with my logic? And how could I get access to the zoomed (or otherwise modified) image?

Unfortunately, the documentation is lousy :cool: