ResizeImage - Problème de qualité

Archive.
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

ResizeImage - Problème de qualité

Message par Le Soldat Inconnu »

Salut,

J'ai ouvert ce sujet sur le forum anglais a propos du problème de qualité de ResizeImage avec des PNG et couche Alpha

http://www.purebasic.fr/english/viewtop ... 7&p=315411

Et j'ai trouvé la solution du problème

Vous prenez cette image
Image

et vous lancez ce code.
Le code est composé de 3 méthodes pour redimensionner un PNG :
- GDI plus : plus rapide mais de qualité moindre
- ResizeImage de PB avec ma correction : Plus rapide que ResizeImage sans correction et avec une meilleur qualité
- ResizeImage de PB sans correction : Qualité pas terrible car il y a un effet de bord avec les zone transparente de l'image

Code : Tout sélectionner

Procedure ResizeAlphaImage_GPIplus(Image1, Image2, Width, Height)
	CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0
		Structure GdiplusStartupInput
			GdiPlusVersion.l
			*DebugCallback
			SuppressBackgroundThread.l
			SuppressExternalCodecs.l
		EndStructure
	CompilerEndIf
	Protected hdc.i, input.GdiplusStartupInput, bmi.BITMAPINFO, bm.BITMAP, *token, *gfx, *image, GDIplus, *pPixels
	#PixelFormat32bppARGB = $26200A
	
	If IsImage(Image1)
		; Get image
		GetObject_(ImageID(Image1), SizeOf(BITMAP), @bm.BITMAP)
		
		bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
		bmi\bmiHeader\biWidth = bm\bmWidth
		bmi\bmiHeader\biHeight = -bm\bmHeight
		bmi\bmiHeader\biPlanes = 1
		bmi\bmiHeader\biBitCount = 32
		If bm\bmBitsPixel = 24
			bmi\bmiHeader\biCompression = #BI_RGB
		EndIf
		
		*pPixels = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
		If *pPixels
			
			hdc = CreateCompatibleDC_(GetDC_(ImageID(Image1)))
			If hdc
				GetDIBits_(hdc, ImageID(Image1), 0, bm\bmHeight, *pPixels, @bmi, #DIB_RGB_COLORS)
				DeleteDC_(hdc)
			EndIf
			
			GDIplus = OpenLibrary(#PB_Any, "gdiplus.dll")
			If GDIplus
				
				Debug "GDI open"
				
				input\GdiPlusVersion = 1
				If CallFunction(GDIplus, "GdiplusStartup", @*token, @input, #Null) = 0
					
					Debug "GDI start"
					
					CallFunction(GDIplus, "GdipCreateBitmapFromScan0", ImageWidth(Image1), ImageHeight(Image1), SizeOf(RGBQUAD) * ImageWidth(Image1), #PixelFormat32bppARGB, *pPixels, @*image)
					
					Debug "GDI scan0"
					
					; Create Target image at 32bpp
					ID = CreateImage(Image2, Width, Height, 32)
					If Image2 = #PB_Any
						Image2 = ID
					EndIf
					
					; Draw the Gdip bitmap object
					hdc = StartDrawing(ImageOutput(Image2))
						Box(0, 0, Width, Height, $FFFFFF)
						DrawingMode(#PB_2DDrawing_AlphaChannel)
						Box(0, 0, Width, Height, 0)
						CallFunction(GDIplus, "GdipCreateFromHDC", hdc, @*gfx)
						CallFunction(GDIplus, "GdipDrawImageRectI", *gfx, *image, 0, 0, Width, Height)
					StopDrawing()
					CallFunction(GDIplus, "GdipDeleteGraphics", *gfx)
					CallFunction(GDIplus, "GdipDisposeImage", *image)
					
					CallFunction(GDIplus, "GdiplusShutdown", *token)
				EndIf
				
				CloseLibrary(GDIplus)
			EndIf
			FreeMemory(*pPixels)
		EndIf
	EndIf
	ProcedureReturn Image2
EndProcedure

Procedure ResizeAlphaImage(Image1, Image2, Width, Height)
	oWidth = ImageWidth(Image1)
	oHeight = ImageHeight(Image1)
	ID = CreateImage(Image2, oWidth, oHeight, 32)
	If Image2 = #PB_Any
		Image2 = ID
	EndIf
	StartDrawing(ImageOutput(Image2))
		Box(0, 0, oWidth, oHeight, $FFFFFF)
		DrawingMode(#PB_2DDrawing_AlphaChannel)
		Box(0, 0, oWidth, oHeight, 0)
		DrawingMode(#PB_2DDrawing_Default)
		DrawAlphaImage(ImageID(Image1), 0, 0)
	StopDrawing()
	ResizeImage(Image2, Width, Height, #PB_Image_Smooth)
	ProcedureReturn Image2
EndProcedure

UsePNGImageDecoder()
LoadImage(0, "Resize_Bug_png1.png")

Time1 = ElapsedMilliseconds()
Counter = 200
ResizeX = 2
ResizeY = 2
For i = 1 To Counter
	
	ResizeAlphaImage_GPIplus(0, 1, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY)
	
Next
Time2 = ElapsedMilliseconds()
For i = 1 To Counter
	
	ResizeAlphaImage(0, 2, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY)
	
Next
Time3 = ElapsedMilliseconds()
For i = 1 To Counter
	
	CopyImage(0, 3)
	ResizeImage(3, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY, #PB_Image_Smooth)
	
Next
Time4 = ElapsedMilliseconds()
MessageRequester("Time", "GDIplus = " + Str((Time2 - Time1) / Counter) + " ms" + Chr(10) + "PB (with correction) = " + Str((Time3 - Time2) / Counter) + " ms" + Chr(10) + "PB = " + Str((Time4 - Time3) / Counter) + " ms")



OpenWindow(0, 0, 0, ImageWidth(1) * 3, ImageHeight(1) + ImageHeight(0), "Resized Image", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
SetWindowColor(0, $FF00FF)
ImageGadget(0, 0, 0, 0, 0, ImageID(0))
ImageGadget(1, 0, ImageHeight(0), 0, 0, ImageID(1))
ImageGadget(2, ImageWidth(1), ImageHeight(0), 0, 0, ImageID(2))
ImageGadget(3, ImageWidth(1) * 2, ImageHeight(0), 0, 0, ImageID(3))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Le résultat donne cela :
Image
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: ResizeImage - Problème de qualité

Message par Le Soldat Inconnu »

une solution plus rapide encore

Code : Tout sélectionner

Procedure ResizeAlphaImage_GPIplus(Image1, Image2, Width, Height)
	CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0
		Structure GdiplusStartupInput
			GdiPlusVersion.l
			*DebugCallback
			SuppressBackgroundThread.l
			SuppressExternalCodecs.l
		EndStructure
	CompilerEndIf
	Protected hdc.i, input.GdiplusStartupInput, bmi.BITMAPINFO, bm.BITMAP, *token, *gfx, *image, GDIplus, *pPixels
	#PixelFormat32bppARGB = $26200A
	
	If IsImage(Image1)
		; Get image
		GetObject_(ImageID(Image1), SizeOf(BITMAP), @bm.BITMAP)
		
		bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
		bmi\bmiHeader\biWidth = bm\bmWidth
		bmi\bmiHeader\biHeight = -bm\bmHeight
		bmi\bmiHeader\biPlanes = 1
		bmi\bmiHeader\biBitCount = 32
		If bm\bmBitsPixel = 24
			bmi\bmiHeader\biCompression = #BI_RGB
		EndIf
		
		*pPixels = AllocateMemory(bm\bmWidth * bm\bmHeight * 4)
		If *pPixels
			
			hdc = CreateCompatibleDC_(GetDC_(ImageID(Image1)))
			If hdc
				GetDIBits_(hdc, ImageID(Image1), 0, bm\bmHeight, *pPixels, @bmi, #DIB_RGB_COLORS)
				DeleteDC_(hdc)
			EndIf
			
			GDIplus = OpenLibrary(#PB_Any, "gdiplus.dll")
			If GDIplus
				
				Debug "GDI open"
				
				input\GdiPlusVersion = 1
				If CallFunction(GDIplus, "GdiplusStartup", @*token, @input, #Null) = 0
					
					Debug "GDI start"
					
					CallFunction(GDIplus, "GdipCreateBitmapFromScan0", ImageWidth(Image1), ImageHeight(Image1), SizeOf(RGBQUAD) * ImageWidth(Image1), #PixelFormat32bppARGB, *pPixels, @*image)
					
					Debug "GDI scan0"
					
					; Create Target image at 32bpp
					ID = CreateImage(Image2, Width, Height, 32)
					If Image2 = #PB_Any
						Image2 = ID
					EndIf
					
					; Draw the Gdip bitmap object
					hdc = StartDrawing(ImageOutput(Image2))
						Box(0, 0, Width, Height, $FFFFFF)
						DrawingMode(#PB_2DDrawing_AlphaChannel)
						Box(0, 0, Width, Height, 0)
						CallFunction(GDIplus, "GdipCreateFromHDC", hdc, @*gfx)
						CallFunction(GDIplus, "GdipDrawImageRectI", *gfx, *image, 0, 0, Width, Height)
					StopDrawing()
					CallFunction(GDIplus, "GdipDeleteGraphics", *gfx)
					CallFunction(GDIplus, "GdipDisposeImage", *image)
					
					CallFunction(GDIplus, "GdiplusShutdown", *token)
				EndIf
				
				CloseLibrary(GDIplus)
			EndIf
			FreeMemory(*pPixels)
		EndIf
	EndIf
	ProcedureReturn Image2
EndProcedure

Procedure ResizeAlphaImage(Image, Width, Height)
	Protected x, x1, x2, Memoire, Image_HDC, Image_Ancienne, Image_Bitmap.BITMAP, Image_BitmapInfo.BITMAPINFO
	If IsImage(Image)
		
		; Chargement du HDC
		Image_HDC = CreateCompatibleDC_(#Null)
		Image_Ancienne = SelectObject_(Image_HDC, ImageID(Image))
		
		; Dimension de l'image
		GetObject_(ImageID(Image), SizeOf(BITMAP), @Image_Bitmap)
		Image_BitmapInfo\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
		Image_BitmapInfo\bmiHeader\biWidth = Image_Bitmap\bmWidth
		Image_BitmapInfo\bmiHeader\biHeight = Image_Bitmap\bmHeight
		Image_BitmapInfo\bmiHeader\biPlanes = 1
		Image_BitmapInfo\bmiHeader\biBitCount = 32
		
		; Zone mémoire pour copier l'image
		xx = Image_Bitmap\bmWidth * Image_Bitmap\bmHeight - 1
		Protected Dim Memoire(xx)
		
		; Copie de l'image en mémoire
		GetDIBits_(Image_HDC, ImageID(Image), 0, Image_Bitmap\bmHeight, @Memoire(), @Image_BitmapInfo, #DIB_RGB_COLORS)
		
		; Modification de l'image en mémoire
		For x = 0 To xx
			If Memoire(x) = 0
				Memoire(x) = $00FFFFFF
			EndIf
		Next
		
		; Transfert de la mémoire dans la l'image de base
		SetDIBits_(Image_HDC, ImageID(Image), 0, Image_Bitmap\bmHeight,  @Memoire(), @Image_BitmapInfo, #DIB_RGB_COLORS)
		
		; Fermeture du HDC
		SelectObject_(Image_HDC, Image_Ancienne)
		DeleteDC_(Image_HDC)
		
		ResizeImage(Image, Width, Height, #PB_Image_Smooth)
	EndIf
EndProcedure

Procedure ResizeAlphaImage2(Image1, Image2, Width, Height)
	oWidth = ImageWidth(Image1)
	oHeight = ImageHeight(Image1)
	ID = CreateImage(Image2, oWidth, oHeight, 32)
	If Image2 = #PB_Any
		Image2 = ID
	EndIf
	StartDrawing(ImageOutput(Image2))
		Box(0, 0, oWidth, oHeight, $FFFFFF)
		DrawingMode(#PB_2DDrawing_AlphaChannel)
		Box(0, 0, oWidth, oHeight, 0)
		DrawingMode(#PB_2DDrawing_Default)
		DrawAlphaImage(ImageID(Image1), 0, 0)
	StopDrawing()
	ResizeImage(Image2, Width, Height, #PB_Image_Smooth)
	ProcedureReturn Image2
EndProcedure

UsePNGImageDecoder()
LoadImage(0, "ResizeAlphaImage3.png")

Time1 = ElapsedMilliseconds()
Counter = 50
ResizeX = 4
ResizeY = 2
For i = 1 To Counter
	
	ResizeAlphaImage_GPIplus(0, 1, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY)
	
Next
Time2 = ElapsedMilliseconds()
For i = 1 To Counter
	
	CopyImage(0, 2)
	ResizeAlphaImage(2, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY)
	
Next
Time3 = ElapsedMilliseconds()
For i = 1 To Counter
	
	ResizeAlphaImage2(0, 3, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY)
	
Next
Time4 = ElapsedMilliseconds()
For i = 1 To Counter
	
	CopyImage(0, 4)
	ResizeImage(4, ImageWidth(0) * ResizeX, ImageHeight(0) * ResizeY, #PB_Image_Smooth)
	
Next
Time5 = ElapsedMilliseconds()


OpenWindow(0, 0, 0, ImageWidth(1) * 2, ImageHeight(1) * 2 + ImageHeight(0) + 48, "Resized Image", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
SetWindowColor(0, $FF00FF)
TextGadget(#PB_Any, 0, 0, ImageWidth(0), 16, "Normal", #PB_Text_Center)
ImageGadget(0, 0, 16, 0, 0, ImageID(0))
TextGadget(#PB_Any, 0, 16 + ImageHeight(0), ImageWidth(1), 16, "Resize GDI = " + StrF((Time2 - Time1) / Counter, 1) + " ms", #PB_Text_Center)
ImageGadget(1, 0, 32 + ImageHeight(0), 0, 0, ImageID(1))
TextGadget(#PB_Any, ImageWidth(1), 16 + ImageHeight(0), ImageWidth(1), 16, "Resize PB with correction API = " + StrF((Time3 - Time2) / Counter, 1) + " ms", #PB_Text_Center)
ImageGadget(2, ImageWidth(1), 32 + ImageHeight(0), 0, 0, ImageID(2))
TextGadget(#PB_Any, ImageWidth(1), 32 + ImageHeight(0) + ImageHeight(1), ImageWidth(1), 16, "Resize PB with correction PB = " + StrF((Time4 - Time3) / Counter, 1) + " ms", #PB_Text_Center)
ImageGadget(3, ImageWidth(1), 48 + ImageHeight(0) + ImageHeight(1), 0, 0, ImageID(3))
TextGadget(#PB_Any, 0, 32 + ImageHeight(0) + ImageHeight(1), ImageWidth(1), 16, "Resize PB = " + StrF((Time5 - Time4) / Counter, 1) + " ms", #PB_Text_Center)
ImageGadget(4, 0, 48 + ImageHeight(0) + ImageHeight(1), 0, 0, ImageID(4))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: ResizeImage - Problème de qualité

Message par Ar-S »

Hum je ne vois pas vraiment de différence entre "resize et resize avec correction" sur ton screenshot
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
TazNormand
Messages : 1294
Inscription : ven. 27/oct./2006 12:19
Localisation : Calvados (14)

Re: ResizeImage - Problème de qualité

Message par TazNormand »

Ar-S a écrit :Hum je ne vois pas vraiment de différence entre "resize et resize avec correction" sur ton screenshot
Je vois un trait "violet" a gauche et à droite du bouton sans la correction, est-ce là le problème ?
Image
Image
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: ResizeImage - Problème de qualité

Message par Ar-S »

Tu as raison mais je le vois aussi avec la correction
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: ResizeImage - Problème de qualité

Message par Le Soldat Inconnu »

il y a un effet de bord sur l'image sans la correction (à gauche), en gros un trait foncé sur le contour de l'image alors que sur l'image du centre, il n'y a pas de bordure noire.

Voilà un zoom sur le défaut
Image donne Image avec une espèce de bord noir flou alors qu'il n'existe pas sur l'image d'origine

J'ai vu ça car j'avais des traits en redimensionnant des PNG et je ne comprenais d'où ils venaient



Avec la correction, c'est parfait (si tu vois un bord noir entre le rose et le beige, c'est ton écran qui donne cet effet, essai le code en mettant le fond de la fenêtre en blanc et tu verras :) )
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Répondre