                         LCMS 2.9.MT
                         ===========

Why does this fork exist?
~~~~~~~~~~~~~~~~~~~~~~~~~

We, Artifex Software, use LCMS 2 in both our  Ghostscript and MuPDF
projects. It's a great library that performs well, and does almost
exactly what we want.

Almost.

In the course of pulling LCMS 2 into MuPDF, we hit some problems
with the library (described in more detail below). We've changed
the code to fix these problems, and therefore released this
version of the library.


Why don't you just pass the changes back to mainline LCMS?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sadly, the changes we've made require changes to some of the API
to LCMS. We consider these changes to be pretty minor, and to
improve the overall API, but they are unavoidable.

You can't just drop this version of the library into an existing
project that uses vanilla LCMS and expect it to work. You will
need to make some changes in your code. Small ones, but changes
nonetheless.

We have offered these changes upstream, with a view to getting
them adopted into mainstream LCMS - perhaps as LCMS 3. Marti
Maria, the original author of LCMS is considering them at the
moment, but no decision has been made.

Marti has plans of his own for LCMS, so until such time as we
figure out a mutually satisfactory way of working, we're doing
this separate release.


So what problem was this intended to solve?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Put simply, we ran into problems with using LCMS in a multi-threaded
environment.

A few years ago, Marti kindly made some changes within LittleCMS
to enable us to safely use LCMS with Ghostscript when run with
multiple threads.

Specifically, Ghostscript needed to use different allocators from
each thread. In order to account for this, Marti added the idea
of the 'cmsContext'. These would carry a 'void *UserData' value
that could be retrieved in the allocators. By using a different
cmsContext in each thread, we could therefore pass thread specific
information through LCMS and safely have it reach the allocators.

In order to make this change without breaking the existing API
Marti added new functions, suffixed with THR, that took these
cmsContext's.

So where in old lcms we had:

 CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin);

we now also had:

 CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin);

Internally within LCMS, the cmsContext values were often stored
within things like profiles and links. For Ghostscript this was
absolutely fine, because we didn't share profiles or links between
different threads.

For MuPDF, however, this was a significant restriction. MuPDF is
designed as a C level library from which people can build applications.
Data objects are reference counted, and are designed to be able to
be passed around the system as required. It would be almost impossible
to enforce the idea that profiles and links can only be used within
the original thread (cmsContext) within which they were created.
Also new versions of Ghostscript will also share profiles and links
among threads to enhance performance with multi-threaded rendering.

Lastly, Ghostscript made use of cmsChangeBuffersFormat to switch the
input or output data format (planar, bytes per component, etc.) to
allow a link profile to be re-used without the computation needed to
create a new link profile. Since the input and output format are
stored within the link profile, one thread changing the format while
another thread was using it for color transform would cause problems.

So what changes have been made?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The changes are very simple and systematic.

1) Every API function (or at least those that might allocate) now takes
a cmsContext pointer.

2) cmsContexts are now passed explicitly throughout the system. They
are never stored in any structures.

3) Accordingly, we have removed the 'THR' API functions (as they no
longer serve any purpose).

4) We have removed the cmsChangeBuffersFormat function (use of which
could lead to a link profile being changed by one thread while it
was in use by another) and replaced it with a thread safe alternative,
cmsCloneTransformChangingFormats. This creates a new transform that
shares the underlying tables of the original transform, but with
new buffer format handlers. Since the underlying tables for the link
are shared, the cost of cloning the profile is very low.

In addition, we've made 1 other change that breaks the ABI, but not
the API:

5) The organisation of the flags word used to describe the format of
input/output pixels has been altered to accommodate more 'extra'
channels (now a maximum of 63 rather than 7).

Finally:

6) We have renamed lcms2.h to be lcms2mt.h.

7) We have tweaked the LCMS_VERSION value (and some of the code
that reads it), to ensure that people don't link binary plugins
expecting other versions against us without an error being given.


So what's the plan from here?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Well, at the very least we hope to keep pulling fixes from mainline
LCMS into this version. We (Artifex Software) need to keep it up to
date and secure for our use of the library.

In the fullness of time we'd love to see these fixes folded back
into a new LCMS release, but this will have to wait for this to be
a convenient time for Marti.


So where should we report bugs?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Report bugs to us, by all means, but please also report them to Marti.
He's likely to be in a far better position to evaluate potential
problems and fixes than we are - this is his library after all.
Ideally every problem that gets fixed in mainline LCMS should get
pulled into our version.

Indeed, to keep this simple, we don't really want to diverge our
version from mainline more than we have to.
