Photoshop DIFF Action

Followup to earlier post. I found some errors eventually, and have I think improved it some.

I have a bit of a fetish for “lossless editing”—working on a photo in such a way that I don’t change the initial set of bits that I imported. I think as you get more experienced it becomes less important; being sure you’ve got something the way you want it means you don’t care whether it’s easy to change later. But, for me, I edit incrementally, taking a while to see the flaws in older edits (especially when I’m editing a bunch of photos that will be displayed together), so it’s very useful to be able to very easily change my mind about things I’ve already done.

So, I use adjustment layers a lot, and adjustment layers with layer masks (which, I say again, are dodging and burning died and gone to heaven!), and then do a lot of pixel fixing writing onto a separate layer.

But there are a few tools, or a few situations maybe, when that’s not the best option. Keeping an entire clean copy of the base layer meets my criteria, but it kind of doubles the file size (layers that are mostly transparent compress pretty well, so my multi-layer files are mostly not that much larger than the base).

So, here’s what I do:

  1. Duplicate the base layer (shortcut: CTRL-j). My process expects the mode of this layer to be “normal”.
  2. Select this new layer
  3. Do the editing that has to be done in the context of all the pixels
  4. Usually, I keep this for a while, until I’ve printed or put the picture on the web or whatever the plan was
  5. Select your edit layer, and run my magic diff script. This deletes every pixel in the edit layer which is the same as is rendered by the stack of layers under it.

So, how does this version of the diff script work? I’m glad you asked!

Listing of diff action
The DIFF Action
  1. Set mode of edit layer to “difference”. This shows the differences between the current layer and the stack under it.
  2. Select all
  3. Copy Merged. This copies the full detailed differences.
  4. Select none
  5. Set mode of edit back to “normal” on this layer
  6. Create new pixel layer
  7. Paste (puts the differences here)
  8. Threshold, level=1. This reduces the difference map to black-and-white, with every unchanged pixel black and every changed pixel white.
  9. Select all
  10. Copy
  11. Delete layer (same one we created above, that was scratch workspace)
  12. (We are now on the original edit layer again)
  13. Set quick mask mode
  14. Paste
  15. Exit quick mask mode. The B&W change mask we made is now a selection.
  16. Add layer mask. The current selection will be put in as that mask. So now we have the edit layer, with a layer mask selecting only the changed pixels on this layer.
  17. Apply layer mask. This deletes all the pixels blocked by the layer mask, and then deletes the layer mask itself. Thus making this layer take a lot fewer bits to store!

Why Unix Tools Are Good

diff -r -w -B -x .svn -x .git -I '$Id' -I '$Head' SvnWD GitWD

I’m verifying that the conversion from a Subversion source control repository to a Git repository hasn’t lost anything crucial. Since we’ve got multiple live branches, and at least the more recent of the versions tagged for production deployment are important, I need to do some fairly heavy testing that the contents of the repository match.  (It’s nice to have the full history, and I think we do, but it’s not actually important.)

That one command looks at every file in two directory trees and compares the corresponding files in the two trees.

Except it skips directories named .svn and directories named .git (which will occur only on one side or the other), and ignores whitespace differences, and ignores the lines that Subversion is substituting keywords into, because Git doesn’t do that.

What’s good about this isn’t so much that the command-line interface is easy. But it’s easier to find what those switches do than what the entries in most dialog boxes do (there’s a much better culture of writing actual documentation in Unix and in the free software world). No, what’s good is that all those capabilities are already there, just waiting for me.

(Before applying the above, I have to use the appropriate “switch” command to have both working directories representing the branch or tag I want to verify. I could do that with command-lines, too. Then I could script the whole thing, with a list of branches and tags to compare. In fact, I could have it fetch the list of branches and tags live from the Subversion repository, so it was checking that everything really was identical. Maybe I should have gone that far; I did have to manually repeat the tests a second time when we had to change the final destination repository.)

There are in fact a few differences; mostly empty directories in Subversion that haven’t been copied to Git (6 of them). The more interesting question is, why is login.php in Subversion and not Git? Given that the copy in Subversion is clearly a test file, and doesn’t even contain actual php code, there’s not a problem here, but why wasn’t it copied over?