I recently wrote a small inhouse bitmap measurement application and decided to generalize it a bit and realease it with source code. Maybe it’s useful for someone else...
My brother had to measure the position and dimensions of user interface elements, especially text fields, on a large bunch of dialog screenshots captured on Windows and Mac OS. There were four languages so he had to measure every field on every screenshot in four versions.
I wrote a specialized Cocoa tool to speed up the task. It allows the user to drop an image into an image view and then drag and resize a small transparent box across the image. The box marks the rectangular area of interest and there is a button to capture its current coordinates. There is a text area which collects the captured coordinate strings. The dialog also lets the user choose a label/identifier for a particular rectangle, as well as a few color and font values.
Since practically every second shaved off this process counts, moving / resizing of the measurement box and capturing of a set of values are highly optimized with keyboard shortcuts. The idea is that after dropping a screenshot image into the image view, the hands stay on the keyboard while the box is being moved around and all areas are measured. Then the resulting list of coordinate/geometry strings is pasted elsewhere and the next image is dropped into the image view.
In the first version of the program, the coordinates were output in a project-specific XML format, unusable for anyone else. In order to be useful for other people, it had to have a generic output format, or better yet a customizable one because manual post-processing of the output strings again wastes time.
I first thought about offering a template string, editable in the preferences. The template string would contain special tokes (%x, %y etc.) which the program would replace with the coordinate values and options picked by the user in the user interface.
The problem with this approach is that it’s not clear which tokens to offer. For example, should the x/y coordinates be passed as absolute integers, percentage values of the image width, factor values of the image width, is zero at the top left or bottom left, is the rectangle defined by a point and a size or by two points etc.
Anticipating and implementing all possible placeholders is a lot of work for me and no matter how many variants I offer, there will always be special use cases which can’t be handled.
The solution: I provide only one basic data format and allow the user to write a bit of JavaScript code which can access the values and format them freely. The pattern string is in effect a short JavaScript program which has access to two predefined objects which contain all the data.
With this solution, the output format possibilities are unlimited, and because there is a full programming language instead of a dumb pattern string, there can even be additional post-processing, as seen in one of the examples which contains a mapping table for additional text inserted depending on the label field value chosen by the user.
Here’s an example JavaScript snippet which produces an HTML client side image map rectangle:
Its output looks like this:
Another script produces this output:
Here the coordinates are factors of the image dimensions and go from 0 to 1.
I learned once again that easy things really are very easy in Cocoa; it took a few hours to get a working version, including learning (and re-learning and understanding for the first time) many new things about NSResponder and NSView programming. It was the first time I programmed a custom NSView that is interactive and draggable / resizable.
Adding JavaScript support was also easy thanks to WebKit. I injected two of my Objective-C objects into the JavaScript scope according to the WebScripting informal protocol. (What tripped me up was that I had to implement isSelectorExcludedFromWebScript: even though the docs say that the default is to allow method access).
You can download the program on the Mac OS X Software page
Currently it is usable in all situations where you need to measure rectangular areas on images. If I find some time I might extend it to support other shapes. If you use it for something interesting, let me know. Also let me know what improvements / enhancements you’d like to see.
|


