Bumped into this web site:
http://codility.com
It's a web site where they test coders, and every so often, they offer a public challenge you can use to hone your algorithm-design and coding skills.
These are great brain-teasers, and I had tremendous fun solving the challenges - I did the last one of 2013 and the new one of 2014 that was just released.
And I managed to get some badges!
Warning: the challenges are not trivial, and it's one of those 'cannot let it go' things: once you click 'Challenge yourself', you'll find yourself hooked!
Saturday, January 11, 2014
Monday, May 13, 2013
Adobe CC. From selling assets to selling consumables.
Adobe recently made a massive switch: they switched from being a tool vendor to becoming a reseller of consumables. The Adobe CC is treated like a consumable (like electricity, petrol, toilet paper, air travel,...), whereas the Adobe CS was treated like an asset (like a chisel, a car, a house...).
The question on my mind is: if I look at companies selling consumables, how much innovation do I see? How much innovation is for the benefit of the consumer?
If I look at companies selling consumables from a monopoly situation, how much innovation do I see?
It'll be interesting to compare the amount of R&D in asset companies vs consumable companies.
Interesting times ahead!
The question on my mind is: if I look at companies selling consumables, how much innovation do I see? How much innovation is for the benefit of the consumer?
If I look at companies selling consumables from a monopoly situation, how much innovation do I see?
It'll be interesting to compare the amount of R&D in asset companies vs consumable companies.
Interesting times ahead!
Sunday, April 7, 2013
ExtendScript Toolkit Unbearably Slow?
ExtendScript Toolkit Slowness
Note added 9-May-2017: in addition to the issues outlined below, another, now common, reason for slowness of ESTK on Macs is the 'app nap'. Background apps on Mac 'fall asleep' and become really slow (to save energy). If ESTK is talking to InDesign and InDesign falls asleep, things get really slow. Quickly switching back and forth to InDesign, then back to ESTK wakes them up. On CS6 you can disable App Nap as a 'Get Info' property on the ESTK and InDesign applications in the Finder. For CC and higher, no quick fixes. I have turned off App Nap on ESTK and InDesign CS6, and I use CS6 for script development when I need ESTK.
Recently, I was working on a fairly large script-based solution for Adobe InDesign.
Things progressed well, and the script was growing at a rapid pace.
For small tasks, I tend to write scripts more in a procedural, ad-hoc manner. For more complex tasks, I will normally define some formal object model with object classes, methods, getters, setters, inheritance,...
In this particular case, the system was teetering between the two realms, and it was clear I'd need to go for a formal object-oriented approach some time later, as the complexity started to increase.
But as I was still testing the waters and getting my head around the many aspects of the solution, I had decided not to start on an object model and a class architecture until things had become better defined. Often, with these projects, I go through a ping-pong process with the users and other stakeholders, and valuable information only emerges after a few initial prototypes have been tried out 'in real life'.
Because the script had to serve as a go-between InDesign and an outside system with a wide API (Application Programming Interface), I had a growing collection of symbolic constants, each representing some kind of 'magical' value for the outside system's API.
All was well: the solution grew, and gradually more and more functionality became available; users were impressed.
Speed and responsiveness were great, even when massive amounts of data were being chewed on.
ExtendScript, despite being an interpreted language, is amazingly fast if you know how to treat it correctly.
Until suddenly some unexpected issue came out of the blue: for some reason, ExtendScript Toolkit became unbearably slow.
At first I thought it was one of those unexplicable things that come and go. So I restarted my Mac, reset the preferences, created a brand new user account and tried that way, switched to another Mac. All to no avail.
Simply trying to run the script in ExtendScript Toolkit almost immediately caused the colored pizza to appear and everything ran like molasses.
Running the script straight from the InDesign Scripts palette worked fine. It was only when the ExtendScript Toolkit got involved that things got really slow.
Initially, it was still somewhat bearable. Having to wait a few minutes just to inspect a variable is annoying, but you can grit your teeth and wait it out. But things got out of control very rapidly: a few hours later, the minute-long waits had become half-hour waits.
Run, breakpoint, colored pizza for 30 minutes. Run, breakpoint, colored pizza for 30 minutes...
Ok, this lobster had enough: the water in the pot was becoming too hot, and something had to be done. I started to investigate.
I used the Mac's Activity Monitor to sample the ExtendScript Toolkit process, and found that the ExtendScript toolkit was working very hard. Some poking and prodding revealed that nearly all that hard work was related to the Data Browser element in the ExtendScript Toolkit.
Eventually, I figured out it had to do with the quantity of constants and variables I had created in the global variable space. The Data Browser had trouble displaying all those elements. If I closed the Data Browser, ExtendScript Toolkit's speed became normal.
For what little info I was able to glean from my poking around, I suspect the Data Browser has an extremely inefficient lookup buried somewhere inside its code: it looks like it has many levels of nested linear lookups, and as more elements start populating the global variable space, things get exponentially (or worse than exponentially) slower.
So, I had to refactor my code earlier than expected - and that fixed the issue. The main change was that instead of something like:
const kExternalSys_BoldAttribute = 0x0001;
const kExternalSys_ItalicAttribute = 0x0002;
...
and so on, thousands of those, I made it into:
var kCST =
{
ExternalSys_BoldAttribute: 0x0001,
ExternalSys_ItalicAttribute: 0x0002
...
};
And instead of referring to kWordSys_BoldAttribute, I now referred to kKCST.WordSys_BoldAttribute and so on.
I further reduced the footprint in the global space by making the script fully object oriented, with nearly all functions as methods attached to object classes, rather than having gobs of globally defined functions.
And now it's all fine again!
So, the morale: keep the global variable space as empty as possible, or ExtendScript Toolkit will get ya!
Wednesday, January 2, 2013
GetURLs.jsx - access HTTP content from InDesign ExtendScript
Note added 9-May-2017: I've revisited GetURL and made a more modern version. More info here:
http://coppieters.nz/?p=133
----
In 2008, I created a sample InDesign ExtendScript called GetURLs.jsx. GetURLs.jsx is a limited http client; it allows you to fetch http URLs straight from an InDesign ExtendScript.
I used the script as sample material to demonstrate a programming technique (state machines).
It turned out the script was quite popular in its own right; I've been adding little tweaks to it over time.
The latest version has been enhanced to handle redirections (when the server returns a status code HTTP 1.0/301 Moved Permanently). Hope it works for you!
The original blog post is here:
http://rorohiko.blogspot.co.nz/2008_07_01_archive.html
and the download link is here:
http://www.rorohiko.com/podcast/geturl.zip
Cheers,
Kris
http://coppieters.nz/?p=133
----
In 2008, I created a sample InDesign ExtendScript called GetURLs.jsx. GetURLs.jsx is a limited http client; it allows you to fetch http URLs straight from an InDesign ExtendScript.
I used the script as sample material to demonstrate a programming technique (state machines).
It turned out the script was quite popular in its own right; I've been adding little tweaks to it over time.
The latest version has been enhanced to handle redirections (when the server returns a status code HTTP 1.0/301 Moved Permanently). Hope it works for you!
The original blog post is here:
http://rorohiko.blogspot.co.nz/2008_07_01_archive.html
and the download link is here:
http://www.rorohiko.com/podcast/geturl.zip
Cheers,
Kris
Thursday, December 6, 2012
Fun with Arduino - how to get into assembler programming.
I am having fun with an Arduino Uno. I am old school; I started with a TRS-80 in the late 1970's, did a lot of Z80 assembly language. My computer had a massive memory (for the time) of 16KB, so in order to wring out a bit more, assembler was the way to go.
Gotta say, this Arduino brings back a lot of memories.
I bought a few tutorial kits (e.g. an Arduino Uno), and by the looks of it, the Arduino has a lot of similarities with my first computer, but it's a bit more powerful.
Its clock is 16MHz (my TRS-80 was 1.7MHz).
Its memory is 32KB Flash + 2KB SRAM + 1KB EEPROM (my TRS-80 had 16KB SRAM + 12KB ROM. And cassette tapes for storage)
It uses an 8-bit CPU (so did my TRS-80, which used a Z80).
Turns out that the Arduino IDE uses C++ as its 'main language' (that was Level 2 Basic on my TRS-80).
(And yes, these are KB - Kilobytes. Not Tera, not Giga, not Mega. Kilo. 1KB being 1024 Bytes. I still find it strange how, in 1978, I thought 16KB was unimaginably large, whereas nowadays 16KB in unimaginably small. My MacBook Pro has 8GB SRAM, more than 500,000 times what my TRS-80 had. Wow. That still flabbergasts me.)
The Arduino IDE is cool and all that, but feels kind of wasteful, so I set out on a quest to do some assembler programming on the Arduino.
Turns out that a lot of effort seems to have gone into discouraging doing this. There is a lot of 'magic' going on, and the Arduino IDE hides a lot of complexity from view. With good reason; there is often no need to look beyond the magic. One can opt to just accept it, and it works perfectly fine.
But I like to understand how it all works; dig into the magic, take it apart, and figure out how it works. I've always found that if you understand the magic, you can make better use of it.
I am pretty sure that most of my future Arduino (or Pinguino or Uno32; I bought one each of those too!) exploits will be using mostly, if not exclusively C/C++, but my first experiments are aimed at understanding how to do assembler programming.
I had to do a lot of fishing around to get enough info: lots and lots of little tidbits here and there, but no real 'how to get started' cookbook. So I decided to put the tidbits together in a wee dokuwiki page, and make it as complete as possible, in the hopes that someone else finds it useful.
While searching, often all I am looking for are a few good, complete examples, and that gets me going.
The dokuwiki page below is an attempt to help other people get going, by offering complete, working examples.
I tried to cover all the necessary steps, from patching up your IDE to accept assembly source code down to some increasingly advanced sample assembler programs.
There are some things I've skimmed over (e.g. I assume you know how to set up a Java development environment on your computer).
So, here goes. In case you're looking to get started with Arduino and assembler, here are my 'useful tidbits', for what they're worth:
http://rwf.co/dokuwiki/doku.php?id=smallcpus
If you want more detail for particular things, let me know. If I can find the time, I'll write additional instructions if needed.
Cheers,
Kris
Gotta say, this Arduino brings back a lot of memories.
I bought a few tutorial kits (e.g. an Arduino Uno), and by the looks of it, the Arduino has a lot of similarities with my first computer, but it's a bit more powerful.
Its clock is 16MHz (my TRS-80 was 1.7MHz).
Its memory is 32KB Flash + 2KB SRAM + 1KB EEPROM (my TRS-80 had 16KB SRAM + 12KB ROM. And cassette tapes for storage)
It uses an 8-bit CPU (so did my TRS-80, which used a Z80).
Turns out that the Arduino IDE uses C++ as its 'main language' (that was Level 2 Basic on my TRS-80).
(And yes, these are KB - Kilobytes. Not Tera, not Giga, not Mega. Kilo. 1KB being 1024 Bytes. I still find it strange how, in 1978, I thought 16KB was unimaginably large, whereas nowadays 16KB in unimaginably small. My MacBook Pro has 8GB SRAM, more than 500,000 times what my TRS-80 had. Wow. That still flabbergasts me.)
The Arduino IDE is cool and all that, but feels kind of wasteful, so I set out on a quest to do some assembler programming on the Arduino.
Turns out that a lot of effort seems to have gone into discouraging doing this. There is a lot of 'magic' going on, and the Arduino IDE hides a lot of complexity from view. With good reason; there is often no need to look beyond the magic. One can opt to just accept it, and it works perfectly fine.
But I like to understand how it all works; dig into the magic, take it apart, and figure out how it works. I've always found that if you understand the magic, you can make better use of it.
I am pretty sure that most of my future Arduino (or Pinguino or Uno32; I bought one each of those too!) exploits will be using mostly, if not exclusively C/C++, but my first experiments are aimed at understanding how to do assembler programming.
I had to do a lot of fishing around to get enough info: lots and lots of little tidbits here and there, but no real 'how to get started' cookbook. So I decided to put the tidbits together in a wee dokuwiki page, and make it as complete as possible, in the hopes that someone else finds it useful.
While searching, often all I am looking for are a few good, complete examples, and that gets me going.
The dokuwiki page below is an attempt to help other people get going, by offering complete, working examples.
I tried to cover all the necessary steps, from patching up your IDE to accept assembly source code down to some increasingly advanced sample assembler programs.
There are some things I've skimmed over (e.g. I assume you know how to set up a Java development environment on your computer).
So, here goes. In case you're looking to get started with Arduino and assembler, here are my 'useful tidbits', for what they're worth:
http://rwf.co/dokuwiki/doku.php?id=smallcpus
If you want more detail for particular things, let me know. If I can find the time, I'll write additional instructions if needed.
Cheers,
Kris
Thursday, December 29, 2011
How to Use DropBox More Efficiently
Lately, we've started to use DropBox more and more. Initially, we used it mainly as a tool to keep multiple workstations and laptops synchronized, as well as a means to quickly provide someone a downloadable link to a file without having to fumble about with FTP or WebDAV or other complicated things.
Then we started using the shared folders more and more.
As we nearly always work together with other people and companies scattered all over the globe, DropBox is a godsend: we set up a shared folder, and that's it. Through DropBox, a distributed workgroup can easily share a bunch of files.
But sharing wildly with all kinds of partners created a small problem. How does one keep track of all these shared folders in DropBox. Which is shared with who? Of course, one can go find out via the DropBox web site, but that's not really a quick thing.
So, now we've started to use specific names for the DropBox folders. If a DropBox folder is shared between two parties, we refer to it as a 'tunnel', and we append the name of the two sharing parties.
If we were regularly working together with a company called, say, 'Ynapmoc', I'd use a folder called 'Tunnel_Ynapmoc_Rorohiko' or 'Tunnel_Rorohiko_Ynapmoc'. Often we tend to work on multiple projects with our partners, and we use the tunnel for shuttling shared documents between us.
If a DropBox folder is shared between more than two parties, we would instead create a new folder for each individual project, and simply use the word 'Shared' followed by the name of the project. So, if we were working with, say, three parties on a project called, say, 'Terces', the folder would be called 'Shared_Terces'.
My DropBox folder now looks a lot better organized, and I can tell immediately what each shared folder is meant for.
If you get a request to share a dropbox folder with a name that starts with 'Tunnel_...' you'll know what that means!
Cheers,
Kris
Then we started using the shared folders more and more.
As we nearly always work together with other people and companies scattered all over the globe, DropBox is a godsend: we set up a shared folder, and that's it. Through DropBox, a distributed workgroup can easily share a bunch of files.
But sharing wildly with all kinds of partners created a small problem. How does one keep track of all these shared folders in DropBox. Which is shared with who? Of course, one can go find out via the DropBox web site, but that's not really a quick thing.
So, now we've started to use specific names for the DropBox folders. If a DropBox folder is shared between two parties, we refer to it as a 'tunnel', and we append the name of the two sharing parties.
If we were regularly working together with a company called, say, 'Ynapmoc', I'd use a folder called 'Tunnel_Ynapmoc_Rorohiko' or 'Tunnel_Rorohiko_Ynapmoc'. Often we tend to work on multiple projects with our partners, and we use the tunnel for shuttling shared documents between us.
If a DropBox folder is shared between more than two parties, we would instead create a new folder for each individual project, and simply use the word 'Shared' followed by the name of the project. So, if we were working with, say, three parties on a project called, say, 'Terces', the folder would be called 'Shared_Terces'.
My DropBox folder now looks a lot better organized, and I can tell immediately what each shared folder is meant for.
If you get a request to share a dropbox folder with a name that starts with 'Tunnel_...' you'll know what that means!
Cheers,
Kris
Tuesday, November 15, 2011
Mac OS X Lion - how to get Unicode back on your Character Viewer.
One handy little tool I use all the time in Mac OS X is the Characters Palette which I can access via the menu bar.
You enable it by going to the System Preferences - Keyboard, and ticking 'Show Keyboard & Character Viewers in menu bar'.
Then scroll all the way down until you see 'Code Tables'. Click the disclosure triangle and tick the checkbox for Unicode.
You enable it by going to the System Preferences - Keyboard, and ticking 'Show Keyboard & Character Viewers in menu bar'.
I've upgraded to Lion a wee while back, and had not needed the characters palette - but recently I wanted to have a quick look at some Unicode character codes. I brought up the characters palette via the menu bar:
But the resulting palette seemed to be quite spartan and bare and the familiar Unicode table just was not there.
Turns out: the Unicode table is still there, but you need to turn it on first. Click on the settings button, and select 'Customize List...'.
Then scroll all the way down until you see 'Code Tables'. Click the disclosure triangle and tick the checkbox for Unicode.
That adds the Unicode table back. Great for browsing around in Unicode!
Hope this saves someone some time and frustration!
Cheers,
Kris
Monday, July 11, 2011
Software Distributors
I am puzzled - not sure how to deal with software distributors.
Here at Rorohiko Workflow Resources, we've been hard at work for many years now, to build a whole range of tools, mainly for users of the Adobe Creative Suite. Our range of tools is slowly but steadily increasing.
In order to sell and try to make our investment pay back for itself, we've built an automated software selling system, which works relatively well: we have a peculiar approach to how we sell our software, which allows us to sell our tools at very low cost despite aiming for a limited market. Part of the secret is automation.
E.g. you can purchase an activation for TextExporter for all of US$19.00. This low cost means that purchasing an activation for one of our tools pays back for itself very quickly.
We're gradually getting more and more traction in the market - which is cool.
Now, lately we've been getting more and more requests from software distributors who want to distribute our products - but most of them have the same puzzling approach.
They want to know what their dealer margin is, and where they can send a purchase order.
A few times, we've tried to accommodate such requests, but invariably, we ended up holding the longest end of the stick: working with software distributors invariably costs us more than it's worth.
- They cause a whole lot of additional administration (purchase orders, paper or PDF invoices,...). Such additional admin costs us money.
- They want to send us a purchase order and in return get an invoice. Then they take their own sweet time to pay up.
They often need one or more reminders. Their purchase department is typically insulated from the rest of the company, and once our invoice is in the slow paper mill, it can take six months or longer before we finally get paid, and there is nothing much we can do about it.
- They want to pay us by cheque or credit card, and don't want to use PayPal. As Rorohiko is still small, and establishing credit card facilities would cost us both in time and money, we make do with PayPal.
(We've looked around, and after that exercise, we think that despite a number of obvious shortcomings, PayPal is one of the better payment processors on the market. Through PayPal we can accept credit cards. People with corporate credit cards seem to have a few extra hoops to jump through - but once they set up an address-verified PayPal account, things seem to work fine.)
- They don't seem to have time to read: we have a lot of info on our web site, and, granted, it's not that well organized, but these people clearly have not even visited our web site. They don't know what our products do, and are not interested in learning how our licensing system works (http://www.rorohiko.com/licensing).
In the end, we sell a single $19 activation, and end up with costs that far surpass that amount - paperwork, having to wait to get paid... it all adds up.
As such, we see any such requests from software distributors as a 'win/lose' scenario: they win, we lose.
My question is: are there some software distributors out there who understand the idea of a 'value proposition'? If you're a software distributor, and you like our products: before e-mailing us, make sure you have something of that is of value to offer in return for the extra hassle. There's many ways you could make this work.
Also, reading up on our products and our approach to licensing beforehand gains you brownie points!
Here at Rorohiko Workflow Resources, we've been hard at work for many years now, to build a whole range of tools, mainly for users of the Adobe Creative Suite. Our range of tools is slowly but steadily increasing.
In order to sell and try to make our investment pay back for itself, we've built an automated software selling system, which works relatively well: we have a peculiar approach to how we sell our software, which allows us to sell our tools at very low cost despite aiming for a limited market. Part of the secret is automation.
E.g. you can purchase an activation for TextExporter for all of US$19.00. This low cost means that purchasing an activation for one of our tools pays back for itself very quickly.
We're gradually getting more and more traction in the market - which is cool.
Now, lately we've been getting more and more requests from software distributors who want to distribute our products - but most of them have the same puzzling approach.
They want to know what their dealer margin is, and where they can send a purchase order.
A few times, we've tried to accommodate such requests, but invariably, we ended up holding the longest end of the stick: working with software distributors invariably costs us more than it's worth.
- They cause a whole lot of additional administration (purchase orders, paper or PDF invoices,...). Such additional admin costs us money.
- They want to send us a purchase order and in return get an invoice. Then they take their own sweet time to pay up.
They often need one or more reminders. Their purchase department is typically insulated from the rest of the company, and once our invoice is in the slow paper mill, it can take six months or longer before we finally get paid, and there is nothing much we can do about it.
- They want to pay us by cheque or credit card, and don't want to use PayPal. As Rorohiko is still small, and establishing credit card facilities would cost us both in time and money, we make do with PayPal.
(We've looked around, and after that exercise, we think that despite a number of obvious shortcomings, PayPal is one of the better payment processors on the market. Through PayPal we can accept credit cards. People with corporate credit cards seem to have a few extra hoops to jump through - but once they set up an address-verified PayPal account, things seem to work fine.)
- They don't seem to have time to read: we have a lot of info on our web site, and, granted, it's not that well organized, but these people clearly have not even visited our web site. They don't know what our products do, and are not interested in learning how our licensing system works (http://www.rorohiko.com/licensing).
In the end, we sell a single $19 activation, and end up with costs that far surpass that amount - paperwork, having to wait to get paid... it all adds up.
As such, we see any such requests from software distributors as a 'win/lose' scenario: they win, we lose.
My question is: are there some software distributors out there who understand the idea of a 'value proposition'? If you're a software distributor, and you like our products: before e-mailing us, make sure you have something of that is of value to offer in return for the extra hassle. There's many ways you could make this work.
Also, reading up on our products and our approach to licensing beforehand gains you brownie points!
Saturday, April 9, 2011
Fitting of Images Into Frames in Automated and Semi-Automated Page Layout Workflows
When developing workflows around InDesign Server or similar automated page layout workflows, one of the recurring themes is the fitting of image material into frames on a page.
This method can easily be implemented in ExtendScript/JavaScript or any other programming language.
I'll also show a corresponding user interface.
It all starts with an image and a frame. Most commonly, both are rectangular, but their shape is not necessarily related: the image might have a landscape orientation and the layout frame that the image needs to fit in might have a portrait orientation.
What I'll present in this article is (as far as I know) a novel way of encoding image fitting data into four numbers, in such a way that the fitting data becomes totally decoupled from the actual frame and image shapes. The same fitting data can be re-applied to images and frames of wildly different shapes, and always gives sensible results.
The fitting data is fairly straightforward to grasp intuitively - the four numbers I use are called (xFactor, yFactor, scale, rotation).
xFactor and yFactor range between -1.0 and 1.0, scale between 0.0 and 1.0, and rotation = 0, 1, 2 or 3.
xFactor = -1.0 means: frame at the extreme left side of image.
xFactor = 0.0 means: frame horizontally in the middle of the image
xFactor = +1.0 means: frame at the extreme right side of the image.yFactor = -1.0 means: frame at the extreme top side of image.
yFactor = 0.0 means: frame vertically in the middle of the image
yFactor = +1.0 means: frame at the extreme bottom side of the image.
scale = 1.0 means: frame as large as possible without going 'outside' the image
scale = 0.0 means: frame infinitely small
rotation = 0: image not rotated
rotation = 1: image rotated 90 degrees
rotation = 2: image rotated 180 degrees
rotation = 3: image rotated 270 degrees
Keep in mind: in the samples below I'm continually using different images and/or frames - the main 'claim to fame' of the decoupled image fitting data is that no matter what image or frame shapes you throw at it, it always gives sensible results.
First two samples, both using the exact same fitting data - xFactor = 0.0, yFactor = 0.0, scale = 1.0, rotation = 0.
As you can see (0.0, 0.0, 1.0, 0) translates to: center the frame on the image, and make the frame as large as possible. It does not matter whether the image has portrait or landscape orientation, and it does not matter whether the frame has portrait or landscape orientation - the same fitting data always works.
(0.0, 0.0, 1.0, 0) is the default fitting data I most commonly use for images and frames that have not been edited by a user.
Now a sample image, and a differently shaped frame, this time using (0.0, 0.0, 0.5, 0) as the fitting data: the scale is 0.5 instead of 1.0. The frame shrinks down to half the largest possible size both horizontally and vertically:
Another sample image and frame, now using (-1.0, -1.0, 0.5, 0): the scale is the same as in the previous sample, but now the frame has moved to the top left corner.Any fitting data with xFactor = -1.0 and yFactor = -1.0 always means: move the frame to the top left corner.
To help understand my image fitting method, think of the frame as a window through which we can see part of the image.
Imagine I float a rectangle in the same shape as the frame on the page 'on top' of the image. I'll combine two actions:
1) Shifting the frame around within the image
2) Resizing the frame so it covers more or less of the image
l'll initially assume the floating frame rectangle is not allowed to go 'outside' the image. It is forced to stay within the confines of the image.
With regards to the positioning of the floating frame: I will be encoding the position of the center of the frame with respect to the center of the image.
For the sake of argument, I'll first only consider the vertical position of the floating frame.
I observe that when the floating frame covers the full height of the image, it has no room to move vertically (otherwise it would escape the confines of the image).
(No vertical leeway: the frame cannot move up or down without leaving the confines of the image)
In essence, the amount of 'vertical leeway' is determined by the difference in height between the floating frame and the image. If the image and floating frame have the same height, the vertical leeway is zero. At the other extreme, if the floating frame height were reduced to zero, the vertical leeway would be the full height of the image.
(Vertical leeway is difference between image height and frame height)
When the floating frame is positioned in the center of the image, I can move it half the vertical leeway towards the top, and half the vertical leeway towards the bottom.
(When the frame is centered on the image we can move half the vertical leeway up, and half the vertical leeway down)
That brings me to one of the key numerical values: given an image and a frame, I calculate half the vertical leeway (in other words: I subtract the frame height from the image height and divide by two).
I then express the vertical position of the frame center with respect to the image center as a value between -1.0 and 1.0. When I multiply this value with half the vertical leeway, I get the frame's center offset along the y-axis in relation to the image center.
I do the same for the horizontal axis: encode the horizontal offset of the frame center from the image center as a value between -1.0 and 1.0. Multiplying this value with half the horizontal leeway gives me the frame center's horizontal offset from the image center.
To encode the frame size, I first rescale the frame so it 'fits' the image in one of the two dimensions. I make the frame as large as possible without 'spilling out' of the image. When I do that, either the horizontal or vertical sizes of image and floating frame will be equal, and in the other dimension the frame size will be less than, or equal to the image size.
I call the 'equal' dimension 'the dominant dimension' - each time someone gives me an image and a frame, I can determine the dominant dimension for that particular (image, frame) pair - it's either horizontal or vertical (and occasionally both - in which case I pick either).
(The vertical dimension is dominant: the frame can be made to fit the image vertically while it remains narrower than the image horizontally)
I now encode the frame scaling as a number between 0.0 and 1.0 along the dominant dimension. If the scale is 1.0 the frame and image have the exact same size along the dominant dimension. If the scale is 0.5, the frame is half the size of the image along the dominant dimension. The non-dominant dimension is resized proportionally.
(scale = 0.5 means that the frame is half of the image size along the dominant dimension)
Finally, I need to encode image rotation: the image can be rotated underneath the frame. I encode that as an integer number from 0 to 3 (0 = not rotated, 1 = 90 degrees... ).
So, to make an image fit into a frame, I have the fitting data encoded as four numbers:
xFactor = -1.0 to 1.0 (floating point)
yFactor = -1.0 to 1.0 (floating point)
scale = 0.0 to 1.0 (floating point)
rotation = 0 to 3 (integer)
I'll now work through a step-by-step procedure of using this fitting data.
Assume I'm given fitting information (a set of four numbers: (xFactor, yFactor, scale, rotation) as well as an image with dimensions (widthImageUnrotated, heightImageUnrotated) and a frame in a page layout with dimensions (widthFrame, heightFrame).
If scale is 0.0, I don't even start the process - it would lead to a division by zero.
First I take into account the rotation. If the rotation is 1 or 3, I need to swap the image width and image height because the image is turned on its side through a quarter turn.
Based on rotation and (widthImageUnrotated, heightImageUnrotated) I define a new pair of rotation-adjusted image dimensions (widthImage, heightImage).
The next step is determining the dominant dimension. I calculate two ratios:
horRatio = widthFrame / widthImage
and
verRatio = heightFrame / heightImage
The larger of these two ratios belongs to the dominant dimension.
For the sake of argument, I'll first assume horRatio ends up to be the larger of the two. That makes the horizontal dimension the dominant one. This means that I can make the frame 'fit' the image horizontally while leaving the vertical frame height less than or at most equal to the image height.
In that case, the scale division factor that I apply to the image, imageScaleDiv, is determined as
imageScaleDiv = scale / horRatio
In the other case, where the verRatio turns out to be the larger of the two instead of horRatio, I would use
imageScaleDiv = scale / verRatio
I rescale the image by dividing the image dimensions by imageScaleDiv, so its new size becomes (widthImageScaled, heightImageScaled):
widthImageScaled = widthImage / imageScaleDiv
and
heightImageScaled = heightImage / imageScaleDiv
Normally, imageScaleDiv should not be zero at this point of the procedure - we don't allow for zero scale values.
I now calculate horizontal and vertical leeways:
horHalfLeeway = (frameWidth - imageScaledWith) / 2.0
and
verHalfLeeway = (frameHeight - imageScaledHeight) / 2.0
Now I multiply these 'half leeways' with the xFactor and yFactor to find the offset of the image center compared to the frame center:
xOffset = xFactor * horHalfLeeway
and
yOffset = yFactor * verHalfLeeway
This concludes the procedure: I've taken a set of four numbers (xFactor, yFactor, scale, rotation), applied them to an image and a frame, and ended up with sufficient scaling information and positioning information to allow me to put the image into the frame.
The power of this encoding becomes apparent when I retain only the fitting information, and apply the same set of four numbers to a completely different image and/or frame: it still works, and in most cases, the 'fit' is 'natural'.
So, if I have a person's portrait in a frame, and swap it for a different portrait, the fit will most probably still be correct - most headshots share the same basic proportions. Here's an example where the two images are very different, yet re-using the same fitting data works well:
(fitting info: (0.0, 0.0, 0.75, 0) )
(fitting info: (0.0, 0.0, 0.75, 0). The same fitting info as the previous image. Even though the image shape is quite different, the same fitting info still works well)
If I position the cropping frame, say, in the top left corner and change the scale, the cropping frame will remain in the top left corner and extend down and to the right.
(fitting info: (-1.0, -1.0, 0.5, 0) )
(fitting info: (-1.0, -1.0, 0.75, 0). Changing the scale from 0.5 to 0.75 keeps the frame 'stuck' in the corner)
If I position the cropping frame dead center and change the scale: it will grow and shrink while remaining centered.
(fitting info: (0.0, 0.0, 0.5, 0) )
(fitting info: (0.0, 0.0, 0.75, 0). Changing the scale from 0.5 to 0.75 keeps the frame 'stuck' in the center)
When an automated or semi-automatic workflow has some image fitting operation in it, storing the image fitting data as a set of four numbers, and applying them as described here increases the chances that the fitting data will continue to give sensible results even when the image is replaced with another, or the frame is resized later on (e.g. when a template is adjusted). The fitting data is fully decoupled from image and frame dimensions.
The method described here also remains usable outside the limitations I originally set out.
By allowing xFactor and yFactor to go outside of the interval [-1.0, 1.0] I can allow for frames that only partially overlap the image.
Similarly, scale factors outside of the interval ] 0.0, 1.0 ] can be used too - I could allow negative scale factors or scale factors larger than 1.0. However, a zero scale factor will never give sensible results - it results in a division by zero.
Finally, the rotation can be allowed to be a floating point number in the interval [0.0, 4.0[ instead of an integer 0 - 3. That way, I can rotate over arbitrary angles - e.g. a rotation of 0.5 would translate into a rotation of the image of 45 degrees.
The screen shots that accompany this blog post demonstrate the related user interface - the screen shots are from an AJAX implementation I made for a real-life project, using Google Web Toolkit (GWT) running in an ordinary web browser.
I found it helpful if I made the scale slider to show the effective image resolutions (instead of the underlying scale factor).
In general it works like this: initially, in an automated setup, I always start with a default fitting of (xFactor, yFactor, scale, rotation) = (0.0, 0.0, 1.0, 0). That centers the frame onto the image, and makes the frame as large as possible, cropping away part of the image if necessary.
When the user edits the image fitting through my user-interface, I store the resulting fitting parameters (xFactor, yFactor, scale, rotation) alongside the layout (e.g. the script labels are a great spot to put this).
When the layout or image changes, I retrieve the fitting data and re-apply the fitting data to the new image or the modified frame.
It works really well for me - hope it does for you too!
(c) 2011 Kris Coppieters - Rorohiko Ltd.
Thursday, March 31, 2011
Are Mac users quicker to upgrade to InDesign CS5 than Windows users?
I recently saw some Facebook 'polls' that looked like an attempt to probe who is using what version of InDesign. Oftentimes, these polls fall flat because the sample size is too small.
But if you want to know how the InDesign user base divvies up, at Rorohiko we have fairly significant, up to date information - further down, I'll share with you some usable percentages and graphs for the month of March 2011.
The clue is in our web server logs. We watch downloads of our APID ToolAssistant for InDesign plug-in, and that tells us a lot (http://www.rorohiko.com/apidtoolassistant).
Here's how it works. APID ToolAssistant in itself does not do anything obvious for the end-user, but in order to use one or more of our extensive range of plug-ins, users need to install APID ToolAssistant on their computer. Each user needs to install APID ToolAssistant only once per installed version of InDesign. Every month we get a few hundreds of downloads of APID ToolAssistant.
What makes APID ToolAssistant unique as a market probing mechanism is that we still support versions of InDesign as far back as InDesign CS - we cover the whole range of CS, CS2, CS3, CS4 and CS5.
On top of that, our downloads are separated - instead of one single download, we provide separate downloads for each platform and each version - 10 downloads in total - so we can monitor each platform/version combination separately.
In March 2011, we had 1548 downloads - and these were separated up as shown below.
To paraphrase the graphs below in words: Mac and Windows are about even, about 10% of all users are still using CS and CS2 and about 30% of all users is still on CS3 or below. Finally, CS5 is slightly ahead of CS4.
P.S. If this info is interesting to you, contact consulting@rorohiko.com - there's more where that came from!
But if you want to know how the InDesign user base divvies up, at Rorohiko we have fairly significant, up to date information - further down, I'll share with you some usable percentages and graphs for the month of March 2011.
The clue is in our web server logs. We watch downloads of our APID ToolAssistant for InDesign plug-in, and that tells us a lot (http://www.rorohiko.com/apidtoolassistant).
Here's how it works. APID ToolAssistant in itself does not do anything obvious for the end-user, but in order to use one or more of our extensive range of plug-ins, users need to install APID ToolAssistant on their computer. Each user needs to install APID ToolAssistant only once per installed version of InDesign. Every month we get a few hundreds of downloads of APID ToolAssistant.
What makes APID ToolAssistant unique as a market probing mechanism is that we still support versions of InDesign as far back as InDesign CS - we cover the whole range of CS, CS2, CS3, CS4 and CS5.
On top of that, our downloads are separated - instead of one single download, we provide separate downloads for each platform and each version - 10 downloads in total - so we can monitor each platform/version combination separately.
In March 2011, we had 1548 downloads - and these were separated up as shown below.
To paraphrase the graphs below in words: Mac and Windows are about even, about 10% of all users are still using CS and CS2 and about 30% of all users is still on CS3 or below. Finally, CS5 is slightly ahead of CS4.
P.S. If this info is interesting to you, contact consulting@rorohiko.com - there's more where that came from!
| Downloads of APID ToolAssistant in March 2011 | ||||
| Mac, CS | 41 | 3% | ||
| Mac, CS2 | 46 | 3% | ||
| Mac, CS3 | 130 | 8% | ||
| Mac, CS4 | 236 | 15% | ||
| Mac, CS5 | 363 | 23% | ||
| Win, CS | 42 | 3% | ||
| Win, CS2 | 51 | 3% | ||
| Win, CS3 | 135 | 9% | ||
| Win, CS4 | 257 | 17% | ||
| Win, CS5 | 247 | 16% | ||
| Total | 1548 | |||
| Downloads of Mac APID ToolAssistant in March 2011 | ||||
| CS | 41 | 5% | ||
| CS2 | 46 | 6% | ||
| CS3 | 130 | 16% | ||
| CS4 | 236 | 29% | ||
| CS5 | 363 | 44% | ||
| Total | 816 | |||
| Downloads of Windows APID ToolAssistant in March 2011 | ||||
| CS | 42 | 6% | ||
| CS2 | 51 | 7% | ||
| CS3 | 135 | 18% | ||
| CS4 | 257 | 35% | ||
| CS5 | 247 | 34% | ||
| Total | 732 | |||
| Downloads of APID ToolAssistant in March 2011 | |||||
| Mac | 816 | 53% | |||
| Windows | 732 | 47% | |||
| Total | 1548 | ||||
Subscribe to:
Posts (Atom)
























