Archive for the 'Graphics' Category

Screencast codec showdown

Friday, December 8th, 2006

So I’m looking at making some screencasts in iShowU. I noticed that, thanks to QuickTime, it supports rather a lot of codecs:

iShowU's codecs pop-up menu, showing 29 different codecs of various suitability.

Dizzying, isn’t it?

So I asked the Goog about some of the codecs, and also more generically about screencast codecs. H.264 is a popular choice, but I found no comparison to other codecs nor any discussion of what any of the codecs is particularly good at.

I also had a small amount of previous experience with the difference between codecs. I’ve watched two of rentzsch‘s screencasts: “Introduction to Core Data” and “Embedded Cocoa Frameworks”. The former is 1024×768 using H.264; the latter is 800×600 using Sorenson 3. “Introduction to Core Data” looked flawless; “Embedded Cocoa Frameworks”, OTOH, had noticeable artifacts. I wondered at first what the difference was, and after I found out, whether there wasn’t a better codec with which to implement screencasts.

Part of the problem is that there really isn’t a codec that’s been well-optimized for screencasting. Video codecs have historically been optimized for, well, video — that is, video shot with a camera. Screen images usually don’t change much except to follow mouse movements; a compressor specifically optimized for recording the screen should make a big difference in screencast file sizes. Are you listening, Apple? (Or Ambrosia?)

Anyway. In order to find the perfect (so far) screencast codec, I recorded a brief screencast using iShowU in demo mode using the None (no-compression) codec, and used QTAmateur by Michael Ash to export it to all the other codecs.

The results? Well, you’ll just have to read the screencast codec showdown for yourself. ☺

Compiling EPS files to PDF files using Xcode

Wednesday, December 6th, 2006

You may remember Daniel Jalkut’s blog post about resolution independence, with its demonstration of the superiority in quality of vector graphics over raster graphics (using an EPS file that I created for him ☺).

The problem with using an EPS file, as I pointed out to him when I emailed him the file originally, is that EPS files are very slow on OS X. The current (Tiger) implementation of NSEPSImageRep uses Quartz’s CGPSConverter to convert the EPS data to PDF data, then instantiates an NSPDFImageRep (kept in a private ivar) that it has do all the real work.

That PostScript-to-PDF conversion is the bottleneck. You don’t want that multiple-second delay (yes, really) at runtime. Better to take it before runtime. At the time, I suggested that he use pstopdf to convert to a PDF file, then put the PDF file into his Xcode project to be copied into the app bundle.

But what if you decide later to change the PostScript file? You need to remember to run pstopdf again. EPS files are just PostScript source code, so why not treat them like any other source code file? Or, a better question: How?

The answer is quite simple: Add a custom rule to your target in Xcode that runs pstopdf over EPS files. Then, you add the EPS file — not the PDF file — to the project, and Xcode will exhibit normal build-only-when-necessary behavior on the EPS file and copy the generated PDF file for you. And of course, you can have as many EPS files as you want — they’re source code files just like any others.

Screenshot of Xcode's Target Info window, showing the custom rule. The rule matches the glob pattern “*.eps” and runs the shell script “pstopdf ${INPUT_FILE_NAME} -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.pdf”. It has one output file, which is “${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.pdf”. In the background is an Xcode project window showing a couple of EPS files in the “Other Sources” group.

New utility: image

Friday, November 17th, 2006

When I was writing “The fun of length-declared strings”, I needed to resize that lightbulb photo down to something more suitable for a blog post. Normally, I’d just use Photoshop, but I’m not on a PowerPC Mac anymore, so Photoshop 5.5 won’t run. So I needed to use other things.

The crop was easy; Preview can do that. But I also needed to scale it, and Preview can’t do that. I tried installing the (sigh) Photoshop CS2 tryout, but that didn’t work; the installer fails while it’s doing something ambiguous to Photoshop’s help files. No surprises there.

And I didn’t want to use iPhoto for it. That would mean importing it into my Library, and I only want to do that for my photos.

The alternatives are sips and GIMPShop. I passed on sips because I don’t know how sips scales images (i.e. which interpolation quality it uses), and because it makes you specify the dimensions backward for no obvious reason. GIMPShop is out of the question because (1) it is slow, and (2) it is an X11 application, and I do not like running X11 applications on my shiny Aqua desktop.

This left only one solution: Write my own. So that’s exactly what I did.

Introducing image. image is a utility that can both scale and convert images; this includes rasterization of vector art. Here are the examples from the webpage:

  • % image piechart.eps pdf
    Output: piechart.pdf
  • % image lightbulb.jpg 50%
    Output: lightbulb-50%.jpg
  • % image lightbulb.jpg 240
    Output: lightbulb-240.jpg (scaled proportionally)
  • % image lightbulb.jpg 320x240
    Output: lightbulb-320×240.jpg
  • % image lightbulb-orig.tiff 50% jpg lightbulb.jpg
    Output: lightbulb.jpg

Pretty useful, huh? I hope so.

Enjoy.

Rez for PNGs?

Friday, July 14th, 2006

There’s a little-known app called SNG (scriptable network graphics) that provides a way to write a PNG file as a text file. The source code comes with an example file:

Screenshot of an xterm window containing vim, with the test.sng file loaded into it.

Looks a lot like Rez to me. And they do perform somewhat similar functions (Rez encodes to a resource file; sng encodes to PNG). Thus my conclusion: it’s Rez for PNGs.

Technorati tags: .

How to make Photoshop open your EPS file

Sunday, May 14th, 2006

Sometimes, when I want to draw a graphic, I write it instead. I write it in PostScript, as an EPS file, and then convert to whatever destination format I want.

The problem with this plan is that I was never able to get Photoshop to import the EPS directly. I always got this error message:

Could not open “foo.eps” because the parser module cannot parse the file.

Finally, today, I went looking for the solution. I used strings to see what the EPS Parser plug-in looks for. I found it in under a minute.

So, at minimum, this is what your EPS file must contain:

%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 width height
%%EndComments

The %%EndComments line is the one that I was missing. Make sure yours isn’t missing it too.

In case you want to know more, these special comments (% is the comment character in PostScript) are defined by the Document Structuring Conventions. EPS is an application of DSC.

Technorati tags: , , , .

Shading in PostScript

Monday, May 8th, 2006

I’ve recently been beating my head against PostScript’s gradient (“shading”) system. Plenty of documentation and examples are available for when you’re working in the DeviceGray color space, but when you’re in DeviceRGB, it gets hard. Part of this is due to the fact that the PostScript Language Reference Manual’s description of shadings and the functions that power them is overly abstract and decorated with too much math for my language-oriented mind.

So, here I’ll try and explain it more clearly, particularly by explaining functions in the context of shadings, rather than separately.

A shading in PostScript is represented by a dictionary. Valid keys in the shading dictionary are:

ShadingType
The type of gradient: axial, radial, etc.
ColorSpace
The color space of colors returned by the function.
Coords
The start and end of the gradient on the page. Defined more specifically by the PLRM.
Function
A function dictionary, or an array of them.

Functions aren’t as you expect them to be. Rather than a callable object (a procedure), a function is a dictionary. (This, BTW, is the architectural reason for Quartz’s CGFunction class, although CGFunction actually uses a C function callback — what would be a procedure in PostScript.) There are three types of function dictionaries; I’ll only deal with type 0, a sampled function (a “sample” is a step in the gradient). A sampled function contains, or fetches from a file, the samples it will return, in a “data source”.

FunctionType
Guess.
Domain
Two numbers for every input, constraining that input to a range. If an input is below the first number, it will be replaced with the first number; if it is above the second number, it will be replaced by the second number. Generally, these two numbers are 0 and 1. In an axial shading function, there is only one input, so your domain should be two numbers (e.g. [0 1]).
Range
The other end from Domain. Works the same way, but it constrains your outputs rather than your inputs. For a shading function, there is one pair of numbers for each component. So, in DeviceGray, Range should be two numbers; in DeviceRGB, it should be six.
BitsPerSample
Named slightly misleadingly (the PLRM clarifies), this is actually the number of bits per component. So if you’re doing 24-bit RGB, this should be 8.
Size
An array containing the number of samples as an int.
DataSource
Either a file or a string from which to get the sample data.

You might expect that the samples should be given as an array. You would be wrong. Instead, PostScript wants pure binary data, either from a file or encoded as a string. So, for example, in RGB, every three characters (bytes) are one sample. I use a hexadecimal literal, or when I want to use an array, this procedure (which you may consider to be under the modified BSD license):

% array -> hexstr -> string
% Converts an array of integers to a string. [ 65 66 67 13 10 ] -> (ABC\r\n).
/hexstr {
4 dict begin
/elements exch def
/len elements length def
/str len string def

/i 0 def
{
i len ge { exit } if

str i
%The element of the array, as a hexadecimal string. If it exceeds 16#FF, this will fail with a rangecheck.
elements i get cvi
put

/i i 1 add def
} loop

str
end
} def

And yes, I know that that procedure has nothing to do with hexadecimal. I was probably tired when I wrote it.

Note: If you use hexstr to create a shading dynamically from an array of samples, be aware that when you divide the length of the array by 1 (gray) or 3 (RGB) or 4 (CMYK) to get the proper value for Size, you must use cvi on the quotient, because div returns a real and makepattern demands an int.

More Beads

Tuesday, May 2nd, 2006

My entry in Iron Coder, Beads, had a bug in it. I fixed this bug and called it 1.1. You can get it at the shiny new Beads webpage.

I also finished an article that I’d been working on, called How to draw Beads. It documents the creation of the pretty bead graphics, step-by-step.

Technorati tags: , .

Free plus and minus images

Wednesday, April 19th, 2006

I’ve created a pair of plus and minus images, similar to those used in the Accounts pane of System Preferences. They are free, released by me into the public domain. Enjoy.

Technorati tags: , .

A programming koan

Tuesday, March 28th, 2006

I considered how to rotate a raster image earlier today. Without doing any research into the subject, I wrote down my thoughts on it on a webpage, complete with images drawn in Photoshop. Feel free to answer the open-hanging question in the comments here.

Photoshop sucks

Monday, February 20th, 2006

Blunt enough title for you?

I’m mainly referring to CS2. I’ve been playing with it intermittently for the past 30 days, and I have built a list of complaints, all of which together stop me from pushing $180 across the counter for the upgrade from 5.5. I mainly arrived at that decision while making the screenshots for BZ Soundboard.


Selections can’t be moved under stupid circumstances.

Namely, when the current layer is hidden, you can’t move the selection. Huh?

Can’t drag-and-drop image files into open images.

Photoshop won’t accept the drop. You’d think it would at least check the file’s name and HFS type. Even better would be to run some kind of file(1)-like scan of the file.

The app insists upon old Mac OS behavior.

Many people like the old behaviour where clicking on any window of an app would bring them all forward. And there are several hacks that bring this to Mac OS X. But this should NOT be forced in an application. Photoshop does this, and it shouldn’t.

Can’t unlink a single layer from a set of linked layers.

Instead of you have to unlink all of them at the same time. Why? Photoshop 5.5 let you do this. Why can’t CS2?

No Unicode support in text layers.

Paste this into a text layer: ☃

Oddly, it’ll show up fine in the layers list; it just won’t render into the image correctly. You get “?” instead.

Excessive use of combo boxes.

Why do I have the ability to enter text here?

Screenshot of Photoshop's ‘Character’ (text settings) palette. Highlighted is a combo-box for entering the font.

Photoshop does provide completion, which is nice, but it should still be a plain pop-up menu. I can enter font names into that with the same effect. Even better, in the Mac version of Photoshop, it should use the Font Panel.

Non-standard UI elements.

Here’s one example:

Screenshot of Photoshop's gradient editor. Highlighted is the color pop-up for a key-point in the gradient. The arrow of the pop-up is excessively large.

Notice the hugemongous arrow. And this is a pop-up menu, not a pull-down menu. You could argue that this is a combo box, but at least on OS X, combo boxes have a text field attached. This should have the double-arrows like you see in the pop-up higher in the dialog. It also needs some kind of indicator (like ‘F’/’B’) when the foreground or background color is selected, as opposed to a static color.

I don’t mind so much this being custom, but it doesn’t look or work like a native UI element.

Preferences key combo is wrong.

Since Mac OS X, it should be ⌘,. Photoshop’s default is ⌘K. I don’t know how they thought of this selection, but it’s been around forever, and should now be retired.

Stupid save bugs.

  1. You can’t Save A Copy of a file, in PNG format, with alpha. But you can Save it As, in PNG format, with alpha. Huh?
  2. If you Save a file As in PNG format, then the window changes to reference the PNG file and the file appears saved (no “dirty” indicator in the close widget). All of this is correct. But if you then try to close the window, it’s suddenly dirty, and Photoshop complains that it “has not been saved completely because the current file format does not support all the features of your document”. Why didn’t you tell me this would happen when I saved the file?

Corrupted TIFF files.

Make sure that the “Save Transparency” checkbox in the TIFF options dialog is turned off (at least if you have an alpha channel). If it’s turned on, Cocoa can’t read your TIFF files.

No alpha support.

It is 2006, Adobe! EVERY graphics application outside of the Creative Suite supports alpha channels!

And amazingly enough, alpha support has actually regressed. Photoshop CS2 would not export the alpha of the two largest screenshots on the BZ Soundboard page (the resize screenshots). I don’t know if there is some hard-coded limit on the number of pixels that Photoshop CS2 will blend with an alpha channel, or if there’s some deeper bug, but CS2 pretended that the alpha did not exist when exporting to PNG or TIFF. I opened the PSD files in 5.5, and it exported the alpha flawlessly.


One thing I noticed while compiling this list: A number of these bugs seem to be in the class of “we’ve always done it this way”. Time for a refactor? (And I mean a real refactor, not just moving stuff around like they’ve done in every major version.)


An update (2008-03-23)

Since I originally published this post more than two years ago, several new image editors have emerged. Most people, I think, can replace Photoshop with one of these, and never miss the lost functionality.

All of these require Mac OS X 10.4 (because they all use Core Image). Prices in $ are US dollars.

  • Acorn ($50) is one of the two most popular—everybody who I know uses either Acorn or Pixelmator uses Acorn). I consider this the 21st-century update of MacPaint, and I mean that as a compliment. Start with this one—you will probably be satisfied.
  • Core Image Fun House (free) is the most basic editor you can get. It provides nothing more than filtering and cropping, and it doesn’t give you much help with the cropping (nor with scaling). However, it’s free, and you already have it: it’s one of the Mac OS X Developer Tools, as well as one of the sample-code applications.
  • Pixelmator ($59) is the most Photoshop-like, and the other most popular editor (it has the most downloads on MacUpdate and VersionTracker). If Acorn is too different from Photoshop for you, or you’re missing some of the more-advanced features, Pixelmator may be more your speed.
  • DrawIt is available in two versions: DrawIt Lite is free, whereas the full DrawIt is €29 ($42 as of this writing). It’s the most different of all the apps: The UI is essentially vector-based. The reason is that, in DrawIt, every operation is non-destructive. It accomplishes by making everything a layer. This works well, so you should definitely give DrawIt a try.
  • Iris is the only one I haven’t personally used. It’s currently a public beta; you can pre-order it for $39, or wait until version 1.0, which will be $79. The screenshot suggests that the UI is a cross between Pixelmator and Acorn.

On writing Image Units

Wednesday, January 11th, 2006

Apple’s Core Image documentation doesn’t clearly state how to make a CPU-executable Image Unit, as opposed to a non-executable (GPU-only) one.

The answer is simple: Don’t make a .cikernel file. You should start with one when you’re running the validation tool over your Image Unit, but if you want to make a CPU-executable Image Unit (and please do, so I can use it on my Cube), move the kernel code into your Obj-C code once it compiles, and then delete the .cikernel file.

(BTW, yes, I am testing MarsEdit. Hence the two posts today. ;)

UPDATE 2008-02-18: I’ve since found out that, in fact, the definition of “non-executable” is more strict than that. The Core Image Programming Guide‘s chapter on Executable vs. Non-executable Filters provides a more exact definition:

  • This type of filter is a pure kernel, meaning that it is fully contained in a .cikernel file. As such, it doesn’t have a filter class and is restricted in the types of processing it can provide.

  • Sampling instructions of the following form are the only types of sampling instructions that are valid for a nonexecutable filter:

    color = sample (someSrc, samplerCoord(someSrc));
  • CPU nonexecutable filters must be packaged as part of an image unit.

  • Core Image assumes that the ROI coincides with the domain of definition. This means that nonexecutable filters are not suited for such effects as blur or distortion.

Testing Image Units

Sunday, January 8th, 2006

Some of you may know that I’ve been studying Apple’s Core Image API — specifically, how to write an Image Unit. I just found this, buried in Apple’s website: Software Licensing & Trademark Agreements: Image Units.

What’s special about that? Read the page closely:

3. Download the Image Units Validation Tool (DMG). Use of this application is subject to the terms of the Validation Tool License (RTF) presented upon launch.

It’s actually a command-line tool, and the agreement is displayed when the image is mounted rather than when the tool is run, but nonetheless — it’s a tool that examines your Image Unit and attempts to compile its .cikernel file, and tells you if it finds anything wrong. Highly useful.

Coolest program name ever: pstops.

Monday, January 2nd, 2006

Even better, it accepts line noise as input. From the manpage:

To put two pages on one sheet (of A4 paper), the pagespec to use is:

2:0L@.7(21cm,0)+1L@.7(21cm,14.85cm)

To select all of the odd pages in reverse order, use:

2:-0

To re-arrange pages for printing 2-up booklets, use

4:-3L@.7(21cm,0)+0L@.7(21cm,14.85cm)

for the front sides, and

4:1L@.7(21cm,0)+-2L@.7(21cm,14.85cm)

for the reverse sides.

pstops is part of psutils.