Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » AutoIt » [решено] WinApi, Как сохранить GDI регион на жесткий диск?

Ответить
Настройки темы
[решено] WinApi, Как сохранить GDI регион на жесткий диск?

Пользователь


Сообщения: 135
Благодарности: 32

Профиль | Отправить PM | Цитировать


Возник интерес создать сложный 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, синтаксис которых мне тоже непонятен.

-------
Создатель знает, что достиг совершенства не когда нечего добавить, а когда нечего убрать. - Антуан де Сент-Экзюпери


Отправлено: 18:23, 09-09-2009

 

Googler


Сообщения: 3665
Благодарности: 1563

Профиль | Отправить PM | Цитировать


Цитата Diamond:
Как сохранить созданный регион в файл, но самое главное как его потом загружать? »
думаю где-то так (извиняюсь - на комменты нет времени):
Код: Выделить весь код
Func _RegionSave($hRgn, $sFile)
    Local $aRet, $tBuf, $hFile, $iErr

    $aRet = DllCall($gdi32dll, "uint", "GetRegionData", "hwnd", $hRgn, "dword", 0, "ptr", 0)
    If $aRet[0]=0 Then Return SetError(2, 1, False)
    $tBuf = DllStructCreate("byte["& $aRet[0] &"]")
    $aRet = DllCall($gdi32dll, "uint", "GetRegionData", "hwnd", $hRgn, "dword", $aRet[0], "ptr", DllStructGetPtr($tBuf))
    If $aRet[0]=0 Then Return SetError(2, 2, False)

    $hFile = FileOpen($sFile, 18)
    If $hFile=-1 Then Return SetError(1, 1, False)
    $iErr = FileWrite($hFile, DllStructGetData($tBuf,1))

    FileClose($hFile)
    Return SetError($iErr, 2, False)
EndFunc

Func _RegionLoad($sFile)
    Local $aRet, $tBuf, $hFile, $bFile, $iErr

    $hFile = FileOpen($sFile, 16)
    If $hFile=-1 Then Return SetError(1, 0, 0)
    $bFile = FileRead ($hFile)
    $zFile = BinaryLen($bFile)
    FileClose($hFile)

    $tBuf = DllStructCreate("byte["& $zFile &"]")
    DllStructSetData($tBuf, 1, $bFile)
    $aRet = DllCall($gdi32dll, "hwnd", "ExtCreateRegion", "ptr", 0, "uint", $zFile, "ptr", DllStructGetPtr($tBuf))
    If $aRet=0 Then Return SetError(2, 0, 0)
    Return $aRet[0]
EndFunc
Цитата Diamond:
Сканировать изображение при каждом запуске скрипта, думаю, плохая идея »
думаю не очень - только придется отказаться от GetPixel, буферизовать всё изображение в память (например через _GDIPlus_BitmapLockBits) и работать уже с массивом пикселей без обращений к GDI

P.S. по ходу полученный регион отличается от исходной картинки, т.к. каждая строка развертки заменяется на две строки (прямоугольник), это так?
Это сообщение посчитали полезным следующие участники:

Отправлено: 05:41, 10-09-2009 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Пользователь


Сообщения: 135
Благодарности: 32

Профиль | Отправить PM | Цитировать


amel27, Супер! Просто нет слов. Спасибо!
Цитата amel27:
буферизовать всё изображение в память (например через _GDIPlus_BitmapLockBits) и работать уже с массивом пикселей без обращений к GDI »
Я даже и не представлял что такое возможно, спасибо за идею, буду разбираться в структуре которую возвращает эта функция.
Цитата amel27:
P.S. по ходу полученный регион отличается от исходной картинки, т.к. каждая строка развертки заменяется на две строки»
Нет вроде бы... всё один к одному. Нарисовал несколько черно-белых картинок , протестировал, и у меня все совпало.

-------
Создатель знает, что достиг совершенства не когда нечего добавить, а когда нечего убрать. - Антуан де Сент-Экзюпери


Отправлено: 07:20, 10-09-2009 | #3


Googler


Сообщения: 3665
Благодарности: 1563

Профиль | Отправить PM | Цитировать


Цитата Diamond:
Нет вроде бы... всё один к одному »
гм... у тебя при вызове SetRectRgn() вертикаль $iY и $iY+1, что соответствует прямоугольнику высотой 2 пикселя, а кодируется линия (высотой 1 пиксель)... другое дело, что для одинаковых Y API ф-ция не сработает... В идеале (как я себе это представляю) нужно сначала на основе файла сваять массив полигонов, представляющих трафарет региона (отдельным UDF), а потом уже применять этот массив к региону... задача нетривиальная, но ИМХО вполне решаема

и еще вопрос - почему ты используешь SetRectRgn вместо CreateRectRgn?

Отправлено: 08:07, 10-09-2009 | #4


Пользователь


Сообщения: 135
Благодарности: 32

Профиль | Отправить PM | Цитировать


Цитата amel27:
у тебя при вызове SetRectRgn() вертикаль $iY и $iY+1, что соответствует прямоугольнику высотой 2 пикселя, а кодируется линия (высотой 1 пиксель)... другое дело, что для одинаковых Y API ф-ция не сработает... »
Я думаю что это особенность GDI, область формируется по внутренней стороне переданных координат, а если так - то всё верно, это как раз и будет прямоугольник высотой в один пиксель.(имхо)
Цитата amel27:
почему ты используешь SetRectRgn вместо CreateRectRgn? »
У меня изначально так и было , мне не понравилось то что приходиться постоянно удалять временный регион после объединения с основным, т.е. получается лишний вызов функции DeleteObject.

-------
Создатель знает, что достиг совершенства не когда нечего добавить, а когда нечего убрать. - Антуан де Сент-Экзюпери


Отправлено: 10:05, 10-09-2009 | #5


Googler


Сообщения: 3665
Благодарности: 1563

Профиль | Отправить PM | Цитировать


Diamond, понятно... а то подумал может так быстрее работает
сделал профилирование твоего скрипта - 95% отбирает GetPixel

Отправлено: 10:25, 10-09-2009 | #6


Пользователь


Сообщения: 135
Благодарности: 32

Профиль | Отправить PM | Цитировать


Цитата amel27:
понятно... а то подумал может так быстрее работает »

Цитата amel27:
сделал профилирование твоего скрипта - 95% отбирает GetPixel »
В общем-то не могу сказать что я сильно удивлён - точнее этого и стоило ожидать, ведь функция вызывается для каждого пикселя картинки, ну и конечно чем проще фигура на самой картинке тем выше этот процент. Ещё я где-то вычитал что GetPixel довольно медлительна сама по себе.
Нашел статью где автор применяет (на c++ вроде бы) схожий с моим скриптом принцип создания региона, но вот упоминания о GetPixel я в его коде не нашёл, также там прилагается ссылка на утилиту RegionCreator(почти в самом низу страницы), да и работает она гораздо быстрее чем мой скрипт.
http://sources.ru/cpp/bitmap/regions.shtml

-------
Создатель знает, что достиг совершенства не когда нечего добавить, а когда нечего убрать. - Антуан де Сент-Экзюпери


Отправлено: 12:16, 10-09-2009 | #7


Googler


Сообщения: 3665
Благодарности: 1563

Профиль | Отправить PM | Цитировать


Diamond, да, там все крутится вокруг GetDIBits()
Это сообщение посчитали полезным следующие участники:

Отправлено: 12:37, 10-09-2009 | #8



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » AutoIt » [решено] WinApi, Как сохранить GDI регион на жесткий диск?

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Установка - [решено] Как отформатировать жесткий диск, если с загрузочного диска установка не начинается. Мартиша Microsoft Windows 2000/XP 17 15-11-2009 22:32
Debian/Ubuntu - [решено] Как правильно установить Knoppix 5.3.1 на жесткий диск CJ F.A.N. Общий по Linux 14 17-07-2009 02:02
Как вылечить жесткий диск alex77754 Microsoft Windows 2000/XP 7 11-12-2006 19:26
Как форматировать жесткий диск? lag Хочу все знать 4 03-03-2006 02:20
как установить жесткий диск? Guest Хочу все знать 1 28-05-2004 15:08




 
Переход