Seite 1 von 1

Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 09:26
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.

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 10:10
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

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 11:01
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)

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 12:21
von ts-soft
Bisonte hat geschrieben:(Liegt an #PB_Any das extrem hohe Nummern vergibt)
Sind ja auch Speicheradressen!

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 12:47
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.

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 19:38
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 ;) )

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 19.10.2016 21:14
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

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 20.10.2016 01:13
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.

Re: Ermitteln der Imagegröße eines CanvasGadgets?

Verfasst: 20.10.2016 11:35
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.