Ermitteln der Imagegröße eines CanvasGadgets?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Kurzer »

Hallo,

ich habe gerade das Problem, dass ich das Image eines CanvasGadgets ersetzen möchte und dazu die exakte Größe des dafür nötigen Images suche. Das CanvasGadget hat einen Rahmen und dieser wird offenbar vom Darstellungsbereich abgezogen.

Über GadgetWidth() und GadgetHeight() bekomme ich die äußeren Maße des Gadgets. Diese Werte sind durch den Rahmen größer als das angezeigte Image. Unter Win 10 sind das z.B. 4 Pixel in jede Richtung.

Nun möchte ich aber nicht mit festen Werten arbeiten (ImageWidth = GadgetWidth() - 4), da diese evtl. von OS zu OS unterschiedlich sind. Gibt es eine Möglichkeit die tatsächlichen Ausmaße des Canvas-Images zu ermitteln?

Mit GetGadgetAttribute(MeinCanvasGadget, #PB_Canvas_Image) bekomme ich leider das Image(Windows-)handle zurück, welches nicht mit ImageWidth() funktioniert.

PS: Dann habe ich noch eine Verständnisfrage.
Ich möchte aus einem großen Image (z.B. 600 x 600 pixel) beim Drüberfahren mit der Maus einen 40 x 40 pixel großen Bereich herauskopieren, um ihn in einem separaten ImageGadget anzuzeigen. Das ganze passiert also bei jedem MouseMove-Event auf dem Canvas, unter Umständen also x mal pro Sekunde.

Frage: Ist der richtige Weg dies zu tun folgender?
1) NeuesImage = GrabImage(#CanvasImage, #PB_Any, MouseX, MouseY, 40, 40)
2) SetGadgetState(#ImageGadget, ImageID(NeuesImage))

Wenn das der richtige Weg ist, muss ich "NeuesImage" dann noch freigeben?
Vom Gefühl her würde ich es eher so machen, dass nicht x mal pro Sekunde ein neues Image generiert wird, sondern hätte gedacht, dass man irgendwie die Pixeldaten von einem Image zum einem anderen, bereits vorhandenen Image kopiert. Dazu habe ich in der Befehlsreferenz allerdings nichts gefunden.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von man-in-black »

Hi,

kann dir da nicht groß helfen, aber wie wäre es mit einem zweiten Canvas, auf dem du das Bild einfach clipst?
Canvas1 ist dann das Original, zuständig für Hover ... und Canvas2 verschiebt sein dargestelltes Bild in einem 40x40 Viewport.

Und zu deinen Dimensionen. Hilft OutputHeight() vielleicht? Habs jetzt nicht getestet, erinnere mich aber an einen anderen Thread.

MFG
MIB
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Bisonte »

Direkt aus dem jaPBe Quellcode... (naja fast, da gabs kein Protected ^^ ) :

Code: Alles auswählen

Procedure GetBitmapWidth(hBitmap)
  Protected BmpInfo.BITMAP
  If hBitmap = 0 : ProcedureReturn 0 : EndIf
  If GetObjectType_(hBitmap) <> #OBJ_BITMAP : ProcedureReturn 0 : EndIf
  If GetObject_(hBitmap, SizeOf(BITMAP), BmpInfo) = 0 : ProcedureReturn 0 : EndIf
  ProcedureReturn BmpInfo\bmWidth
EndProcedure
Procedure GetBitmapHeight(hBitmap)
  Protected BmpInfo.BITMAP
  If hBitmap = 0 : ProcedureReturn 0 : EndIf
  If GetObjectType_(hBitmap) <> #OBJ_BITMAP : ProcedureReturn 0 : EndIf
  If GetObject_(hBitmap, SizeOf(BITMAP), BmpInfo) = 0 : ProcedureReturn 0 : EndIf
  ProcedureReturn BmpInfo\bmHeight
EndProcedure
Hier werden die Ausmaße einer Bitmap zurückgegeben (also dein OS-Handle).
Ich denke das hast du jetzt gesucht.

Nachtrag :
Wenn Du #PB_Any zum erstellen nutzt, musst du freigeben. Bei einer festen Nummernvergabe nicht.
Dann kann man einfach "überschreiben". (Liegt an #PB_Any das extrem hohe Nummern vergibt)
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von ts-soft »

Bisonte hat geschrieben:(Liegt an #PB_Any das extrem hohe Nummern vergibt)
Sind ja auch Speicheradressen!
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Kurzer »

Danke Bisonte, die Prozeduren funktionieren einwandfrei. :allright:

Mit dem Grabben habe ich es jetzt so gelöst.

Code: Alles auswählen

	If StartDrawing(CanvasOutput(Window_Screenshot_Canvas_Screenshot))
		 iImageClip = GrabDrawingImage(#PB_Any, x, y, iImageWidth, iImageHeight)
		StopDrawing()
	EndIf
	If iImageClip = 0 : ProcedureReturn : EndIf
	
	SetGadgetState(Window_Screenshot_Image_Screenshot, ImageID(iImageClip))
	FreeImage(iImageClip)
Das funktioniert, ist aber halt eine ewige "GrabImage / FreeImage" Orgie.

Da ich die Image-Lib Internas nicht kenne, kann ich nicht beurteilen, wie groß der Overhead beim hochfrequenten Neuerstellen eines Images ist.

Wie gesagt, logischer wäre für mich, wenn man den BitmapInhalt eines Images in die Bitmap eines anderen Images kopieren könnte (ggf. auch als Ausschnitt) ohne dabei jedes mal ein drittes Image als temporären "Datenträger" benutzen zu müssen. Aber das scheint mit PB-eigenen Mitteln nicht zu gehen.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Bisonte »

Wie gesagt. Wenn Du eine feste PB Objektnummer wählst, anstelle von #PB_Any, kannst du laufend "überschreiben". ohne freigabe des vorherigen Bildes.

Also die GrabImage Variante ist mit GrabImage(#CanvasImage, #ImageAusschnitt, MouseX, MouseY, 40, 40) noch am sinnvollsten (von der Logik her)
Kein Ewiges erstellen und freigeben, sondern überschreiben.

P.S.
Wobei ich gerade die Idee hatte, anstelle eines ImageGadgets ein Canvas zu nehmen und dort einfach nur versetzt zu zeichnen. so wie z.B. Ein Grosses Bild liegt unter einem kleinen ausschnitt und wird bewegt...
Dann nur noch die Koordinaten berechnen und an das kleinere Canvas schicken, das das bild unter dem ausschnitt richtig hinschiebt ....
(Kopierschutz Monkey Island damals ;) )
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von man-in-black »

Hi,
Bisonte hat geschrieben:P.S.
Wobei ich gerade die Idee hatte, anstelle eines ImageGadgets ein Canvas zu nehmen und dort einfach nur versetzt zu zeichnen. so wie z.B. Ein Grosses Bild liegt unter einem kleinen ausschnitt und wird bewegt...
Dann nur noch die Koordinaten berechnen und an das kleinere Canvas schicken, das das bild unter dem ausschnitt richtig hinschiebt ....
(Kopierschutz Monkey Island damals ;) )
man-in-black hat geschrieben: kann dir da nicht groß helfen, aber wie wäre es mit einem zweiten Canvas, auf dem du das Bild einfach clipst?
Canvas1 ist dann das Original, zuständig für Hover ... und Canvas2 verschiebt sein dargestelltes Bild in einem 40x40 Viewport.
zu spät :P
man-in-black hat geschrieben:Und zu deinen Dimensionen. Hilft OutputHeight() vielleicht?
Ich hab folgendes einfach mal q&d mit Win7 ausgeführt. "Leider" gibts bei mir keinen Rahmen, weshalb ich da nichts weiter testen kann.
Da obiges bereits überlesen wurde, häng ich meinen Testcode einfach mal an :P
Vielleicht mag das ein W10 Nutzer mal ausführen. Würd mich auch interessieren.

Code: Alles auswählen

OpenWindow(#PB_Any,0,0,800,600,"")
CanvasGadget(1,0,0,800,600)

Repeat
  event = WaitWindowEvent()
 
  If event = #PB_Event_Gadget
    Select EventGadget()
      Case 1
        If EventType() = #PB_EventType_LeftClick
          Debug GadgetHeight(1)
          Debug GadgetWidth(1)
          
          StartDrawing(CanvasOutput(1))
            Debug OutputHeight()
            Debug OutputWidth()
            
            DrawingMode(#PB_2DDrawing_Outlined)
            Box(0,0,OutputWidth(),OutputHeight(),Random($FFFFFF))   ;visueller Test, ob Maße stimmen
          
          StopDrawing()
          Debug "-----"
          
        EndIf
    EndSelect
  EndIf

Until event = #PB_Event_CloseWindow
MIB
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Bisonte »

Ok das hab ich wohl irgendwie wegen der Fachausdrücke nicht gerafft ;) Man möge einem alten Mann verzeihen ....

Zu deinen Q&D TestCode auf Win 10... Rahmen beim Canvas gibts per #PB_Canvas_Border als Flag ;)
Und die OutputWidth() + OutputHeight() Angaben sind tatsächlich auch mit Rahmen korrekt.

800x600 ohne Rahmen
796x596 mit Rahmen

Edit : Hier mal schnell zusammengeschusterst als beispiel beide Techniken... verschieben und überschreiben....

(halt entsprechend auskommentieren)

Code: Alles auswählen

#BigImage = 1
#SmallImage = 2

Global mx, my

Procedure CanvasImage_Events()
  
  If EventType() = #PB_EventType_MouseMove
    mx = GetGadgetAttribute(EventGadget(), #PB_Canvas_MouseX)
    my = GetGadgetAttribute(EventGadget(), #PB_Canvas_MouseY)
    GrabImage(#BigImage, #SmallImage, mx, my, 40, 40) ; Die überschreibvariante
    PostEvent(#PB_Event_Gadget, 0, 2, #PB_EventType_Change)
  EndIf
    
EndProcedure
Procedure CanvasMini_Events()
  
  If EventType() = #PB_EventType_Change

    StartDrawing(CanvasOutput(2))
    DrawImage(ImageID(#SmallImage), 0, 0) ; Die Überschreibvariante
    ; DrawImage(ImageID(#BigImage), -mx, -my) ; Die Verschiebetechnik
    StopDrawing()
    
  EndIf
    
EndProcedure


UsePNGImageDecoder()

LoadImage(#BigImage, "D:\Dein600x600px_Image.png")

OpenWindow(0, 0, 0, 800, 600, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

CanvasGadget(1, 0, 0, 600, 600, #PB_Canvas_Border)
StartDrawing(CanvasOutput(1))
DrawImage(ImageID(#BigImage), 0, 0)
StopDrawing()

CanvasGadget(2, 610, 0, 40, 40, #PB_Canvas_Border)

BindGadgetEvent(1,@CanvasImage_Events())
BindGadgetEvent(2,@CanvasMini_Events())

Repeat
  Event = WaitWindowEvent()
  If Event = #PB_Event_CloseWindow
    Break
  EndIf
ForEver
Wobei hier die Verschiebetechnik doch etwas mehr CPU Last erzeugt..
Es wird ja schliesslich noch das komplette Bild gezeichnet, auch wenn man es nicht sieht.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Beitrag von Kurzer »

Moinsen,

besten Dank für Eure konstruktiven Beiträge. :allright: Ich werde es dann wohl mit festen Imagenummern realisieren.
Schade, dass diese Imagenummerierung von PureBasic (#PB_Any bzw. feste Werte, ImageID() usw.) so viel Spielraum für Missverständnisse bereit hält. Da hätte man sich vielleicht lieber auf ein einziges System geeinigt, z.B. alles nur mit Handles regeln, die dann auch das OS versteht.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Antworten