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

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'.


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!

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.

In this blog post I'll demonstrate a method for efficiently storing re-usable image fitting data. The image fitting data is resistant to image replacement or layout changes in the page layout.

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 (xFactoryFactorscalerotation).


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

Below are a few intuitive samples.

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 (widthImageUnrotatedheightImageUnrotated) 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)

Another advantage is that I can tie the image fitting info to the user interface, and get something that acts rather 'naturally'.

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 (xFactoryFactorscalerotation) = (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 (xFactoryFactorscalerotation) 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!

Downloads of APID ToolAssistant in March 2011
Mac, CS413%
Mac, CS2463%
Mac, CS31308%
Mac, CS423615%
Mac, CS536323%
Win, CS423%
Win, CS2513%
Win, CS31359%
Win, CS425717%
Win, CS524716%
Total1548

Downloads of Mac APID ToolAssistant in March 2011
CS415%
CS2466%
CS313016%
CS423629%
CS536344%
Total816


Downloads of Windows APID ToolAssistant in March 2011
CS426%
CS2517%
CS313518%
CS425735%
CS524734%
Total732


Downloads of APID ToolAssistant in March 2011
Mac81653%
Windows73247%
Total1548