Canvas speichern - gelöst :-)

Anfängerfragen zum Programmieren mit PureBasic.
GerhardHoeberth
Beiträge: 24
Registriert: 14.03.2015 18:22
Wohnort: Wasserburg
Kontaktdaten:

Canvas speichern - gelöst :-)

Beitrag von GerhardHoeberth »

Ich habe vor Jahren mit VB6 programmiert und habe mir jetzt - da .NET keine Alternative ist, PureBasic gekauft.
Bin aber hier nun wieder blutiger Anfänger :-(

Seit Tagen durchsuche ich hier das Forum nach einer Antwort auf mein Problem. Da ich nicht fündig geworden bin (was sicherlich auch daran liegt, dass ich das meiste noch gar nicht verstehe und daher auch nicht nachvollziehen kann) poste ich jetzt mal meine Frage.

Ich möchte auf einem Canvas zeichnen und dann das Bild abspeichern. Weiß aber nicht, sie ich den Inhalt des Canvas auf ein Image bekomme.
Ich habe dazu drei Dateien (test2.pbf, test2.pbi und test2.pb)

test2.pbf

Code: Alles auswählen

Global Window_0

Global Button_0, Canvas_0, Button_1

Declare Speichern(EventType)
Declare Zeichne(EventType)

Procedure OpenWindow_0(x = 0, y = 0, width = 750, height = 500)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
  Button_0 = ButtonGadget(#PB_Any, 50, 120, 90, 40, "Start", #PB_Button_Left)
  GadgetToolTip(Button_0, "startet zeichnen")
  Canvas_0 = CanvasGadget(#PB_Any, 220, 10, 480, 480)
  Button_1 = ButtonGadget(#PB_Any, 50, 240, 90, 40, "Speichern")
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          Zeichne(EventType())          
        Case Button_1
          Speichern(EventType())          
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure
test2.pbi

Code: Alles auswählen

OpenWindow_0()

Repeat
  
  pgrlauf = Window_0_Events(WaitWindowEvent())
  
Until pgrlauf = #False 

End
test2.pb

Code: Alles auswählen

IncludeFile "test2.pbf"
IncludeFile "test2.pbi"

Procedure Zeichne(EventType)
  a = 480
  b = 480
  StartDrawing(CanvasOutput(Canvas_0))
  For i = 0 To a - 1
    For j = 0 To b - 1
      Plot(i, j, RGB(Mod((i/3)*(j/5), 255), Mod(i*j, 255), Mod(a, 255)))
    Next j  
  Next i  
  StopDrawing()

EndProcedure

Procedure Speichern(EventType)
  File$ = SaveFileRequester("Save Image...", "Mandala", "BMP-Images|*.bmp", 0)
  If File$ And (FileSize(File$) = -1 Or MessageRequester("CanvasGadget", "Overwrite this file? " + File$, #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes)
    
   
       If SaveImage(CanvasOutput(Canvas_0), File$, #PB_ImagePlugin_BMP ) = 0
          MessageRequester("CanvasGadget", "Cannot save image: " + File$)
       EndIf
              
    EndIf            
  
EndProcedure
Ergebnis ist aber [ERROR] Das angegebene #Image ist nicht initialisiert. :bluescreen:

So funktioniert es offenbar nicht :-(
Wie überträgt man also den Inhalt eines Canvas auf ein Image, das man dann speichern kann?

herzlichen Gruß
Gerhard
Zuletzt geändert von GerhardHoeberth am 24.03.2015 22:49, insgesamt 1-mal geändert.
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Re: Canvas speichern

Beitrag von edel »

Kopiere den Inhalt des Canvasgadget in ein neues Bild und speichere dieses.

Beispiel :

Code: Alles auswählen

Enumeration Window
  #WINDOW
EndEnumeration

Enumeration Gadget
  #GAD_START
  #GAD_SAVE
  #GAD_CANV
EndEnumeration

Procedure SaveImageFromCanvas(CanvasNr, FileName.s)  
  Protected result.l
  ;ermittelt die groesse des Bildes uber das Gadget
  Protected cx = GadgetWidth(CanvasNr) 
  Protected cy = GadgetHeight(CanvasNr)
  ; erstellt ein temporaeres leeres Bild
  
  Protected ImgNr = CreateImage(#PB_Any, cx, cy)
  
  ; holt das Bild vom Canvasgadget
  Protected CanvasImageID = GetGadgetAttribute(CanvasNr, #PB_Canvas_Image)
  
  ;oeffnet die Ausgabe auf das leere Bild
  StartDrawing(ImageOutput(ImgNr))
  ;kopiert CanvasImageID in das leere Bild
  DrawImage(CanvasImageID, 0, 0)
  StopDrawing()
  
  ;speichert das Bild
  result = SaveImage(ImgNr, FileName)
  ;löscht das temporaere bild wieder
  FreeImage(ImgNr)
  
  ProcedureReturn result
EndProcedure

Procedure Event_Button_Start()
  
  StartDrawing(CanvasOutput(#GAD_CANV))
  
  a = OutputWidth()
  b =  OutputHeight()
  
  For i = 0 To a - 1
    For j = 0 To b - 1
      Plot(i, j, RGB(Mod((i/3)*(j/5), 255), Mod(i*j, 255), Mod(a, 255)))
    Next j  
  Next i  
  StopDrawing()  
  
EndProcedure

Procedure Event_Button_Save()
  Protected FileName.s
  
  FileName = SaveFileRequester("", "mandala.bmp", "BMP-Images|*.bmp", 0)
  
  If FileName
    SaveImageFromCanvas(#GAD_CANV, FileName)  
  EndIf
  
EndProcedure


Procedure Main()
  
  If OpenWindow(#WINDOW, #PB_Ignore, #PB_Ignore, 600, 400, "")
    
    ButtonGadget(#GAD_START, 5, 5, 100, 23, "Start")
    ButtonGadget(#GAD_SAVE, 5, 35, 100, 23, "Save")
    CanvasGadget(#GAD_CANV, 110, 5, 485, 390, #PB_Canvas_Border)
    
    BindGadgetEvent(#GAD_START, @Event_Button_Start(), #PB_EventType_LeftClick)
    BindGadgetEvent(#GAD_SAVE, @Event_Button_Save(), #PB_EventType_LeftClick)
    
    Repeat
    Until WaitWindowEvent() = #PB_Event_CloseWindow
    
    
  EndIf
  
EndProcedure:End Main()

GerhardHoeberth
Beiträge: 24
Registriert: 14.03.2015 18:22
Wohnort: Wasserburg
Kontaktdaten:

Re: Canvas speichern

Beitrag von GerhardHoeberth »

edel hat geschrieben:Kopiere den Inhalt des Canvasgadget in ein neues Bild und speichere dieses.
Vielen herzlichen Dank für die rasche Antwort.
Ich habs bei mir eingefügt und ausprobiert ... ES FUNKTIONIERT :lol: :D

jetzt muss ich es nur noch durcharbeiten, um es auch zu verstehen und schon hab ich wieder was dazu gelernt ;-)

herzlichen Gruß
Gerhard

PS: Gibt es hier eine Möglichkeit, ein Thema als "abgeschlossen" oder "beantwortet" zu markieren?
Und gibt es eine Möglichkeit, einem Mitglied, das einem geholfen hat, einen Dankpunkt zukommen zu lassen?
Andesdaf
Moderator
Beiträge: 2673
Registriert: 15.06.2008 18:22
Wohnort: Dresden

Re: Canvas speichern

Beitrag von Andesdaf »

alternativ könntest du auch direkt auf das Image zeichnen.

Code: Alles auswählen

IncludeFile "test2.pbf"
IncludeFile "test2.pbi"

Procedure Zeichne(Output)
  a = 480
  b = 480
  StartDrawing(Output)
  For i = 0 To a - 1
    For j = 0 To b - 1
      Plot(i, j, RGB(Mod((i/3)*(j/5), 255), Mod(i*j, 255), Mod(a, 255)))
    Next j 
  Next i 
  StopDrawing()

EndProcedure

Procedure Speichern(EventType)
  Protected cx = GadgetWidth(Canvas_0)
  Protected cy = GadgetHeight(Canvas_0)
  Protected ImgNr = CreateImage(#PB_Any, cx, cy)
  File$ = SaveFileRequester("Save Image...", "Mandala", "BMP-Images|*.bmp", 0)
  If File$ And (FileSize(File$) = -1 Or MessageRequester("CanvasGadget", "Overwrite this file? " + File$, #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes)
   
       Zeichne(ImageOutput(ImgNr))
       If SaveImage(ImgNr, File$, #PB_ImagePlugin_BMP ) = 0
          MessageRequester("CanvasGadget", "Cannot save image: " + File$)
       EndIf
             
    EndIf           
 
EndProcedure
Dann müsstest du statt Zeichne(EventType()) in der test2.pbf Zeichne(CanvasOutput(Canvas_0)) aufrufen.
Ob das mit dem Formdesigner geht weiß ich aber gerade nicht aus dem Stand.
Win11 x64 | PB 6.20
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: Canvas speichern

Beitrag von ts-soft »

GerhardHoeberth hat geschrieben:PS: Gibt es hier eine Möglichkeit, ein Thema als "abgeschlossen" oder "beantwortet" zu markieren?
Und gibt es eine Möglichkeit, einem Mitglied, das einem geholfen hat, einen Dankpunkt zukommen zu lassen?
Die Möglichkeit gibt es hier nicht, wobei die auch nicht jeder als sinnvoll erachtet. Einige fügen "erledigt" oder ähnlich,
nachträglich in den Titel ein (1. Beitrag, Editieren!).
Viel wichtiger ist es immer einen sinnvollen Titel zu haben (hat geklappt :allright: ), damit die Suchfunktion auch mal greift.

Danke Button gibt es offiziell nicht, aber den kann man nachträglich einfügen, siehe hier: http://www.purebasic.fr/german/viewtopi ... 38#p287738
ansonsten macht es auch ein einfaches danke schön :wink:

PS: Interessante Homepage, wenn auch ganz anderes Thema.

Gruß
Thomas
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
GerhardHoeberth
Beiträge: 24
Registriert: 14.03.2015 18:22
Wohnort: Wasserburg
Kontaktdaten:

Re: Canvas speichern

Beitrag von GerhardHoeberth »

Andesdaf hat geschrieben:alternativ könntest du auch direkt auf das Image zeichnen.
Man kann direkt auf ein Image zeichnen? Wozu benötige ich dann überhaupt das Canvas-Objekt? :shock:
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Canvas speichern - gelöst :-)

Beitrag von NicTheQuick »

Damit kann man das Bild gut anzeigen. Und da es Double Buffering nutzt, kann man darin auch interaktiv das Bild ändern. Mit einem ImageGadget geht das nicht besonders gut.
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: Canvas speichern

Beitrag von Nino »

GerhardHoeberth hat geschrieben:Man kann direkt auf ein Image zeichnen? Wozu benötige ich dann überhaupt das Canvas-Objekt? :shock:
Vergleiche doch mal die Eigenschaften von CanvasGadget() und ImageGadget(). :-)
GerhardHoeberth
Beiträge: 24
Registriert: 14.03.2015 18:22
Wohnort: Wasserburg
Kontaktdaten:

Re: Canvas speichern

Beitrag von GerhardHoeberth »

Nino hat geschrieben:Vergleiche doch mal die Eigenschaften von CanvasGadget() und ImageGadget(). :-)
Wenn ich das richtig sehe, gibt es bei Canvas wesentlich mehr Möglichkeiten von Events?

In meinem Fall wäre dann wohl tatsächlich das Image die bessere Wahl, weil ich die Zeichnung nur automatisiert nach bestimmten Parametern erstellen lassen will und keinesfalls ein Mausevent benötige...
Danke für die Links :-)

Gerhard
Antworten