News:

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

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

Siekmanski

Bare Minimum GDIplus code to save different Image Types.
Without the GDIplus helper functions to make the code smaller and easier to read.
Only 1 CLSID guid is used for all the Image Types.

Includes the JPEG Quality Encoder, so creating very small .jpg files is easy.
Creative coders use backward thinking techniques as a strategy.

Vortex

Hi Siekmanski,

Your example works fine on Windows XP :thumbsup:

Siekmanski

Creative coders use backward thinking techniques as a strategy.

hutch--

Gratsie, works fine on my Win10 64. This will be very useful.  :thumbsup:

hutch--

Marinus,

I have a question for you, using your earlier work I got a number of file formats working but had an unusual result saving the image as a bitmap. The source bitmap was a bit over 500k, when saved it was over 800k, the only compression method I have every understood with bitmaps was RLE encodings, do you have any grasp of why the result is so much bigger ?

Siekmanski

#5
These 6 types of ".BMP" Bitmaps are the most commonly used. ( there are more exotic types... )

ARGB  = 32 bits per pixel ( includes the alpha channel )
RGB   = 24 bits per pixel
RGB16 = 16 bits per pixel
RGB8  =  8 bits per pixel ( pixels are indexed using a 256 color map )
RGB4  =  4 bits per pixel ( pixels are indexed using a 16 color map )
RGB1  =  1 bits per pixel ( pixels are indexed using a 2 color map )

There are 2 types of storing, Raw uncompressed and RLE encoded.
RLE encoded, depends on the repeating patterns of equal valued pixels, therefore will vary in size.

So, I think the 800K is raw ARGB and the 500K RLE encoded.

It's possible to create those different types of BMP bitmaps with GDIplus.
Look for:

    invoke  GdipBitmapLockBits,pImage,NULL,ImageLockModeRead,PixelFormat32bppARGB,offset GDIplusBitmapData

    invoke  GdipCreateBitmapFromScan0,I_Width,I_Height,pLockedRect.Pitch,PixelFormat32bppRGB,pLockedRect.pBits,addr pImage


ImageLockModeRead               equ 1
ImageLockModeWrite              equ 2
ImageLockModeReadWrite          equ 3
ImageLockModeUserInputBuf       equ 4

PixelFormat1bppIndexed          equ 30101h
PixelFormat4bppIndexed          equ 30402h
PixelFormat8bppIndexed          equ 30803h
PixelFormat16bppGreyScale       equ 101004h
PixelFormat16bppRGB555          equ 21005h
PixelFormat16bppRGB565          equ 21006h
PixelFormat16bppARGB1555        equ 61007h
PixelFormat24bppRGB             equ 21808h
PixelFormat32bppRGB             equ 22009h
PixelFormat32bppARGB            equ 26200Ah
PixelFormat32bppPARGB           equ 0E200Bh

EDIT:
Useful functions for indexed color types (256 or less colors)

GdipInitializePalette
GdipBitmapConvertFormat
Creative coders use backward thinking techniques as a strategy.

wind

great, works on my win10 64 too.  :thumbsup:

only 1 small issues, have to comment out line 19-24, or else get an assembling error:


C:\Temp\GDIplusSmall\GDIplusSmall.asm(20) : error A2163: non-benign structure redefinition: incorrect initializers : GdiplusStartupInput
C:\Temp\GDIplusSmall\GDIplusSmall.asm(21) : error A2163: non-benign structure redefinition: incorrect initializers : GdiplusStartupInput
C:\Temp\GDIplusSmall\GDIplusSmall.asm(22) : error A2163: non-benign structure redefinition: incorrect initializers : GdiplusStartupInput
C:\Temp\GDIplusSmall\GDIplusSmall.asm(23) : error A2163: non-benign structure redefinition: incorrect initializers : GdiplusStartupInput


windows.inc already has the structure defined.

Siekmanski

Yes, you are right.  :thumbsup:
Didn't know some GdiPlus includes were added in the latest 2012 windows.inc ( Shouldn't they belong in gdiplus.inc ?)
My windows.inc is an older version, time to update I guess. :tongue:
Creative coders use backward thinking techniques as a strategy.

hutch--

I can get JPG code to work but I have not discovered how to set the last argument for "GdipSaveImageToFile". The range of reference material I can access has conflicting definitions of what is a structure. It currently converts a 6 meg bitmap to a JPG 137194 bytes and nothing I have tried changes the compression level. Using a image app that I have had for years, if I set the compression rate to about 75% I get a JPG of near identical size ad the GDIP conversion looks fine with no visible deterioration.


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

    encoder STRUCT QWORD
      count dq ?
      pguid dq ?
      dwtyp dq ?
      nmval dq ?
    encoder ENDS

;     typedef struct EncoderParameters {
;       GUID Guid:
;       ULONG NumberOfValues;
;       ULONG Type;
;       void * Value;
;     };

;     typedef struct EncoderParameters {
;        UINT Count;
;        EncoderParameter Parameter|i|;
;     };




;    Jose Roca
;    eps.count = 1
;    eps.Parameter(0).pGuid = $EncoderQuality
;    eps.Parameter(0).dwType = %EncoderParameterValueTypeLong
;    eps.Parameter(0).NumberOfValues = 1

  .data
    CLSID_ImageType GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>>
    CLSID_EncoderQuality GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>

   .code

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

SaveJpgQualityImage proc hBMP:QWORD,pFilename:QWORD,Image_Quality:QWORD

    LOCAL hGdip :QWORD
    LOCAL pTemp :QWORD
    LOCAL pqual :QWORD
    LOCAL ptype :QWORD
    LOCAL penc  :QWORD
    LOCAL encd  :encoder

    mov ptype, ptr$(CLSID_ImageType)
    mov pqual, ptr$(CLSID_EncoderQuality)

    mov encd.count, 1                   ; count
    mrm encd.pguid, pqual               ; pointer to CLSID_EncoderQuality
    mrm encd.dwtyp, 75                   ; EncoderParameterValueTypeLong
    mov encd.nmval, 1                   ; NumberOfValues

    mov penc, ptr$(encd.count)

    invoke GdipCreateBitmapFromHBITMAP,hBMP,0,ptr$(hGdip)       ; OK
    invoke GdipCloneImage,hGdip,ptr$(pTemp)                     ; OK
    test rax, rax
    jnz  Done

    invoke GdipSaveImageToFile,pTemp,L(pFilename),ptype,penc    ; last arg does not work

    invoke GdipDisposeImage,pTemp                               ; release image copy
    invoke GdipDisposeImage,hGdip

  Done:
    ret

SaveJpgQualityImage endp

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



Siekmanski

The order of the struct is this,

    LOCAL iqual :QWORD


    encoder STRUCT QWORD
      count dq ? ; = 1
      pguid dq ? ; = pointer to CLSID_EncoderQuality
      nmval dq ? ; = 1  NumberOfValues
      dwtyp dq ? ; = 4  (EncoderParameterValueTypeLong)
      QualityLevel dq ? ; pointer to Image_Quality
    encoder ENDS

    mov iqual, ptr$(Image_Quality) ; 75 in your example

    mov encd.count, 1                   ; count
    mrm encd.pguid, pqual               ; pointer to CLSID_EncoderQuality
    mov encd.nmval, 1                   ; NumberOfValues
    mov encd.dwtyp, 4                   ; EncoderParameterValueTypeLong
    mrm encd.QualityLevel, iqual        ; JPG QualityLevel

In your example you don't need to clone the image -> GdipCloneImage


Did not test it, hope it works.  :biggrin:
Creative coders use backward thinking techniques as a strategy.

Siekmanski

Bare Minimum GDIplus code to save different Image Types and PixelFormat conversions.

Creative coders use backward thinking techniques as a strategy.

hutch--

I modified the algo to this form but it still won't change the compression ratio. I wondered if I am using the correct GUID

CLSID_EncoderQuality GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>



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

    encoder STRUCT QWORD
      count dq ?            ; = 1
      pguid dq ?            ; = pointer to CLSID_EncoderQuality
      nmval dq ?            ; = 1  NumberOfValues
      dwtyp dq ?            ; = 4  (EncoderParameterValueTypeLong)
      qlevl dq ?            ; = pointer to Image_Quality
    encoder ENDS

  .data
    CLSID_ImageType GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>>
    CLSID_EncoderQuality GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>

   .code

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

SaveJpgQualityImage proc hBMP:QWORD,pFilename:QWORD,Image_Quality:QWORD

    LOCAL hGdip :QWORD
    LOCAL pTemp :QWORD
    LOCAL pqual :QWORD
    LOCAL ptype :QWORD
    LOCAL penc  :QWORD
    LOCAL iqual :QWORD
    LOCAL encd  :encoder

    mov ptype, ptr$(CLSID_ImageType)
    mov pqual, ptr$(CLSID_EncoderQuality)

    mov iqual, ptr$(Image_Quality)

    mov encd.count, 1                   ; count
    mrm encd.pguid, pqual               ; pointer to CLSID_EncoderQuality
    mov encd.nmval, 1                   ; NumberOfValues
    mov encd.dwtyp, 4                   ; EncoderParameterValueTypeLong
    mrm encd.qlevl, iqual               ; JPG qlevl

    mov penc, ptr$(encd.count)

    invoke GdipCreateBitmapFromHBITMAP,hBMP,0,ptr$(hGdip)       ; OK
    invoke GdipSaveImageToFile,hGdip,L(pFilename),ptype,penc    ; last arg does not work
    invoke GdipDisposeImage,hGdip

    ret

SaveJpgQualityImage endp

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

Siekmanski

Maybe this will work ( I'm not experienced in 64bit code )

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

    encoder STRUCT QWORD
      count dq ?            ; = 1
      pguid dq ?            ; = pointer to CLSID_EncoderQuality
      nmval dq ?            ; = 1  NumberOfValues
      dwtyp dq ?            ; = 4  (EncoderParameterValueTypeLong)
      qlevl dq ?            ; = pointer to Image_Quality
    encoder ENDS

  .data
    CLSID_ImageType GUID <0557CF401h,01A04h,011D3h,<09Ah,073h,000h,000h,0F8h,01Eh,0F3h,02Eh>>
    CLSID_EncoderQuality GUID <01d5be4b5h,0fa4ah,0452dh,<09ch,0ddh,05dh,0b3h,051h,005h,0e7h,0ebh>>

   .code

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

SaveJpgQualityImage proc hBMP:QWORD,pFilename:QWORD,Image_Quality:QWORD

    LOCAL hGdip :QWORD
    LOCAL pTemp :QWORD
    LOCAL pqual :QWORD
    LOCAL ptype :QWORD
    LOCAL penc  :QWORD
    LOCAL iqual :QWORD
    LOCAL iJPGQ :QWORD
    LOCAL encd  :encoder

    mov ptype, ptr$(CLSID_ImageType)
    mov pqual, ptr$(CLSID_EncoderQuality)

    mov rax,Image_Quality
    mov iJPGQ,rax
    mov iqual, ptr$(iJPGQ)

    mov encd.count, 1                   ; count
    mrm encd.pguid, pqual               ; pointer to CLSID_EncoderQuality
    mov encd.nmval, 1                   ; NumberOfValues
    mov encd.dwtyp, 4                   ; EncoderParameterValueTypeLong
    mrm encd.qlevl, iqual               ; JPG qlevl

    mov penc, ptr$(encd.count)

    invoke GdipCreateBitmapFromHBITMAP,hBMP,0,ptr$(hGdip)       ; OK
    invoke GdipSaveImageToFile,hGdip,L(pFilename),ptype,penc    ; last arg does not work
    invoke GdipDisposeImage,hGdip

    ret

SaveJpgQualityImage endp

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

Creative coders use backward thinking techniques as a strategy.

hutch--

I gave it a blast but no change, maybe the 64 bit version of GDIP is broken somewhere.

nidud

#14
deleted