I've been lately working hard in two black thingies. Namely, black point compensation and black preserving intents. Black preserving intents are worth of a post, and still there are some subtle bugs, so let's go fot the black point compensation first. BPC has been implemented in lcms for years. It works. So if ain't broken don't fix it. Well, not really. It seemed to me lcms2 would be a good chance to implement Adobe's BPC... oh, that's a nice story.
BPC is a sort of "poor man's" gamut mapping. It basically adjust contrast of images in a way that darkest tone of source device gets mapped to darkest tone of destination device. If you have an image that is adjusted to be displayed on a monitor, and want to print it on a large format printer, you should realize printer can render black significantly darker that the screen. So BPC can do the adjustment for you. It only makes sense on relative colorimetric intent. Perceptual and saturation does have an implicit BPC .
Works like magic but it is quite simple: just a plain linear scaling in XYZ space.
What turns out the real problem: It is easy to implement BPC as long as you can figure out what the black point is. The black point tag doesn't help. There is such quantity of bogus profiles that ICC has deprecated the tag in a recent addendum. It is up to the poor CMM to figure out what the black point is.
And it is a hard task tough. Ok, you may argue, just use the relative colorimetric in the input direction, feed RGB=(0, 0, 0) and ... wait, what about CMYK? Ok, CMY=(255, 255, 255,255)... Hum.. CMYK devices are ink limited, that is, the maximum amout of ink that a given paper can accept is limited (else ink will spread all over) so this doesn't work either. What lcms do, is to use perceptual intent to convert Lab of zero to CMYK and then this CMYK to Lab using rel. colorimetric. This works fine on all but some broken profiles. Well, Adobe's paper target those profiles.
The funny part is the complexity of Adobe's algorith. The perceptual trick is used as a seed on certain profiles, then black axis of a round-trip on L* is examined. If the difference is greater than 4, then a least-squares fitting of the curve to a quadratic curve should be done. The black point is the vertex.
In fact it is more complex as I'm ommiting constants depending on the intent and other gory details. Such complex. After the 6th time you read the paper, it begins to make sense.
But unfortunately it doesn't work to me. And unfortunately, it doesn't work for the ICC reference implementation CMM. We both get the same bad guess of L* = 625 for a given profile. And guess what? I've tried Photoshop CS4, and the reported black point does exactly match with my humble, perceptual to rel.col. algorith, so I will keep this one for a while.