Sign in to follow this  
Followers 0
GodlessSinner

Why grayscaled image size is more than a colored?

6 posts in this topic

#1 ·  Posted (edited)

#Include <GDIPlus.au3>
#include <ScreenCapture.au3>
_GDIPlus_Startup()

_ScreenCapture_SetJPGQuality(20)
_ScreenCapture_Capture("test.jpg",0,0,100,100)
$hImage1 = _GDIPlus_ImageLoadFromFile("test.jpg")
;$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP(_ScreenCapture_Capture("",0,0,100,100))
$hImage2 = _GDIPlus_ImageGreyscale($hImage1)
_GDIPlus_ImageSaveToFile($hImage2, "test_grey.jpg")

_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)

_GDIPlus_ShutDown()
Exit

;; _GDIPlus_ImageGreyscale()
;;      Creates a greyscale copy of Image object and returns its handle. To destroy it, use _GDIPlus_ImageDispose() or _GDIPlus_BitmapDispose()
Func _GDIPlus_ImageGreyscale(Const ByRef $hImage)
    Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage), $hGraphics, $hGraphics2, $hBitmap
;;create color matrix data
    $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
    ;greyscale values:
    $x = DllStructSetData($tColorMatrix, 1, 0.3, 1) * DllStructSetData($tColorMatrix, 1, 0.3, 2) * DllStructSetData($tColorMatrix, 1, 0.3, 3) * _
        DllStructSetData($tColorMatrix, 2, 0.59, 1) * DllStructSetData($tColorMatrix, 2, 0.59, 2) * DllStructSetData($tColorMatrix, 2, 0.59, 3) * _
        DllStructSetData($tColorMatrix, 3, 0.11, 1) * DllStructSetData($tColorMatrix, 3, 0.11, 2) * DllStructSetData($tColorMatrix, 3, 0.11, 3) * _
        DllStructSetData($tColorMatrix, 4, 1.0, 4) * _
        DllStructSetData($tColorMatrix, 5, 1.0, 5)
;;create an image attributes object and update its color matrix
    $hImgAttrib = _GDIPlus_ImageAttributesCreate()
    _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, 1, DllStructGetPtr($tColorMatrix))
;;copy image
    $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hBitmap)
;;draw original into copy with attributes
    _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics2, $hImage, 0, 0, $iW, $iH, 0, 0, $iW, $iH, 2, $hImgAttrib)
;;clean up
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_GraphicsDispose($hGraphics2)
    _GDIPlus_ImageAttributesDispose($hImgAttrib)

    Return $hBitmap
EndFunc

Func _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, $iColorAdjustType, $pColorMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
    Local $fEnable = 1, $aResult = DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr",$hImgAttrib, "int",$iColorAdjustType, _
                                            "int",$fEnable, "ptr",$pColorMatrix, "ptr",$pGrayMatrix, "int",$iColorMatrixFlags)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;Creates ImageAttributes object
Func _GDIPlus_ImageAttributesCreate()
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
    Return SetError($aResult[0], 0, $aResult[1])
EndFunc

;;Deletes ImageAttributes object
Func _GDIPlus_ImageAttributesDispose($hImgAttrib)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;; _GDIPlus_GraphicsDrawImageRectRectEx()
;; Same as _GDIPlus_GraphicsDrawImageRectRect(), but adds 1 optional parameter - $hImgAttrib (handle to ImageAttributes object)
Func _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics, $hImage, $iSrcX, $iSrcY, $iSrcWidth, $iSrcHeight, $iDstX, $iDstY, $iDstWidth, $iDstHeight, $iUnit = 2, $hImgAttrib = 0)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRectI", "hwnd", $hGraphics, "hwnd", $hImage, "int", $iDstX, "int", _
            $iDstY, "int", $iDstWidth, "int", $iDstHeight, "int", $iSrcX, "int", $iSrcY, "int", $iSrcWidth, "int", _
            $iSrcHeight, "int", $iUnit, "ptr", $hImgAttrib, "int", 0, "int", 0)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;=============================

EDIT: Saying "image size", i mean file size.

Edited by GodlessSinner

_____________________________________________________________________________

Share this post


Link to post
Share on other sites



For me the greyscale image is slightly smaller than the color image. 2.63 vs 2.87 kB.

This is how I think it works, but it's by no means backed up by any knowledge about the subject. It just seems to make sense.

The reason the grayscale image file isn't much smaller is because both images use 24bit depth and compression quality 20.

In short they can both hold about 16m different color variations (2^24), but for the greyscale image they are all shades of grey.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

#Include <GDIPlus.au3>
#include <ScreenCapture.au3>
_GDIPlus_Startup()

_ScreenCapture_SetJPGQuality(20)
_ScreenCapture_Capture("test.jpg",0,0,100,100)
$hImage1 = _GDIPlus_ImageLoadFromFile("test.jpg")
;$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP(_ScreenCapture_Capture("",0,0,100,100))
$hImage2 = _GDIPlus_ImageGreyscale($hImage1)
_GDIPlus_ImageSaveToFile($hImage2, "test_grey.jpg")

_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)

_GDIPlus_ShutDown()
Exit

;; _GDIPlus_ImageGreyscale()
;; Creates a greyscale copy of Image object and returns its handle. To destroy it, use _GDIPlus_ImageDispose() or _GDIPlus_BitmapDispose()
Func _GDIPlus_ImageGreyscale(Const ByRef $hImage)
 Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage), $hGraphics, $hGraphics2, $hBitmap
;;create color matrix data
 $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
 ;greyscale values:
 $x = DllStructSetData($tColorMatrix, 1, 0.3, 1) * DllStructSetData($tColorMatrix, 1, 0.3, 2) * DllStructSetData($tColorMatrix, 1, 0.3, 3) * _
 DllStructSetData($tColorMatrix, 2, 0.59, 1) * DllStructSetData($tColorMatrix, 2, 0.59, 2) * DllStructSetData($tColorMatrix, 2, 0.59, 3) * _
 DllStructSetData($tColorMatrix, 3, 0.11, 1) * DllStructSetData($tColorMatrix, 3, 0.11, 2) * DllStructSetData($tColorMatrix, 3, 0.11, 3) * _
 DllStructSetData($tColorMatrix, 4, 1.0, 4) * _
 DllStructSetData($tColorMatrix, 5, 1.0, 5)
;;create an image attributes object and update its color matrix
 $hImgAttrib = _GDIPlus_ImageAttributesCreate()
 _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, 1, DllStructGetPtr($tColorMatrix))
;;copy image
 $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage)
 $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
 $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hBitmap)
;;draw original into copy with attributes
 _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics2, $hImage, 0, 0, $iW, $iH, 0, 0, $iW, $iH, 2, $hImgAttrib)
;;clean up
 _GDIPlus_GraphicsDispose($hGraphics)
 _GDIPlus_GraphicsDispose($hGraphics2)
 _GDIPlus_ImageAttributesDispose($hImgAttrib)

 Return $hBitmap
EndFunc

Func _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, $iColorAdjustType, $pColorMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
 Local $fEnable = 1, $aResult = DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr",$hImgAttrib, "int",$iColorAdjustType, _
 "int",$fEnable, "ptr",$pColorMatrix, "ptr",$pGrayMatrix, "int",$iColorMatrixFlags)
 Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;Creates ImageAttributes object
Func _GDIPlus_ImageAttributesCreate()
 Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
 Return SetError($aResult[0], 0, $aResult[1])
EndFunc

;;Deletes ImageAttributes object
Func _GDIPlus_ImageAttributesDispose($hImgAttrib)
 Local $aResult = DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
 Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;; _GDIPlus_GraphicsDrawImageRectRectEx()
;; Same as _GDIPlus_GraphicsDrawImageRectRect(), but adds 1 optional parameter - $hImgAttrib (handle to ImageAttributes object)
Func _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics, $hImage, $iSrcX, $iSrcY, $iSrcWidth, $iSrcHeight, $iDstX, $iDstY, $iDstWidth, $iDstHeight, $iUnit = 2, $hImgAttrib = 0)
 Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRectI", "hwnd", $hGraphics, "hwnd", $hImage, "int", $iDstX, "int", _
 $iDstY, "int", $iDstWidth, "int", $iDstHeight, "int", $iSrcX, "int", $iSrcY, "int", $iSrcWidth, "int", _
 $iSrcHeight, "int", $iUnit, "ptr", $hImgAttrib, "int", 0, "int", 0)
 Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;=============================

EDIT: Saying "image size", i mean file size.

You are making a screenshot and saving it with quality 20,

afterwards you are loading the saved image and converting it to greyscale and finally you save the greyscaled image!

First: you are loading the compressed image with more artefacts as the orginal image

which means a higher file size when saving it back.

Second: saving the second image back is with standard quality settings only which means automatically

a higher file size than the 1st image with quality 20!

Third: after converting the image to greyscale it has still 24bpp and not 8bpp which has also an impact to the file size!

Currently I didn't investigate how to convert a 32/24bpp to 8bpp but here the code that saves the 2nd image also with quality 20.

#Include <GDIPlus.au3>
#include <ScreenCapture.au3>
_GDIPlus_Startup()

_ScreenCapture_SetJPGQuality(20)
_ScreenCapture_Capture("test.jpg",0,0,100,100)
$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP(_ScreenCapture_Capture("",0,0,100,100))
;$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP(_ScreenCapture_Capture("",0,0,100,100))
$hImage2 = _GDIPlus_ImageGreyscale($hImage1)

$sCLSID = _GDIPlus_EncodersGetCLSID ("JPG")
$tParams = _GDIPlus_ParamInit (1)
$tData = DllStructCreate("int Quality")
DllStructSetData($tData, "Quality", 20) ;quality 0-100
$pData = DllStructGetPtr($tData)
_GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData)
$pParams = DllStructGetPtr($tParams)
_GDIPlus_ImageSaveToFileEx($hImage2, "test_grey.jpg", $sCLSID, $pParams)
$tData = 0

_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)

_GDIPlus_ShutDown()
Exit

;; _GDIPlus_ImageGreyscale()
;;  Creates a greyscale copy of Image object and returns its handle. To destroy it, use _GDIPlus_ImageDispose() or _GDIPlus_BitmapDispose()
Func _GDIPlus_ImageGreyscale(Const ByRef $hImage)
    Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage), $hGraphics, $hGraphics2, $hBitmap
;;create color matrix data
    $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
    ;greyscale values:
    $x = DllStructSetData($tColorMatrix, 1, 0.3, 1) * DllStructSetData($tColorMatrix, 1, 0.3, 2) * DllStructSetData($tColorMatrix, 1, 0.3, 3) * _
    DllStructSetData($tColorMatrix, 2, 0.59, 1) * DllStructSetData($tColorMatrix, 2, 0.59, 2) * DllStructSetData($tColorMatrix, 2, 0.59, 3) * _
    DllStructSetData($tColorMatrix, 3, 0.11, 1) * DllStructSetData($tColorMatrix, 3, 0.11, 2) * DllStructSetData($tColorMatrix, 3, 0.11, 3) * _
    DllStructSetData($tColorMatrix, 4, 1.0, 4) * _
    DllStructSetData($tColorMatrix, 5, 1.0, 5)
;;create an image attributes object and update its color matrix
    $hImgAttrib = _GDIPlus_ImageAttributesCreate()
    _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, 1, DllStructGetPtr($tColorMatrix))
;;copy image
    $hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    $hGraphics2 = _GDIPlus_ImageGetGraphicsContext($hBitmap)
;;draw original into copy with attributes
    _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics2, $hImage, 0, 0, $iW, $iH, 0, 0, $iW, $iH, 2, $hImgAttrib)
;;clean up
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_GraphicsDispose($hGraphics2)
    _GDIPlus_ImageAttributesDispose($hImgAttrib)

    Return $hBitmap
EndFunc

Func _GDIPlus_ImageAttributesSetColorMatrix($hImgAttrib, $iColorAdjustType, $pColorMatrix = 0, $pGrayMatrix = 0, $iColorMatrixFlags = 0)
    Local $fEnable = 1, $aResult = DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr",$hImgAttrib, "int",$iColorAdjustType, _
    "int",$fEnable, "ptr",$pColorMatrix, "ptr",$pGrayMatrix, "int",$iColorMatrixFlags)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;Creates ImageAttributes object
Func _GDIPlus_ImageAttributesCreate()
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
    Return SetError($aResult[0], 0, $aResult[1])
EndFunc

;;Deletes ImageAttributes object
Func _GDIPlus_ImageAttributesDispose($hImgAttrib)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;; _GDIPlus_GraphicsDrawImageRectRectEx()
;; Same as _GDIPlus_GraphicsDrawImageRectRect(), but adds 1 optional parameter - $hImgAttrib (handle to ImageAttributes object)
Func _GDIPlus_GraphicsDrawImageRectRectEx($hGraphics, $hImage, $iSrcX, $iSrcY, $iSrcWidth, $iSrcHeight, $iDstX, $iDstY, $iDstWidth, $iDstHeight, $iUnit = 2, $hImgAttrib = 0)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipDrawImageRectRectI", "hwnd", $hGraphics, "hwnd", $hImage, "int", $iDstX, "int", _
    $iDstY, "int", $iDstWidth, "int", $iDstHeight, "int", $iSrcX, "int", $iSrcY, "int", $iSrcWidth, "int", _
    $iSrcHeight, "int", $iUnit, "ptr", $hImgAttrib, "int", 0, "int", 0)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc

;;=============================

I assume that the file size of both image should be nearly the same.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Looking at the screencapture function, it should be possible to take the return value from that function and then save it as a jpg with the desired properties.

That would eliminate quality loss by using a the compressed in-between image and should allow for a smaller filesize.

Going to have a shot at it.

Edit: Just noticed the line that was commented out in UEZ' script doing just what I had in mind, except for reducing the bpp. I can't seem to get the settings for lowering the bpp right though.

Edited by Tvern

Share this post


Link to post
Share on other sites

UEZ, big thanks! Would be perfect to convert to 8bpp, just I need to decrease quality so much, as possible, and keeping text's readability.


_____________________________________________________________________________

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

... keeping text's readability ... 4bpp(16gray), 1bpp(B/W, fax)

Erm. JPG supporting those? (think not.)

Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0