Page 1 of 2

How to print window contents?

Posted: Wed Jan 20, 2010 4:51 am
by WilliamL
It seems like this should be easy. (Hasn't this been asked before?)

How can I get the active window into an image so I can send it to the printer? It seems like I would read the Point(x,y) of the window and Plot(x,y) them to an image.. or maybe it is something entirely different.

There isn't any API here (on a Mac), so how do I do it with pb only?

Re: How to print window contents?

Posted: Wed Jan 20, 2010 7:15 pm
by WilliamL
Here is some code that will copy a section of a window and put it into a image (which can be sent to the printer). All code was written by luis but I cannot find which thread he posted it in. I do not profess to understand how the code works... many thanks luis!

Code: Select all

;this code will copy a part of the Window (not screen) into an image
;all code written by luis in thread (http://www.purebasic.fr/english/viewtopic.php?f=12&t=38975&hilit=rotate+image )

procedure CopyImageToMemory(image_no.l,w,h, *mem) 
    Protected x.l, y.l, mem_pos.l ; Mac only
    mem_pos = 0 
    StartDrawing(WindowOutput(image_no)) 
    For y = 0 To h - 1 
      For x = 0 To w - 1 
        PokeL(*mem + mem_pos,(Point(x, y))) 
        mem_pos + 4 
      Next 
    Next 
    StopDrawing() 
EndProcedure 

Procedure CopyMemoryToImage(*mem,w,h, image_no.l) 
    Protected x.l, y.l, mem_pos.l 
    mem_pos = 0 
    If CreateImage(image_no,w,h)
        StartDrawing(ImageOutput(image_no)) 
        For y = 0 To ImageHeight(image_no) - 1 
          For x = 0 To ImageWidth(image_no) - 1 
            Plot(x, y, (PeekL(*mem + mem_pos))) 
            mem_pos + 4 
          Next 
        Next    
        StopDrawing() 
    Else
        MessageRequester("Image not created","")
    EndIf
EndProcedure

#wndw=1
#imageid=2
#gadgetid=3

w=200
h=200
If OpenWindow(#wndw,0,0,400,400, "2D Drawing Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 

    If StartDrawing(WindowOutput(#wndw))
        Box(150,20,20,20,RGB(0,255,0))
        Circle(100,100,50,RGB(0,0,255)) ; filled circle
        DrawingMode(#PB_2DDrawing_Outlined)
        Circle(110,110,50,RGB(0,0,255)) ; empty cirle
        For k=0 To 20
            LineXY(10,10+k*8,200, 0,RGB(k*10,0,k*10))
        Next
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(10,50,"Hello, this is a test",$00FF00)
        StopDrawing()
    EndIf

    mem_size = w * h << 2 
    *mem = AllocateMemory(mem_size) 
    If *mem = 0 
        MessageRequester("NO *mem","") 
    EndIf 
    CopyImageToMemory(#wndw,w,h, *mem) 
    CopyMemoryToImage(*mem,w,h,#imageid) 
    
    ImageGadget(#gadgetid, 0,200,w,h, ImageID(#imageid))
  
    Repeat
        EventID = WaitWindowEvent() 
    Until EventID = #PB_Event_CloseWindow
  
EndIf

End

Re: How to print window contents?

Posted: Wed Jan 20, 2010 8:07 pm
by luis
UH ? Maybe you got inspired in some way by that thread but honestly I don't think you have to thanks me, what you posted here it's not something "I" wrote, it's all yours.

Bye !

Re: How to print window contents?

Posted: Wed Jan 20, 2010 8:12 pm
by freak
There is GrabDrawingImage() in PB 4.40 ;)

Re: How to print window contents?

Posted: Wed Jan 20, 2010 8:39 pm
by jamirokwai
freak wrote:There is GrabDrawingImage() in PB 4.40 ;)
Great, I was going to post this... This Function copys the content of the current StartDrawing()-destination into an image using a memory buffer and Point()...
freak, You could have saved me about one hour or so to figure this out... :shock: I needed this function for my newest project.

Do I have to read the manual??? :roll:

Code: Select all

Procedure CopyScreenToImage(Breite, Hoehe, Image_No)  ; working on Mac OS X - yeah!
 Protected x.l, y.l, mem_pos.l, *Cache
 
 *Cache = AllocateMemory(Breite * Hoehe * 4)
 Mem_Pos = 0
 For y = 0 To Hoehe - 1
  For x = 0 To Breite - 1
   PokeL(*Cache + Mem_Pos, Point(x,y))
   Mem_Pos + 4
  Next x
 Next y

 StopDrawing()
 CreateImage(Image_No, Breite, Hoehe, 32) 
 StartDrawing(ImageOutput(Image_No))
 Mem_Pos = 0
 For y = 0 To Hoehe - 1
  For x = 0 To Breite - 1 
   Plot(x, y, PeekL(*Cache + Mem_Pos));Point(x,y))
   Mem_Pos + 4
  Next x
 Next y
 StopDrawing()
 
 FreeMemory(*Cache)
EndProcedure

Re: How to print window contents?

Posted: Wed Jan 20, 2010 8:44 pm
by WilliamL
- Added: GrabDrawingImage(), DrawRotatedText()
Yep, I knew just as soon as I posted the code someone would have a much better solution.

I don't see GrabDrawingImage() in the manual so how about some info? Would it be GrabDrawingImage(WindowOutput(#wndid),w,h) or what?

@Freak - you should have let me enjoy the effort for a few minutes.. at least. :? (wry humor)

@jamirokwai ยป Thanks for the effort. I appreciate it. Maybe I can repay you by getting an explanation of how the command works.

Re: How to print window contents?

Posted: Wed Jan 20, 2010 9:09 pm
by luis
WilliamL wrote: I don't see GrabDrawingImage() in the manual so how about some info?
http://www.purebasic.com/documentation/ ... image.html

It's in the helpfile too, at least in the 4.41 RC1.

Re: How to print window contents?

Posted: Wed Jan 20, 2010 9:49 pm
by WilliamL
Thanks again luis,

I see it with your link. I'm really glad to have this info so I can 'get on with it'.. what a time saver.

Code: Select all

#wndw=1
#imageid=2
#gadgetid=3

w=200
h=200
If OpenWindow(#wndw,0,0,400,400, "2D Drawing Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 

    If StartDrawing(WindowOutput(#wndw))
        Box(150,20,20,20,RGB(0,255,0))
        Circle(100,100,50,RGB(0,0,255)) ; filled circle
        DrawingMode(#PB_2DDrawing_Outlined)
        Circle(110,110,50,RGB(0,0,255)) ; empty cirle
        For k=0 To 20
            LineXY(10,10+k*8,200, 0,RGB(k*10,0,k*10))
        Next
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(10,50,"Hello, this is a test",$00FF00)
        
        GrabDrawingImage(#imageid,0,0,w,h)
        
        StopDrawing()
    EndIf

    
    ImageGadget(#gadgetid, 0,200,w,h, ImageID(#imageid))
  
    Repeat
        EventID = WaitWindowEvent() 
    Until EventID = #PB_Event_CloseWindow
  
EndIf
End

Re: How to print window contents?

Posted: Wed Jan 20, 2010 10:32 pm
by WilliamL
Here is a stab at printing the window. This does not work and I get a black box in the print-out. (I use Preview in the Print dialoge to save paper) Any ideas why?

Code: Select all


 >>>>. see the example below, by luis, that works!

[code]#wndw=1
#gadget1=2

Procedure PrintWindow(wndid.l)
    Define imageid.l
    
    w=WindowWidth(wndid)
    h=WindowHeight(wndid)
    If CreateImage(imageid,w,h)
        If StartDrawing(WindowOutput(wndid))
            GrabDrawingImage(ImageOutput(imageid),0,0,w,h)
            StopDrawing()
        EndIf
    EndIf
        
    If PrintRequester()
        If StartPrinting("Print window")
            If StartDrawing(PrinterOutput())
                DrawImage(ImageID(imageid),0,0,w,h) 
                StopDrawing()
            EndIf
            StopPrinting()
        EndIf

    EndIf
EndProcedure

w=200
h=200
If OpenWindow(#wndw,0,0,w,h+64, "2D Drawing Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 

    If StartDrawing(WindowOutput(#wndw))
        Box(150,20,20,20,RGB(0,255,0))
        Circle(100,100,50,RGB(0,0,255)) ; filled circle
        DrawingMode(#PB_2DDrawing_Outlined)
        Circle(110,110,50,RGB(0,0,255)) ; empty cirle
        For k=0 To 20
            LineXY(10,10+k*8,200, 0,RGB(k*10,0,k*10))
        Next
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(10,50,"Hello, this is a test",$00FF00)
        StopDrawing()
    EndIf
    ListViewGadget(#gadget1,4,210,w-8,50)
        AddGadgetItem(#gadget1,-1,"Line 1")
    
    PrintWindow(#wndw)

    Repeat
        EventID = WaitWindowEvent() 
    Until EventID = #PB_Event_CloseWindow
  
EndIf

End

Re: How to print window contents?

Posted: Wed Jan 20, 2010 10:59 pm
by luis
I'm not sure what you are trying to accomplish, if to get an hard-copy of the window (with buttons, gui elements, etc.) or to print the content of graphic area (a bitmap on the window)

Anyway, for the example you posted probably it's better to use an image and draw to that...

Code: Select all

#wndw=1
#img=1

Procedure PrintWindow(nImage)
;     Define imageid.l
;    
;     w=WindowWidth(wndid)
;     h=WindowHeight(wndid)
;     If CreateImage(imageid,w,h)
;         If StartDrawing(ImageOutput(imageid))
;             GrabDrawingImage(WindowOutput(wndid),0,0,w,h)
;             StopDrawing()
;         EndIf
;     Else
;    
;     EndIf
       
    If PrintRequester()
        If StartPrinting("Print window")
            If StartDrawing(PrinterOutput())
                DrawImage(ImageID(nImage),ImageWidth(nImage),ImageHeight(nImage))
                StopDrawing()
            EndIf
       
            StopPrinting()
        EndIf

    EndIf
EndProcedure

w=200
h=200
If OpenWindow(#wndw,0,0,w,h, "2D Drawing Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    nImage = CreateImage(#PB_Any, w,h)
    ImageGadget(#img, 0,0,w,h,ImageID(nImage))
    If StartDrawing(ImageOutput(nImage))
        Box(150,20,20,20,RGB(0,255,0))
        Circle(100,100,50,RGB(0,0,255)) ; filled circle
        DrawingMode(#PB_2DDrawing_Outlined)
        Circle(110,110,50,RGB(0,0,255)) ; empty cirle
        For k=0 To 20
            LineXY(10,10+k*8,200, 0,RGB(k*10,0,k*10))
        Next
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(10,50,"Hello, this is a test",$00FF00)
        StopDrawing()
    EndIf

    PrintWindow(nImage)

    Repeat
        EventID = WaitWindowEvent()
    Until EventID = #PB_Event_CloseWindow
 
EndIf

End
This *should* work... oh , maybe you have to fill the image white before drawing to it, I cannot test it right now.

Re: How to print window contents?

Posted: Wed Jan 20, 2010 11:03 pm
by WilliamL
luis,

Yes, that does work and I've used it before. I'm trying to get all the graphics and gadgets in the window to print (actually I'm more interested in gadgets at this point). I edited my code above.

Re: How to print window contents?

Posted: Wed Jan 20, 2010 11:08 pm
by luis
You are using GrabDrawingImage() the wrong way I believe. I never used before but I seee in the help the first param is an image number or #PB_Any, check your code :)

I imagine it works grabbing the area from the currently "open" output, you don't have to pass it as a param !

Re: How to print window contents?

Posted: Wed Jan 20, 2010 11:19 pm
by luis

Code: Select all

#wndw=1
#gadget1=1
#gadget2=2

Procedure PrintWindow(wndid.l)
    Define imageid.l
   
    w=WindowWidth(wndid)
    h=WindowHeight(wndid)
    If CreateImage(imageid,w,h)
        If StartDrawing(WindowOutput(wndid))
            imageid = GrabDrawingImage(#PB_Any,0,0,w,h)
            StopDrawing()
        EndIf
    EndIf
       
    If PrintRequester()
        If StartPrinting("Print window")
            If StartDrawing(PrinterOutput())
                DrawImage(ImageID(imageid),w,h)
                StopDrawing()
            EndIf
            StopPrinting()
        EndIf

    EndIf
EndProcedure

w=200
h=200
If OpenWindow(#wndw,0,0,w,h+64, "tes", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    ButtonGadget(#gadget2, 10, 10, 100, 30, "print")
    
    ListViewGadget(#gadget1,4,210,w-8,50)
    AddGadgetItem(#gadget1,-1,"Line 1")       
  
          
    Repeat
        EventID = WaitWindowEvent()
        
        If EventID = #PB_Event_Gadget
            If EventGadget() = #gadget2
                PrintWindow(#wndw)  
            EndIf
        EndIf
                    
    Until EventID = #PB_Event_CloseWindow
 
EndIf

End


Re: How to print window contents?

Posted: Wed Jan 20, 2010 11:21 pm
by luis
Your code was using the GrabDrawingImage() in the wrong way, see the code above.

Another problem was the fact you have to give time to the window to process the events to paint itself, you shouldn't try to print it while constructing it (adding the pieces).

Re: How to print window contents?

Posted: Wed Jan 20, 2010 11:30 pm
by WilliamL
luis,

Yes, that works! I'm studying your code to understand the event problem. I would normally use the print routine with a button anyway and my example was for brevity.

Thanks again and again for your help, I was about to give up. :D