BigDaddyO Posted January 16, 2019 Share Posted January 16, 2019 I'm trying to remove the background of some screenshots but I can't figure out how to find the most frequent color, as that should be the background to remove. Right now, I'm just getting the pixel color at -5 from the bottom right corner of the image for the background color which works for now, but I'd prefer to find and remove the most frequent. Any ideas? This is what I have so far. #include <ScreenCapture.au3> _TransparentBackground(0, 0, 500, 300) Func _TransparentBackground($x = 0, $y = 0, $w = @DesktopWidth, $h = @DesktopHeight) ;Change the most common color (usually background) to transparent? _GDIPlus_Startup() Local $hHBitmap = _ScreenCapture_Capture("", $x, $y, $w - 1, $h - 1) Local $hBmp = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap) Local $hBitmap_Result = _GDIPlus_BitmapCreateFromScan0($w, $h) Local $hBitmap_Result_Ctxt = _GDIPlus_ImageGetGraphicsContext($hBitmap_Result) Local $hIA = _GDIPlus_ImageAttributesCreate() ;How do I find the background color (Most Frequent Color)? This is working for me but not ideal... $iPixel = "0x" & Hex(PixelGetColor($x + $w - 5, $y + $h - 5)) ConsoleWrite("Pixel Color = " & $iPixel & @CRLF) _GDIPlus_ImageAttributesSetColorKeys($hIA, 1, True, $iPixel, $iPixel) _GDIPlus_GraphicsDrawImageRectRect($hBitmap_Result_Ctxt, $hBmp, 0, 0, $w, $h, 0, 0, $w, $h, $hIA) _GDIPlus_ImageSaveToFile($hBitmap_Result, @ScriptDir & "\TransPtResult.png") _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hBitmap_Result_Ctxt) _GDIPlus_BitmapDispose($hBitmap_Result) _GDIPlus_BitmapDispose($hBmp) _WinAPI_DeleteObject($hHBitmap) _GDIPlus_Shutdown() ShellExecute(@ScriptDir & "\TransPtResult.png") ;For testing, will be used for OCR EndFunc Thanks, Mike Link to comment Share on other sites More sharing options...
Nine Posted January 16, 2019 Share Posted January 16, 2019 (edited) Here what I would do to find the most common pixel color : expandcollapse popup#include <ScreenCapture.au3> #include <Array.au3> Opt ("MustDeclareVars", 1) CountPixels (100,100,200,200) Func CountPixels ($Left=0,$Top=0,$Right=-1,$Bottom=-1) Local $hBitmap, $hImage, $BitmapData, $Width, $Height, $Scan, $Pos = 0 _GDIPlus_Startup () $hBitmap = _ScreenCapture_Capture ("",$Left,$Top,$Right,$Bottom,False) $hImage = _GDIPlus_BitmapCreateFromHBITMAP ($hBitmap) _WinAPI_DeleteObject ($hBitmap) $Width = _GDIPlus_ImageGetWidth($hImage) $Height = _GDIPlus_ImageGetHeight($hImage) $BitmapData = _GDIPlus_BitmapLockBits ($hImage, 0, 0, $Width, $Height, $GDIP_ILMREAD, $GDIP_PXF32RGB) $Scan = DllStructGetData($BitmapData, "Scan0") Local $tPixel = DllStructCreate("int[" & $Width * $Height & "]", $Scan) Local $aPixel[0][2], $p, $i, $c = 0 For $row = 0 To $Height-1 For $col = 0 To $Width-1 $Pos += 1 $p = BitAnd(DllStructGetData($tPixel,1,$Pos),0xFFFFFF) $i = _ArraySearch ($aPixel,$p,0,0,0,0,1,0) if $i < 0 then $c += 1 Redim $aPixel[$c][2] $aPixel[$c-1][0] = $p $aPixel[$c-1][1] = 1 else $aPixel[$i][1] += 1 endif Next Next _ArrayDisplay ($aPixel) _GDIPlus_BitmapUnlockBits($hImage, $BitmapData) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc Untested... Edited January 16, 2019 by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 17, 2019 Author Share Posted January 17, 2019 Thanks Nine, the _GDIPlus_BitmapLockBits that you used gave me the hint that I was looking for. Once I was able to get all the pixels, I ended up using Scripting.Dictionary to drastically speed up the search. Here is my finished sample script. Now for me to work it into my main script. expandcollapse popup#include <ScreenCapture.au3> #include <Array.au3> $iTimer = TimerInit() $aUnique = _CommonColorSD(50, 100, 200, 200) $iMaxIndex=_ArrayMaxIndex($aUnique,1,1,-1,1) ConsoleWrite("Max Pixel Color = " & $aUnique[$iMaxIndex][0] & ", Count = " & $aUnique[$iMaxIndex][1] & @CRLF) $iTime = TimerDiff($iTimer) ConsoleWrite("ColorA time = (" & $iTime & ")" & @CRLF) _ArrayDisplay($aUnique, '_countUniqueElements') ;Max Pixel Color = 2039583, Count = 31054 ;ColorA time = (716.606813754679) Func _CommonColorSD($x = 0, $y = 0, $iW = @DesktopWidth, $iH = @DesktopHeight) ;Change the most common color (usually background) to transparent? Local $oDict = ObjCreate("Scripting.Dictionary") _GDIPlus_Startup() Local $hHBitmap = _ScreenCapture_Capture("", $x, $y, $iW - 1, $iH - 1) Local $hBmp = _GDIPlus_BitmapCreateFromHBITMAP($hHBitmap) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsDrawImageRect($hContext, $hBmp, 0, 0, $iW, $iH) Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iW, $iH, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD), $GDIP_PXF32ARGB) ;locks a portion of a bitmap for reading and writing. More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx Local $iScan0 = DllStructGetData($tBitmapData, "Scan0") ;get scan0 (pixel data) from locked bitmap Local $tPixel = DllStructCreate("int[" & $iW * $iH & "];", $iScan0) Local $iPixel, $iRowOffset $iCount = 0 For $iY = 0 To $iH - 1 $iRowOffset = $iY * $iW + 1 For $iX = 0 To $iW - 1 ;get each pixel in each line and row $iPixel = BitAnd(DllStructGetData($tPixel, 1, $iRowOffset + $iX), 0xFFFFFF) ;This gets the normal Windows pixel color. Without BitAnd it returns Decimal Windows Color :( blah... If $oDict.Exists($iPixel) Then $oDict.Item($iPixel) = $oDict.Item($iPixel) + 1 Else $oDict.Add($iPixel, 1) EndIf Next Next _GDIPlus_BitmapUnlockBits($hBitmap, $tBitmapData) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits ConsoleWrite("Count = " & $iCount & @CRLF) Local $iUniq = $oDict.Count Local $aRet[$iUniq][2] For $i = 0 To $iUniq - 1 $aRet[$i][0] = $oDict.Keys[$i] $aRet[$i][1] = $oDict.Items[$i] Next Return $aRet EndFunc Link to comment Share on other sites More sharing options...
Nine Posted January 17, 2019 Share Posted January 17, 2019 Thanks for the scripting.dictionnary object. I didn't know about it, and it is truly a nice add-on when 2d array is invoked. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Nine Posted January 18, 2019 Share Posted January 18, 2019 @BigDaddyO After revisiting your code, I have found a way to get the 2D array up faster (about 40x) : $p = 0 For $vKeys in $oDict $aPixel[$p][0] = $vKeys $aPixel[$p][1] = $oDict.item ($vKeys) $p += 1 Next Thanks again for that nice discovery ... “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 18, 2019 Author Share Posted January 18, 2019 @Nine I found that you can speed it up even more by not using an array and simply doing a compare while looping through the $oDict Using one of my larger captures, my original loop took (135276.2844)ms Your updated For In loop took (2437.6408)ms This new For In loop took (864.1878)ms $iMax = 0 For $vKeys in $oDict If $oDict.Item($vKeys) > $iMax Then $iMax = $oDict.Item($vKeys) $iPixel = $vKeys EndIf Next Now to speed up loading the pixels into the scripting dictionary as this large screen capture it taking (120661.1699)ms! Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 18, 2019 Author Share Posted January 18, 2019 So, the BitAnd when pulling each pixel is totally unnecessary. I switched to capturing the raw Windows binary colors and only do the BitAND on the one pixel color I identify as Max and it dropped from 120 seconds down to 6 seconds runtime! Link to comment Share on other sites More sharing options...
Nine Posted January 18, 2019 Share Posted January 18, 2019 48 minutes ago, BigDaddyO said: So, the BitAnd when pulling each pixel is totally unnecessary. I switched to capturing the raw Windows binary colors and only do the BitAND on the one pixel color I identify as Max and it dropped from 120 seconds down to 6 seconds runtime! Really ? Congrats. I never thought that BITAND would be so gluttonous “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 18, 2019 Author Share Posted January 18, 2019 (edited) I am now able to identify the background pixel color (most common) and I can replace those pixels with transparent. I'd also like to be able to replace those background pixels with a specified color but I'm not able to get that working. I know I need to use _GDIPlus_ImageAttributesSetRemapTable instead of _GDIPlus_ImageAttributesSetColorKeys and I thought I did it correctly, but it's not working. In the example below, the 3rd one is supposed to change the background to White 0xFFFFFF but it's not working. _GDIPlus_ImageAttributesSetRemapTable is not returning an error so I'm not sure what else to try. Any ideas on this? expandcollapse popup;Testing the replace pixel color #include <ScreenCapture.au3> ;Capture an un-modified screenshot to use as a base for visually verifying changes _ScreenCapture_Capture("C:\TEMP\Raw.jpg", 100, 50, 700, 550, False) ;This one works! Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_No_Mod.Tiff", 3, 0, 0, 0, 0) ;Just capture a screenshot and enlarge to Scale 3, save as TIFF ;This one works! Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_Transparent.Tiff", 3, 0, 0, 0, 0, -1) ;Capture a screenshot, Make background transparent, scale 3, save as TIFF ;This one doesnt change background to White! Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_White.Tiff", 3, 0, 0, 0, 0, -1, 0xFFFFFF) ;Capture a screenshot, Make background WHITE, Scale 3, save as TIFF Func Swap_Background($x1, $y1, $x2, $y2, $sOutImage = "", $scale = 1, $left_indent = 0, $top_indent = 0, $right_indent = 0, $bottom_indent = 0, $Background = 0, $Replacement = -1) Local $hBitmap, $hwnd, $hDC, $hBMP, $hImage1, $hGraphic, $CLSID, $tParams, $pParams, $tData, $hImage2, $pos[4], $screenpos[4], $pos[4] Local $iPixel = 0 Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1)) Local $giTIFColorDepth = 24 Local $giTIFCompression = $GDIP_EVTCOMPRESSIONNONE $hTimerCapt = TimerInit() $hBitmap = _ScreenCapture_Capture("", $x1, $y1, $x2, $y2, False) _GDIPlus_Startup() ConsoleWrite("Captured initial screenshot to analyze in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) If $Background = -1 Then ;Find the most common pixel color (background) $hTimerCapt = TimerInit() Local $hBmpClr = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) Local $hBitmap0 = _GDIPlus_BitmapCreateFromScan0($x2 - $x1, $y2 - $y1) Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap0) _GDIPlus_GraphicsDrawImageRect($hContext, $hBmpClr, 0, 0, $x2 - $x1, $y2 - $y1) Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap0, 0, 0, $x2 - $x1, $y2 - $y1, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD), $GDIP_PXF32ARGB) ;locks the bitmap for reading and writing. More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx Local $iScan0 = DllStructGetData($tBitmapData, "Scan0") ;get scan0 (pixel data) from locked bitmap Local $tPixel = DllStructCreate("int[" & ($x2 - $x1) * ($y2 - $y1) & "];", $iScan0) Local $iPixelr, $iRowOffset Local $oDict = ObjCreate("Scripting.Dictionary") ;Create the Dictionary to store unique Pixel color counts For $iY = 0 To ($y2 - $y1) - 1 $iRowOffset = $iY * ($x2 - $x1) + 1 For $iX = 0 To ($x2 - $x1) - 1 ;get each pixel in each line and row $iPixelr = DllStructGetData($tPixel, 1, $iRowOffset + $iX) If $oDict.Exists($iPixelr) Then $oDict.Item($iPixelr) = $oDict.Item($iPixelr) + 1 Else $oDict.Add($iPixelr, 1) EndIf Next Next ;Clear up memory usage _GDIPlus_BitmapUnlockBits($hBitmap0, $tBitmapData) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits _GDIPlus_GraphicsDispose($hContext) _GDIPlus_BitmapDispose($hBitmap0) _GDIPlus_BitmapDispose($hBmpClr) ConsoleWrite("Finished identifying all Image colors in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) $hTimerCapt = TimerInit() $iMax = 0 For $vKeys in $oDict If $oDict.Item($vKeys) > $iMax Then $iMax = $oDict.Item($vKeys) $iPixel = $vKeys EndIf Next ConsoleWrite("Pre BitAND Pixel = (" & $iPixel & ")" & @CRLF) $iPixel = BitAnd($iPixel, 0xFFFFFF) ;This switches the Decimal Windows Color into normal Windows pixel color. ConsoleWrite("Finished identifying main color Converted to (" & $iPixel & ") in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) ElseIf $Background = 0 Then ;Dont remove any pixels from the image (Default) $iPixel = "" Else ;If a Value was entered for $Background, assume it was a pixel color to remove $iPixel = $Background EndIf ; Convert the image to a bitmap $hImage2 = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) $hwnd = _WinAPI_GetDesktopWindow() $hDC = _WinAPI_GetDC($hwnd) $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, (($x2 - $x1) * $scale) - ($right_indent * $scale), (($y2 - $y1) * $scale) - ($bottom_indent * $scale)) _WinAPI_ReleaseDC($hwnd, $hDC) $hImage1 = _GDIPlus_BitmapCreateFromHBITMAP($hBMP) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage1) If $Replacement = -1 Then ;Setup the Transparency details $hTimerCapt = TimerInit() Local $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetColorKeys($hIA, 1, True, $iPixel, $iPixel) _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage2, 0 - $left_indent, 0 - $top_indent, ($x2 - $x1) + $left_indent, ($y2 - $y1) + $top_indent, 0 - ($left_indent * $scale), 0 - ($top_indent * $scale), (($x2 - $x1) * $scale) + $left_indent, (($y2 - $y1) * $scale) + $top_indent, $hIA) ConsoleWrite("Finished changing main color to Transparent in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) Else ;A color was identified, need to replace the background $iPixel with $Replacement $hTimerCapt = TimerInit() ConsoleWrite("Replacing (" & $iPixel & ") with (" & $Replacement & ")" & @CRLF) Local $aRemapTable[2][2] $aRemapTable[0][0] = 1 $aRemapTable[1][0] = $iPixel $aRemapTable[1][1] = $Replacement Local $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetRemapTable($hIA, $aRemapTable, 1) If @error Then ConsoleWrite("Error on RemapTable: (" & @error & ") @extended = (" & @extended & ")" & @CRLF) _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage2, 0 - $left_indent, 0 - $top_indent, ($x2 - $x1) + $left_indent, ($y2 - $y1) + $top_indent, 0 - ($left_indent * $scale), 0 - ($top_indent * $scale), (($x2 - $x1) * $scale) + $left_indent, (($y2 - $y1) * $scale) + $top_indent, $hIA) ConsoleWrite("Finished swapping main color (" & $aRemapTable[1][0] & ") with (" & $aRemapTable[1][1] & ") in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) EndIf $hTimerCapt = TimerInit() $CLSID = _GDIPlus_EncodersGetCLSID($Ext) ; Set TIFF parameters $tParams = _GDIPlus_ParamInit(2) $tData = DllStructCreate("int ColorDepth;int Compression") DllStructSetData($tData, "ColorDepth", $giTIFColorDepth) DllStructSetData($tData, "Compression", $giTIFCompression) _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOLORDEPTH, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "ColorDepth")) _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOMPRESSION, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "Compression")) If IsDllStruct($tParams) Then $pParams = DllStructGetPtr($tParams) ; Save TIFF and cleanup _GDIPlus_ImageSaveToFileEx($hImage1, $sOutImage, $CLSID, $pParams) _GDIPlus_ImageDispose($hImage1) _GDIPlus_ImageDispose($hImage2) _GDIPlus_GraphicsDispose($hGraphic) _WinAPI_DeleteObject($hBMP) _GDIPlus_Shutdown() ConsoleWrite("Generated the Scaled TIFF image in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) EndFunc Thanks, Mike Edited January 18, 2019 by BigDaddyO Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 22, 2019 Author Share Posted January 22, 2019 Finally figured out swapping the color with a specific color. Turns out the GDI stuff uses 8 character aRGB not just normal 6 character RGB that you find in most google searches. the first 2 characters are for Transparency. 00 is totally transparent and FF = not transparent at all. So, now this sample will create 4 images. A basic capture, a Capture scaled up 3x, a Capture Scaled up 3x with a transparent background, a Capture scaled up 3x with a white background. expandcollapse popup;Testing the replace pixel color #include <ScreenCapture.au3> ;Capture an un-modified screenshot to use as a base for visually verifying changes _ScreenCapture_Capture("C:\TEMP\Raw.jpg", 100, 50, 700, 550, False) ;Should I check OCR to see if it works better with greyscale? _GDIPlus_BitmapConvertFormat() ;Need to convert the specified Pixel color into a Negative number like I get from the Pixel Search for this to change to! ;Capture a screenshot and enlarge to Scale 3, save as TIFF Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_No_Mod.Tiff", 3, 0, 0, 0, 0) ;Make background transparent! ; Scale = 3, the image will be 3x the size which is usefull for OCR Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_Transparent.Tiff", 3, 0, 0, 0, 0, -1) ;Change background to White! could use 0x00000000 to make background transparent! ; Make background WHITE (Must use aRGB code, where first FF = transparency, remaining 6 FF are pulled from normal windows spy or color picker ; Could use this for setting background to transparent by using 0x00FFFFFF or 0x00000000 ; Scale = 3, the image will be 3x the size which is usefull for OCR Swap_Background(100, 50, 700, 550, "C:\TEMP\Enlarged_White.Tiff", 3, 0, 0, 0, 0, True, 0xFFFFFFFF) Func Swap_Background($x1, $y1, $x2, $y2, $sOutImage = "", $scale = 1, $left_indent = 0, $top_indent = 0, $right_indent = 0, $bottom_indent = 0, $Background = False, $NewColor = True) ConsoleWrite("$NewColor = " & hex($NewColor) & ", True Hex = " & Hex(True) & @CRLF) $hTimerFull = TimerInit() Local $hBitmap, $hwnd, $hDC, $hBMP, $hImage1, $hGraphic, $CLSID, $tParams, $pParams, $tData, $hImage2, $pos[4], $screenpos[4], $pos[4] Local $iPixel = 0 Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1)) Local $giTIFColorDepth = 24 Local $giTIFCompression = $GDIP_EVTCOMPRESSIONNONE $hTimerCapt = TimerInit() $hBitmap = _ScreenCapture_Capture("", $x1, $y1, $x2, $y2, False) _GDIPlus_Startup() ConsoleWrite("Captured initial screenshot to analyze in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) If $Background = True Then ;Find the most common pixel color (background) $hTimerCapt = TimerInit() Local $hBmpClr = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) Local $hBitmap0 = _GDIPlus_BitmapCreateFromScan0($x2 - $x1, $y2 - $y1) Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap0) _GDIPlus_GraphicsDrawImageRect($hContext, $hBmpClr, 0, 0, $x2 - $x1, $y2 - $y1) Local $tBitmapData = _GDIPlus_BitmapLockBits($hBitmap0, 0, 0, $x2 - $x1, $y2 - $y1, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD), $GDIP_PXF32ARGB) ;locks the bitmap for reading and writing, returns aRGB (first 2 are transpancy, FF for not transparent 00 for full transparent). More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx Local $iScan0 = DllStructGetData($tBitmapData, "Scan0") ;get scan0 (pixel data) from locked bitmap Local $tPixel = DllStructCreate("int[" & ($x2 - $x1) * ($y2 - $y1) & "];", $iScan0) Local $iPixelr, $iRowOffset Local $oDict = ObjCreate("Scripting.Dictionary") ;Create the Dictionary to store unique Pixel color counts For $iY = 0 To ($y2 - $y1) - 1 $iRowOffset = $iY * ($x2 - $x1) + 1 For $iX = 0 To ($x2 - $x1) - 1 ;get each pixel in each line and row $iPixelr = DllStructGetData($tPixel, 1, $iRowOffset + $iX) If $oDict.Exists($iPixelr) Then $oDict.Item($iPixelr) = $oDict.Item($iPixelr) + 1 Else $oDict.Add($iPixelr, 1) EndIf Next Next ;Clear up memory usage _GDIPlus_BitmapUnlockBits($hBitmap0, $tBitmapData) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits _GDIPlus_GraphicsDispose($hContext) _GDIPlus_BitmapDispose($hBitmap0) _GDIPlus_BitmapDispose($hBmpClr) ConsoleWrite("Finished identifying all Image colors in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) $hTimerCapt = TimerInit() $iMax = 0 For $vKeys in $oDict If $oDict.Item($vKeys) > $iMax Then $iMax = $oDict.Item($vKeys) $iPixel = $vKeys EndIf Next ConsoleWrite("Pre BitAND Pixel = (" & $iPixel & ") - Post BitAND Pixel = (" & BitAnd($iPixel, 0xFFFFFFFF) & ")" & @CRLF) ;~ $iPixel = BitAnd($iPixel, 0xFFFFFF) ;This switches the Decimal Windows Color into normal Windows pixel color. ConsoleWrite("Finished identifying main color Converted to (" & $iPixel & ") in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) ElseIf $Background = False Then ;Dont remove any pixels from the image (Default) $iPixel = "" Else ;If a Value was entered for $Background, assume it was a pixel color to remove $iPixel = $Background EndIf ; Convert the image to a bitmap $hImage2 = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) $hwnd = _WinAPI_GetDesktopWindow() $hDC = _WinAPI_GetDC($hwnd) $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, (($x2 - $x1) * $scale) - ($right_indent * $scale), (($y2 - $y1) * $scale) - ($bottom_indent * $scale)) _WinAPI_ReleaseDC($hwnd, $hDC) $hImage1 = _GDIPlus_BitmapCreateFromHBITMAP($hBMP) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage1) If hex($NewColor) = hex(True) Then ;8 digit color codes (aRGB) always seem to return as -1 which seem to match True?!? just using Hex to match so it works properly. ;Setup the Transparency details $hTimerCapt = TimerInit() Local $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetColorKeys($hIA, 1, True, $iPixel, $iPixel) _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage2, 0 - $left_indent, 0 - $top_indent, ($x2 - $x1) + $left_indent, ($y2 - $y1) + $top_indent, 0 - ($left_indent * $scale), 0 - ($top_indent * $scale), (($x2 - $x1) * $scale) + $left_indent, (($y2 - $y1) * $scale) + $top_indent, $hIA) ConsoleWrite("Finished changing main color to Transparent in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) ElseIf hex($NewColor) = hex(False) Then ;Dont mess with the background color ;;; Else ;A color was identified, need to replace the background $iPixel with $Replacement $hTimerCapt = TimerInit() ConsoleWrite("Replacing (" & $iPixel & ") with (" & $NewColor & ")" & @CRLF) Local $aRemapTable[2][2] $aRemapTable[0][0] = 1 $aRemapTable[1][0] = $iPixel $aRemapTable[1][1] = $NewColor Local $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetRemapTable($hIA, $aRemapTable, 1) If @error Then ConsoleWrite("Error on RemapTable: (" & @error & ") @extended = (" & @extended & ")" & @CRLF) _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage2, 0 - $left_indent, 0 - $top_indent, ($x2 - $x1) + $left_indent, ($y2 - $y1) + $top_indent, 0 - ($left_indent * $scale), 0 - ($top_indent * $scale), (($x2 - $x1) * $scale) + $left_indent, (($y2 - $y1) * $scale) + $top_indent, $hIA) ConsoleWrite("Finished swapping main color (" & $aRemapTable[1][0] & ") with (" & $aRemapTable[1][1] & ") in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) EndIf $hTimerCapt = TimerInit() $CLSID = _GDIPlus_EncodersGetCLSID($Ext) ; Set TIFF parameters $tParams = _GDIPlus_ParamInit(2) $tData = DllStructCreate("int ColorDepth;int Compression") DllStructSetData($tData, "ColorDepth", $giTIFColorDepth) DllStructSetData($tData, "Compression", $giTIFCompression) _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOLORDEPTH, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "ColorDepth")) _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOMPRESSION, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "Compression")) If IsDllStruct($tParams) Then $pParams = DllStructGetPtr($tParams) ; Save TIFF and cleanup _GDIPlus_ImageSaveToFileEx($hImage1, $sOutImage, $CLSID, $pParams) _GDIPlus_ImageDispose($hImage1) _GDIPlus_ImageDispose($hImage2) _GDIPlus_GraphicsDispose($hGraphic) _WinAPI_DeleteObject($hBMP) _GDIPlus_Shutdown() ConsoleWrite("Generated the Scaled TIFF image in (" & TimerDiff($hTimerCapt) & ")ms" & @CRLF) ConsoleWrite("Completed Image modification. Total time = (" & Round(TimerDiff($hTimerFull) / 1000, 1) & ")seconds" & @CRLF & @CRLF) EndFunc junkew 1 Link to comment Share on other sites More sharing options...
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