% +--------------------------------------------------+ % | Typeset colorspace.tex to get the documentation. | % +--------------------------------------------------+ % %% Copyright (C) 2015 Javier Bezos %% All Rights Reserved %% http://www.tex-tipografia.com %% %% This work may be distributed and/or modified under the conditions %% of the LaTeX Project Public License, either version 1.3 of this %% license or (at your option) any later version. The latest version %% of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2003/12/01 or later. %% %% This work has the LPPL maintenance status "maintained". %% %% This Current Maintainer of this work is Javier Bezos. %% %% This work consists of the files colorspace.tex and colorspace.sty. \ProvidesPackage{colorspace} [2015/06/01 v1.1.0 PDF color spaces (spot colors...) for pdfTeX] \edef\spc@savedcatcodes{% \catcode`\noexpand\/=\the\catcode`\/ \catcode`\noexpand\&=\the\catcode`\& % & is 'other' here! \catcode`\noexpand\<=\the\catcode`\< \catcode`\noexpand\>=\the\catcode`\>} \catcode`\/=12 \catcode`\>=12 \catcode`\<=12 \catcode`\&=11 % we use it in macro names \def\spc@unknown#1#2{% \@ifundefined{#1}% {\PackageError{colorspace}{Unknown #2}% {You haven't defined it or perhaps you misspelled it.}}% {}} \@ifundefined{XC@sdef}{\RequirePackage{xcolor}}{} \long\def\spc@afterfi#1\fi{\fi#1} % Trim spaces in strings and normalize to single spaces \def\spc@spaces#1 #2{% #1\ifx\@empty#2\else\spc@afterfi\spc@spaces@i{#1}#2\fi} \def\spc@spaces@i#1{% \ifx\\#1\\\else\space\fi\spc@spaces} \def\spc@dospaces#1{% \edef#1{#1\space}% \edef#1{\expandafter\spc@spaces#1\@empty}} % Define a pseudo-model for spot colors. We need define the following % 3 macros: \XC@sdef\XC@mod@&spot{&spot} \def\color@&spot#1#2{% \c@lor@arg{#2}% \edef#1{\spc@ir\space cs \spc@ir\space CS #2 sc #2 SC}} \def\XC@clr@&spot@white{0} % A somewhat dirty hack for converting cmyk to spot. The internal % format is {}{/&Color cs /&Color CS n sc n SC}{spot}{n}, where n=1 is % a tint of 100%. The original CMYK values are stored in % \spc@ascmyk@. \def\spc@cmyktospot#1#2{% \begingroup \def\spc@tempc##1 ##2 ##3 ##4 k##5\@@{##1 ##2 ##3 ##4}% \def\xcolor@##1##2##3##4{% \expandafter\protected@xdef\csname\string\color@#1\endcsname{% \noexpand\xcolor@{##1}{/ cs / CS 1 sc 1 SC}{&spot}{1}}% \xdef\spc@tempa{\spc@tempc##2\@@}% \expandafter\xdef\csname spc@ascmyk@#1\endcsname{##4}}% \csname\string\color@#1\endcsname \endgroup} % The internal PDF name (which is like the public one with a & % prepended) is available in the first argument of \xcolor@. The % following macros extract it. \def\spc@getir#1{% \begingroup \def\xcolor@##1##2##3##4{\spc@getref##2\@@}% \@nameuse{#1}% \endgroup} \def\spc@getref#1 #2\@@{\gdef\spc@ir{#1}} % We need to redefine an xcolor macro for the tint operator ! to be % recognized. It's done in a more modular way than xcolor: \def\spc@infl@cmyk{\let\spc@inflcommas\@empty}% 4 values=4-4 commas \def\spc@infl@gray{\def\spc@inflcommas{,,,}}% 1 value=4-1 commas \def\spc@infl@&spot{% \spc@getir{\string\color@\@@nam}% \def\spc@inflcommas{,,,}}% \def\XC@inflate#1#2#3#4{% \def\spc@inflcommas{,}% Assume 3 values=4-3 commas \@nameuse{spc@infl@\@@mod}% \edef#4{#2,\spc@inflcommas#3\spc@inflcommas}} % The following macro stores all spot colors, with the LaTeX name. It % also stores other color spaces. Internally is an \spc@elt list. \let\spc@csall\@empty % Now the main command for defining spot colors. \spc@ir@ % contains {/&Spot X 0 R} \newcommand\definespotcolor[2]{\protected@edef\spc@tempa{{#1}{#2}}\spc@defsc} \newcommand\spc@defsc[2][cmyk]{\expandafter\spc@defsc@i\spc@tempa{#1}{#2}} \def\spc@defsc@i#1#2#3#4{% \def\spc@tempc##1 ##2{% Converts spaces to #20 ##1% \ifx\@empty##2\else \ifx\\##1\\\string####20\else\string####20\fi \spc@afterfi\spc@tempc##2% \fi}% \edef\spc@tempb{\spc@tempc#2 \@empty}% Apply to convert \def\spc@elt##1##2{% \@expandtwoargs\in@{/&\spc@tempb\space}{\@nameuse{spc@ir@##2}}% \ifin@ \PackageError{colorspace}{Duplicated spot name `#2'}% {This spot name was taken by `##2'.}% \fi} \spc@csall \definecolor{#1}{cmyk:#3}{#4}% internally always cmyk \expandafter\spc@cmyktospot{#1}\spc@tempb % Convert from cmyk to spot \immediate\pdfobj{[ /Separation /\spc@tempb\space /DeviceCMYK << /FunctionType 2 /Domain [0 1] /C0 [0 0 0 0] /C1 [\spc@tempa] /N 1 >> ]}% pdf separation \expandafter\xdef\csname spc@ir@#1\endcsname{% /&\spc@tempb\space\the\pdflastobj\space 0 R}% save ref to obj \let\spc@elt\relax \xdef\spc@csall{\spc@csall\spc@elt2{#1}}} \AtBeginDocument{% \ifx\spc@csall\@empty\else % ie, if spot/iccbased colors \resetpagecolorspace \fi} % Page color spaces. The arrays mapping the spot colors to the obj % refs are saved into the pdf as objects, and then we also save its % reference for later recovery. Well, \pdfpageresources is not % exactly "programmer"-friendy. We add the /ColorSpace, but if we % switch from a previoss one, the latter must be removed, too. This % is what \spc@remcs does. We also make sure a color space is % defined once: first we rebuild the argument without spaces and % then form the macro name using the order in csall, which is % fixed. The macro name is built with the PDF names. \let\spc@currcs\@empty \let\spc@cs@\@empty \newcommand\pagecolorspace[1]{% \protected@edef\spc@tempa{{#1}}% \expandafter\spc@pagecs\spc@tempa} \def\spc@pagecs#1{% \ifx\spc@currcs\@empty\else \edef\tempa{% \noexpand\spc@remcs\the\pdfpageresources \noexpand\spc@remcs{\spc@currcs}}% \tempa \fi \let\spc@tempd\@empty % list with known spaces \@for\spc@tempa:=#1\do{% \ifx\spc@tempa\@empty\else \spc@dospaces\spc@tempa \spc@unknown{spc@ir@\spc@tempa}{color (space) `\spc@tempa'}% \edef\spc@tempd{,\spc@tempd,\spc@tempa,}% \fi}% \let\spc@tempb\@empty % elements in /ColorSpace \let\spc@tempc\@empty % name for macro (\..&..&) with pdf ref \def\spc@elt##1##2{% \@expandtwoargs\in@{,##2,}{\spc@tempd}% \ifin@ \protected@edef\spc@tempb{% \spc@tempb\@nameuse{spc@ir@##2}\space}% \protected@edef\spc@tempc{% \spc@tempc\@nameuse{spc@ir@##2}&}% \fi}% \spc@csall % Uses \spc@elt \@ifundefined{spc@cs@\spc@tempc}% {\immediate\pdfobj{<< \spc@tempb>>}% \expandafter\xdef\csname spc@cs@\spc@tempc\endcsname{\the\pdflastobj}}% {}% \expandafter\let\expandafter\spc@currcs\csname spc@cs@\spc@tempc\endcsname \ifx\spc@currcs\@empty\else \edef\spc@tempa{\pdfpageresources{% \the\pdfpageresources\space/ColorSpace \@nameuse{spc@cs@\spc@tempc} 0 R}}% \spc@tempa \fi} \newcommand\resetpagecolorspace{% \def\spc@elt##1##2{\ifnum##1>1 ##2,\fi}% \edef\spc@tempa{{\spc@csall}}% \expandafter\pagecolorspace\spc@tempa} \def\spc@remcs#1\spc@remcs#2{% \def\spc@tempc##1 /ColorSpace #2 ##2 R##3\spc@tempc{% \pdfpageresources{##1##3}}% \spc@tempc#1\spc@tempc} % Support for pgf (I hope--) \def\pgfsys@color@&spot@stroke#1{% \spc@getir{\string\color@pgfstrokecolor}% \pgfsysprotocol@literal{\spc@ir\space CS}% \pgfsysprotocol@literal{#1 SC}} \def\pgfsys@color@&spot@fill#1{% \spc@getir{\string\color@pgffillcolor}% \pgfsysprotocol@literal{\spc@ir\space cs}% \pgfsysprotocol@literal{#1 sc}} \def\pgfsys@color@&spot#1{% \pgfsys@color@&spot@stroke{#1}% \pgfsys@color@&spot@fill{#1}} % ==== Mixed colors ==== % xspace assumes color models have 1, 3 or 4 components. We need % modify a couple of macros, but we'll do it only if a 2-component % space is defined: \def\spc@twocomps{% \let\spc@twocomps\relax \gdef\XC@vec##1,##2,##3,##4,##5,##6,##7,##8,##9{% \def\@@tmp{}% \XC@vec@{##1}{##5}% \ifx,##2,\else\XC@vec@{##2}{##6}% \ifx,##3,\else\XC@vec@{##3}{##7}% \ifx,##4,\else\XC@vec@{##4}{##8}% \fi\fi\fi \aftergroupdef##9\@@tmp}% \gdef\XC@calc@##1,##2,##3,##4,##5:##6{% \XC@let@Nc\@@cmd{XC@calc##6}% \@@cmd{##1}\@@tmp \ifx,##2,% \else\@@cmd{##2}\@tempa \ifx,##3,\edef\@@tmp{\@@tmp,\@tempa}% \else\@@cmd{##3}\@tempb \ifx,##4,\edef\@@tmp{\@@tmp,\@tempa,\@tempb}% \else\@@cmd{##4}\@tempc\edef\@@tmp{\@@tmp,\@tempa,\@tempb,\@tempc}% \fi\fi\fi}} % The following macros define models with 1 to 4 components. It's % written with the "copypaste" pattern, so it should be % improved. Here, the limitations of xcolor become aparent, because % 5 components would require "-1" commas. \def\spc@mix@i#1#2{% \expandafter\XC@sdef\csname XC@mod@#1\endcsname{#1}% \@namedef{color@#1}##1##2{\@nameuse{c@lor@@#1}##2\@@##1}% \@namedef{c@lor@@#1}##1\@@##2{% \c@lor@arg{##1}% \edef##2{#2 cs #2 CS ##1 scn ##1 SCN}}% \@namedef{XC@clr@#1@white}{0}% \@namedef{spc@infl@#1}{\def\spc@inflcommas{,,,}}} % 1 value = 4 - 1 commas \def\spc@mix@ii#1#2{% \expandafter\XC@sdef\csname XC@mod@#1\endcsname{#1}% \@namedef{color@#1}##1##2{\@nameuse{c@lor@@#1}##2\@@##1}% \@namedef{c@lor@@#1}##1,##2\@@##3{% \c@lor@arg{##1}% \c@lor@arg{##2}% \edef##3{#2 cs #2 CS ##1 ##2 scn ##1 ##2 SCN}}% \@namedef{XC@clr@#1@white}{0,0}% \@namedef{spc@infl@#1}{\def\spc@inflcommas{,,}}} % 2 values = 4 - 2 commas \def\spc@mix@iii#1#2{% \expandafter\XC@sdef\csname XC@mod@#1\endcsname{#1}% \@namedef{color@#1}##1##2{\@nameuse{c@lor@@#1}##2\@@##1}% \@namedef{c@lor@@#1}##1,##2,##3\@@##4{% \c@lor@arg{##1}% \c@lor@arg{##2}% \c@lor@arg{##3}% \edef##4{#2 cs #2 CS ##1 ##2 ##3 scn ##1 ##2 ##3 SCN}}% \@namedef{XC@clr@#1@white}{0,0,0}% \@namedef{spc@infl@#1}{\def\spc@inflcommas{,}}} % 3 values = 4 - 1 commas \def\spc@mix@iv#1#2{% \expandafter\XC@sdef\csname XC@mod@#1\endcsname{#1}% \@namedef{color@#1}##1##2{\@nameuse{c@lor@@#1}##2\@@##1}% \@namedef{c@lor@@#1}##1,##2,##3,##4\@@##5{% \c@lor@arg{##1}% \c@lor@arg{##2}% \c@lor@arg{##3}% \c@lor@arg{##4}% \edef##5{#2 cs #2 CS ##1 ##2 ##3 ##4 scn ##1 ##2 ##3 ##4 SCN}}% \@namedef{XC@clr@#1@white}{0,0,0,0}% \@namedef{spc@infl@#1}{\let\spc@inflcommas\@empty}} % 4 value = 4 - % 0 commas % A few auxliary macros: \def\spc@nl{^^J} \def\spc@getirbase/ #2\@@{#1} \def\spc@getirbaseC/ #2\@@{#1 #2} \def\spc@writecomp#1#2{% \advance\@tempcntb\@ne \edef#1{#1 \the\numexpr\@tempcntb-\@tempcnta\relax\space index -#2\space mul 1.0 add mul\spc@nl}} \def\spc@writecmykcomps#1,#2,#3,#4\@@{% \spc@writecomp\spc@@cyan{#1}% \spc@writecomp\spc@@magenta{#2}% \spc@writecomp\spc@@yellow{#3}% \spc@writecomp\spc@@black{#4}} % And the main macro: \newif\ifspc@dflt \newcommand\definecolorspace{% \@ifstar {\spc@dflttrue\spc@defcs}% {\spc@dfltfalse\spc@defcs}} \def\spc@defcs#1#2#3{% \@ifundefined{spc@defcs@#2}% {\spc@unknown{spc@defcs@#2}{color space type `#2'}}% {\protected@edef\spc@tempa{% \expandafter\noexpand\csname spc@defcs@#2\endcsname {#1}{#3}}% \spc@tempa}} \def\spc@defcs@mixed#1#2{% \ifspc@dflt \PackageError{colorspace}{Unsupported}% {`mixed' only works with the unstarred command}% \fi \begingroup % the process part of the tint transform: \def\spc@@Pcyan{1.0\spc@nl}\def\spc@@Pmagenta{1.0\spc@nl}% \def\spc@@Pyellow{1.0\spc@nl}\def\spc@@Pblack{1.0\spc@nl}% % the spot part: \let\spc@@cyan\@empty\let\spc@@magenta\@empty \let\spc@@yellow\@empty\let\spc@@black\@empty % position on stack \edef\spc@@poscyan{0}\edef\spc@@posmagenta{1}% \edef\spc@@posyellow{2}\edef\spc@@posblack{3}% \@tempcntb\z@ % Number of colors \let\spc@pdfdoms\@empty % stores /Domain \let\spc@@pops\@empty \@for\spc@tempa:=#2\do{% \advance\@tempcntb\@ne % Count colors \edef\spc@@pops{\spc@@pops\space pop}% \edef\spc@pdfdoms{\spc@pdfdoms0 1 }}% \ifcase\@tempcntb\or1\or\spc@twocomps\or\or\else \PackageError{colorspace}{Too many inks}% {Currently, only up to 4 components are supported}% \fi \@tempcnta\z@ % position on stack \let\spc@pdfdevn\@empty % stores names for /DeviceN \let\spc@pdfclrnts\@empty % stores /Colorants \let\spc@name\@empty % stores name for page /ColorSpace \def\spc@ir@cyan{Cyan}\def\spc@ir@magenta{Magenta}% \def\spc@ir@yellow{Yellow}\def\spc@ir@black{Black}% \@for\spc@tempa:=#2\do{% \spc@dospaces\spc@tempa \advance\@tempcnta\@ne \edef\spc@ir{\csname spc@ir@\spc@tempa\endcsname}% \@expandtwoargs\in@{,\spc@tempa,}{,cyan,magenta,yellow,black,}% \ifin@ \edef\spc@pdfdevn{\spc@pdfdevn\space/\spc@ir}% \edef\spc@name{\spc@name &\spc@ir}% \expandafter \edef\csname spc@@P\spc@tempa\endcsname{% \the\numexpr\@tempcntb+\@nameuse{spc@@pos\spc@tempa}% -\@tempcnta\relax\space index neg 1.0 add\spc@nl}% ========== \else \@ifundefined{spc@ascmyk@\spc@tempa}% {\spc@unknown{spc@ascmyk@\spc@tempa}{spot color `\spc@tempa'}}% {}% \edef\spc@pdfdevn{\spc@pdfdevn\space /\expandafter\spc@getirbase\spc@ir\@@}% \edef\spc@pdfclrnts{\spc@pdfclrnts\space /\expandafter\spc@getirbaseC\spc@ir\@@}% \edef\spc@name{\spc@name &\expandafter\spc@getirbase\spc@ir\@@}% \expandafter\expandafter\expandafter\spc@writecmykcomps \csname spc@ascmyk@\spc@tempa\endcsname\@@ \advance\@tempcntb-4\relax \fi}% \immediate\pdfobj stream attr {/FunctionType 4 /Domain [ \spc@pdfdoms] /Range [ 0 1 0 1 0 1 0 1 ]}% {\string{\space \spc@@Pcyan\spc@@cyan neg 1.0 add\spc@nl \spc@@Pmagenta\spc@@magenta neg 1.0 add\spc@nl \spc@@Pyellow\spc@@yellow neg 1.0 add\spc@nl \spc@@Pblack\spc@@black neg 1.0 add\spc@nl \the\numexpr4+\@tempcntb\relax\space 4 roll\spc@@pops \space\string}}% \immediate\pdfobj{[ /DeviceN [\spc@pdfdevn\space] /DeviceCMYK \the\pdflastobj\space0 R << /Colorants <<\spc@pdfclrnts\space >> >> ]}% \expandafter\xdef\csname spc@ir@#1\endcsname{% /\spc@name\space\the\pdflastobj\space 0 R}% save ref to obj \let\spc@elt\relax \xdef\spc@csall{\spc@csall\spc@elt2{#1}}% \xdef\spc@tempa{% \expandafter\noexpand \csname spc@mix@\romannumeral\@tempcntb\endcsname {#1}{/\spc@name}}% \endgroup \spc@tempa} % === ICC based dafault spaces === % luatex removed pdffiledump, so we use lua code. \def\spc@defcs@iccbased#1#2{% \ifspc@dflt\else \PackageError{colorspace}{Unsupported}% {`iccbased' only works with the starred command}% \fi \begingroup % hex equivalents (which is the filedump format) and literal % (which is the lua format) \@namedef{spc@@47524159}{0}\@namedef{spc@@GRAY}{0}% \@namedef{spc@@52474220}{1}\@namedef{spc@@RGB }{1}% \@namedef{spc@@434D594B}{2}\@namedef{spc@@CMYK}{2}% \def\spc@@space{\ifcase\spc@tempa Gray\or RGB\or CMYK\fi}% \def\spc@@spacelc{\ifcase\spc@tempa gray\or rgb\or cmyk\fi}% % read the icc file and extract the space it applies to \ifx\pdffiledump\@undefined \directlua{ local icc = io.open([[#2]], "r") if icc then icc:seek("set", 16) tex.print([[\noexpand\csname @namedef\endcsname{spc@tempa}{]] .. icc:read(4) .. [[}]]) end}% \else \edef\spc@tempa{\pdffiledump offset 16 length 4 {#2}}% \fi \@ifundefined{spc@@\spc@tempa}% {\PackageError{colorspace}{Unsupported ICC space}% {Currently, only Gray, RGB and CMYK are supported}}% {\edef\spc@tempa{\@nameuse{spc@@\spc@tempa}}}% \immediate\pdfobj stream attr {\ifcase\spc@tempa /N 1 /Alternate /DeviceGray\or /N 3 /Alternate /DeviceRGB\or /N 4 /Alternate /DeviceCMYK\fi}% file {#2}% \immediate\pdfobj{[ /ICCBased \the\pdflastobj\space 0 R ]}% % to the default color list, add an intermediate name * % (only once) containing the last setting (add also the % actual name with flag 1 instead of 2) \let\spc@elt\relax \@ifundefined{spc@ir@*\spc@@spacelc}% {\xdef\spc@csall{\spc@csall\spc@elt2{*\spc@@spacelc}}}% {} % -- do nothing \expandafter\xdef\csname spc@ir@*\spc@@spacelc\endcsname{% /Default\spc@@space\space\the\pdflastobj\space 0 R}% \xdef\spc@csall{\spc@csall\spc@elt1{#1}}% \expandafter\xdef\csname spc@ir@#1\endcsname{% /Default\spc@@space\space\the\pdflastobj\space 0 R}% \endgroup} % ==== Overprint/Knokout ==== \DeclareOption{overprint}{\def\spc@op{1}} \DeclareOption{opm=0}{\def\spc@op{0}\def\spc@opm{0}} \DeclareOption{opm=1}{} \DeclareOption{knockout}{\def\spc@op{2}} % After opm! \def\spc@opm{1} \ProcessOptions\relax \ifx\spc@op\@undefined \spc@savedcatcodes \endinput\fi % One line! \def\spc@op@no{2} \@namedef{spc@op@1}{1} \@namedef{spc@op@0}{0} \newcommand\overprintstate[1]{% \spc@unknown{spc@op@#1}{overprint state `#1'}% \ifnum\csname spc@op@#1\endcsname=\spc@op\else \expandafter\let\expandafter\spc@op\csname spc@op@#1\endcsname \spc@setop \fi} \newcommand\textoverprint[2][\spc@opm]{{\overprintstate{#1}#2}} \immediate\pdfobj{<< /Type /ExtGState /op false /OP false >>}% \edef\spc@tempa{/SPCko \the\pdflastobj\space 0 R }% \immediate\pdfobj{<< /Type /ExtGState /op true /OP true /OPM 0 >>}% \edef\spc@tempa{\spc@tempa/SPCmz \the\pdflastobj\space 0 R }% \immediate\pdfobj{<< /Type /ExtGState /op true /OP true /OPM 1 >>}% \edef\spc@tempa{\spc@tempa/SPCop \the\pdflastobj\space 0 R }% \immediate\pdfobj{<< \spc@tempa>>}% \edef\spc@tempa{\global\pdfpageresources{\the\pdfpageresources \space /ExtGState \the\pdflastobj\space 0 R }} \spc@tempa \def\spc@setop{% \pdfcolorstack\spc@opstack push{\spc@getop}% \aftergroup\spc@resetop} \def\spc@resetop{\pdfcolorstack\spc@opstack pop\relax} \def\spc@getop{% \ifcase\spc@op /SPCmz gs \or /SPCop gs \or /SPCko gs \fi} \chardef\spc@opstack\pdfcolorstackinit page direct{\spc@getop} \spc@savedcatcodes \endinput