[Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von DarkDragon »

Cool, vielen Dank ;-) .
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Benutzeravatar
Falko
Admin
Beiträge: 3535
Registriert: 29.08.2004 11:27
Computerausstattung: PC: MSI-Z590-GC; 32GB-DDR4, ICore9; 2TB M2 + 2x3TB-SATA2 HDD; Intel ICore9 @ 3600MHZ (Win11 Pro. 64-Bit),
Acer Aspire E15 (Win11 Home X64). Purebasic LTS 6.11b1
HP255G8 Notebook @AMD Ryzen 5 5500U with Radeon Graphics 2.10 GHz 3.4GHz, 32GB_RAM, 3TB_SSD (Win11 Pro 64-Bit)
Kontaktdaten:

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von Falko »

dito :allright:
Bild
Win11 Pro 64-Bit, PB_6.11b1
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von rolaf »

DarkDragon hat geschrieben:Cool, vielen Dank ;-) .
dito no.2 :allright:
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
dige
Beiträge: 1235
Registriert: 08.09.2004 08:53

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von dige »

@Danilo: Vielen Dank für Deine wertvolle Arbeit! Das sind ja wahnsinns Möglichkeiten. Ich habe GDI bisher
völlig unterschätzt...
"Papa, ich laufe schneller - dann ist es nicht so weit."
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von STARGÅTE »

Ich muss leider noch mal nachhken.
Bei mir funktioneirt gDrawText() irgendwie garnicht, oder nur sehr schlecht:

Bei mir werden Texte mit einer Schriftgröße zwischen 9 und 17 garnicht bzw. in einer falschen farbe dagestellt:
10 ist sogar breiter als 11 :?

Bild

Hier mein Code:

Code: Alles auswählen


Enumeration
	#Window : #Gadget : #Image
EndEnumeration

XIncludeFile "gDrawing.pbi"

gInit()

CreateImage(#Image, 256, 512, 32|#PB_Image_Transparent)

StartDrawing(ImageOutput(#Image))
DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
For Size = 1 To 24
	DrawText(10, Size*Size*0.8, Str(Size), $FF000000)
Next
Box(50, 0, 100, 512, $FFF0A050)
StopDrawing()

gStartDrawing(ImageOutput(#Image))
For Size = 1 To 24
	gSetFont("Arial", Size)
	gDrawText(60, Size*Size*0.8, "Hallo", $FF000000)
Next
gStopDrawing()

OpenWindow(#Window, 0, 0, ImageWidth(#Image), ImageHeight(#Image), "Image", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ImageGadget(#Gadget, 0, 0, ImageWidth(#Image), ImageHeight(#Image), ImageID(#Image))

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Hat noch jemand diesen Fehler?
Habe die unveränderte Include genutzt.

Kannst du Danilo oder jemand anderes mir sagen, wie ich das beheben kann?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von rolaf »

STARGÅTE hat geschrieben:Hat noch jemand diesen Fehler?
Hier gleiches Ergebnis:

Bild
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von Danilo »

Noch ein kleiner Trick mit gScale() / gScaleAt():
Wenn man für die Skalierungswerte -1 verwendet, kann man die
Zeichenbefehle spiegeln.

Am besten mal ausprobieren.

Code: Alles auswählen

XIncludeFile "gDrawing.pbi"

Procedure ScaleDemo(scaleX.f, scaleY.f)
    img = CreateImage(#PB_Any,400,300,24)
    If gStartDrawing( ImageOutput(img) )
        gClear( RGBA($AA,$AA,$AA,$FF) )

        gScaleAt(200,150,scaleX,scaleY)
    
        gStartTransform()
            gDrawingMode( #PB_2DDrawing_Outlined )
            ;
            ; gEllipse rotieren
            ;
            For i = 0 To 90 Step 10
                gRotateAt(50,50,i) : gEllipse(50,50,50,15) : gResetTransform()
            Next i
        gStopTransform()

        gStopDrawing()
    EndIf
    ProcedureReturn img
EndProcedure

If gInit()
    mainWin = OpenWindow(#PB_Any,0,0,800,600,"gDrawing scale demo",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    ImageGadget(#PB_Any,  0,  0,400,300,ImageID( ScaleDemo( 1, 1) )) ; normal
    ImageGadget(#PB_Any,400,  0,400,300,ImageID( ScaleDemo(-1, 1) )) ; gespiegelt um Y-Achse
    ImageGadget(#PB_Any,  0,300,400,300,ImageID( ScaleDemo( 1,-1) )) ; gespiegelt um X-Achse
    ImageGadget(#PB_Any,400,300,400,300,ImageID( ScaleDemo(-1,-1) )) ; gespiegelt um X- und Y-Achse
    Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
    gEnd()
EndIf
Und hier eine Procedure MirrorImage():

Code: Alles auswählen

EnableExplicit

XIncludeFile "gDrawing.pbi"

Procedure MirrorImage(original,x,y)
    Protected copy, w, h
    copy = CreateImage(#PB_Any,ImageWidth(original),ImageHeight(original),24)
    ;copy = CopyImage(original,#PB_Any)
    If copy
        w = ImageWidth(original)
        h = ImageHeight(original)
        If gStartDrawing( ImageOutput(copy) )
            gSetPenImage( ImageID(original) ,#WrapModeTileFlipXY)
            If x : gSetPenOrigin(0,h) : EndIf
            If y : gSetPenOrigin(w,0) : EndIf
            gBox(0,0,w,h)
            gStopDrawing()
        EndIf
    EndIf
    ProcedureReturn copy
EndProcedure

Procedure DrawShearedImage(img,x.f,y.f,ShearX.f,ShearY.f)
    gStartTransform()
        gShearAt(x,y,ShearX,ShearY)
        gSetPenImage( ImageID(img) )
        gSetPenOrigin(x,y)
        gBox(x,y,ImageWidth(img),ImageHeight(img))
    gStopTransform()
EndProcedure

Define pbLogo, pbLogoMirror, img

pbLogo = LoadImage(#PB_Any,#PB_Compiler_Home+"Examples\Sources\Data\PureBasicLogo.bmp")
If Not pbLogo : MessageRequester("ERROR","Unable to load PureBasic logo!") : End : EndIf

If gInit()

    pbLogoMirror = MirrorImage(pbLogo,1,0)
    
    img = CreateImage(#PB_Any,800,600)
    If gStartDrawing( ImageOutput(img) )
        DrawImage(ImageID(pblogo),100,100)
        DrawShearedImage(pbLogoMirror,100,100+ImageHeight(pbLogo),0.8,0)
        gStopDrawing()
    EndIf

    OpenWindow(#PB_Any,0,0,800,600,"gDrawing gShear",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
    ImageGadget(#PB_Any,0,0,800,600,ImageID( img ),#PB_Image_Border ) ; normal
    Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
    gEnd()
EndIf
STARGÅTE hat geschrieben:Bei mir funktioneirt gDrawText() irgendwie garnicht, oder nur sehr schlecht:
[...]
Kannst du Danilo oder jemand anderes mir sagen, wie ich das beheben kann?
Schaue ich morgen früh. Jetzt muß ich gleich auf Arbeit.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
PureLust
Beiträge: 1145
Registriert: 21.07.2005 00:02
Computerausstattung: Hab aktuell im Grunde nur noch 'nen Lenovo Yoga 2 Pro im Einsatz.
Wohnort: am schönen Niederrhein

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von PureLust »

STARGÅTE hat geschrieben:Kannst du Danilo oder jemand anderes mir sagen, wie ich das beheben kann?
Das Problem liegt an dem (in gStartDrawing() vordefinierten) Wert des TextAntialiasingModes.
Die FarbProbleme treten seltsamerweise bei #TextAntialiasMode_AntiAliasGridFit sowie #TextAntialiasMode_SingleBitPerPixelGridFit auf.

Du könntest also zuvor gSetTextAntialiasMode(#TextAntialiasMode_AntiAlias) ausführen.
Vermutlich wäre aber ein anderer Defaultwert in gStartDrawing() die bessere Lösung.

@Danilo:
In gSetFont() ist noch ein (kleiner) Fehler, da die Fontgröße beim Erstellen/Laden des Fonts zuerst noch entsprechend der DPI-Auflösung des Ausgabedevices angepasst werden muss.
Ohne Anpassung werden die Schriftarten für eine Auflösung von 72 DPI erstellt (was der üblichen DPI-Auflösung früherer Röhrenmonitore entspricht).
Bei heutigen TFT-Bildschirmen liegt die Auflösung jedoch bei rund 96 DPI - wodurch die Schriften dann ohne Anpassung der Größe zu klein sind.

Nachfolgend die nötige Umrechnung für eine Ausgabe auf dem Bildschirm:

Code: Alles auswählen

Protected *hdc = GetDC_(#Null);
AlignedFontSize = (FontSize *  GetDeviceCaps_(*hdc, #LOGPIXELSY) / 72)
ReleaseDC_(#Null, *hdc)
Um auch eine korrekte Fontgröße auf anderen Devices (z.B. Druckern) sicher zu stellen, muss man auf den DC zugreifen können, auf den auch gezeichnet wird.
Da ich nirgends gefunden habe, dass Du den *hDC zwischenspeicherst, den Du bei StartDrawing() erhaltenen hast, poste ich anbei mal ein paar Änderungen durch die sowohl die FarbProbleme bei der Fontausgabe behoben werden, als auch der DC zwischengespeichert wird um die Fontgröße korrekt auf den DC anpassen zu können:

Code: Alles auswählen

; --- einfügen in Zeile 331
Global __currentDC.i          ; <--- neue Variable, um DC zwischen zu speichern
Nachfolgend die angepassten Funktionen: gStartDrawing(), gStopDrawing() & gSetFont():

Code: Alles auswählen

Procedure gStartDrawing( out )
    Protected hDC

    hDC = StartDrawing(out)
    If Not hDC : ProcedureReturn 0 : EndIf
    
    GdipCreateFromHDC_(hDC ,@__graphics)
    If Not __graphics
        StopDrawing()
        ProcedureReturn 0
    EndIf
    
    __drawingMode  = #PB_2DDrawing_Default
    __lineCapStart = #LineCapFlat
    __lineCapEnd   = #LineCapFlat
    __currentTextAntialiasingMode = #TextAntialiasMode_AntiAlias
    gSetPen(RGBA($FF,$FF,$FF,$FF),1.0)
    gSetFont("Arial",12,#PB_Font_Default)
    GdipCreateMatrix_(@__transformMatrix)
    GdipSetSmoothingMode_     (__graphics,#SmoothingModeAntiAlias)
    GdipSetCompositingMode_   (__graphics,#CompositingModeSourceOver)
    GdipSetCompositingQuality_(__graphics,#CompositingQualityGammaCorrected)
    GdipSetInterpolationMode_ (__graphics,#InterpolationModeHighQualityBicubic)
    GdipSetPixelOffsetMode_   (__graphics,#PixelOffsetModeNone)
    __currentDC = hDC			; <--- buffering DC
    ProcedureReturn hDC
EndProcedure

Procedure gStopDrawing()
    If __graphics        : GdipDeleteGraphics_( __graphics      ) : __graphics        = 0 : EndIf
    If __currentPen      : GdipDeletePen_     ( __currentPen    ) : __currentPen      = 0 : EndIf
    If __currentBrush    : GdipDeleteBrush_   ( __currentBrush  ) : __currentBrush    = 0 : EndIf
    If __currentFont     : GdipDeleteFont_    ( __currentFont   ) : __currentFont     = 0 : EndIf
    If __transformMatrix : GdipDeleteMatrix_  (__transformMatrix) : __transformMatrix = 0 : EndIf
    StopDrawing()
    __currentDC = #False		; <--- Clearing buffered DC
EndProcedure

Procedure gSetFont( FontName$="Arial", FontSize.f=12, FontStyle.l = 0)
    Protected fs, *fontFamily, *font, *fontName
    If FontStyle = #PB_Font_Default   : FontStyle = 0: EndIf
    If FontStyle & #PB_Font_Bold      : fs | 1 : EndIf
    If FontStyle & #PB_Font_Italic    : fs | 2 : EndIf
    If FontStyle & #PB_Font_Underline : fs | 4 : EndIf
    If FontStyle & #PB_Font_StrikeOut : fs | 8 : EndIf

    If Not __currentDC
        Protected *hdc = GetDC_(#Null);
        AlignedFontSize = (FontSize *  GetDeviceCaps_(*hdc, #LOGPIXELSY) / 72)
        ReleaseDC_(#Null, *hdc)
    Else
        AlignedFontSize = (FontSize *  GetDeviceCaps_(__currentDC, #LOGPIXELSY) / 72)
    EndIf
	
    CompilerIf #PB_Compiler_Unicode = 0
        Protected len  = Len(FontName$)
        Protected tmp$ = Space(len*2+2)
        PokeS(@tmp$,FontName$,-1,#PB_Unicode)
        *fontName = @tmp$
    CompilerElse
        *fontName = @FontName$
    CompilerEndIf

    If GdipCreateFontFamilyFromName_(*fontName,0, @*fontFamily)
        If GdipGetGenericFontFamilySansSerif_(@*fontFamily)
            If GdipGetGenericFontFamilySerif_(@*fontFamily)
                If GdipGetGenericFontFamilyMonospace_(@*fontFamily)
                    ProcedureReturn
                EndIf
            EndIf
        EndIf
    EndIf
    If Not GdipCreateFont_(*fontFamily,FontSize,fs,2,@*font)
        If __currentFont : GdipDeleteFont_(__currentFont) : EndIf
        __currentFont = *font
        GdipDeleteFontFamily_(*fontFamily)
    EndIf
EndProcedure
Zum Schluss nochmal das etwas abgeänderte Beispiel von STARGÅTE,
bei dem man dann - ohne die obigen Anpassungen vorzunehmen - auch die fehlerhafte Schriftgröße sehen kann:

Code: Alles auswählen

Enumeration
   #Window : #Gadget : #Image
EndEnumeration

XIncludeFile "gDrawing.pbi"

gInit()

CreateImage(#Image, 256, 512, 32|#PB_Image_Transparent)

StartDrawing(ImageOutput(#Image))
DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
For Size = 1 To 24
   DrawText(10, Size*Size*0.8, Str(Size), $FF000000)
Next
Box( 50, 0, 100, 512, $FFF0A050)
Box(150, 0, 100, 512, $FFF050a0)
StopDrawing()

For Size = 1 To 24
 	LoadFont(0, "Arial", Size)
	gStartDrawing(ImageOutput(#Image))
	gSetFont("Arial", Size)
	gDrawText(60, Size*Size*0.8, "Hallo", $FF000000)
	DrawingFont(FontID(0))
	DrawingMode(#PB_2DDrawing_Transparent)
	DrawText(160, Size*Size*0.8, "Hallo", $FF000000)
	gStopDrawing()
Next

OpenWindow(#Window, 0, 0, ImageWidth(#Image), ImageHeight(#Image), "Image", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ImageGadget(#Gadget, 0, 0, ImageWidth(#Image), ImageHeight(#Image), ImageID(#Image))

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Ach ja ... @Danilo: Echt seeehr schicke Lib !!! :allright:

Greetz, PL.

PS: Anbei noch ein paar ScreenShots.
Links ohne Änderungen, rechts mit den o.g. Änderungen:

Bild Bild
Zuletzt geändert von PureLust am 12.07.2011 08:38, insgesamt 3-mal geändert.
[Dynamic-Dialogs] - komplexe dynamische GUIs einfach erstellen
[DeFlicker] - Fenster flimmerfrei resizen
[WinFX] - Window Effekte (inkl. 'durchklickbares' Window)
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von Danilo »

@STARGÅTE:
Du kannst übrigens die 2 Schleifen auch kombinieren und gDrawing- und 2DDrawing-Befehle
mixen, da gStartDrawing() intern StartDrawing() aufruft.

Code: Alles auswählen

Enumeration
   #Window : #Gadget : #Image
EndEnumeration

XIncludeFile "gDrawing.pbi"

If gInit()
    CreateImage(#Image, 256, 512, 24);|#PB_Image_Transparent)
    If gStartDrawing(ImageOutput(#Image))
        gSetTextAntialiasMode(#TextAntialiasMode_Antialias)
        DrawingMode(#PB_2DDrawing_AlphaBlend|#PB_2DDrawing_Transparent)
        Box(50,  0, 100, 512, $FFF0A050)
        For Size = 1 To 24
           DrawText(10, Size*Size*0.8, Str(Size), $FF000000)
           gSetFont("Arial", Size)
           gDrawText(60, Size*Size*0.8, "Hallo", $FF000000)
        Next
        gStopDrawing()
    EndIf
    OpenWindow(#Window, 0, 0, ImageWidth(#Image), ImageHeight(#Image), "Image", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
    ImageGadget(#Gadget, 0, 0, ImageWidth(#Image), ImageHeight(#Image), ImageID(#Image))
    
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
    gEnd()
EndIf
@PureLust:
Vielen Dank! Wird übernommen. :)

EDIT: Update v0.66, Include & Beispiel
- gSetFont() geändert wie von PureLust vorgeschlagen
- Fehler bei gTextWidth() nach Transformationen behoben

TODO: Unterstützung für 32bit PB-Images bei gSetPenImage() einbauen,
der Alphakanal geht durch GDI+ verloren (offiziell dokumentiert).
Zuletzt geändert von Danilo am 12.07.2011 11:00, insgesamt 1-mal geändert.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Windows] 2DDrawing Befehle mit AntiAliasing durch GDI+

Beitrag von STARGÅTE »

Oke danke, wäre das schon mal gelöst.

Nächstes Problem, ist genau die schon angesprochene Auflösung:
Lasse ich:

Code: Alles auswählen

	gSetPen($FF000000, 100)
	gLineXY(100,100, 200, 100)
Auf einem Image laufen, bekomme ich genau eine Linie von 100px länge und 100px Breite bei Position 100,100
Auf einem Drucker (zB. FreePDF) bekomme ich jedoch völlig anderes:
- Die linie ist nicht bei 100px,100px und sie ist ca 6mal länger. (600dpi zu 96dpi)
Das einzige was stimmt ist die Breite von 100px.

Daraus schließe ich, das noch irgendwo eine Anpassung vorgenommen werde muss, damit alle gDrawing-Befehle auch bei verschiedenen Auflösungen richtig (wie PB) arbeiten.

ich glaube irgendwo gelesen zu haben, das man sogar bei GDI+ die Einheit angegeben kann, in der die Befehle arbeiten sollen.
Dort müsste dann alles auf Pixel und nicht auf Punkte gestellt werden.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten