any way to screencapture frontmost window?

hi,

i’d like a non-interactive screencapture of the frontmost window.

best case scenario would be something like:
do shell scriptscreencapture -fcx
where ‘f’ means frontmost window capture but i don’t think anything like this exists…

does anyone know of a way / or come up with a workaround to accomplish this?

thank you

I don’t have much time right now so I won’t type up the scripts, but I’ll be back Saturday with some time to make a script or two if needed.

I can think of two ways just off the top of my head:
b[/b] Make the window full screen (in Lion) and then screen capture the screen. :smiley: I’m sure that’s not what you were after, but it answers your question. lol
b[/b] GUI scripting using “System Events” to press keys, click around, etc.
¢ in the keyboard pane of System Preferences, go to the Keyboard Shortcuts tab and in the list on the left, click screen shots, then see what hotkey is set for save picture of selected area as a file. If nothing is set, then proceed to set one.
¢ in whatever application you want the window saved as a pic, get the bounds of the window, either with the application’s own dictionary or with “System Events” (position and size ” do the math)
¢ when the window you want saved is visible, have “System Events” press whatever that hotkey is to capture a selection with keystroke blah. using {blah down, etc.}
¢ have “System Events” send clicks, mouse down events, etc. at the top-left (position) and the bottom-right (position + size)

Whew! not the tidiest way I’m sure. I wrote it in case you feel like playing around writing this up and testing it while waiting for someone else’s much simpler solution. :stuck_out_tongue:

Aesthir

Hi Flat5
I quickly wrote a little script that uses the screencapture command from the terminal.

tell application "System Events" -- get frontmost process
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	set visible of frontmostProcess to false -- hide the script process
	repeat while (frontmostProcess is frontmost) -- wait until the script is hided
		delay 0.2
	end repeat
	set secondFrontmost to name of first process where it is frontmost -- get name of frontmost process (ignoring the script process)
	set frontmost of frontmostProcess to true -- unhide the script process
end tell
tell application secondFrontmost to set winID to id of window 1 -- get WindowID of frontmost window of frontmost process
do shell script "screencapture -c -x -l " & winID -- -c is used to store it in the clipboard. -x is used to mute the sound. -l is used to refer to the prefered windowid.

The first thing I did was determine the frontmost process and, of course, this is the process of the script. So the Second thing I did was hiding that script process so that the “real” frontmost process appears. Then I stored the name of that process into the variable secondFrontmost. I then unhide the script process and stored the windowID of the frontmost window of the “real” frontmost process into winID. Then the only thing left is the do shell command

I hope this can help you
Damiaan

the app i’m scripting can’t go full screen… but yeah, i don’t think that’s what i’m after anyway :slight_smile:

as far as i can tell, all the keystroke options (shift-cmd-4 etc) are doable with the screencapture shell script. but you’ll notice that of all the different variations on the keystroke screencapture, none of them will allow a screenshot to happen without mouse interaction except the full screenshot…

but yeah, i do plan on cropping etc once i figure out how to get the window captured (a window capture will still get the toolbars and such in there that i don’t want)… at first, i was going to just capture the entire screen the crop out what i needed except the image events crop only seems to crop the middle of an image (where as i’d like to be able to describe the exact crop location (via maths & window position,size,etc)… but regardless, another problem with that is there are often floating toolbars/dialogs on top of the area i’d like to capture which would then be included in the full screen shot – and there’s no way to really get rid of them…

uhh… wow!.. i never knew of the -l with screencapture
(my only reference has been this:
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/screencapture.1.html)

i guess a lot of your script has to do with identifying the frontmost window etc… in the script i’m working on, i already have the window which i’d like to capture identified so i don’t think i need a lot of what you wrote there…

it’s basically the screencapture -l that seems to be exactly what i’m after, except, i can’t get the window id in the app i’m scripting :frowning:

using safari for an example, this little script works absolutely great for what i want:

tell application "Safari"
	activate
	set winID to id of window 1
	do shell script "screencapture -c -x -o -l " & winID -- (added the -o for no shadow)
end tell

so i guess my question now becomes – what can i use to identify the window with -l besides the windowID? (if i simply put do shell script "screencapture -c -x -o -l " & window 1 then it doesn’t work…

In fact, I guess that you missed that the script is storing the screenshot in the clipboard.

To store it in a file you must pass the filepath .

I never did that but I guess that it must be :

do shell script “screencapture -x -l " & winID &” "& quoted form of pictureUnixPath

Yvan KOENIG (VALLAURIS, France) vendredi 13 avril 2012 21:23:29

no… i want it to go to the clipboard (hence the -c) so i can paste it in the ‘get info’ panel in order to give a newly saved file an image icon…

the problem is capturing the right window without user interaction…

Your message let me think that you wanted to get the screenshot in a file because the code posted by Damiaan correctly put it in the clipboard, at least here under 10.7.3.


activate  application "Safari"
tell application "Safari" to set winID to id of window 1 -- get WindowID of frontmost window of frontmost process

do shell script "screencapture -c -x -l " & winID -- -c is used to store it in the clipboard. -x is used to mute the sound. -l is used to refer to the prefered windowid.

Yvan KOENIG (VALLAURIS, France) samedi 14 avril 2012 16:05:34

hey Yvan…

the original post had a hypothetical -fcx with -f being frontmost window (not real)… -c being clipboard…-x being no sound (ie- i wanted it in the clipboard all along)

the screencapture documentation i was looking at didn’t have the -l listed as shown by damiaan (but upon typing screencapture -help in terminal, the -l does show up there…

regardless… i can’t get the proper screenshot in the first place so it doesn’t matter at this point wether or not i’m saving it to a file or placing it in the clipboard…

the -l option appears to require a windowID but not all windows have an ID…the window i want to capture does not have a windowID assigned…

so the question now becomes:
Is there a way to assign an ID to a window? Or some other way to tell the screencapture command which window to capture (without user interaction)?

If i try this, i get “error “Safari got an error: screencapture: illegal option – l” number 1”.

If i open man page for screencapture, it don’t have -l option at all???

Hello.

you are on Snow Leopard or earlier cirno. Try increasing the number of seconds before it clicks, and focus the window in the mean time. I think that worked for me, when I tried it. :slight_smile:

And even if you had the -l option, it wouldn’t turn up in the manual page, it comes up with the command line help of screen capture.

Hello.

This is my take on scripting ScreenCapture, it should make a ScreenCapture, with the saved snapshot following the same naming standard of a snapshot by ScreenCapture, when you do it manually. It also puts the resulting picture of the same type as manual Screen Capture , in the same folder, as it would have been with manual ScreenCapture. (cmd-opt 4, then space, then left mouse click).

use AppleScript version "2.3"
use scripting additions
# Copyright © 2015 McUsr and released under the BSD-3 license: (see http://opensource.org/licenses/BSD-3-Clause)
# in addition, you can't publish the handlers on a webpage, where those handlers can be perceived to be
# the main content, nor use the handlers in a book.
-- http://macscripter.net/viewtopic.php?pid=179402#p179402

script loc
	(*

Documentation:

This handler is for returning a localized string, on 
some machine from some app, according to the current users
language and locale settings.


How to use this handler:

You have to open the resources folder of the app that you 
inted to retrieve the localized string from, and other than
assure that you have got the correct "key" for your localized
string, you have to make a list with any spelled out language
names, and a related list with the language codes, this page may
help when contstructing the lists:

http://www.loc.gov/standards/iso639-2/php/English_list.php


Returns:

The correct bundle according to the users language and locale 
settings,  from which we can get the correct localized string.

*)
	on getTheLProjBundle(pxPathToResourcesFolder, langList, lProjList)
		
		# http://macscripter.net/viewtopic.php?pid=179383#p179383
		set sysLang to word 1 of (do shell script "defaults read -g AppleLanguages")
		# StefanK
		if (count langList) ≠ (count lProjList) then error "getTheLProjBundle: langList is not as long as lProjList"
		set pass to 1
		repeat
			
			if pass = 1 then
				-- check if the first language is amongst the "big" languages.
				if sysLang is in langList then
					repeat with i from 1 to (count langList)
						if sysLang is item i of langList then return item i of lProjList
					end repeat
				else
					set pass to 2
				end if
			else if pass = 2 then
				-- check if the current AppleLocales are among the very detailed localization bundles.
				try
					set curLocale to do shell script "/usr/bin/defaults read -g AppleLocale"
				on error
					set pass to 3
				end try
				if pass = 2 then -- still
					try
						tell application id "MACS"
							set locBundleName to name of first folder of folder (POSIX file pxPathToResourcesFolder as text) whose name begins with curLocale
						end tell
						return locBundleName
					on error
						set pass to 3
					end try
				end if
			else if pass = 3 then
				-- check and see if the language, has a related, *normal region specific bundle*
				try
					set region to (do shell script "/usr/bin/grep  \"" & sysLang & "_*\"  /usr/share/locale/locale.alias |/usr/bin/head -1 |/usr/bin/sed -En 's/([[:alpha:]]+[[:blank:]]+)([^_]+)_([^.]+)(.*)/\\3/p' |/usr/bin/tr 'A-Z' 'a-z'")
				on error
					set pass to 4
				end try
				if pass = 3 then -- still . . . 
					try
						tell application id "MACS"
							set locBundleName to name of first folder of folder (POSIX file pxPathToResourcesFolder as text) whose name begins with region
						end tell
						return locBundleName
					on error
						set pass to 4
					end try
				end if
			else if pass = 4 then
				-- fall back
				-- Thanks to Shane Stanley
				tell application id "MACS"
					set rcsFol to folder (POSIX file pxPathToResourcesFolder as text)
					if exists folder "English.lproj" of rcsFol then
						return "English.lproj"
					else if exists folder "en.lproj" of rcsFol then
						return "en.lproj"
					else
						error "getTheLProjBundle: No english localization bundle in this App!!"
					end if
				end tell
			end if
		end repeat
	end getTheLProjBundle
end script

script dt
	on ISO8601LikeDateAndClock()
		-- Thanks to Dan Shockley for putting me in the right direction.
		
		-- ISoLike: because I use dashes to separate the date elements.
		-- like Apple do.
		-- Other than that, the format for the date is YYYYY-MM-DD
		-- The clock is whatever, including seconds, but the entities
		-- are separated with dots like: HH.MM.SS 
		-- We deal with an am/pm clock or a 24 hour clock.
		-- the 24 hour clock gets a strict two-digit format.
		-- Am/pm are more "human". :)
		
		tell (current date)
			set D to its short date string
			
			set numyear to year of it as integer
			set numMonth to text -2 thru -1 of ("0" & (month of it as integer))
			set numDay to text -2 thru -1 of ("0" & (day of it as integer))
			set isolikeDate to (numyear & "-" & numMonth & "-" & numDay) as text
			
			-- It is probably an easier way to do this . . . 
			set timeFormatProbe to its time string
			
			if "am" is in timeFormatProbe then
				set timeFormatType to "am"
			else if "pm" is in timeFormatProbe then
				set timeFormatType to "pm"
			else
				set timeFormatType to "" -- 24h clock
			end if
			
			if timeFormatType is not "" then --  not 24 hour clock!
				if pm is timeFormatType then
					set theHours to (hours of it) - 12
				else
					set theHours to (hours of it)
				end if
				set theMinutes to (minutes of it)
				set theSeconds to (seconds of it)
				set clocktime to theHours & "." & theMinutes & "." & theSeconds & space & timeFormatType
			else
				set theHours to text -2 thru -1 of ("0" & (hours of it))
				set theMinutes to text -2 thru -1 of ("0" & (minutes of it))
				set theSeconds to text -2 thru -1 of ("0" & (seconds of it))
				set clocktime to theHours & "." & theMinutes & "." & theSeconds
			end if
		end tell
		return {isolikeDate, clocktime}
	end ISO8601LikeDateAndClock
	
end script

on FileNameFormatString()
	set hfsAppName to "Macintosh HD:System:Library:CoreServices:SystemUIServer.app:"
	-- WARNING! the hfsname is hardcoded, run the line below, and change the contents of hfsAppName with it.
	-- return (path to application "SystemUIServer" as text)
	set langList to {"nl", "en", "fr", "de", "it", "jp", "es"}
	set lProjList to {"Dutch.lproj", "English.lproj", "French.lproj", "German.lproj", "Italian.lproj", "Japanese.lproj", "Spanish.lproj"}
	set rscPath to POSIX path of ((hfsAppName & "Contents:Resources") as alias)
	set correctLProj to loc's getTheLProjBundle(rscPath, langList, lProjList)
	set correctResource to path to resource correctLProj in bundle file hfsAppName
	set locString to localized string of "%@ %@ at %@" from table "ScreenCapture" in bundle correctResource
	return locString
end FileNameFormatString


on ScreenShotStemName()
	try
		set stemName to do shell script "defaults read com.apple.screencapture name"
	on error
		set stemName to "Screen Shot"
	end try
end ScreenShotStemName


on screenCaptureType()
	try
		set picType to do shell script "defaults read com.apple.screencapture type"
	on error
		set picType to "PNG"
		-- This is an inaccuracy, it should have been "JPEG", but it works as of 2015-03-17. 
	end try
	return picType
end screenCaptureType


on getPictureLocation()
	try
		set pictFolder to do shell script "defaults read com.apple.screencapture location"
		tell application id "sevs"
			set pictFolder to POSIX path of item pictFolder
		end tell
	on error
		set pictFolder to POSIX path of (path to desktop folder)
	end try
end getPictureLocation


on stemFileNameForScreenShot(picType)
	-- You'll have to localize this one, so you'll have one that
	-- gives the filenames like the screen capture
	
	set formatStr to FileNameFormatString()
	set stemName to ScreenShotStemName()
	--	set picPath to getPictureLocation()
	set {picDate, picTime} to dt's ISO8601LikeDateAndClock()
	-- Assembly
	
	set ofs1 to offset of space in formatStr
	if ofs1 = 0 then error "The filename format string is probably localized for right to left reading: -->" & formatStr & "<--"
	set intermed to stemName & text ofs1 thru -1 of formatStr
	
	set ofs2 to offset of "%@" in intermed
	if ofs2 = 0 then error "The filename format string is probably localized for right to left reading: -->" & formatStr & "<--"
	set intermed to text 1 thru (ofs2 - 1) of intermed & picDate & text (ofs2 + 2) thru -1 of intermed
	set ofs3 to offset of "%@" in intermed
	set newFn to text 1 thru (ofs3 - 1) of intermed & picTime & "." & picType
	return newFn
end stemFileNameForScreenShot

set picType to screenCaptureType()
set picName to getPictureLocation() & "/" & stemFileNameForScreenShot(picType)

-- Details concerning the screen capture 

try
	set dropShadow to (do shell script "defaults read  com.apple.screencapture disable-shadow") as integer as boolean
on error
	set dropShadow to false
end try

if dropShadow then
	set shadowOpt to " -o "
else
	set shadowOpt to ""
end if

-- http://macscripter.net/viewtopic.php?id=38482
tell application id "sevs" -- get frontmost process
	set frontmostProcess to name of first application process where it is frontmost -- this will be the script process
end tell


tell application frontmostProcess to set winID to id of window 1
do shell script "screencapture -x " & shadowOpt & "-T 0 -t " & picType & " -l " & winID & space & quoted form of picName
-- -c is used to store it in the clipboard. -x is used to mute the sound. 
-- -T is delay, default is a delay of 0 seconds.
-- -l is used to refer to the prefered windowid.

Edit
Added a comment inside FileNameFormatString() that the path to SystemUIServer is hardcoded, and added an out-commented line that may be run to get the actual path to it.

Edit 2015-03-19
I have set the image type to be of PNG, and not JPG, when it isn’t set in the defaults database.
I have also set the default value for disable drop shadows to false, as I am sure that the shadows are on by default.