diff options
Diffstat (limited to 'pl/plsrgb.c')
-rw-r--r-- | pl/plsrgb.c | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/pl/plsrgb.c b/pl/plsrgb.c new file mode 100644 index 000000000..251f9aee6 --- /dev/null +++ b/pl/plsrgb.c @@ -0,0 +1,402 @@ +/* Portions Copyright (C) 2001 artofcode LLC. + Portions Copyright (C) 1996, 2001 Artifex Software Inc. + Portions Copyright (C) 1988, 2000 Aladdin Enterprises. + This software is based in part on the work of the Independent JPEG Group. + All Rights Reserved. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ or + contact Artifex Software, Inc., 101 Lucas Valley Road #110, + San Rafael, CA 94903, (415)492-9861, for further information. */ +/*$Id$ */ + +/* plsrgb.c - setting of srgb device independent color space. */ +#include "math_.h" +#include "string_.h" +#include "gstypes.h" +#include "gsmemory.h" +#include "gscspace.h" +#include "gsstate.h" +#include "gscie.h" +#include "gscolor2.h" +#include "gscrdp.h" +#include "gscrd.h" +#include "gsparam.h" +#include "gxstate.h" +#include "gzstate.h" +#include "plsrgb.h" + +/* uncomment the following definition to specify the device does the + color conversion. If the definition is commented out we set up an + srgb color space and associated color rendering dictionary using + the regular color conversion machinery in the graphics library + pipeline. The wtsimdi device is an example device that does color + conversion as a "postprocess" and requires the definition. If + defined all additive colors are passed through as Device RGB but + the device assumes the triples are in fact sRGB. NB eventually + this should be decided at run time. */ + +#define DEVICE_DOES_COLOR_CONVERSION + +bool +pl_device_does_color_conversion() +{ +#ifdef DEVICE_DOES_COLOR_CONVERSION + return true; +#endif + return false; +} + + +/* shared language (pcl and pclxl) for setting up sRGB to XYZ and an + associated default CRD to be used. The code will request a crd + from the driver which will override the default crd. We use the + postscript definitions (converted to C) from www.srgb.com, these + definitions are repeated here + + [ /CIEBasedABC << + % sRGB gamma transform + /DecodeLMN [ + {dup 0.03928 le {12.92321 div}{0.055 add 1.055 div 2.4 exp}ifelse} + bind dup dup ] + + % sRGB to XYZ (D65) matrix (ITU-R BT.709-2 Primaries) + /MatrixLMN [ + 0.412457 0.212673 0.019334 + 0.357576 0.715152 0.119192 + 0.180437 0.072175 0.950301 ] + /WhitePoint [ 0.9505 1 1.0890 ] % D65 + /BlackPoint[0 0 0] + >> ] setcolorspace + + << + % sRGB output CRD, D65 white point + /ColorRenderingType 1 + /RangePQR [ -0.5 2 -0.5 2 -0.5 2 ] + + % Bradford Cone Space + /MatrixPQR [0.8951 -0.7502 0.0389 + 0.2664 1.7135 -0.0685 + -0.1614 0.0367 1.0296] + + % VonKries-like transform in Bradford Cone Space + /TransformPQR + [{exch pop exch 3 get mul exch pop exch 3 get div} bind + {exch pop exch 4 get mul exch pop exch 4 get div} bind + {exch pop exch 5 get mul exch pop exch 5 get div} bind] + + /MatrixLMN [3.240449 -0.969265 0.055643 + -1.537136 1.876011 -0.204026 + -0.498531 0.041556 1.057229] + + % Inverse sRGB gamma transform + /EncodeABC [{dup 0.00304 le {12.92321 mul} + {1 2.4 div exp 1.055 mul 0.055 sub}ifelse} + bind dup dup] + + /WhitePoint[0.9505 1 1.0890] % D65 + /BlackPoint [0 0 0] + >> setcolorrendering +*/ + + +/* CIEBasedABC definitions */ +/* Decode LMN procedures for srgb color spaces or sRGB gamma transform. */ +inline static float +pl_decodeLMN(floatp val, const gs_cie_common *pcie) +{ + if ( val <= 0.03928 ) + return (float)(val / 12.92321); + else + return (float)pow((val + 0.055) / 1.055, (double)2.4); +} + + +static float +pl_DecodeLMN_0(floatp val, const gs_cie_common *pcie) +{ + return pl_decodeLMN(val, pcie); +} + +static float +pl_DecodeLMN_1(floatp val, const gs_cie_common *pcie) +{ + return pl_decodeLMN(val, pcie); +} + +static float +pl_DecodeLMN_2(floatp val, const gs_cie_common *pcie) +{ + return pl_decodeLMN(val, pcie); +} + +static const gs_cie_common_proc3 pl_DecodeLMN = { + { pl_DecodeLMN_0, pl_DecodeLMN_1, pl_DecodeLMN_2 } +}; + +/* LMN matrix for srgb. sRGB to XYZ (D65) matrix (ITU-R BT.709-2 Primaries) */ +static const gs_matrix3 pl_MatrixLMN = { + {0.412457, 0.212673, 0.019334}, + {0.357576, 0.715152, 0.119192}, + {0.180437, 0.072175, 0.950301}, + false +}; + +/* LMN matrix for the crd, just the inverse of the color spaces LMN. */ +static const gs_matrix3 pl_MatrixCRDLMN = { + {3.240449, -0.969265, 0.055643}, + {-1.537136, 1.876011, -0.204026}, + {-0.498531, 0.041556, 1.057229}, + false +}; + +/* D65 white point */ +static const gs_vector3 pl_WhitePoint = {0.9505, 1.0, 1.0890}; +static const gs_vector3 pl_BlackPoint = {0.0, 0.0, 0.0}; + +/* Bradford Cone Space - www.srgb.com */ +static const gs_matrix3 pl_MatrixPQR = { + {0.8951, -0.7502, 0.0389}, + {0.2664, 1.7135, -0.0685}, + {-0.1614, 0.0367, 1.0296}, + false +}; + +static const gs_range3 pl_RangePQR = { + {{-0.5, 2.0}, + {-0.5, 2.0}, + {-0.5, 2.0}} +}; + + +/* tranform pqr */ +static int +pl_TransformPQR_proc(int indx, floatp val, const gs_cie_wbsd *cs_wbsd, + gs_cie_render *pcrd, float *pnew_val) +{ + const float *pcrd_wht = (float *)&(cs_wbsd->wd.pqr); + const float *pcs_wht = (float *)&(cs_wbsd->ws.pqr); + *pnew_val = val * pcrd_wht[indx] / pcs_wht[indx]; + return 0; +} + +static const gs_cie_transform_proc3 pl_TransformPQR = { + pl_TransformPQR_proc, + NULL, + { NULL, 0 }, + NULL +}; + + +/* ABC - inverse srgb gamma transform */ +inline static float +pl_encodeABC(floatp in, const gs_cie_render * pcrd) +{ + if ( in <= 0.00304 ) + return (float)(in * 12.92321); + return (float)(pow(in, (1.0 / 2.4)) * 1.055 - 0.055); +} + +static float +pl_EncodeABC_0(floatp in, const gs_cie_render * pcrd) +{ + return pl_encodeABC(in, pcrd); +} + +static float +pl_EncodeABC_1(floatp in, const gs_cie_render * pcrd) +{ + return pl_encodeABC(in, pcrd); +} + +static float +pl_EncodeABC_2(floatp in, const gs_cie_render * pcrd) +{ + return pl_encodeABC(in, pcrd); +} + +static const gs_cie_render_proc3 pl_EncodeABC_procs = { + {pl_EncodeABC_0, pl_EncodeABC_1, pl_EncodeABC_2} +}; + +/* + * See if the default CRD is specified by the device. + * + * To simplify selection of more than one default CRD, this code allows more + * than one CRD to be included in the parameters associated with a device, + * and uses the device parameter "CRDName" to select the one that is to be + * used as a default. + * + */ + +static bool +pl_read_device_CRD(gs_cie_render *pcrd, gs_state *pgs) +{ + gx_device * pdev = gs_currentdevice(pgs); + gs_c_param_list list; + gs_param_string dstring; + char nbuff[64]; /* ample size */ + int code = 0; + + /*get the CRDName parameter from the device */ + gs_c_param_list_write(&list, gs_state_memory(pgs)); + if (param_request((gs_param_list *)&list, "CRDName") < 0) + return false; + + if ((code = gs_getdeviceparams(pdev, (gs_param_list *)&list)) >= 0) { + gs_c_param_list_read(&list); + if ( (code = param_read_string( (gs_param_list *)&list, + "CRDName", + &dstring + )) == 0 ) { + if (dstring.size > sizeof(nbuff) - 1) + code = 1; + else { + strncpy(nbuff, (char *)dstring.data, dstring.size); + nbuff[dstring.size] = '\0'; + } + } + } + gs_c_param_list_release(&list); + if (code != 0) + return false; + + gs_c_param_list_write(&list, gs_state_memory(pgs)); + if (param_request((gs_param_list *)&list, nbuff) < 0) + return false; + if ((code = gs_getdeviceparams(pdev, (gs_param_list *)&list)) >= 0) { + gs_param_dict dict; + + gs_c_param_list_read(&list); + if ( (code = param_begin_read_dict( (gs_param_list *)&list, + nbuff, + &dict, + false + )) == 0 ) { + code = param_get_cie_render1(pcrd, dict.list, pdev); + param_end_read_dict((gs_param_list *)&list, nbuff, &dict); + if (code > 0) + code = 0; + } + } + gs_c_param_list_release(&list); + return (code == 0); +} + + +/* statics to see if the crd has been built, in practice the crd is a + singleton. */ +gs_cie_render *pl_pcrd; +bool pl_pcrd_built = false; /* the crd has been built */ + + +static int +pl_build_crd(gs_state *pgs) +{ + int code; + /* nothing to do */ + if ( pl_pcrd_built == true ) + return gs_setcolorrendering(pgs, pl_pcrd); + + code = gs_cie_render1_build(&pl_pcrd, gs_state_memory(pgs), "build_crd"); + if ( code < 0 ) + return code; + pl_pcrd_built = true; + + if ( pl_read_device_CRD(pl_pcrd, pgs) ) { + dprintf("CRD initialized from device\n"); + return 0; + } + + code = gs_cie_render1_initialize(pgs->memory, + pl_pcrd, + NULL, + &pl_WhitePoint, + &pl_BlackPoint, + &pl_MatrixPQR, + &pl_RangePQR, + &pl_TransformPQR, + &pl_MatrixCRDLMN, + NULL, /* EncodeLMN */ + NULL, /* RangeLMN */ + NULL, /* MatrixABC */ + &pl_EncodeABC_procs, + NULL, + NULL); + if ( code < 0 ) + return code; /* should not fail */ + code = gs_setcolorrendering(pgs, pl_pcrd); + return code; +} + + +/* return SRGB color space to the client */ +int +pl_cspace_init_SRGB(gs_color_space **ppcs, const gs_state *pgs) +{ + + int code; + /* make sure we have a crd set up */ +#ifdef DEVICE_DOES_COLOR_CONVERSION + *ppcs = gs_cspace_new_DeviceRGB(pgs->memory); + return 0; +#endif + + code = pl_build_crd((gs_state *)pgs); + if ( code < 0 ) + return code; + + + + code = gs_cspace_build_CIEABC(ppcs, NULL, gs_state_memory(pgs)); + if ( code < 0 ) + return code; + *(gs_cie_DecodeLMN(*ppcs)) = pl_DecodeLMN; + *(gs_cie_MatrixLMN(*ppcs)) = pl_MatrixLMN; + (gs_cie_WhitePoint(*ppcs)) = pl_WhitePoint; + (gs_cie_BlackPoint(*ppcs)) = pl_BlackPoint; + return 0; +} + +/* set the srgb color space */ +static int +pl_setSRGB(gs_state *pgs) +{ + gs_color_space *pcs; + int code; + + code = pl_cspace_init_SRGB(&pcs, pgs); + if ( code < 0 ) + return code; + code = gs_setcolorspace(pgs, pcs); + rc_decrement(pcs, "ps_setSRGB"); + return code; +} + +/* set an srgb color */ +int +pl_setSRGBcolor(gs_state *pgs, float r, float g, float b) +{ + int code; + gs_client_color color; + +#ifdef DEVICE_DOES_COLOR_CONVERSION + return gs_setrgbcolor(pgs, r, g, b); +#endif + /* make sure we have a crd set up */ + code = pl_build_crd(pgs); + if ( code < 0 ) + return code; + + code = pl_setSRGB(pgs); + if ( code < 0 ) + return code; + + /* set the color */ + color.paint.values[0] = r; + color.paint.values[1] = g; + color.paint.values[2] = b; + code = gs_setcolor(pgs, &color); + return code; +} |