152 lines
5.7 KiB
Plaintext
152 lines
5.7 KiB
Plaintext
|
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.
|