WinApi, Как сохранить GDI регион на жесткий диск?
Возник интерес создать сложный GDI регион на основе изображения(bitmap), регион создал, но не смотря на все ухищрения, скорость создания региона оставляет желать лучшего.
Пример сканирования:
читать дальше »
Код:
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <WinApi.au3>
#include <Constants.au3>
Global $hGui, $gdi32dll, $hBmp, $hMemDC, $hOldBmp, $hRgn, $TagBitmap, $tBitmap, $iW, $iH, $Color
$hGui = GUICreate("Test_BitmapInRegion", 200, 200, -1, -1, $WS_POPUPWINDOW)
$gdi32dll = DllOpen("gdi32.dll")
;~ Загружаю bitmap из файла:
$hBmp = _WinAPI_LoadImage(0, "Form.bmp", $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
;~ Определяю его ширину и высоту:
$TagBitmap = "int bmType;int bmWidth;int bmHeight;int bmWidthBytes;byte bmPlanes;byte bmBitsPixel;ptr bmBits"
$tBitmap = DllStructCreate($TagBitmap)
_WinAPI_GetObject($hBmp, DllStructGetSize($tBitmap), DllStructGetPtr($tBitmap))
$iW = DllStructGetData($tBitmap, 2)
$iH = DllStructGetData($tBitmap, 3)
$tObject = ""
;~ создаю контекст устpойства памяти:
$hMemDC = _WinAPI_CreateCompatibleDC(0)
;~ заменяю bitmap по умолчанию, bitmap'ом загруженным из файла:
$hOldBmp = _WinAPI_SelectObject($hMemDC, $hBmp)
;~ Создаю пустой регион:
$hRgn = _WinAPI_CreateRectRgn(0, 0, 0, 0)
$Color = 0xFFFFFF ; <- цвет на основе которого будут добавляться (или исключаться) области.
;~ Есть два варианта создания региона на основе bitmap, путём добавления к региону($RGN_OR), и путём исключения из него($RGN_DIFF).
;~ В первом варианте создаётся пустой регион к которому впоследствии (в цикле) добавляются нужные нам области.
;~ Во втором варианте создаётся прямоугольный регион идентичный размеру bitmap, из которого будут исключаться лишние области.
;~ Какой из способов предпочтительнее, зависит от размеров региона по отношению к размеру изображения,
;~ если площадь нужного нам региона (визуально) превышает 50% площади изображения, то второй вариант будет работать чуть быстрее.
;~ Формирую регион путём добавления(сканирование "горизонтальными блоками" высотой в 1 пиксель):
Dim $fState, $iXStart, $iX, $iY, $hRgnBlock, $iColor
$hRgnBlock = _WinAPI_CreateRectRgn(0, 0, 0, 0)
For $iY = 0 To $iH
For $iX = 0 To $iW
$iColor = GetPixel($hMemDC, $iX, $iY, $gdi32dll) ; определяю цвет
If $iColor = $Color Then ; если цвет совпадает
If Not $fState Then ; Если цвет на текущей линии (для этого блока) совпал впервые
$iXStart = $iX ;<- запоминаю стартовую позицию.
$fState = True ; <- Отмечаю что сканирование блока было начато
ElseIf $iX = $iW Then ; если достигнут правый край изображения и цвет совпал
SetRectRgn($hRgnBlock, $iXStart, $iY, $iX, $iY+1, $gdi32dll)
_WinAPI_CombineRgn($hRgn, $hRgn, $hRgnBlock, $RGN_OR)
$fState = False ; <- Отмечаю что сканирование текущего блока было завершено
EndIf
ElseIf $fState Then ; если цвет не совпал, но уже совпадал раньше для этого блока(там где мы запоминали стартовую позицию)
SetRectRgn($hRgnBlock, $iXStart, $iY, $iX, $iY+1, $gdi32dll)
_WinAPI_CombineRgn($hRgn, $hRgn, $hRgnBlock, $RGN_OR)
$fState = False ; <- Отмечаю что сканирование текущего блока было завершено
EndIf
Next
Next
_WinAPI_DeleteObject($hRgnBlock)
_WinAPI_SetWindowRgn($hGui, $hRgn, False)
;~ возвращаю старый bitmap:
_WinAPI_SelectObject($hMemDC, $hOldBmp)
;~ освобождаю контекст:
_WinAPI_DeleteDC($hMemDC)
;~ удаляю загруженный bitmap:
_WinAPI_DeleteObject($hBmp)
DllClose($gdi32dll)
GUISetState(@SW_SHOW)
While 1
$msg = GUIGetMsg()
Switch $msg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Func GetPixel($hDC, $iX, $iY, $gdi32dll="gdi32.dll")
Local $aResult
$aResult = DllCall($gdi32dll, "long", "GetPixel", "hwnd", $hDC, "int", $iX, "int", $iY)
If @error Then Return SetError(@error, 0, 0)
Return SetError(0, 0, $aResult[0])
EndFunc ;==>GetPixel
;~ Преобразует область, в прямоугольную область с указанным pазмеpом.
;~ $hRgn - Идентификатор области.
;~ $X1, $Y1 - Веpхний левый угол пpямоугольной области.
;~ $X2, $Y2 - Нижний пpавый угол пpямоугольной области.
Func SetRectRgn($hRgn, $iX1, $iY1, $iX2, $iY2, $gdi32dll="gdi32.dll")
Local $aResult
$aResult = DllCall($gdi32dll, "int", "SetRectRgn", "hwnd", $hRgn, "int", $iX1, "int", $iY1, "int", $iX2, "int", $iY2)
If @error Then Return SetError(@error, 0, 0)
Return SetError(0, 0, $aResult[0])
EndFunc ;==>SetRectRgn
Сканировать изображение при каждом запуске скрипта, думаю, плохая идея.
Вопрос: Как сохранить созданный регион в файл, но самое главное как его потом загружать?
P.S. Я знаю что при загрузке и сохранении региона, используются функции GetRegionData и ExtCreateRegion, синтаксис которых мне тоже непонятен.
|