1 (изменено: MandarinKa02, 2019-01-08 00:00:37)

Тема: AHK: Gdi+ bitmap из bitmap

Есть следующая функция:

+ открыть спойлер

GDI_CreateBitmapFromFile(dir,w=0,h=0,bkg=0) {
	bitmap:=Gdip_CreateBitmapFromFile(dir)
	if(w<=0 || h<=0)
		return bitmap
	bOut:=Gdip_CreateBitmap(w,h)
	graphics:=Gdip_GraphicsFromImage(bOut)

	if(bkg)
		pBrush:=Gdip_BrushCreateSolid(bkg)
		,Gdip_FillRectangle(graphics,pBrush,0,0,w,h) ;for Transparence ;TO_EDIT (need +1?)
		,Gdip_DeleteBrush(pBrush)

		start:=A_TickCount
	Gdip_DrawImage(graphics,bitmap, 0,0,w,h,0,0,Gdip_GetImageWidth(bitmap),Gdip_GetImageHeight(bitmap),1)
	msgbox % A_TickCount-start "ms" "`nuo"
	Gdip_DeleteGraphics(graphics)
	Gdip_DisposeImage(bitmap)
	return bOut
}

Если помимо директории файла, указать длину и ширину, то функция уменьшит/увеличит изображение, сохраняя пропорции.
MsgBox при этом выводит около 265мс, что не есть хорошо.
Кто-то сталкивался с таким, и если нет, подкиньте, пожалуйста документацию по этому поводу.

P.S. используемая библиотека

2

Re: AHK: Gdi+ bitmap из bitmap

P.P.S. забыл уточнить. Конвертирую изображение размером 4160х2340 в 72х72(или около-того).

3

Re: AHK: Gdi+ bitmap из bitmap

Я бы посмотрел у какой функции  dll идут тормоза. После чего уже можно гуглить, можно ли ее чем-то заменить или поправить,чтобы увеличить скорость.

4

Re: AHK: Gdi+ bitmap из bitmap

Функция GdipDrawImageRectRect.
Скачал *тут* библиотеку и подгрузил ее через LoadLibrary.
Результат тот же.
Подумал, может все равно использует другую библиотеку? Так, похоже, и оказалось. Через ProcessMonitor видно, что подгружает gdiplus.dll из другого источника.
https://i.imgur.com/F1buStw.png

5 (изменено: Malcev, 2019-01-14 12:19:46)

Re: AHK: Gdi+ bitmap из bitmap

Думаю не в этом дело.
Похоже зависит от многих факторов, например того каким способом загружаете картинку.
Изучайте и тестируйте (5 частей).
https://photosauce.net/blog/post/image- … ce-resizer
У меня с изменением InterpolationMode на NearestNeighbor скорость увеличилась.
А если одну и ту же картинку требуется переконвертировать в несколько размеров, то скорость заметно увеличится если картинку предварительно форсированно отвалидейтить.

DllCall("gdiplus\GdipImageForceValidation", Ptr, bitmap)
loop 10
{
   bOut%A_Index%:=Gdip_CreateBitmap(w+A_Index,h+A_Index)
   graphics%A_Index%:=Gdip_GraphicsFromImage(bOut%A_Index%)
   Gdip_DrawImage(graphics%A_Index%,bitmap, 0,0,w,h,0,0,Gdip_GetImageWidth(bitmap),Gdip_GetImageHeight(bitmap),1)
}

6

Re: AHK: Gdi+ bitmap из bitmap

Спасибо за наводку.

У меня с изменением InterpolationMode на NearestNeighbor скорость увеличилась.

Тоже пробовал с этим играться, скорость обработки уменьшилась на 20мс. (220-230мс)

7

Re: AHK: Gdi+ bitmap из bitmap

Из статьи понял, что bitmapFromStream не валидирует/валидейтит изображение.
Из этого вышла следующая функция: (недописанная)

+ открыть спойлер
GDI_CreateBitmapFromFile(dir,w=0,h=0,bkg=0) {
	bOut:=Gdip_CreateBitmap(w,h)
	graphics:=Gdip_GraphicsFromImage(bOut)

		start:=A_TickCount
	;Gdip_SetInterpolationMode(graphics,5)
	;Gdip_BitmapSetResolution()
	H:=File_Open("Read",dir)
	size:=File_Read(H,data,File_Size(H))

	hData := DllCall("GlobalAlloc", "UInt",2, "UInt",size)
    pData := DllCall("GlobalLock", "UInt",hData, "Ptr")
    DllCall("RtlMoveMemory", "Ptr",pData, "Ptr",&data, "UInt",size)
    DllCall("GlobalUnlock", "UInt",hData)
    rc3 := DllCall("ole32\CreateStreamOnHGlobal", "UInt",hData, "Int",True, "Ptr*",pStream)

	DllCall("gdiplus\GdipCreateBitmapFromStream", "UPtr", pStream, "UPtr*", pBitmap, "UInt") "`nh=" H
	;DllCall("gdiplus\GdipImageForceValidation", Ptr, pBitmap)
	;Gdip_SetInterpolationMode(graphics,1)
	;Gdip_SetSmoothingMode(graphics,3)
	Gdip_DrawImage(graphics,pBitmap, 0,0,w,h,0,0,Gdip_GetImageWidth(pBitmap),Gdip_GetImageHeight(pBitmap),1)
	msgbox % A_TickCount-start "ms"
	Gdip_DeleteGraphics(graphics)
	Gdip_DisposeImage(bitmap)
	return bOut
}














File_Open(sType, sFile) {

	bRead := InStr(sType, "READ")
	bSeq  := sType = "READSEQ"

	;Open the file for writing with GENERIC_WRITE/GENERIC_READ, NO SHARING/FILE_SHARE_READ & FILE_SHARE_WRITE, and
	;OPEN_ALWAYS/OPEN_EXISTING, and FILE_FLAG_SEQUENTIAL_SCAN
	hFile := DllCall("CreateFile", "Str", sFile, "UInt", bRead ? 0x80000000 : 0x40000000, "UInt", bRead ? 3 : 0, "Ptr", 0
								 , "UInt", bRead ? 3 : 4, "UInt", bSeq ? 0x08000000 : 0, "Ptr", 0, "Ptr")
	If (hFile=-1 || ErrorLevel) { ;Check for any error other than ERROR_FILE_EXISTS
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return 0 ;Return INVALID_HANDLE_VALUE
	} Else Return hFile
}

File_Read(hFile, ByRef bData, iLength = 0, bPtr=0) {

	;Check if we're reading up to the rest of the file
	If Not iLength ;Set the length equal to the remaining part of the file
		iLength := File_Size(hFile) - File_Pointer(hFile)

	;Prep the variable
	if(!bPtr)
	VarSetCapacity(bData, iLength, 0)

	;Read the file
	r := DllCall("ReadFile", "Ptr", hFile, "Ptr", (bPtr?bData:&bData), "UInt", iLength, "UInt*", iLengthRead, "Ptr", 0)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return 0
	} Else Return iLengthRead
}

File_Size(hFile) {
	r := DllCall("GetFileSizeEx", "Ptr", hFile, "Int64*", iFileSize)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return 0
	} Else Return iFileSize
}

Прирост производительности значителен, теперь 40-70мс. Похоже, получилось.
Но, один дефект таки имеется: функция не уменьшает изображения соблюдая пропорции, а как-то криво его обрезает.
*тык*

8

Re: AHK: Gdi+ bitmap из bitmap

Проверяйте, что получаете в pBitmap.

9 (изменено: MandarinKa02, 2019-01-17 16:08:36)

Re: AHK: Gdi+ bitmap из bitmap

В pBitmap получаю загружаемое изображение. Проверял через Gdip_SaveBitmapToFile()

10 (изменено: MandarinKa02, 2019-01-17 16:46:34)

Re: AHK: Gdi+ bitmap из bitmap

Ошибка до такой степени проста..

GDI_CreateBitmapFromFile(...w=0...)
...
H:=File_Open("Read",dir)
...
msgbox % h "==" H

UPDATE:
Даже при таком раскладе на выходе 266ms.

GDI_CreateBitmapFromFile(dir,w=0,h=0,bkg=0) {
	if(w<=0 || h<=0)
		return bitmap:=Gdip_CreateBitmapFromFile(dir)
	handle:=File_Open("Read",dir),size:=File_Read(handle,data,File_Size(handle)),File_Close(handle)

	hData := DllCall("GlobalAlloc", "UInt",2, "UInt",size)
    pData := DllCall("GlobalLock", "UInt",hData, "Ptr")
    DllCall("RtlMoveMemory", "Ptr",pData, "Ptr",&data, "UInt",size)
    DllCall("GlobalUnlock", "UInt",hData)
    rc3 := DllCall("ole32\CreateStreamOnHGlobal", "UInt",hData, "Int",True, "Ptr*",pStream)

	DllCall("gdiplus\GdipCreateBitmapFromStream", "UPtr", pStream, "UPtr*", pBitmap, "UInt")


	bOut:=Gdip_CreateBitmap(w,h)
	graphics:=Gdip_GraphicsFromImage(bOut)
	if(bkg)
		pBrush:=Gdip_BrushCreateSolid(bkg)
		,Gdip_FillRectangle(graphics,pBrush,0,0,w,h) ;for Transparence ;TO_EDIT (need +1?)
		,Gdip_DeleteBrush(pBrush)

	start:=A_TickCount
	Gdip_DrawImage(graphics,pBitmap, 0,0,w,h,0,0,Gdip_GetImageWidth(pBitmap),Gdip_GetImageHeight(pBitmap),1)
	msgbox % A_TickCount-start "ms"
	Gdip_DeleteGraphics(graphics)
	Gdip_DisposeImage(bitmap)
	return bOut
}

11

Re: AHK: Gdi+ bitmap из bitmap

ИМХО использовать тормознутый gdi для скоростной обработки изображений не самый лучший вариант.