Page 1 of 1
GrapDrawingImage()
Posted: Tue Apr 07, 2015 10:32 pm
by WilliamL
This code is supposed to grab the entire active window and save it to a file. I get a file which is the correct dimensions but it is of only the 'save' button greatly enlarged. What am I doing wrong or is a problem with 5.31x64?
Code: Select all
#wndw=1
#gadget1=1
#gadget2=2
Procedure SaveWindow(wndid)
Define imageid
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
Else
MessageRequester("imageid","no image created")
EndIf
filename$ = SaveFileRequester("Saving 'Test' as jpg.", "Test.jpg",".jpg",0)
If filename$
UseJPEGImageEncoder()
SaveImage(imageid,filename$ ,#PB_ImagePlugin_JPEG)
EndIf
FreeImage(imageid)
EndProcedure
w=200
h=264
If OpenWindow(#wndw,0,0,w,h, "test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget(#gadget2, 10, 10, 100, 30, "save")
ListViewGadget(#gadget1,4,210,w-8,50)
AddGadgetItem(#gadget1,-1,"Line 1")
Repeat
EventID = WaitWindowEvent()
If EventID = #PB_Event_Gadget
If EventGadget() = #gadget2
SaveWindow(#wndw)
EndIf
EndIf
Until EventID = #PB_Event_CloseWindow
EndIf
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 8:07 am
by wilbert
I don't know what is wrong but this writes a png
Code: Select all
ImportC ""
CGWindowListCreateImage(x.CGFloat, y.CGFloat, w.CGFloat, h.CGFloat, windowOption, windowID, imageOption)
CGImageRelease(image)
EndImport
Procedure SaveWindow(Wnd, IgnoreFraming = #True)
Protected FileName.s = SaveFileRequester("Saving window as png.", "Test.png", ".png", 0)
If FileName
Protected WindowImage = CGWindowListCreateImage(0, 0, 0, 0, 8, CocoaMessage(0, WindowID(Wnd), "windowNumber"), IgnoreFraming & 1)
If WindowImage
Protected ImageRep = CocoaMessage(0, CocoaMessage(0, 0, "NSBitmapImageRep alloc"), "initWithCGImage:", WindowImage)
Protected PngData = CocoaMessage(0, ImageRep, "representationUsingType:", #NSPNGFileType, "properties:", #nil)
CocoaMessage(0, PngData, "writeToFile:$", @FileName, "atomically:", #YES)
CocoaMessage(0, ImageRep, "release")
CGImageRelease(WindowImage)
EndIf
EndIf
EndProcedure
Returning a PB image
Code: Select all
ImportC ""
CGWindowListCreateImage(x.CGFloat, y.CGFloat, w.CGFloat, h.CGFloat, windowOption, windowID, imageOption)
CGImageRelease(image)
EndImport
Procedure.i GrabWindow(Wnd, IgnoreFraming = #True)
Protected.i Result, WindowImage, ImageObj, Size.NSSize
WindowImage = CGWindowListCreateImage(0, 0, 0, 0, 8, CocoaMessage(0, WindowID(Wnd), "windowNumber"), IgnoreFraming & 1)
If WindowImage
ImageObj = CocoaMessage(0, CocoaMessage(0, 0, "NSImage alloc"), "initWithCGImage:", WindowImage, "size:@", @Size)
CocoaMessage(@Size, ImageObj, "size")
If Size\width And Size\height
Result = CreateImage(#PB_Any, Size\width, Size\height, 32, #PB_Image_Transparent)
If Result
StartDrawing(ImageOutput(Result))
DrawAlphaImage(ImageObj, 0, 0)
StopDrawing()
EndIf
EndIf
CocoaMessage(0, ImageObj, "release")
CGImageRelease(WindowImage)
EndIf
ProcedureReturn Result
EndProcedure
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 9:00 am
by Shardik
WilliamL wrote:This code is supposed to grab the entire active window and save it to a file. I get a file which is the correct dimensions but it is of only the 'save' button greatly enlarged. What am I doing wrong or is a problem with 5.31x64?
In
this thread luis already described the solution for your problem: your grabbed image is 32 bit and the alpha component is set to fully transparent for the background so you have to set it to fully opaque. Therefore you have to insert the following part into to your code after StopDrawing():
Code: Select all
If StartDrawing(ImageOutput(imageid))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0, 0, w, h, RGBA(0, 0, 0, 255))
StopDrawing()
EndIf
and you should obtain the complete contents of your window. Unfortunately I am currently at work and can't test this on MacOS but I have tested it successfully on Windows XP, Windows 8.1 x64 and Ubuntu 14.04 x86 with Unity.
To make the testing easier I have written a new example which displays the grabbed window directly beneath the source window:
Code: Select all
EnableExplicit
Procedure GrabWindow(WindowID.I)
Protected ImageGadgetID.I
Protected ImageID.I
Protected WindowHeight = WindowHeight(WindowID)
Protected WindowWidth = WindowWidth(WindowID)
If CreateImage(0, WindowWidth, WindowHeight)
OpenWindow(#PB_Any, WindowX(WindowID) + WindowWidth + 20, WindowY(WindowID),
WindowWidth, WindowHeight, "Grabbed Window")
ImageGadgetID = ImageGadget(#PB_Any, 0, 0, WindowHeight, WindowWidth, 0)
; ---- Flush events (otherwise the button will appear as depressed)
While WindowEvent() : Wend
If StartDrawing(WindowOutput(WindowID))
ImageID = GrabDrawingImage(#PB_Any, 0, 0, WindowWidth, WindowHeight)
StopDrawing()
If StartDrawing(ImageOutput(ImageID))
DrawingMode(#PB_2DDrawing_AlphaChannel)
Box(0, 0, WindowWidth, WindowHeight, RGBA(0, 0, 0, 255))
StopDrawing()
SetGadgetState(ImageGadgetID, ImageID(ImageID))
EndIf
EndIf
EndIf
EndProcedure
OpenWindow(0, 100, 100, 200, 264, "Original window")
ButtonGadget(0, 10, 10, 100, 30, "Grab window")
ListViewGadget(1, 10, 210, WindowWidth(0) - 20, 50)
AddGadgetItem(1, -1, "Line 1")
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
If EventGadget() = 0
GrabWindow(0)
EndIf
EndSelect
ForEver
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 5:23 pm
by WilliamL
Hi Shardik and wilbert,
You guys are the best! I really appreciate how you come thru every time!
I got my original code from the thread Shardik refers to and my problem isn't that the image is transparent but that is is highly magnified to the point that only the button is partially showing (and duplicated!). You can see below what I am talking about. I tried flushing the events before grabbing the image but that didn't help. I would be interested to know what you would get if you tried my example?
Oh, something just occurred to me... I wonder if, since I'm using a retina display, the resolution (dpi) is doubled and that is throwing off the size?
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 5:31 pm
by WilliamL
Hey, great news!
I used
Code: Select all
w=WindowWidth(wndid)*2
h=WindowHeight(wndid)*2
and it worked perfectly! Well, the pict is twice as big but I suppose I could resize it.
Now I know to use this work-around but there will need to be a PB 'awareness' of this retina display problem (hint Fred).
Come to think of it, I will need to be able to discern which type of display the app is on since the other computer is not a retina. Is there any way to tell which type of display the computer has?
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 5:41 pm
by wilbert
I see you already answered your own question.
Anyway, this is what the captures look like on my OSX without retina display.
Shardik code . wrote:
My code IgnoreFraming = #True . wrote:
My code IgnoreFraming = #False . wrote:
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 6:33 pm
by WilliamL
@wilbert,
I tried your cocoa code and it worked fine but the resulting image was twice the original size. Your code is easier but if I want it the original size I will still need to know whether to reduce the size or not. I was also not able to figure out the size and image id to use the ResizeImage() command.
Code: Select all
ResizeImage(imageid,ImageWidth(WindowImage)/2,ImageHeight(WindowImage)/2) ; must reduce by 2 with retina display
This code give me an 'image not initalised' error.
One thing that puzzles me. If I use my code (with out doubling the w/h sizes) and send it to the printer it works fine but the image is shifted down and right about the image size.

Well, this is for another day....
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 7:01 pm
by wilbert
This should check retina
Code: Select all
OpenWindow(0, 0, 0, 100, 50, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
Retina = #False
If OSVersion() >= #PB_OS_MacOSX_10_7
CocoaMessage(@ScaleFactor.CGFloat, WindowID(0), "backingScaleFactor")
If ScaleFactor > 1
Retina = #True
EndIf
EndIf
If Retina
Debug "Retina"
Else
Debug "No retina"
EndIf
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 7:49 pm
by WilliamL
Thanks wilbert, that will let me get on with my project.

Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 7:57 pm
by wilbert
WilliamL wrote:Thanks wilbert, that will let me get on with my project.

Since ScalingFactor contains exactly what you need for resizing, you can probably use it like this
Code: Select all
If OSVersion() >= #PB_OS_MacOSX_10_7
CocoaMessage(@ScaleFactor.CGFloat, WindowID(0), "backingScaleFactor")
If ScaleFactor > 1
ResizeImage(WindowImage, ImageWidth(WindowImage)/ScaleFactor, ImageHeight(WindowImage)/ScaleFactor)
EndIf
EndIf
Re: GrapDrawingImage()
Posted: Wed Apr 08, 2015 9:06 pm
by WilliamL
@wilbert,
Yes, I like using a variable like that. Very efficient!
Code: Select all
CocoaMessage(@ScaleFactor.CGFloat, WindowID(0), "backingScaleFactor") ; 1=std 2=retina
w=WindowWidth(wndid)*scalefactor
h=WindowHeight(wndid)*scalefactor
...
ResizeImage(WindowImage, ImageWidth(WindowImage)/ScaleFactor, ImageHeight(WindowImage)/ScaleFactor)