Making time
- Posted
26 October 2003
What better time than the first day of daylight savings to be thinking about time.
The time icons have had the subtle upgrade they demanded since my last post. As promised I’m documenting their construction.
Lately I have spent a lot of time with actionscript for Flash. This led me to first consider embedding a flash movie for each clock. The advantage being there would only need to be one .swf file — the particular time for each clock generated from a variable set in it’s embed tag. The disadvantage being the lack of pixel perfect control in flash — I want my clocks to be as small as possible — this means making them around pixels not fuzzy vectors. I realise this is less of a problem in the Flash MX 2004 so perhaps it will be an option when I upgrade.
Flash used in ths way would seem to be the easiest approach. But I sometimes enjoy making things difficult for myself :)
The number of images required to present each clock as a gif creates a potentially very tedious problem. To tackle this I made the quantity more manageable by deciding I would display only every five minutes as uniquely. To make up for that idea I decided I wanted to include an AM/PM indicator in the same image – doubling the number of images to 288. AppleScript provides the most obvious answer to this task. Combined with the Photoshop 7.0 Scripting plug-in; Applescript offers a great deal more power than Photoshop actions alone.
Rounding each minute of the hour to the closest five minutes reduces the number of images but there seemed to be no obvious way (at least to my knowledge) of executing the same rounding in Movable Type. A job for a plug-in I guess.
As I know nothing of perl, I stuck to what I know and used CSS to assign the times to their respective images. To avoid the likely RSI and melted brain required to type this hefty CSS file, AppleScript came to the rescue once more but this time driving BBEdit. I’ll include that here but to reflect the order of the process as I followed it — Photoshop first.
The Photoshop file includes:
Twelve “minute hand” layers representing each five minute division of each hour.
Named: “0m”, “5m”, “10m” etc. to “55m” where 0m points to the twelve.
Twenty four “hour hand” layers representing every half hour division of each twelve hour period. Named: 0h to 11h where 0h is twelve o’clock. There is an additional hand between each of these positions on the clock face. It is named by adding “f” to the name current hour. For example the sequence should appear as: “2h”, “2hf”, “3h”, “3hf” etc.
Two layers provide distinction between AM and PM, completing the tweenty four hour cycle. These are named, predictably: “am”, “pm”.
To be accessible by this script none of these layers can be inside layer sets.
This script toggles the visiblity attribute of the layers of the prepared Photoshop file to create the 288 combinations of clock hands as layers in a separate open file called “clocks”. The new layers are named according to their corresponding 24hour time. For example 14_30 represents 2:30 PM.
This will create a file with a great many layers. Incidently this will mean you will require a version of Photoshop that doesn’t have the old limit of 99 layers. I don’t recall exactly what version made the change.
An issue with my install of Photoshop prevented me using “Save for web” instead I used Imageready to create the gifs. Rather than attempt to switch apps for each file I chose to do it as a batch with a Droplet action. A better script wouldn’t require the handling of this monster file by instead creating and saving individual files from the start. If you want to write it let me know and I’ll link to it from here, beside I’m keen to learn!
Before starting the script, make sure none of the layers are visible except for those bearing any additional layers you may wish to appear on every “time”, the clock face for example.
It may be worth noting that this script ties up your computer for as long as it takes to complete the task. The use of the clipboard makes the window focus significant, clicking on anything while it is running is likely cause an error. Not that this should bother you as the idea is to allow your computer to do to work while you do something you would rather do :)
set hrCount to 0
set minCount to 0
set hrs to 0
set mns to 0
tell application "Adobe Photoshop 7.0"
activate
set buildDoc to current document
select all of current document
repeat until hrCount is 24
repeat until mns is 60
--define active am/pm layer
if hrCount is less than or equal to 12 then
set ampmLayer to "am"
else
set ampmLayer to "pm"
end if
set visible of layer ampmLayer of current document to true
--define active hour layer
if mns is less than 20 then
set hrsLayer to hrs & "h" as string
end if
if mns is greater than or equal to 20 then
set hrsLayer to hrs & "h" & "f" as string
end if
--rotate hour
if mns is equal to 40 then
set hrs to hrs + 1
if hrs is 12 then
set hrs to 0
end if
end if
if mns is greater than or equal to 40 then
set hrsLayer to hrs & "h" as string
end if
--make defined hour layer visible
set visible of layer hrsLayer of current document to true
--define hour name
if hrCount is less than 10 then
set hrsName to "0" & hrCount as string
else
set hrsName to hrCount as string
end if
--define active minute layer
set mnsLayer to mns & "m" as string
--make defined minute layer visible
set visible of layer mnsLayer of current document to true
--define minute layer name
if mns is less than 10 then
set mnsName to "0" & mns as string
else
set mnsName to mns as string
end if
--define name of new layer
set newLayerName to hrsName & "_" & mnsName as string
--save new face to clipboard
copy merged
--reset layers for next loop
set visible of layer ampmLayer of current document to false
set visible of layer hrsLayer of current document to false
set visible of layer mnsLayer of current document to false
--create new layer in "clocks document"
set current document to document "clocks"
make new art layer at beginning of current document with properties ¬
{name:newLayerName, blend mode:normal}
paste
--return to build document for next loop
set current document to buildDoc
set mns to mns + 5 --add 5 minutes for next loop
set minCount to minCount + 1 --count loop number
end repeat
--reset variables for next loop
set mns to 0
set minCount to 0
set hrCount to hrCount + 1
end repeat
display dialog "Finished"
end tell
For record’s sake I have included the script I used to separates the layers into individual files, naming each file with the name of it’s former layer. Generally I don’t like the idea of mixing up scripts with actions. It makes the script less portable — to use it you must first ensure the appropriately named actions appear in your Photoshop actions palette.
But by this stage I was getting impatient with my learning curve so this script includes a few Photoshop actions to patch up my AppleScript shortcomings. They both appear in a set called “Scripts”:
To create “Select next layer” simply record “Select next forward layer” in Photoshop.
Record “clock save” by saving a Photoshop file in a directory where you wish to save the rest. Most of the save options are not significant here, just make sure you don’t record a new name for the file or it will override the carefully preserved name made by the AppleScript.
This script will happily run with Photoshop in the background so if the last script kept you away from your email for too long, you can catch up while this one does the tedious work of saving the named files.
--You must first select the top layer of the document in Photoshop
tell application "Adobe Photoshop 7.0"
set buildDoc to current document
set layerCount to count the layers of the current document
set layerNumber to 1
repeat until layerNumber is greater than layerCount
--anyone know how to do this with AppleScript? I'd love to know
do action "Select next layer" from "Scripts"
set layerName to the name of the current layer of the current document as string
--I could have got this to work with any size document, call me lazy :P
set newDocument to make new document with properties ¬
{name:layerName, width:17 as pixels, height:17 as pixels, mode:RGB, resolution:72}
set current document to buildDoc
duplicate the current layer of the current document to the beginning of newDocument
set current document to newDocument
merge visible layers of newDocument
--some actions are just easier to record as scripts in Photoschop :)
do action "clock save" from "Scripts"
close current document
set layerNumber to layerNumber + 1
end repeat
display dialog "Finished"
end tell
With the gifs made, the HTML and CSS remain. The technique I have used to make the clocks appear is a variation of Fahrner Image Replacement. Basically the image is specified as a background-image in a span with CSS. Each particular time is specified with a class on this span.
This span wraps the text as it would normally appear.
<span class="t1903" title="07:03 PM">07:03 PM </span>
By including a range of classes for each image the five minute rounding problem is solved.
.t1900, .t1901, .t1902, .t1903, .t1904 {
background-image: url(gifs/19_00.gif)
}
The remaining CSS is common regardless of the time of day — most of which positions the clock to my satisfaction.
div.comments-body span {
display: block;
float: left;
text-indent: -100em;
background-repeat: no-repeat;
background-position: 0px 30%;
position: relative;
padding-top: .3em;
margin-left: -20px;
width: 20px;
height: 1.2em;
}
The first line of CSS is only one of 288 lines! My typing could be better so instead I put together an AppleScript to type it for me. The only preparation it requires in an open BBEdit file.
set hrs to 0
set mns to 0
tell application "BBEdit 6.5"
repeat until hrs is 24
repeat until mns is 60 --repeat for each 5 minutes
-- set name for hours
if hrs is less than 10 then
set hrsName to "0" & hrs as string
end if
if hrs is greater than or equal to 10 then
set hrsName to hrs as string
end if
--stagger variables for 5 minute range
set mns1 to mns + 1
set mns2 to mns + 2
set mns3 to mns + 3
set mns4 to mns + 4
-- set name for minutes
if mns is less than 10 then
set mnsName to "0" & mns as string
end if
if mns is greater than or equal to 10 then
set mnsName to mns as string
end if
if mns1 is less than 10 then
set mnsName1 to "0" & mns1 as string
end if
if mns1 is greater than or equal to 10 then
set mnsName1 to mns1 as string
end if
if mns2 is less than 10 then
set mnsName2 to "0" & mns2 as string
end if
if mns2 is greater than or equal to 10 then
set mnsName2 to mns2 as string
end if
if mns3 is less than 10 then
set mnsName3 to "0" & mns3 as string
end if
if mns3 is greater than or equal to 10 then
set mnsName3 to mns3 as string
end if
if mns4 is less than 10 then
set mnsName4 to "0" & mns4 as string
end if
if mns4 is greater than or equal to 10 then
set mnsName4 to mns4 as string
end if
--compile statement
set pasteString to ¬
".t" & hrsName & mnsName & ¬
", .t" & hrsName & mnsName1 & ¬
", .t" & hrsName & mnsName2 & ¬
", .t" & hrsName & mnsName3 & ¬
", .t" & hrsName & mnsName4 & ¬
" {background-image: url(gifs/" & ¬
hrsName & "_" & mnsName & ".gif);} " as string
set the selection to pasteString
select insertion point after selection
set selection to return
select insertion point after selection
--set minutes for next loop
set mns to mns + 5
end repeat
--set minutes and hours for next loop
set hrs to hrs + 1
set mns to 0
end repeat
end tell
My web searches for resources on Scripting Photoshop were largely fruitless. I hope my notes here help someone else attempting to take advantage of this powerful but seemingly underused tool.