
% language=us runpath=texruns:manuals/colors

\startcomponent colors-basics

\environment colors-environment

\startchapter[title=Graphics][color=darkblue]

\startsection[title=Conversion]

There is not that much to tell about graphics and color simply because from the
perspective of \TEX\ a graphic is just a blob with dimensions that travels
through the system and in the backend gets included as|-|is. This means that when
there is a problem with an image you have to go back to the source of that image
and fix it there.

It can happen that you need to manipulate an image and in a fully automated
workflow that can be cumbersome. For that reason \CONTEXT\ has a mechanism for
converting graphics.

\startluacode
    context.starttabulate { "|BT|T|" }
    context.NC() context.bold("original")
    context.NC() context.bold("target")
    context.NC() context.NR()
    for k, v in table.sortedhash(figures.converters) do
        context.NC() context(k)
        context.NC() context("%{\\quad }t",table.sortedkeys(v))
        context.NC() context.NR()
    end
    context.stoptabulate()
\stopluacode

Some of these converters are applied automatically. For instance if you include
an \type {eps} image, \CONTEXT\ will try to convert it into a \PDF\ file and only
do that once (unless the image changed). Of course it needs a conversion program,
but as long as you have GhostScript, GraphicMagick and InkScape on your machine
it should work out well.

You can also define your own converters (we use a verbose variant):

\starttyping
\startluacode
    -- of course we need options

    local resolutions = {
        [interfaces.variables.low]    = "150x150",
        [interfaces.variables.medium] = "300x300",
        [interfaces.variables.high]   = "600x600",
    }

    figures.programs.lowrespng = {
        command  = "gm",
        argument = [[convert -resample %resolution% "%oldname%" "%newname%"]],
    }

    figures.converters["png"]["lowres.png"] = function(oldname,newname,resolution)
        runprogram (
            figures.programs.lowrespng.command,
            figures.programs.lowrespng.argument,
            {
                oldname    = oldname,
                newname    = newname,
                resolution = resolutions[resolution] or "150x150"
            }
        )
    end
\stopluacode
\stoptyping

Usage is as follows:

\starttyping
\externalfigure[mill.png][conversion=lowres.png]
\stoptyping

\stopsection

\startsection[title=Recoloring]

You can think of more complex conversions, like converting a gray scale image to
a colored one.

\startbuffer
\startluacode
    figures.programs.recolor = {
        command  = "gm",
        argument = [[convert -recolor "%color%" "%oldname%" "%newname%"]],
    }

    figures.converters["png"]["recolor.png"] =
        function(oldname,newname,resolution,arguments)
            figures.programs.run (
                figures.programs.recolor.command,
                figures.programs.recolor.argument,
                {
                    oldname = oldname,
                    newname = newname,
                    color   = arguments or ".5 0 0 .7 0 0 .9 0 0",
                }
            )
        end
\stopluacode
\stopbuffer

\typebuffer % built in so no \getbuffer

\startbuffer
\useexternalfigure[mill][mill.png][conversion=recolor.png]
\startcombination[3*2]
  {\externalfigure[mill][arguments=.5 0 0 .7 0 0 .9 0 0]}{\figurefilearguments}
  {\externalfigure[mill][arguments=.7 0 0 .9 0 0 .5 0 0]}{\figurefilearguments}
  {\externalfigure[mill][arguments=.9 0 0 .5 0 0 .7 0 0]}{\figurefilearguments}
  {\externalfigure[mill][arguments=.5 0 0 .9 0 0 .7 0 0]}{\figurefilearguments}
  {\externalfigure[mill][arguments=.7 0 0 .5 0 0 .9 0 0]}{\figurefilearguments}
  {\externalfigure[mill][arguments=.9 0 0 .7 0 0 .5 0 0]}{\figurefilearguments}
\stopcombination
\stopbuffer

This can be applied as follows. The \type {resolution} and \type {color}
parameters get passed to the converter. This method is actually built
in already.

\typebuffer

The results are shown in \in {figure} [fig:recolor]. In this case we pass the
colors to be use in a kind of matrix notation that GraphicMagick needs.

\startplacefigure[reference=fig:recolor,title={Recoloring bitmap images.}]
    \getbuffer
\stopplacefigure

Recoloring an image this way is actually not the best solution because
there is an internal mechanism that does the same. This trick (currently)
only works with spot colors.

\startbuffer
\definecolor [my-blue]   [c=1,m=.38,y=0,k=.64] % pms 2965 uncoated m
\definecolor [my-yellow] [c=0,m=.28,y=1,k=.06] % pms  124 uncoated m

\definespotcolor [my-blue-100]   [my-blue]   [p=1]
\definespotcolor [my-yellow-100] [my-yellow] [p=1]
\definespotcolor [my-blue-50]    [my-blue]   [p=.5]
\definespotcolor [my-yellow-50]  [my-yellow] [p=.5]

\definemultitonecolor [my-mix] [my-blue=.12,my-yellow=.28] [c=.1,m=.1,y=.3,k=.1]
\stopbuffer

\typebuffer \getbuffer

These colors show up as:

\starttabulate[|T||]
\NC my-blue       \NC \blackrule[color=my-blue,      width=.6\textwidth,height=5mm] \NC \NR
\NC my-blue-50    \NC \blackrule[color=my-blue-50,   width=.6\textwidth,height=5mm] \NC \NR
\NC my-blue-100   \NC \blackrule[color=my-blue-100,  width=.6\textwidth,height=5mm] \NC \NR
\NC my-yellow     \NC \blackrule[color=my-yellow,    width=.6\textwidth,height=5mm] \NC \NR
\NC my-yellow-50  \NC \blackrule[color=my-yellow-50, width=.6\textwidth,height=5mm] \NC \NR
\NC my-yellow-100 \NC \blackrule[color=my-yellow-100,width=.6\textwidth,height=5mm] \NC \NR
\NC my-mix        \NC \blackrule[color=my-mix,       width=.6\textwidth,height=5mm] \NC \NR
\stoptabulate

\useexternalfigure[demofig][mill.png][object=no,width=.2\textwidth]

\startbuffer
\startcombination[4*1]
  {\externalfigure[demofig]}                      {no color}
  {\externalfigure[demofig][color=my-mix]}        {indexed duotone}
  {\externalfigure[demofig][color=my-blue-100]}   {spot color}
  {\externalfigure[demofig][color=my-yellow-100]} {spot color}
\stopcombination
\stopbuffer

\typebuffer

This time we don't call an external program but we add an indexed color map to the
image. The result can be seen in \in {figure} [fig:reindexing].

\startplacefigure[reference=fig:reindexing,title={Reindexing bitmap images.}]
    \getbuffer
\stopplacefigure

\stopsection

\startsection[title=Profiles]

Color profiles are used to control the printing process. There is some (limited)
support for that built in. An example of a setup that we use in a project is the
following:

\starttyping
\setupexternalfigures
  [order={pdf,eps,png,jpg},
   conversion=cmyk.pdf,
   method=auto]
\stoptyping

So, we prefer \PDF\ vector images, if needed converted from \EPS. When there is
no vector image we check for a \PNG\ and as last resort for a \JPG. The
\type{method} is set to \type {auto} which means that we check if the image file
indeed is reflected in the suffix. This is needed because in a workflow with tens
of thousands of images there can be bad ones.

The \type {conversion} parameter will make \CONTEXT\ check if there is a \type
{cmyk.pdf} converter defined and when that is the case, it's applied. That
specific converter will add a color profile to the image. You can set the
profiles with:

\starttyping
\enabledirectives[graphics.conversion.rgbprofile=srgb.icc]
\enabledirectives[graphics.conversion.cmykprofile=isocoated_v2_eci.icc]
\stoptyping

and these happens to be the defaults. You have to make sure that the files are
present, preferable in \type{t:/texmf/colors/icc/context}. If you add profiles
you need to make sure that \type {colorprofiles.lua} is updated accordingly.

Just for completeness, in our situation, we also have set:

\starttyping
\enabledirectives[graphics.conversion.eps.cleanup.ai]
\enabledirectives[graphics.extracheck]
\stoptyping

The first directive will make sure that confusing sections (for instance meant to
the drawing program) are stripped from an \EPS\ file, and the second one forces
some extra checking on the image (just to make sure that the engine doesn't exit
on bad images).

\stopsection

\startsection[title=Masks]

A \PNG\ bitmap image can have a mask that permits a background to shine through
but you can also apply that effect to a regular \PNG\ image. The next examples
use two (pre)defined masks:

\startbuffer
\registerfiguremask [mymask1] {
    {
        {   0, 100, 0x00 },
        { 101, 200, 0x7F },
        { 201, 255, 0xFF },
    }
}

\registerfiguremask [mymask2] {
    210
}
\stopbuffer

% demomask = {
%     {   0,  63,   0 },
%     {  64, 127, 127 },
%     { 128, 195, 195 },
%     { 196, 255, 255 },
% }

% \registerfiguremask [mymask1] {
%     function()
%         return {
%             {   0, 100, 0x00 },
%             { 101, 200, 0x7F },
%             { 201, 255, 0xFF },
%         }
%     end
% }

\typebuffer

The first mask maps the (grayscale) image values onto a mask value by range while
the second just passes a criterium. The argument to \type {\registerfiguremask}
is a number, table or string in \LUA\ speak

\getbuffer

For the examples we define two colors:

\startbuffer
\definecolor[mymaskcolor1][darkred]
\definecolor[mymaskcolor2][.75(darkblue,white)]
\stopbuffer

\typebuffer

\getbuffer

\startbuffer[zero]
\externalfigure
  [2019-sneaky-bw-lowres.png]
  [width=\measure{combination}]
\stopbuffer

\startbuffer[one]
\externalfigure
  [2019-sneaky-bw-lowres.png]
  [background=color,
   backgroundcolor=mymaskcolor1,
   mask=mymask1,
   width=\measure{combination}]
\stopbuffer

\startbuffer[two]
\externalfigure
  [2019-sneaky-bw-lowres.png]
  [background=color,
   backgroundcolor=mymaskcolor2,
   mask=mymask2,
   width=\measure{combination}]
\stopbuffer

\startbuffer[three]
\externalfigure
  [2019-sneaky-bw-lowres.png]
  [background=color,
   backgroundcolor=mymaskcolor2,
   mask=demomask,
   width=\measure{combination}]
\stopbuffer

We now include two images:

\typebuffer[one]

and

\typebuffer[two]

The result is shown in \in {figure} [fig:masks:one] and shows that one has
probably experiment a bit with the values. The first shows the original and the
last the predefined \quote {demomask} that uses a table with four ranges.

\startplacefigure[title=Masks,reference=fig:masks:one]
    \startcombination[4*1]
        {\inlinebuffer[zero]} {original}
        {\inlinebuffer[one]}  {table}
        {\inlinebuffer[two]}  {number}
        {\inlinebuffer[three]}{demomask}
    \stopcombination
\stopplacefigure

We can also use an image as mask. Take these three definitions:

\startbuffer[one]
\externalfigure
  [mill.png]
  [height=5cm]
\stopbuffer

\startbuffer[two]
\externalfigure
  [2019-sneaky-bw-lowres.png]
  [height=5cm]
\stopbuffer

\startbuffer[three]
\externalfigure
  [mill.png]
  [mask=2019-sneaky-bw-lowres.png,height=5cm]
\stopbuffer

\typebuffer[one,two,three]

In \in {figure} [fig:masks:two] the third example has both images stacked.

\startplacefigure[title=Masks,reference=fig:masks:two]
    \startcombination[3*1]
        {\inlinebuffer[one]}  {}
        {\inlinebuffer[two]}  {}
        {\inlinebuffer[three]}{}
    \stopcombination
\stopplacefigure

Next we show how to make an image lighter or darker. For this we use the \type
{range} key. It can be assigned a number (fraction) or a name that serves as
lookup in a registry. As with masks these are \LUA\ definitions. AN example of a
range definition is:

\startbuffer
\registerfigurerange [myrange] {
    { 0.2, 1.2 }
}
\stopbuffer

For an \RGB\ you can provide two or six values. In \in {figure} [fig:ranges:gray]
we show a lighter, normal, darker and limited example. In \in {figure}
[fig:ranges:color] we apply them to a \JPEG\ image.

\typebuffer \getbuffer

\startplacefigure[title=Ranges,reference=fig:ranges:gray]
    \startcombination[4*1]
        {\externalfigure[mill.png][width=\measure{combination},range=0.80]}    {\type{range=0.80}}
        {\externalfigure[mill.png][width=\measure{combination}]}               {default}
        {\externalfigure[mill.png][width=\measure{combination},range=1.20]}    {\type{range=1.20}}
        {\externalfigure[mill.png][width=\measure{combination},range=myrange]} {\type{range=myrange}}
    \stopcombination
\stopplacefigure

\startplacefigure[title=Ranges,reference=fig:ranges:color]
    \startcombination[4*1]
        {\externalfigure[hacker.jpg][width=\measure{combination},range=0.80]}    {\type{range=0.80}}
        {\externalfigure[hacker.jpg][width=\measure{combination}]}               {default}
        {\externalfigure[hacker.jpg][width=\measure{combination},range=1.20]}    {\type{range=1.20}}
        {\externalfigure[hacker.jpg][width=\measure{combination},range=myrange]} {\type{range=myrange}}
    \stopcombination
\stopplacefigure

\stopsection

\stopchapter

\stopcomponent
