corgano Posted May 5, 2017 Posted May 5, 2017 What I am trying to accomplish is to simplify a .PNG image and convert it to use only a specified pallet of colors. Eg if I have a pallet of 0xFF0000, 0x00FF00, 0x0000FF, it would change every pixel in the image to one of those three colors by whichever color is closest. The simplest method I have tried is simply converting the image to a 16 bit bitmap, and that does simplify the pallet of the image, but I want to be able to specify what colors it specifies to. The other problem is the resulting saved .BMP file is much larger (file size) than the original, and I don't know if it's possible to make a 16 bit jpg. It looks like _GDIPlus_BitmapConvertFormat is the solution but the help file doesn't go into how to use the pallet and I couldn't find an example that did what I needed. Can anyone help me? 0x616e2069646561206973206c696b652061206d616e20776974686f7574206120626f64792c20746f206669676874206f6e6520697320746f206e657665722077696e2e2e2e2e
UEZ Posted May 5, 2017 Posted May 5, 2017 (edited) Something like this here? GDI+ v1.1 required -> Windows 7+ expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Global $sFile = FileOpenDialog("Selecet an image", "", "Images (*.jpg;*.png;*.bmp)") If @error Then Exit MsgBox(16, "Error", "You must select an image!", 30) _GDIPlus_Startup() $hImage = _GDIPlus_ImageLoadFromFile($sFile) $iW = _GDIPlus_ImageGetWidth($hImage) $iH = _GDIPlus_ImageGetHeight($hImage) $hGUI = GUICreate("GDI+ v1.1 needed", $iW * 2 + 30, $iH + 20) GUISetState() $hDC = _WinAPI_GetDC($hGUI) $hGraphics1 = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hImage, 10, 10, $iW, $iH) _GDIPlus_GraphicsDispose($hGraphics1) _WinAPI_ReleaseDC($hGUI, $hDC) $iColors = 4 Local $tPalette = _GDIPlus_PaletteInitialize(256, $GDIP_PaletteTypeFixedHalftone256, $iColors, False, $hImage) ConsoleWrite(@error & @CRLF) $tPalette.ARGB((1)) = 0xFF0000FF $tPalette.ARGB((2)) = 0xFF00FF00 $tPalette.ARGB((3)) = 0xFFFF0000 $tPalette.ARGB((4)) = 0xFF000000 _GDIPlus_BitmapConvertFormat($hImage, $GDIP_PXF04INDEXED, $GDIP_DitherTypeDualSpiral8x8, $GDIP_PaletteTypeFixedHalftone256, $tPalette) DllCall($__g_hGDIPDll, "int", "GdipSetImagePalette", "handle", $hImage, "struct*", $tPalette) $hDC = _WinAPI_GetDC($hGUI) $hGraphics2 = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics2, $hImage, $iW + 20, 10, $iW, $iH) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _WinAPI_ReleaseDC($hGUI, $hDC) _GDIPlus_GraphicsDispose($hGraphics2) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() GUIDelete() Exit EndSwitch Until False Edited May 5, 2017 by UEZ Gianni 1 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
corgano Posted May 6, 2017 Author Posted May 6, 2017 I knew it would be UEZ to respond. You really are our local GDI expert. That is really cool and i think we're on the right track, but I'm not looking to use various dots to make up the color, I want to make each area the solid color it's closest to in the pallet. For instance turns into but the result I'm looking for is 0x616e2069646561206973206c696b652061206d616e20776974686f7574206120626f64792c20746f206669676874206f6e6520697320746f206e657665722077696e2e2e2e2e
Malkey Posted May 6, 2017 Posted May 6, 2017 Try this. expandcollapse popup#include <Color.au3> #include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <Misc.au3> #include <ScreenCapture.au3> Opt('MustDeclareVars', 1) Global $width, $height, $hGUI1, $hGUI2, $hImage, $hImage2, $hGraphic1, $hGraphic2, $iX, $iY, $sImageIn _Main() Func _Main() ; Capture top left corner of the screen ;$sImageIn = "GDIPlus_Image.png" ;_ScreenCapture_Capture($sImageIn, 0, 0, 400, 400) ;Or ;$sImageIn = FileOpenDialog("First image", "", "All images (*.jpg;*.png;*.gif;*.bmp;)") ;If $sImageIn = "" Then Exit ;ConsoleWrite($sImageIn & @LF) ;Or InetGet("https://i.imgur.com/a4Dnd88.png", @ScriptDir & "\a4Dnd88.png") $sImageIn = @ScriptDir & "\a4Dnd88.png" ;or ;InetGet("http://img11.nnm.ru/a/1/5/b/0/1dba2209d5a133d9e84431a5587.jpg","FireWorksSydney.jpg") ;$sImageIn = "FireWorksSydney.jpg" ; Create a GUI for the original image $hGUI1 = GUICreate("Original", 400, 400, 0, 0) GUISetState() ; Create a GUI for the zoomed image $hGUI2 = GUICreate("Ctrl + Left click to save image", 400, 400, 0, 400) GUISetState() GUIRegisterMsg(0xF, "MY_PAINT") ; Initialize GDI+ library and load image _GDIPlus_Startup() $hImage = _GDIPlus_ImageLoadFromFile($sImageIn) $iX = _GDIPlus_ImageGetWidth($hImage) $iY = _GDIPlus_ImageGetHeight($hImage) ConsoleWrite($iX & " x " & $iY & @CRLF) ; Draw original image $hGraphic1 = _GDIPlus_GraphicsCreateFromHWND($hGUI1) _GDIPlus_GraphicsDrawImageRectRect($hGraphic1, $hImage, 0, 0, $iX, $iY, 0, 0, 400, 400) $hImage2 = _ImageColorFunc($hImage, "CF") ; <======= Use function CF() on each pixel. ; Draw returned image from _ImageColorFunc $hGraphic2 = _GDIPlus_GraphicsCreateFromHWND($hGUI2) _GDIPlus_GraphicsDrawImageRectRect($hGraphic2, $hImage2, 0, 0, $iX, $iY, 0, 0, 400, 400) ; Loop until user exits Do If _IsPressed("01") And _IsPressed("11") Then ; Left click + Ctrl key to save image. Do Until Not _IsPressed("01") Local $PathFile = FileSaveDialog("Choose a name.", @ScriptDir & "\", "Images (*.bmp;*.jpg;*.png;*.gif)|All files (*.*)", 16, "ColourModify.png") If Not @error Then _GDIPlus_ImageSaveToFile($hImage2, $PathFile) ;ShellExecute($PathFile) EndIf EndIf Sleep(10) Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Release resources _GDIPlus_GraphicsDispose($hGraphic1) _GDIPlus_GraphicsDispose($hGraphic2) _GDIPlus_ImageDispose($hImage) _GDIPlus_ImageDispose($hImage2) _GDIPlus_Shutdown() EndFunc ;==>_Main ; ========= _ImageColorFunc($hImage, $ColorFunc) ===================== ;Paramerers:- ; $hImage - Handle to a Bitmap object ; $ColorFunc - A function that will be applied to every pixel in image. ; Func _ImageColorFunc($hImage, $ColorFunc) Local $Reslt, $stride, $format, $Scan0, $iIW, $iIH, $hBitmap1 Local $v_BufferA, $AllPixels, $sREResult1, $sResult $iIW = _GDIPlus_ImageGetWidth($hImage) $iIH = _GDIPlus_ImageGetHeight($hImage) ;ConsoleWrite($iIW & " " & $iIH & @LF) $hBitmap1 = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iIW, $iIH, $GDIP_PXF32ARGB) ; Locks a portion of a bitmap for reading or writing $Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $iIW, $iIH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB) ;Get the returned values of _GDIPlus_BitmapLockBits () $width = DllStructGetData($Reslt, "width") $height = DllStructGetData($Reslt, "height") $stride = DllStructGetData($Reslt, "stride") $format = DllStructGetData($Reslt, "format") $Scan0 = DllStructGetData($Reslt, "Scan0") $v_BufferA = DllStructCreate("byte[" & $height * $width * 4 & "]", $Scan0) ; Create DLL structure for all pixels $AllPixels = DllStructGetData($v_BufferA, 1) ;ConsoleWrite("$AllPixels, raw data, first few colours = " & StringRegExpReplace($AllPixels, "(.{98})(.*)", "\1") & @CRLF) ; Searches on this string - $sREResult1 whch has the prefix "0x" removed and a space put between pixels 8 characters long. $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ") ;ConsoleWrite("$sREResult1 first few colours = " & StringRegExpReplace($sREResult1, "(.{81})(.*)", "\1") & @CRLF) ; Create an executable string with each pixel as a parameter of $ColorFunc function and remove all spaces. $sResult = StringStripWS(StringRegExpReplace($sREResult1, "(.{8}) ", $ColorFunc & '("\1")&'), 8) ;ConsoleWrite("$sREResult1 first few colours = " & StringRegExpReplace($sResult, "(.{81})(.*)", "\1") & @CRLF) ; Remove trailing "&", execute string, $sResult, and, add a leading, "0x. $sResult = "0x" & Execute(StringTrimRight($sResult, 1)) ;ConsoleWrite("$sREResult1 first 9 colours = " & StringRegExpReplace($sResult, "(.{81})(.*)", "\1") & @CRLF) DllStructSetData($v_BufferA, 1, $sResult) _GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt) ; Releases the locked region Return $hBitmap1 EndFunc ;==>_ImageColorFunc Func MY_PAINT($hWnd, $msg, $wParam, $lParam) If $hWnd = $hGUI1 Then _GDIPlus_GraphicsDrawImageRectRect($hGraphic1, $hImage, 0, 0, $iX, $iY, 0, 0, 400, 400) ; _GDIPlus_GraphicsDrawImageRect($hGraphic1, $hImage, 0, 0, $width, $height) If $hWnd = $hGUI2 Then _GDIPlus_GraphicsDrawImageRectRect($hGraphic2, $hImage2, 0, 0, $iX, $iY, 0, 0, 400, 400) ; _GDIPlus_GraphicsDrawImageRect($hGraphic2, $hImage2, 0, 0, $width, $height) Return $GUI_RUNDEFMSG EndFunc ;==>MY_PAINT ; The function used as a parameter in _ImageColorFunc() function. Func CF($iColor) Local $aPalet = [0x0000FF, 0x00FF00, 0xFF0000, 0x000000], $iCol $iColor = "0x" & StringRegExpReplace($iColor, "(.{2})(.{2})(.{2})(.{2})", "$3$2$1") ; convert to AARRGGBB If _ColorGetRed($iColor) >= _ColorGetGreen($iColor) And _ColorGetRed($iColor) >= _ColorGetBlue($iColor) Then $iCol = $aPalet[0] If _ColorGetRed($iColor) <= 0x80 Then $iCol = $aPalet[3] EndIf If _ColorGetGreen($iColor) >= _ColorGetRed($iColor) And _ColorGetGreen($iColor) >= _ColorGetBlue($iColor) Then $iCol = $aPalet[1] If _ColorGetGreen($iColor) <= 0x80 Then $iCol = $aPalet[3] EndIf If _ColorGetBlue($iColor) >= _ColorGetRed($iColor) And _ColorGetBlue($iColor) >= _ColorGetGreen($iColor) Then $iCol = $aPalet[2] If _ColorGetBlue($iColor) <= 0x80 Then $iCol = $aPalet[3] EndIf Return Hex($iCol, 6) & "FF" EndFunc ;==>CF
UEZ Posted May 6, 2017 Posted May 6, 2017 @corgano you have to be more precise what you want. If you disable dithering in the code from post #2 you will get very similar results: expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Global $sFile = FileOpenDialog("Selecet an image", "", "Images (*.jpg;*.png;*.bmp)") If @error Then Exit MsgBox(16, "Error", "You must select an image!", 30) _GDIPlus_Startup() Global $hImage = _GDIPlus_ImageLoadFromFile($sFile) Global $iW = _GDIPlus_ImageGetWidth($hImage) Global $iH = _GDIPlus_ImageGetHeight($hImage) Global $hGUI = GUICreate("GDI+ v1.1 needed", $iW * 2 + 30, $iH + 20) GUISetState() Global $hGraphics1 = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsDrawImageRect($hGraphics1, $hImage, 10, 10, $iW, $iH) _GDIPlus_GraphicsDispose($hGraphics1) Global $iColors = 4 Global $tPalette = _GDIPlus_PaletteInitialize(256, $GDIP_PaletteTypeOptimal, $iColors, False, $hImage) $tPalette.ARGB((1)) = 0xFF0000FF $tPalette.ARGB((2)) = 0xFF00FF00 $tPalette.ARGB((3)) = 0xFFFF0000 $tPalette.ARGB((4)) = 0xFF000000 _GDIPlus_BitmapConvertFormat($hImage, $GDIP_PXF04INDEXED, $GDIP_DitherTypeSolid, $GDIP_PaletteTypeOptimal, $tPalette) DllCall($__g_hGDIPDll, "int", "GdipSetImagePalette", "handle", $hImage, "struct*", $tPalette) Global $hGraphics2 = _GDIPlus_GraphicsCreateFromHWND($hGUI) _GDIPlus_GraphicsDrawImageRect($hGraphics2, $hImage, $iW + 20, 10, $iW, $iH) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _GDIPlus_GraphicsDispose($hGraphics1) _GDIPlus_GraphicsDispose($hGraphics2) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() GUIDelete() Exit EndSwitch Until False @Malkey nice to see you posting GDI+ stuff again. I learned so much from your posts! Gianni 1 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
InnI Posted May 6, 2017 Posted May 6, 2017 How about _GDIPlus_ImageAttributesSetRemapTable ? Global $aRemapTable[5][2] $aRemapTable[0][0] = 4 $aRemapTable[1][0] = 0xFFD3B4BA $aRemapTable[1][1] = 0xFFFF0000 $aRemapTable[2][0] = 0xFFB5D7B0 $aRemapTable[2][1] = 0xFF00FF00 $aRemapTable[3][0] = 0xFFACAFDB $aRemapTable[3][1] = 0xFF0000FF $aRemapTable[4][0] = 0xFF646464 $aRemapTable[4][1] = 0xFF000000 Or simply fill the area #include <GDIPlus.au3> _GDIPlus_Startup () $hImage = _GDIPlus_ImageLoadFromFile("a4Dnd88.png") $hBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage) _GDIPlus_ImageDispose($hImage) $hCDC = _WinAPI_CreateCompatibleDC(0) $hOldBmp = _WinAPI_SelectObject($hCDC, $hBmp) $hBrush = _WinAPI_GetStockObject($DC_BRUSH) $hOldBrush = _WinAPI_SelectObject($hCDC, $hBrush) _WinAPI_SetDCBrushColor($hCDC, 0xFF0000) _WinAPI_ExtFloodFill($hCDC, 0, 0, _WinAPI_GetPixel($hCDC, 0, 0), 1) _WinAPI_SetDCBrushColor($hCDC, 0x00FF00) _WinAPI_ExtFloodFill($hCDC, 100, 0, _WinAPI_GetPixel($hCDC, 100, 0), 1) _WinAPI_SetDCBrushColor($hCDC, 0x0000FF) _WinAPI_ExtFloodFill($hCDC, 0, 100, _WinAPI_GetPixel($hCDC, 0, 100), 1) _WinAPI_SetDCBrushColor($hCDC, 0x000000) _WinAPI_ExtFloodFill($hCDC, 100, 100, _WinAPI_GetPixel($hCDC, 100, 100), 1) $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp) _GDIPlus_ImageSaveToFile($hImage, "result.png") _GDIPlus_ImageDispose($hImage) _WinAPI_SelectObject($hCDC, $hOldBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_SelectObject($hCDC, $hOldBmp) _WinAPI_DeleteObject($hBmp) _WinAPI_DeleteDC($hCDC) _GDIPlus_ShutDown()
UEZ Posted May 6, 2017 Posted May 6, 2017 @InnI the magic key word is here color quantization. Probably corgano's example is just a simple one for demonstration purposes. 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now