Что нового

Как обрезать часть изображения при помощи GDI+?

Gealut

Новичок
Сообщения
38
Репутация
0
Имеется уже загруженное и смасштабированное изображение. Теперь нужно его обрезать слева и справа на какое-то (определяемое юзером) количество пикселей. Сломал голову, перерыл весь форум - все примеры именно на перемасштабирование картинок, а на кадрирование только с использованием внешних dll (FreeImage и пр.). А мне хотелось бы обойтись без них.

Вот тут лаконичный совет использовать _GDIPlus_GraphicsDrawImageRect. Но как? Я же не могу в качестве предпоследнего параметра задать отрицательное число...

Подскажите, плиз, на конкретном примере: есть изображение, скажем, 400х700 пикселей. Его надо обрезать до 300х700 пикселей (то есть полоски по 50 пикселей слева и справа). Как это сделать? Без внешних длл, без промежуточного сохранения в файл.

Тут код функции (найденной на английском форуме и переработанной), используемой мной для масштабирования изображения:

Код:
$PicPreview = GUICtrlCreatePic("", $CoverWindow_H, $CoverWindow_V, $PreviewSizeW, $PreviewSizeH)

...

$hBMP = _GetImage($CurDir & $CurCover, $PreviewSizeW, $PreviewSizeH, $Color0)
_hBmpToPicControl($PicPreview, $hBMP, 1)

...

Func _GetImage($sFile, $iWH, $iHH, $iBkClr = 0xFFFFFF)
    Local $hBmp1, $hBitmap, $hGraphic, $hImage, $iW, $iH, $aGS, $hBmp2
    _GDIPlus_Startup()
    $hBmp1 = _WinAPI_CreateBitmap($iWH, $iHH, 1, 32)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp1)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _WinAPI_DeleteObject($hBmp1)
    _GDIPlus_GraphicsClear($hGraphic, BitOR(0xFF000000, $iBkClr))
    $hImage = _GDIPlus_ImageLoadFromFile($sFile)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $aGS = _GetScaleNew($iW, $iH, $iWH, $iHH)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, $aGS[0], $aGS[1], $aGS[2], $aGS[3])
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)
    $hBmp2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_Shutdown()
    Return $hBmp2
EndFunc

Func _GetScaleNew($iW, $iH, $iWH, $iHH)
    Local $aRet[4]
    If $iW = $iWH And $iH = $iHH Then
        $aRet[2] = $iWH
        $aRet[3] = $iHH
        $aRet[0] = 0
        $aRet[1] = 0
	ElseIf $iW < $iWH And $iH < $iHH Then
        $aRet[2] = $iW
        $aRet[3] = $iH
        $aRet[0] = ($iWH - $iW)/2
        $aRet[1] = 0
	ElseIf $iW > $iWH Then
		$aRet[2] = $iWH
		$aRet[3] = ($iH/$iW)*$iWH
		$aRet[0] = 0
		$aRet[1] = 0
		If $aRet[3] > $iHH Then
			$aRet[2] = ($iW/$iH)*$iHH
			$aRet[3] = $iHH
			$aRet[0] = 0
			$aRet[1] = 0
		EndIf
	ElseIf $iH > $iHH Then
		$aRet[2] = ($iW/$iH)*$iHH
		$aRet[3] = $iHH
		$aRet[0] = 0
		$aRet[1] = 0
	EndIf
    Return $aRet
EndFunc

Func _hBmpToPicControl($iCID, ByRef $hBmp, $iFlag = 0)
    Local Const $STM_SETIMAGE = 0x0172
    Local Const $IMAGE_BITMAP = 0
    Local $hOldBmp
    $hOldBmp = GUICtrlSendMsg($iCID, $STM_SETIMAGE, $IMAGE_BITMAP, $hBmp)
    If $hOldBmp Then _WinAPI_DeleteObject($hOldBmp)
    If $iFlag Then _WinAPI_DeleteObject($hBmp)
EndFunc

Эта функция "вписывает" изображение в окно заданных размеров. А мне нужно предусмотреть вариант, что юзер фиксирует высоту изображения и тогда пропорционально уменьшенное изображение может быть шире имеющегося окна. И это изображение надо обрезать с краев, чтобы оно влезло в окно. Как предусмотреть - вопросов нет, вопрос только в самом механизме обрезки изображения.

Заранее спасибо за любую помощь.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Код:
#Include <GDIPlus.au3>

_GDIPlus_Startup()

$hSource = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\400x700.png')
$Size = _GDIPlus_GetImageDimension($hSource)
$hDestination = _GDIPlus_CreateBitmapFromScan0($Size[0] - 100, $Size[1], 0, _GDIPlus_GetImagePixelFormat($hSource))
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hDestination)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hSource, -50, 0, $Size[0], $Size[1])
_GDIPlus_ImageSaveToFile($hDestination, @ScriptDir & '\300x700.png')
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_ImageDispose($hDestination)
_GDIPlus_ImageDispose($hSource)

_GDIPlus_Shutdown()

Func _GDIPlus_CreateBitmapFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
	Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromScan0', 'int', $iWidth, 'int', $iHeight, 'int', $iStride, 'int', $iPixelFormat, 'ptr', $pScan0, 'ptr*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[6]
EndFunc   ;==>_GDIPlus_CreateBitmapFromScan0

Func _GDIPlus_GetImageDimension($hImage)
	Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hImage, 'float*', 0, 'float*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Local $Result[2]
	$Result[0] = $Ret[2]
	$Result[1] = $Ret[3]
	Return $Result
EndFunc   ;==>_GDIPlus_GetImageDimension

Func _GDIPlus_GetImagePixelFormat($hImage)
    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImagePixelFormat', 'ptr', $hImage, 'uint*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
    Return $Ret[2]
EndFunc   ;==>_GDIPlus_GetImagePixelFormat
 
Автор
G

Gealut

Новичок
Сообщения
38
Репутация
0
Спасибо, оказывается, у меня не работало с отрицательным числом в параметрах _GDIPlus_GraphicsDrawImageRect потому, что я ошибся в формулах пересчета размеров. Как исправлю - попробую еще раз.
 
Автор
G

Gealut

Новичок
Сообщения
38
Репутация
0
Все, спасибо, исправил ошибку, теперь все прекрасно работает.
 

alexnasa

Новичок
Сообщения
50
Репутация
0
Подскажите дилетанту.. не работает, понимаешь..
пишет-
Код:
>"C:\Program Files\AutoIt3\SciTE\..\autoit3.exe" /ErrorStdOut "C:\Users\admin\Pictures\AutoIt v3 Script.au3"    
"C:\Users\admin\Pictures\AutoIt v3 Script.au3" (26) : ==> Variable used without being declared.:
Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hImage, 'float*', 0, 'float*', 0)
Local $Ret = DllCall(^ ERROR
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
сейчас эта переменная
Код:
$ghGDIPDll

имеет другое имя.
Код:
$__g_hGDIPDll

смотри библиотеку GDIPlus.au3. там почти в самом начале
 

alexnasa

Новичок
Сообщения
50
Репутация
0
joiner сказал(а):
сейчас эта переменная
Код:
$ghGDIPDll

имеет другое имя.
Код:
$__g_hGDIPDll

смотри библиотеку GDIPlus.au3. там почти в самом начале
Точно!!! Спассибоо!! Работает!

А ещё один момент! Можно ли сделать так, что бы фото обрезало не справа- слева, а сверху - снизу?
Yashied сказал(а):
Код:
#Include <GDIPlus.au3>

_GDIPlus_Startup()

$hSource = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\400x700.png')
$Size = _GDIPlus_GetImageDimension($hSource)
$hDestination = _GDIPlus_CreateBitmapFromScan0($Size[0] - 100, $Size[1], 0, _GDIPlus_GetImagePixelFormat($hSource))
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hDestination)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hSource, -50, 0, $Size[0], $Size[1])
_GDIPlus_ImageSaveToFile($hDestination, @ScriptDir & '\300x700.png')
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_ImageDispose($hDestination)
_GDIPlus_ImageDispose($hSource)

_GDIPlus_Shutdown()

Func _GDIPlus_CreateBitmapFromScan0($iWidth, $iHeight, $iStride = 0, $iPixelFormat = 0x0026200A, $pScan0 = 0)
	Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromScan0', 'int', $iWidth, 'int', $iHeight, 'int', $iStride, 'int', $iPixelFormat, 'ptr', $pScan0, 'ptr*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[6]
EndFunc   ;==>_GDIPlus_CreateBitmapFromScan0

Func _GDIPlus_GetImageDimension($hImage)
	Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hImage, 'float*', 0, 'float*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Local $Result[2]
	$Result[0] = $Ret[2]
	$Result[1] = $Ret[3]
	Return $Result
EndFunc   ;==>_GDIPlus_GetImageDimension

Func _GDIPlus_GetImagePixelFormat($hImage)
    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImagePixelFormat', 'ptr', $hImage, 'uint*', 0)
	If (@error) Or ($Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
    Return $Ret[2]
EndFunc   ;==>_GDIPlus_GetImagePixelFormat
 

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
alexnasa
справа- слева, сверху - снизу
Код:
#Include <GDIPlus.au3>

_GDIPlus_Startup()

$hSource = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\400x700.png')
$Size = _GDIPlus_ImageGetDimension($hSource)

; по ширине
$hDestination = _GDIPlus_BitmapCreateFromScan0($Size[0] - 100, $Size[1], _GDIPlus_ImageGetPixelFormat($hSource)[0])
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hDestination)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hSource, -50, 0, $Size[0], $Size[1])
_GDIPlus_ImageSaveToFile($hDestination, @ScriptDir & '\300x700.png')

; по высоте
$hDestination = _GDIPlus_BitmapCreateFromScan0($Size[0], $Size[1] - 100, _GDIPlus_ImageGetPixelFormat($hSource)[0])
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hDestination)
_GDIPlus_GraphicsDrawImageRect($hGraphics, $hSource, 0, -50, $Size[0], $Size[1])
_GDIPlus_ImageSaveToFile($hDestination, @ScriptDir & '\400x600.png')

_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_ImageDispose($hDestination)
_GDIPlus_ImageDispose($hSource)

_GDIPlus_Shutdown()
 
Верх