colorspace.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "color-imp.h"
  24. #include <assert.h>
  25. #include <math.h>
  26. #include <string.h>
  27. #if FZ_ENABLE_ICC
  28. #include "icc/gray.icc.h"
  29. #include "icc/rgb.icc.h"
  30. #include "icc/cmyk.icc.h"
  31. #include "icc/lab.icc.h"
  32. void fz_new_colorspace_context(fz_context *ctx)
  33. {
  34. fz_colorspace_context *cct;
  35. fz_buffer *gray = NULL;
  36. fz_buffer *rgb = NULL;
  37. fz_buffer *cmyk = NULL;
  38. fz_buffer *lab = NULL;
  39. fz_var(gray);
  40. fz_var(rgb);
  41. fz_var(cmyk);
  42. fz_var(lab);
  43. cct = ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
  44. cct->ctx_refs = 1;
  45. fz_new_icc_context(ctx);
  46. ctx->icc_enabled = 1;
  47. fz_try(ctx)
  48. {
  49. gray = fz_new_buffer_from_shared_data(ctx, resources_icc_gray_icc, resources_icc_gray_icc_len);
  50. rgb = fz_new_buffer_from_shared_data(ctx, resources_icc_rgb_icc, resources_icc_rgb_icc_len);
  51. cmyk = fz_new_buffer_from_shared_data(ctx, resources_icc_cmyk_icc, resources_icc_cmyk_icc_len);
  52. lab = fz_new_buffer_from_shared_data(ctx, resources_icc_lab_icc, resources_icc_lab_icc_len);
  53. cct->gray = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_GRAY, FZ_COLORSPACE_IS_DEVICE, "DeviceGray", gray);
  54. cct->rgb = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, FZ_COLORSPACE_IS_DEVICE, "DeviceRGB", rgb);
  55. cct->bgr = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_BGR, FZ_COLORSPACE_IS_DEVICE, "DeviceBGR", rgb);
  56. cct->cmyk = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_CMYK, FZ_COLORSPACE_IS_DEVICE, "DeviceCMYK", cmyk);
  57. cct->lab = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_LAB, FZ_COLORSPACE_IS_DEVICE, "Lab", lab);
  58. }
  59. fz_always(ctx)
  60. {
  61. fz_drop_buffer(ctx, gray);
  62. fz_drop_buffer(ctx, rgb);
  63. fz_drop_buffer(ctx, cmyk);
  64. fz_drop_buffer(ctx, lab);
  65. }
  66. fz_catch(ctx)
  67. {
  68. fz_rethrow(ctx);
  69. }
  70. }
  71. void fz_enable_icc(fz_context *ctx)
  72. {
  73. ctx->icc_enabled = 1;
  74. }
  75. void fz_disable_icc(fz_context *ctx)
  76. {
  77. ctx->icc_enabled = 0;
  78. }
  79. #else
  80. void fz_new_colorspace_context(fz_context *ctx)
  81. {
  82. fz_colorspace_context *cct;
  83. cct = ctx->colorspace = fz_malloc_struct(ctx, fz_colorspace_context);
  84. cct->ctx_refs = 1;
  85. cct->gray = fz_new_colorspace(ctx, FZ_COLORSPACE_GRAY, FZ_COLORSPACE_IS_DEVICE, 1, "DeviceGray");
  86. cct->rgb = fz_new_colorspace(ctx, FZ_COLORSPACE_RGB, FZ_COLORSPACE_IS_DEVICE, 3, "DeviceRGB");
  87. cct->bgr = fz_new_colorspace(ctx, FZ_COLORSPACE_BGR, FZ_COLORSPACE_IS_DEVICE, 3, "DeviceBGR");
  88. cct->cmyk = fz_new_colorspace(ctx, FZ_COLORSPACE_CMYK, FZ_COLORSPACE_IS_DEVICE, 4, "DeviceCMYK");
  89. cct->lab = fz_new_colorspace(ctx, FZ_COLORSPACE_LAB, FZ_COLORSPACE_IS_DEVICE, 3, "Lab");
  90. }
  91. void fz_enable_icc(fz_context *ctx)
  92. {
  93. fz_warn(ctx, "ICC support is not available");
  94. }
  95. void fz_disable_icc(fz_context *ctx)
  96. {
  97. }
  98. #endif
  99. fz_colorspace_context *fz_keep_colorspace_context(fz_context *ctx)
  100. {
  101. fz_keep_imp(ctx, ctx->colorspace, &ctx->colorspace->ctx_refs);
  102. return ctx->colorspace;
  103. }
  104. void fz_drop_colorspace_context(fz_context *ctx)
  105. {
  106. if (fz_drop_imp(ctx, ctx->colorspace, &ctx->colorspace->ctx_refs))
  107. {
  108. fz_drop_colorspace(ctx, ctx->colorspace->gray);
  109. fz_drop_colorspace(ctx, ctx->colorspace->rgb);
  110. fz_drop_colorspace(ctx, ctx->colorspace->bgr);
  111. fz_drop_colorspace(ctx, ctx->colorspace->cmyk);
  112. fz_drop_colorspace(ctx, ctx->colorspace->lab);
  113. #if FZ_ENABLE_ICC
  114. fz_drop_icc_context(ctx);
  115. #endif
  116. fz_free(ctx, ctx->colorspace);
  117. ctx->colorspace = NULL;
  118. }
  119. }
  120. fz_colorspace *fz_device_gray(fz_context *ctx)
  121. {
  122. return ctx->colorspace->gray;
  123. }
  124. fz_colorspace *fz_device_rgb(fz_context *ctx)
  125. {
  126. return ctx->colorspace->rgb;
  127. }
  128. fz_colorspace *fz_device_bgr(fz_context *ctx)
  129. {
  130. return ctx->colorspace->bgr;
  131. }
  132. fz_colorspace *fz_device_cmyk(fz_context *ctx)
  133. {
  134. return ctx->colorspace->cmyk;
  135. }
  136. fz_colorspace *fz_device_lab(fz_context *ctx)
  137. {
  138. return ctx->colorspace->lab;
  139. }
  140. /* Same order as needed by LCMS */
  141. static const char *fz_intent_names[] =
  142. {
  143. "Perceptual",
  144. "RelativeColorimetric",
  145. "Saturation",
  146. "AbsoluteColorimetric",
  147. };
  148. int fz_lookup_rendering_intent(const char *name)
  149. {
  150. int i;
  151. for (i = 0; i < (int)nelem(fz_intent_names); i++)
  152. if (!strcmp(name, fz_intent_names[i]))
  153. return i;
  154. return FZ_RI_RELATIVE_COLORIMETRIC;
  155. }
  156. const char *fz_rendering_intent_name(int ri)
  157. {
  158. if (ri >= 0 && ri < (int)nelem(fz_intent_names))
  159. return fz_intent_names[ri];
  160. return "RelativeColorimetric";
  161. }
  162. /* Colorspace feature tests */
  163. const char *fz_colorspace_name(fz_context *ctx, fz_colorspace *cs)
  164. {
  165. return cs ? cs->name : "None";
  166. }
  167. enum fz_colorspace_type fz_colorspace_type(fz_context *ctx, fz_colorspace *cs)
  168. {
  169. return cs ? cs->type : FZ_COLORSPACE_NONE;
  170. }
  171. int fz_colorspace_n(fz_context *ctx, fz_colorspace *cs)
  172. {
  173. return cs ? cs->n : 0;
  174. }
  175. int fz_colorspace_is_gray(fz_context *ctx, fz_colorspace *cs)
  176. {
  177. return cs && cs->type == FZ_COLORSPACE_GRAY;
  178. }
  179. int fz_colorspace_is_rgb(fz_context *ctx, fz_colorspace *cs)
  180. {
  181. return cs && cs->type == FZ_COLORSPACE_RGB;
  182. }
  183. int fz_colorspace_is_cmyk(fz_context *ctx, fz_colorspace *cs)
  184. {
  185. return cs && cs->type == FZ_COLORSPACE_CMYK;
  186. }
  187. int fz_colorspace_is_lab(fz_context *ctx, fz_colorspace *cs)
  188. {
  189. return cs && cs->type == FZ_COLORSPACE_LAB;
  190. }
  191. int fz_colorspace_is_indexed(fz_context *ctx, fz_colorspace *cs)
  192. {
  193. return cs && (cs->type == FZ_COLORSPACE_INDEXED);
  194. }
  195. int fz_colorspace_is_device_n(fz_context *ctx, fz_colorspace *cs)
  196. {
  197. return cs && (cs->type == FZ_COLORSPACE_SEPARATION);
  198. }
  199. int fz_colorspace_is_subtractive(fz_context *ctx, fz_colorspace *cs)
  200. {
  201. return cs && (cs->type == FZ_COLORSPACE_CMYK || cs->type == FZ_COLORSPACE_SEPARATION);
  202. }
  203. int fz_colorspace_is_device(fz_context *ctx, fz_colorspace *cs)
  204. {
  205. return cs && (cs->flags & FZ_COLORSPACE_IS_DEVICE);
  206. }
  207. int fz_colorspace_is_icc(fz_context *ctx, fz_colorspace *cs)
  208. {
  209. return cs && (cs->flags & FZ_COLORSPACE_IS_ICC);
  210. }
  211. int fz_colorspace_is_lab_icc(fz_context *ctx, fz_colorspace *cs)
  212. {
  213. return cs && (cs->type == FZ_COLORSPACE_LAB) && (cs->flags & FZ_COLORSPACE_IS_ICC);
  214. }
  215. int fz_colorspace_is_device_gray(fz_context *ctx, fz_colorspace *cs)
  216. {
  217. return fz_colorspace_is_device(ctx, cs) && fz_colorspace_is_gray(ctx, cs);
  218. }
  219. int fz_colorspace_is_device_cmyk(fz_context *ctx, fz_colorspace *cs)
  220. {
  221. return fz_colorspace_is_device(ctx, cs) && fz_colorspace_is_cmyk(ctx, cs);
  222. }
  223. int fz_colorspace_device_n_has_only_cmyk(fz_context *ctx, fz_colorspace *cs)
  224. {
  225. return cs && ((cs->flags & FZ_COLORSPACE_HAS_CMYK_AND_SPOTS) == FZ_COLORSPACE_HAS_CMYK);
  226. }
  227. int fz_colorspace_device_n_has_cmyk(fz_context *ctx, fz_colorspace *cs)
  228. {
  229. return cs && (cs->flags & FZ_COLORSPACE_HAS_CMYK);
  230. }
  231. int fz_is_valid_blend_colorspace(fz_context *ctx, fz_colorspace *cs)
  232. {
  233. return cs == NULL ||
  234. cs->type == FZ_COLORSPACE_GRAY ||
  235. cs->type == FZ_COLORSPACE_RGB ||
  236. cs->type == FZ_COLORSPACE_CMYK;
  237. }
  238. fz_colorspace *fz_base_colorspace(fz_context *ctx, fz_colorspace *cs)
  239. {
  240. if (cs == NULL)
  241. return NULL;
  242. if (cs->type == FZ_COLORSPACE_INDEXED)
  243. return cs->u.indexed.base;
  244. return cs;
  245. }
  246. fz_colorspace *
  247. fz_keep_colorspace(fz_context *ctx, fz_colorspace *cs)
  248. {
  249. return fz_keep_key_storable(ctx, &cs->key_storable);
  250. }
  251. void
  252. fz_drop_colorspace(fz_context *ctx, fz_colorspace *cs)
  253. {
  254. fz_drop_key_storable(ctx, &cs->key_storable);
  255. }
  256. fz_colorspace *
  257. fz_keep_colorspace_store_key(fz_context *ctx, fz_colorspace *cs)
  258. {
  259. return fz_keep_key_storable_key(ctx, &cs->key_storable);
  260. }
  261. void
  262. fz_drop_colorspace_store_key(fz_context *ctx, fz_colorspace *cs)
  263. {
  264. fz_drop_key_storable_key(ctx, &cs->key_storable);
  265. }
  266. void
  267. fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_)
  268. {
  269. fz_colorspace *cs = (fz_colorspace *)cs_;
  270. int i;
  271. if (cs->type == FZ_COLORSPACE_INDEXED)
  272. {
  273. fz_drop_colorspace(ctx, cs->u.indexed.base);
  274. fz_free(ctx, cs->u.indexed.lookup);
  275. }
  276. if (cs->type == FZ_COLORSPACE_SEPARATION)
  277. {
  278. fz_drop_colorspace(ctx, cs->u.separation.base);
  279. cs->u.separation.drop(ctx, cs->u.separation.tint);
  280. for (i = 0; i < FZ_MAX_COLORS; i++)
  281. fz_free(ctx, cs->u.separation.colorant[i]);
  282. }
  283. #if FZ_ENABLE_ICC
  284. if (cs->flags & FZ_COLORSPACE_IS_ICC)
  285. {
  286. fz_drop_icc_profile(ctx, cs->u.icc.profile);
  287. fz_drop_buffer(ctx, cs->u.icc.buffer);
  288. }
  289. #endif
  290. fz_free(ctx, cs->name);
  291. fz_free(ctx, cs);
  292. }
  293. fz_colorspace *
  294. fz_new_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, int n, const char *name)
  295. {
  296. fz_colorspace *cs = fz_malloc_struct(ctx, fz_colorspace);
  297. FZ_INIT_KEY_STORABLE(cs, 1, fz_drop_colorspace_imp);
  298. if (n > FZ_MAX_COLORS)
  299. fz_throw(ctx, FZ_ERROR_ARGUMENT, "too many color components (%d > %d)", n, FZ_MAX_COLORS);
  300. if (n < 1)
  301. fz_throw(ctx, FZ_ERROR_ARGUMENT, "too few color components (%d < 1)", n);
  302. fz_try(ctx)
  303. {
  304. cs->type = type;
  305. cs->flags = flags;
  306. cs->n = n;
  307. cs->name = Memento_label(fz_strdup(ctx, name ? name : "UNKNOWN"), "cs_name");
  308. }
  309. fz_catch(ctx)
  310. {
  311. fz_free(ctx, cs);
  312. fz_rethrow(ctx);
  313. }
  314. return cs;
  315. }
  316. fz_colorspace *
  317. fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup)
  318. {
  319. fz_colorspace *cs;
  320. char name[100];
  321. if (high < 0 || high > 255)
  322. fz_throw(ctx, FZ_ERROR_SYNTAX, "invalid maximum value in indexed colorspace");
  323. fz_snprintf(name, sizeof name, "Indexed(%d,%s)", high, base->name);
  324. cs = fz_new_colorspace(ctx, FZ_COLORSPACE_INDEXED, 0, 1, name);
  325. cs->u.indexed.base = fz_keep_colorspace(ctx, base);
  326. cs->u.indexed.high = high;
  327. cs->u.indexed.lookup = lookup;
  328. return cs;
  329. }
  330. fz_colorspace *
  331. fz_new_icc_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, const char *name, fz_buffer *buf)
  332. {
  333. #if FZ_ENABLE_ICC
  334. fz_icc_profile *profile = NULL;
  335. fz_colorspace *cs = NULL;
  336. unsigned char *data;
  337. char name_buf[100];
  338. size_t size;
  339. int n;
  340. fz_var(profile);
  341. fz_var(cs);
  342. fz_var(type);
  343. fz_try(ctx)
  344. {
  345. size = fz_buffer_storage(ctx, buf, &data);
  346. profile = fz_new_icc_profile(ctx, data, size);
  347. n = fz_icc_profile_components(ctx, profile);
  348. switch (type)
  349. {
  350. default:
  351. fz_throw(ctx, FZ_ERROR_SYNTAX, "invalid colorspace type for ICC profile");
  352. case FZ_COLORSPACE_NONE:
  353. switch (n)
  354. {
  355. default:
  356. fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile has unexpected number of channels: %d", n);
  357. case 1:
  358. type = FZ_COLORSPACE_GRAY;
  359. break;
  360. case 3:
  361. if (fz_icc_profile_is_lab(ctx, profile))
  362. type = FZ_COLORSPACE_LAB;
  363. else
  364. type = FZ_COLORSPACE_RGB;
  365. break;
  366. case 4:
  367. type = FZ_COLORSPACE_CMYK;
  368. break;
  369. }
  370. break;
  371. case FZ_COLORSPACE_GRAY:
  372. if (n != 1)
  373. fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not Gray", n);
  374. break;
  375. case FZ_COLORSPACE_RGB:
  376. case FZ_COLORSPACE_BGR:
  377. if (n != 3 || fz_icc_profile_is_lab(ctx, profile))
  378. fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not RGB", n);
  379. break;
  380. case FZ_COLORSPACE_LAB:
  381. if (n != 3 || !fz_icc_profile_is_lab(ctx, profile))
  382. fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not Lab", n);
  383. break;
  384. case FZ_COLORSPACE_CMYK:
  385. if (n != 4)
  386. fz_throw(ctx, FZ_ERROR_SYNTAX, "ICC profile (N=%d) is not CMYK", n);
  387. break;
  388. }
  389. if (!name)
  390. {
  391. char cmm_name[100];
  392. fz_icc_profile_name(ctx, profile, cmm_name, sizeof cmm_name);
  393. switch (type)
  394. {
  395. default: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(%d,%s)", n, cmm_name); break;
  396. case FZ_COLORSPACE_GRAY: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(Gray,%s)", cmm_name); break;
  397. case FZ_COLORSPACE_RGB: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(RGB,%s)", cmm_name); break;
  398. case FZ_COLORSPACE_BGR: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(BGR,%s)", cmm_name); break;
  399. case FZ_COLORSPACE_CMYK: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(CMYK,%s)", cmm_name); break;
  400. case FZ_COLORSPACE_LAB: fz_snprintf(name_buf, sizeof name_buf, "ICCBased(Lab,%s)", cmm_name); break;
  401. }
  402. name = name_buf;
  403. }
  404. cs = fz_new_colorspace(ctx, type, flags | FZ_COLORSPACE_IS_ICC, n, name);
  405. cs->u.icc.buffer = fz_keep_buffer(ctx, buf);
  406. cs->u.icc.profile = profile;
  407. fz_md5_buffer(ctx, buf, cs->u.icc.md5);
  408. }
  409. fz_catch(ctx)
  410. {
  411. fz_drop_icc_profile(ctx, profile);
  412. fz_drop_colorspace(ctx, cs);
  413. fz_rethrow(ctx);
  414. }
  415. return cs;
  416. #else
  417. switch (type)
  418. {
  419. default: fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown colorspace type");
  420. case FZ_COLORSPACE_GRAY: return fz_keep_colorspace(ctx, fz_device_gray(ctx));
  421. case FZ_COLORSPACE_RGB: return fz_keep_colorspace(ctx, fz_device_rgb(ctx));
  422. case FZ_COLORSPACE_BGR: return fz_keep_colorspace(ctx, fz_device_bgr(ctx));
  423. case FZ_COLORSPACE_CMYK: return fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
  424. case FZ_COLORSPACE_LAB: return fz_keep_colorspace(ctx, fz_device_lab(ctx));
  425. }
  426. #endif
  427. }
  428. fz_colorspace *fz_new_cal_gray_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma)
  429. {
  430. #if FZ_ENABLE_ICC
  431. fz_buffer *buf = fz_new_icc_data_from_cal(ctx, wp, bp, &gamma, NULL, 1);
  432. fz_colorspace *cs;
  433. fz_try(ctx)
  434. cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_GRAY, 0, "CalGray", buf);
  435. fz_always(ctx)
  436. fz_drop_buffer(ctx, buf);
  437. fz_catch(ctx)
  438. fz_rethrow(ctx);
  439. return cs;
  440. #else
  441. return fz_keep_colorspace(ctx, fz_device_gray(ctx));
  442. #endif
  443. }
  444. fz_colorspace *fz_new_cal_rgb_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma[3], float matrix[9])
  445. {
  446. #if FZ_ENABLE_ICC
  447. fz_buffer *buf = fz_new_icc_data_from_cal(ctx, wp, bp, gamma, matrix, 3);
  448. fz_colorspace *cs;
  449. fz_try(ctx)
  450. cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, "CalRGB", buf);
  451. fz_always(ctx)
  452. fz_drop_buffer(ctx, buf);
  453. fz_catch(ctx)
  454. fz_rethrow(ctx);
  455. return cs;
  456. #else
  457. return fz_keep_colorspace(ctx, fz_device_rgb(ctx));
  458. #endif
  459. }
  460. void fz_colorspace_name_colorant(fz_context *ctx, fz_colorspace *cs, int i, const char *name)
  461. {
  462. if (i < 0 || i >= cs->n)
  463. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Attempt to name out of range colorant");
  464. if (cs->type != FZ_COLORSPACE_SEPARATION)
  465. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Attempt to name colorant for non-separation colorspace");
  466. fz_free(ctx, cs->u.separation.colorant[i]);
  467. cs->u.separation.colorant[i] = NULL;
  468. cs->u.separation.colorant[i] = fz_strdup(ctx, name);
  469. if (!strcmp(name, "Cyan") || !strcmp(name, "Magenta") || !strcmp(name, "Yellow") || !strcmp(name, "Black"))
  470. cs->flags |= FZ_COLORSPACE_HAS_CMYK;
  471. else
  472. cs->flags |= FZ_COLORSPACE_HAS_SPOTS;
  473. }
  474. const char *fz_colorspace_colorant(fz_context *ctx, fz_colorspace *cs, int i)
  475. {
  476. if (!cs || i < 0 || i >= cs->n)
  477. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Colorant out of range");
  478. switch (cs->type)
  479. {
  480. case FZ_COLORSPACE_NONE:
  481. return "None";
  482. case FZ_COLORSPACE_GRAY:
  483. return "Gray";
  484. case FZ_COLORSPACE_RGB:
  485. if (i == 0) return "Red";
  486. if (i == 1) return "Green";
  487. if (i == 2) return "Blue";
  488. break;
  489. case FZ_COLORSPACE_BGR:
  490. if (i == 0) return "Blue";
  491. if (i == 1) return "Green";
  492. if (i == 2) return "Red";
  493. break;
  494. case FZ_COLORSPACE_CMYK:
  495. if (i == 0) return "Cyan";
  496. if (i == 1) return "Magenta";
  497. if (i == 2) return "Yellow";
  498. if (i == 3) return "Black";
  499. break;
  500. case FZ_COLORSPACE_LAB:
  501. if (i == 0) return "L*";
  502. if (i == 1) return "a*";
  503. if (i == 2) return "b*";
  504. break;
  505. case FZ_COLORSPACE_INDEXED:
  506. return "Index";
  507. case FZ_COLORSPACE_SEPARATION:
  508. return cs->u.separation.colorant[i];
  509. }
  510. return "None";
  511. }
  512. void
  513. fz_clamp_color(fz_context *ctx, fz_colorspace *cs, const float *in, float *out)
  514. {
  515. if (cs->type == FZ_COLORSPACE_LAB)
  516. {
  517. out[0] = fz_clamp(in[0], 0, 100);
  518. out[1] = fz_clamp(in[1], -128, 127);
  519. out[2] = fz_clamp(in[2], -128, 127);
  520. }
  521. else if (cs->type == FZ_COLORSPACE_INDEXED)
  522. {
  523. /* round color index to integer before rescaling to hival */
  524. out[0] = fz_clamp((int)(in[0]+0.5), 0, cs->u.indexed.high) / 255.0f;
  525. }
  526. else
  527. {
  528. int i, n = cs->n;
  529. for (i = 0; i < n; ++i)
  530. out[i] = fz_clamp(in[i], 0, 1);
  531. }
  532. }
  533. const fz_color_params fz_default_color_params = { FZ_RI_RELATIVE_COLORIMETRIC, 1, 0, 0 };
  534. fz_default_colorspaces *fz_new_default_colorspaces(fz_context *ctx)
  535. {
  536. fz_default_colorspaces *default_cs = fz_malloc_struct(ctx, fz_default_colorspaces);
  537. default_cs->refs = 1;
  538. default_cs->gray = fz_keep_colorspace(ctx, fz_device_gray(ctx));
  539. default_cs->rgb = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
  540. default_cs->cmyk = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
  541. default_cs->oi = NULL;
  542. return default_cs;
  543. }
  544. fz_default_colorspaces *fz_clone_default_colorspaces(fz_context *ctx, fz_default_colorspaces *base)
  545. {
  546. fz_default_colorspaces *default_cs = fz_malloc_struct(ctx, fz_default_colorspaces);
  547. default_cs->refs = 1;
  548. if (base)
  549. {
  550. default_cs->gray = fz_keep_colorspace(ctx, base->gray);
  551. default_cs->rgb = fz_keep_colorspace(ctx, base->rgb);
  552. default_cs->cmyk = fz_keep_colorspace(ctx, base->cmyk);
  553. default_cs->oi = fz_keep_colorspace(ctx, base->oi);
  554. }
  555. return default_cs;
  556. }
  557. fz_default_colorspaces *fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
  558. {
  559. return fz_keep_imp(ctx, default_cs, &default_cs->refs);
  560. }
  561. void
  562. fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs)
  563. {
  564. if (fz_drop_imp(ctx, default_cs, &default_cs->refs))
  565. {
  566. fz_drop_colorspace(ctx, default_cs->gray);
  567. fz_drop_colorspace(ctx, default_cs->rgb);
  568. fz_drop_colorspace(ctx, default_cs->cmyk);
  569. fz_drop_colorspace(ctx, default_cs->oi);
  570. fz_free(ctx, default_cs);
  571. }
  572. }
  573. fz_colorspace *fz_default_gray(fz_context *ctx, const fz_default_colorspaces *default_cs)
  574. {
  575. return (default_cs && default_cs->gray) ? default_cs->gray : fz_device_gray(ctx);
  576. }
  577. fz_colorspace *fz_default_rgb(fz_context *ctx, const fz_default_colorspaces *default_cs)
  578. {
  579. return (default_cs && default_cs->rgb) ? default_cs->rgb : fz_device_rgb(ctx);
  580. }
  581. fz_colorspace *fz_default_cmyk(fz_context *ctx, const fz_default_colorspaces *default_cs)
  582. {
  583. return (default_cs && default_cs->cmyk) ? default_cs->cmyk : fz_device_cmyk(ctx);
  584. }
  585. fz_colorspace *fz_default_output_intent(fz_context *ctx, const fz_default_colorspaces *default_cs)
  586. {
  587. return default_cs ? default_cs->oi : NULL;
  588. }
  589. void fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
  590. {
  591. if (cs->type == FZ_COLORSPACE_GRAY && cs->n == 1)
  592. {
  593. fz_drop_colorspace(ctx, default_cs->gray);
  594. default_cs->gray = fz_keep_colorspace(ctx, cs);
  595. }
  596. }
  597. void fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
  598. {
  599. if (cs->type == FZ_COLORSPACE_RGB && cs->n == 3)
  600. {
  601. fz_drop_colorspace(ctx, default_cs->rgb);
  602. default_cs->rgb = fz_keep_colorspace(ctx, cs);
  603. }
  604. }
  605. void fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
  606. {
  607. if (cs->type == FZ_COLORSPACE_CMYK && cs->n == 4)
  608. {
  609. fz_drop_colorspace(ctx, default_cs->cmyk);
  610. default_cs->cmyk = fz_keep_colorspace(ctx, cs);
  611. }
  612. }
  613. void fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs)
  614. {
  615. fz_drop_colorspace(ctx, default_cs->oi);
  616. default_cs->oi = NULL;
  617. /* FIXME: Why do we set DefaultXXX along with the output intent?! */
  618. switch (cs->type)
  619. {
  620. default:
  621. fz_warn(ctx, "Ignoring incompatible output intent: %s.", cs->name);
  622. break;
  623. case FZ_COLORSPACE_GRAY:
  624. default_cs->oi = fz_keep_colorspace(ctx, cs);
  625. if (default_cs->gray == fz_device_gray(ctx))
  626. fz_set_default_gray(ctx, default_cs, cs);
  627. break;
  628. case FZ_COLORSPACE_RGB:
  629. default_cs->oi = fz_keep_colorspace(ctx, cs);
  630. if (default_cs->rgb == fz_device_rgb(ctx))
  631. fz_set_default_rgb(ctx, default_cs, cs);
  632. break;
  633. case FZ_COLORSPACE_CMYK:
  634. default_cs->oi = fz_keep_colorspace(ctx, cs);
  635. if (default_cs->cmyk == fz_device_cmyk(ctx))
  636. fz_set_default_cmyk(ctx, default_cs, cs);
  637. break;
  638. }
  639. }
  640. /* Link cache */
  641. #if FZ_ENABLE_ICC
  642. typedef struct {
  643. int refs;
  644. unsigned char src_md5[16];
  645. unsigned char dst_md5[16];
  646. fz_color_params rend;
  647. unsigned char src_extras;
  648. unsigned char dst_extras;
  649. unsigned char copy_spots;
  650. unsigned char format;
  651. unsigned char proof;
  652. unsigned char bgr;
  653. } fz_link_key;
  654. static void *
  655. fz_keep_link_key(fz_context *ctx, void *key_)
  656. {
  657. fz_link_key *key = (fz_link_key *)key_;
  658. return fz_keep_imp(ctx, key, &key->refs);
  659. }
  660. static void
  661. fz_drop_link_key(fz_context *ctx, void *key_)
  662. {
  663. fz_link_key *key = (fz_link_key *)key_;
  664. if (fz_drop_imp(ctx, key, &key->refs))
  665. fz_free(ctx, key);
  666. }
  667. static int
  668. fz_cmp_link_key(fz_context *ctx, void *k0_, void *k1_)
  669. {
  670. fz_link_key *k0 = (fz_link_key *)k0_;
  671. fz_link_key *k1 = (fz_link_key *)k1_;
  672. return
  673. memcmp(k0->src_md5, k1->src_md5, 16) == 0 &&
  674. memcmp(k0->dst_md5, k1->dst_md5, 16) == 0 &&
  675. k0->src_extras == k1->src_extras &&
  676. k0->dst_extras == k1->dst_extras &&
  677. k0->rend.bp == k1->rend.bp &&
  678. k0->rend.ri == k1->rend.ri &&
  679. k0->copy_spots == k1->copy_spots &&
  680. k0->format == k1->format &&
  681. k0->proof == k1->proof &&
  682. k0->bgr == k1->bgr;
  683. }
  684. static void
  685. fz_format_link_key(fz_context *ctx, char *s, size_t n, void *key_)
  686. {
  687. static const char *hex = "0123456789abcdef";
  688. fz_link_key *key = (fz_link_key *)key_;
  689. char sm[33], dm[33];
  690. int i;
  691. for (i = 0; i < 16; ++i)
  692. {
  693. sm[i*2+0] = hex[key->src_md5[i]>>4];
  694. sm[i*2+1] = hex[key->src_md5[i]&15];
  695. dm[i*2+0] = hex[key->dst_md5[i]>>4];
  696. dm[i*2+1] = hex[key->dst_md5[i]&15];
  697. }
  698. sm[32] = 0;
  699. dm[32] = 0;
  700. fz_snprintf(s, n, "(link src_md5=%s dst_md5=%s)", sm, dm);
  701. }
  702. static int
  703. fz_make_hash_link_key(fz_context *ctx, fz_store_hash *hash, void *key_)
  704. {
  705. fz_link_key *key = (fz_link_key *)key_;
  706. memcpy(hash->u.link.dst_md5, key->dst_md5, 16);
  707. memcpy(hash->u.link.src_md5, key->src_md5, 16);
  708. hash->u.link.ri = key->rend.ri;
  709. hash->u.link.bp = key->rend.bp;
  710. hash->u.link.src_extras = key->src_extras;
  711. hash->u.link.dst_extras = key->dst_extras;
  712. hash->u.link.format = key->format;
  713. hash->u.link.proof = key->proof;
  714. hash->u.link.copy_spots = key->copy_spots;
  715. hash->u.link.bgr = key->bgr;
  716. return 1;
  717. }
  718. static fz_store_type fz_link_store_type =
  719. {
  720. "fz_icc_link",
  721. fz_make_hash_link_key,
  722. fz_keep_link_key,
  723. fz_drop_link_key,
  724. fz_cmp_link_key,
  725. fz_format_link_key,
  726. NULL
  727. };
  728. fz_icc_link *
  729. fz_find_icc_link(fz_context *ctx,
  730. fz_colorspace *src, int src_extras,
  731. fz_colorspace *dst, int dst_extras,
  732. fz_colorspace *prf,
  733. fz_color_params rend,
  734. int format,
  735. int copy_spots,
  736. int premult)
  737. {
  738. fz_icc_link *link, *old_link;
  739. fz_link_key key, *new_key;
  740. fz_var(link);
  741. /* Check the storable to see if we have a copy. */
  742. key.refs = 1;
  743. memcpy(&key.src_md5, src->u.icc.md5, 16);
  744. memcpy(&key.dst_md5, dst->u.icc.md5, 16);
  745. key.rend = rend;
  746. key.src_extras = src_extras;
  747. key.dst_extras = dst_extras;
  748. key.copy_spots = copy_spots;
  749. key.format = (format & 1) | (premult*2);
  750. key.proof = (prf != NULL);
  751. key.bgr = (dst->type == FZ_COLORSPACE_BGR);
  752. link = fz_find_item(ctx, fz_drop_icc_link_imp, &key, &fz_link_store_type);
  753. if (!link)
  754. {
  755. new_key = fz_malloc_struct(ctx, fz_link_key);
  756. memcpy(new_key, &key, sizeof (fz_link_key));
  757. fz_try(ctx)
  758. {
  759. link = fz_new_icc_link(ctx, src, src_extras, dst, dst_extras, prf, rend, format, copy_spots, premult);
  760. old_link = fz_store_item(ctx, new_key, link, 1000, &fz_link_store_type);
  761. if (old_link)
  762. {
  763. /* Found one while adding! Perhaps from another thread? */
  764. fz_drop_icc_link(ctx, link);
  765. link = old_link;
  766. }
  767. }
  768. fz_always(ctx)
  769. {
  770. fz_drop_link_key(ctx, new_key);
  771. }
  772. fz_catch(ctx)
  773. {
  774. fz_drop_icc_link(ctx, link);
  775. fz_rethrow(ctx);
  776. }
  777. }
  778. return link;
  779. }
  780. #endif
  781. /* Color conversions */
  782. static void indexed_via_base(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst)
  783. {
  784. fz_colorspace *ss = cc->ss_via;
  785. const unsigned char *lookup = ss->u.indexed.lookup;
  786. int high = ss->u.indexed.high;
  787. int n = ss->u.indexed.base->n;
  788. float base[4];
  789. int i, k;
  790. i = src[0] * 255;
  791. i = fz_clampi(i, 0, high);
  792. if (ss->u.indexed.base->type == FZ_COLORSPACE_LAB)
  793. {
  794. base[0] = lookup[i * 3 + 0] * 100 / 255.0f;
  795. base[1] = lookup[i * 3 + 1] - 128;
  796. base[2] = lookup[i * 3 + 2] - 128;
  797. }
  798. else
  799. {
  800. for (k = 0; k < n; ++k)
  801. base[k] = lookup[i * n + k] / 255.0f;
  802. }
  803. cc->convert_via(ctx, cc, base, dst);
  804. }
  805. static void separation_via_base(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst)
  806. {
  807. fz_colorspace *ss = cc->ss_via;
  808. float base[4];
  809. ss->u.separation.eval(ctx, ss->u.separation.tint, src, ss->n, base, ss->u.separation.base->n);
  810. cc->convert_via(ctx, cc, base, dst);
  811. }
  812. static void indexed_via_separation_via_base(fz_context *ctx, fz_color_converter *cc, const float *src, float *dst)
  813. {
  814. fz_colorspace *ss = cc->ss_via;
  815. fz_colorspace *ssep = cc->ss_via->u.indexed.base;
  816. const unsigned char *lookup = ss->u.indexed.lookup;
  817. int high = ss->u.indexed.high;
  818. int n = ss->u.indexed.base->n;
  819. float base[4], mid[FZ_MAX_COLORS];
  820. int i, k;
  821. /* First map through the index. */
  822. i = src[0] * 255;
  823. i = fz_clampi(i, 0, high);
  824. for (k = 0; k < n; ++k)
  825. mid[k] = lookup[i * n + k] / 255.0f;
  826. /* Then map through the separation. */
  827. ssep->u.separation.eval(ctx, ssep->u.separation.tint, mid, ssep->n, base, ssep->u.separation.base->n);
  828. /* Then convert in the base. */
  829. cc->convert_via(ctx, cc, base, dst);
  830. }
  831. static void
  832. fz_init_process_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_colorspace *is, fz_color_params params)
  833. {
  834. if (ss->type == FZ_COLORSPACE_INDEXED)
  835. fz_throw(ctx, FZ_ERROR_ARGUMENT, "base colorspace must not be indexed");
  836. if (ss->type == FZ_COLORSPACE_SEPARATION)
  837. fz_throw(ctx, FZ_ERROR_ARGUMENT, "base colorspace must not be separation");
  838. #if FZ_ENABLE_ICC
  839. if (ctx->icc_enabled)
  840. {
  841. /* Handle identity case. */
  842. if (ss == ds || (!memcmp(ss->u.icc.md5, ds->u.icc.md5, 16)))
  843. {
  844. cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
  845. return;
  846. }
  847. /* Handle DeviceGray to CMYK as K only. See note in Section 6.3 of PDF spec 1.7. */
  848. if (ss->type == FZ_COLORSPACE_GRAY && (ss->flags & FZ_COLORSPACE_IS_DEVICE))
  849. {
  850. if (ds->type == FZ_COLORSPACE_CMYK)
  851. {
  852. cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
  853. return;
  854. }
  855. }
  856. fz_try(ctx)
  857. {
  858. cc->link = fz_find_icc_link(ctx, ss, 0, ds, 0, is, params, 1, 0, 0);
  859. cc->convert = fz_icc_transform_color;
  860. }
  861. fz_catch(ctx)
  862. {
  863. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  864. fz_report_error(ctx);
  865. fz_warn(ctx, "cannot create ICC link, falling back to fast color conversion");
  866. cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
  867. }
  868. }
  869. else
  870. {
  871. cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
  872. }
  873. #else
  874. cc->convert = fz_lookup_fast_color_converter(ctx, ss, ds);
  875. #endif
  876. }
  877. void
  878. fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_separations *dseps, fz_colorspace *is, fz_color_params params)
  879. {
  880. cc->ds = ds;
  881. cc->dseps = NULL;
  882. cc->dst_n = ds->n;
  883. #if FZ_ENABLE_ICC
  884. cc->link = NULL;
  885. #endif
  886. if (ds->type == FZ_COLORSPACE_INDEXED)
  887. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot convert into Indexed colorspace.");
  888. if (ds->type == FZ_COLORSPACE_SEPARATION)
  889. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Cannot convert into Separation colorspace.");
  890. if (ss->type == FZ_COLORSPACE_INDEXED)
  891. {
  892. if (ss->u.indexed.base->type == FZ_COLORSPACE_SEPARATION)
  893. {
  894. cc->ss = ss->u.indexed.base->u.separation.base;
  895. cc->ss_via = ss;
  896. fz_init_process_color_converter(ctx, cc, cc->ss, ds, is, params);
  897. cc->convert_via = cc->convert;
  898. cc->convert = indexed_via_separation_via_base;
  899. }
  900. else
  901. {
  902. cc->ss = ss->u.indexed.base;
  903. cc->ss_via = ss;
  904. fz_init_process_color_converter(ctx, cc, cc->ss, ds, is, params);
  905. cc->convert_via = cc->convert;
  906. cc->convert = indexed_via_base;
  907. }
  908. }
  909. else if (ss->type == FZ_COLORSPACE_SEPARATION)
  910. {
  911. if (dseps &&
  912. fz_init_separation_copy_color_converter(ctx, cc, ss, ds, dseps, is, params))
  913. {
  914. /* We can just copy separations from ss to dseps */
  915. cc->dseps = dseps;
  916. cc->dst_n += fz_count_separations(ctx, dseps);
  917. }
  918. else
  919. {
  920. cc->ss = ss->u.separation.base;
  921. cc->ss_via = ss;
  922. fz_init_process_color_converter(ctx, cc, cc->ss, ds, is, params);
  923. cc->convert_via = cc->convert;
  924. cc->convert = separation_via_base;
  925. }
  926. }
  927. else
  928. {
  929. cc->ss = ss;
  930. fz_init_process_color_converter(ctx, cc, ss, ds, is, params);
  931. }
  932. }
  933. void
  934. fz_drop_color_converter(fz_context *ctx, fz_color_converter *cc)
  935. {
  936. #if FZ_ENABLE_ICC
  937. if (cc->link)
  938. {
  939. fz_drop_icc_link(ctx, cc->link);
  940. cc->link = NULL;
  941. }
  942. #endif
  943. }
  944. void
  945. fz_convert_color(fz_context *ctx, fz_colorspace *ss, const float *sv, fz_colorspace *ds, float *dv, fz_colorspace *is, fz_color_params params)
  946. {
  947. fz_color_converter cc;
  948. fz_find_color_converter(ctx, &cc, ss, ds, NULL, is, params);
  949. cc.convert(ctx, &cc, sv, dv);
  950. fz_drop_color_converter(ctx, &cc);
  951. }
  952. /* Cached color converter using hash table. */
  953. typedef struct fz_cached_color_converter
  954. {
  955. fz_color_converter base;
  956. fz_hash_table *hash;
  957. } fz_cached_color_converter;
  958. static void fz_cached_color_convert(fz_context *ctx, fz_color_converter *cc_, const float *ss, float *ds)
  959. {
  960. fz_cached_color_converter *cc = cc_->opaque;
  961. if (cc->hash)
  962. {
  963. float *val = fz_hash_find(ctx, cc->hash, ss);
  964. int n = cc->base.dst_n * sizeof(float);
  965. if (val)
  966. {
  967. memcpy(ds, val, n);
  968. return;
  969. }
  970. cc->base.convert(ctx, &cc->base, ss, ds);
  971. val = Memento_label(fz_malloc_array(ctx, cc->base.dst_n, float), "cached_color_convert");
  972. memcpy(val, ds, n);
  973. fz_try(ctx)
  974. fz_hash_insert(ctx, cc->hash, ss, val);
  975. fz_catch(ctx)
  976. {
  977. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  978. fz_report_error(ctx);
  979. fz_free(ctx, val);
  980. }
  981. }
  982. else
  983. {
  984. cc->base.convert(ctx, &cc->base, ss, ds);
  985. }
  986. }
  987. void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *ss, fz_colorspace *ds, fz_separations *dseps, fz_colorspace *is, fz_color_params params)
  988. {
  989. int n = ss->n;
  990. fz_cached_color_converter *cached = fz_malloc_struct(ctx, fz_cached_color_converter);
  991. cc->opaque = cached;
  992. cc->convert = fz_cached_color_convert;
  993. cc->ss = ss;
  994. cc->ds = ds;
  995. #if FZ_ENABLE_ICC
  996. cc->link = NULL;
  997. #endif
  998. fz_try(ctx)
  999. {
  1000. fz_find_color_converter(ctx, &cached->base, ss, ds, dseps, is, params);
  1001. if (n * sizeof(float) <= FZ_HASH_TABLE_KEY_LENGTH)
  1002. cached->hash = fz_new_hash_table(ctx, 256, n * sizeof(float), -1, fz_free);
  1003. else
  1004. fz_warn(ctx, "colorspace has too many components to be cached");
  1005. }
  1006. fz_catch(ctx)
  1007. {
  1008. fz_drop_color_converter(ctx, &cached->base);
  1009. fz_drop_hash_table(ctx, cached->hash);
  1010. fz_free(ctx, cached);
  1011. cc->opaque = NULL;
  1012. fz_rethrow(ctx);
  1013. }
  1014. }
  1015. void fz_fin_cached_color_converter(fz_context *ctx, fz_color_converter *cc_)
  1016. {
  1017. fz_cached_color_converter *cc;
  1018. if (cc_ == NULL)
  1019. return;
  1020. cc = cc_->opaque;
  1021. if (cc == NULL)
  1022. return;
  1023. cc_->opaque = NULL;
  1024. fz_drop_hash_table(ctx, cc->hash);
  1025. fz_drop_color_converter(ctx, &cc->base);
  1026. fz_free(ctx, cc);
  1027. }
  1028. /* Pixmap color conversion */
  1029. static inline void
  1030. template_convert_lab(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params, int sa, int da, int spots)
  1031. {
  1032. float srcv[FZ_MAX_COLORS];
  1033. float dstv[FZ_MAX_COLORS];
  1034. size_t w = src->w;
  1035. int h = src->h;
  1036. fz_colorspace *src_cs = src->colorspace;
  1037. fz_colorspace *dst_cs = dst->colorspace;
  1038. unsigned char *s = src->samples;
  1039. unsigned char *d = dst->samples;
  1040. int src_n = spots ? src->n : 3+sa;
  1041. int dst_c = dst->n - (spots ? dst->s : 0) - da;
  1042. int dst_n = dst->n;
  1043. fz_color_converter cc;
  1044. int alpha = 255;
  1045. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1046. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1047. int k;
  1048. fz_find_color_converter(ctx, &cc, src_cs, dst_cs, NULL, is, params);
  1049. while (h--)
  1050. {
  1051. size_t ww = w;
  1052. while (ww--)
  1053. {
  1054. if (sa)
  1055. {
  1056. alpha = s[4];
  1057. srcv[0] = fz_div255(s[0], alpha) / 255.0f * 100;
  1058. srcv[1] = fz_div255(s[1], alpha) - 128;
  1059. srcv[2] = fz_div255(s[2], alpha) - 128;
  1060. }
  1061. else
  1062. {
  1063. srcv[0] = s[0] / 255.0f * 100;
  1064. srcv[1] = s[1] - 128;
  1065. srcv[2] = s[2] - 128;
  1066. }
  1067. s += src_n;
  1068. cc.convert(ctx, &cc, srcv, dstv);
  1069. if (da)
  1070. {
  1071. for (k = 0; k < dst_c; k++)
  1072. *d++ = fz_mul255(dstv[k] * 255, alpha);
  1073. /* Just fill in spots as empty */
  1074. if (spots)
  1075. for (; k < dst_n; k++)
  1076. *d++ = 0;
  1077. *d++ = alpha;
  1078. }
  1079. else
  1080. {
  1081. for (k = 0; k < dst_c; k++)
  1082. *d++ = dstv[k] * 255;
  1083. if (spots)
  1084. for (; k < dst_n; k++)
  1085. *d++ = 0;
  1086. }
  1087. }
  1088. d += d_line_inc;
  1089. s += s_line_inc;
  1090. }
  1091. fz_drop_color_converter(ctx, &cc);
  1092. }
  1093. static void convert_lab(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1094. {
  1095. template_convert_lab(ctx, src, dst, is, params, 0, 0, 0);
  1096. }
  1097. static void convert_lab_sa(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1098. {
  1099. template_convert_lab(ctx, src, dst, is, params, 1, 0, 0);
  1100. }
  1101. static void convert_lab_da(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1102. {
  1103. template_convert_lab(ctx, src, dst, is, params, 0, 1, 0);
  1104. }
  1105. static void convert_lab_sa_da(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1106. {
  1107. template_convert_lab(ctx, src, dst, is, params, 1, 1, 0);
  1108. }
  1109. static void convert_lab_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1110. {
  1111. template_convert_lab(ctx, src, dst, is, params, 0, 0, 1);
  1112. }
  1113. static void convert_lab_sa_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1114. {
  1115. template_convert_lab(ctx, src, dst, is, params, 1, 0, 1);
  1116. }
  1117. static void convert_lab_da_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1118. {
  1119. template_convert_lab(ctx, src, dst, is, params, 0, 1, 1);
  1120. }
  1121. static void convert_lab_sa_da_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1122. {
  1123. template_convert_lab(ctx, src, dst, is, params, 1, 1, 1);
  1124. }
  1125. static inline void
  1126. template_brute_force(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params, int sa, int da, int spots)
  1127. {
  1128. float srcv[FZ_MAX_COLORS];
  1129. float dstv[FZ_MAX_COLORS];
  1130. size_t w = src->w;
  1131. int h = src->h;
  1132. fz_colorspace *src_cs = src->colorspace;
  1133. fz_colorspace *dst_cs = dst->colorspace;
  1134. unsigned char *s = src->samples;
  1135. unsigned char *d = dst->samples;
  1136. int src_c = src->n - (spots ? src->s : 0) - sa;
  1137. int src_n = src->n;
  1138. int dst_c = dst->n - (spots ? dst->s : 0) - da;
  1139. int dst_n = dst->n;
  1140. fz_color_converter cc;
  1141. int alpha = 255;
  1142. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1143. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1144. int k;
  1145. fz_find_color_converter(ctx, &cc, src_cs, dst_cs, NULL, is, params);
  1146. while (h--)
  1147. {
  1148. size_t ww = w;
  1149. while (ww--)
  1150. {
  1151. if (sa)
  1152. {
  1153. alpha = s[src_n];
  1154. for (k = 0; k < src_c; k++)
  1155. srcv[k] = fz_div255(s[k], alpha) / 255.0f;
  1156. }
  1157. else
  1158. {
  1159. for (k = 0; k < src_c; k++)
  1160. srcv[k] = s[k] / 255.0f;
  1161. }
  1162. s += src_n;
  1163. cc.convert(ctx, &cc, srcv, dstv);
  1164. if (da)
  1165. {
  1166. for (k = 0; k < dst_c; k++)
  1167. *d++ = fz_mul255(dstv[k] * 255, alpha);
  1168. if (spots)
  1169. for (; k < dst_n; k++)
  1170. *d++ = 0;
  1171. *d++ = alpha;
  1172. }
  1173. else
  1174. {
  1175. for (k = 0; k < dst_c; k++)
  1176. *d++ = dstv[k] * 255;
  1177. if (spots)
  1178. for (; k < dst_n; k++)
  1179. *d++ = 0;
  1180. }
  1181. }
  1182. d += d_line_inc;
  1183. s += s_line_inc;
  1184. }
  1185. fz_drop_color_converter(ctx, &cc);
  1186. }
  1187. static void brute_force(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1188. {
  1189. template_brute_force(ctx, src, dst, is, params, 0, 0, 0);
  1190. }
  1191. static void brute_force_sa(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1192. {
  1193. template_brute_force(ctx, src, dst, is, params, 1, 0, 0);
  1194. }
  1195. static void brute_force_da(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1196. {
  1197. template_brute_force(ctx, src, dst, is, params, 0, 1, 0);
  1198. }
  1199. static void brute_force_sa_da(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1200. {
  1201. template_brute_force(ctx, src, dst, is, params, 1, 1, 0);
  1202. }
  1203. static void brute_force_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1204. {
  1205. template_brute_force(ctx, src, dst, is, params, 0, 0, 1);
  1206. }
  1207. static void brute_force_sa_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1208. {
  1209. template_brute_force(ctx, src, dst, is, params, 1, 0, 1);
  1210. }
  1211. static void brute_force_da_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1212. {
  1213. template_brute_force(ctx, src, dst, is, params, 0, 1, 1);
  1214. }
  1215. static void brute_force_sa_da_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1216. {
  1217. template_brute_force(ctx, src, dst, is, params, 1, 1, 1);
  1218. }
  1219. static void
  1220. lookup_1d(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1221. {
  1222. float srcv[FZ_MAX_COLORS];
  1223. float dstv[FZ_MAX_COLORS];
  1224. size_t w = src->w;
  1225. int h = src->h;
  1226. fz_colorspace *src_cs = src->colorspace;
  1227. fz_colorspace *dst_cs = dst->colorspace;
  1228. unsigned char *s = src->samples;
  1229. unsigned char *d = dst->samples;
  1230. int sa = src->alpha;
  1231. int da = dst->alpha;
  1232. int dst_s = dst->s;
  1233. int dst_n = dst->n;
  1234. int dst_c = dst_n - dst_s - da;
  1235. fz_color_converter cc;
  1236. int alpha = 255;
  1237. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1238. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1239. int i, k;
  1240. unsigned char lookup[FZ_MAX_COLORS * 256];
  1241. fz_find_color_converter(ctx, &cc, src_cs, dst_cs, NULL, is, params);
  1242. for (i = 0; i < 256; i++)
  1243. {
  1244. srcv[0] = i / 255.0f;
  1245. cc.convert(ctx, &cc, srcv, dstv);
  1246. for (k = 0; k < dst_c; k++)
  1247. lookup[i * dst_c + k] = dstv[k] * 255;
  1248. }
  1249. fz_drop_color_converter(ctx, &cc);
  1250. while (h--)
  1251. {
  1252. size_t ww = w;
  1253. while (ww--)
  1254. {
  1255. if (sa)
  1256. {
  1257. alpha = s[1];
  1258. i = fz_div255(s[0], alpha);
  1259. s += 2;
  1260. }
  1261. else
  1262. {
  1263. i = *s++;
  1264. }
  1265. if (da)
  1266. {
  1267. for (k = 0; k < dst_c; k++)
  1268. *d++ = fz_mul255(lookup[i * dst_c + k], alpha);
  1269. for (; k < dst_n; k++)
  1270. *d++ = 0;
  1271. *d++ = alpha;
  1272. }
  1273. else
  1274. {
  1275. for (k = 0; k < dst_c; k++)
  1276. *d++ = lookup[i * dst_c + k];
  1277. for (; k < dst_n; k++)
  1278. *d++ = 0;
  1279. }
  1280. }
  1281. d += d_line_inc;
  1282. s += s_line_inc;
  1283. }
  1284. }
  1285. static void
  1286. memoize_nospots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1287. {
  1288. float srcv[FZ_MAX_COLORS];
  1289. float dstv[FZ_MAX_COLORS];
  1290. size_t w = src->w;
  1291. int h = src->h;
  1292. fz_colorspace *src_cs = src->colorspace;
  1293. fz_colorspace *dst_cs = dst->colorspace;
  1294. unsigned char *s = src->samples;
  1295. unsigned char *d = dst->samples;
  1296. int sa = src->alpha;
  1297. int src_s = src->s;
  1298. int src_n = src->n;
  1299. int src_c = src_n - src_s - sa;
  1300. int da = dst->alpha;
  1301. int dst_s = dst->s;
  1302. int dst_n = dst->n;
  1303. int dst_c = dst_n - dst_s - da;
  1304. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1305. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1306. int k;
  1307. fz_hash_table *lookup;
  1308. unsigned char *color;
  1309. unsigned char dummy = s[0] ^ 255;
  1310. unsigned char *sold = &dummy;
  1311. unsigned char *dold;
  1312. fz_color_converter cc;
  1313. int alpha = 255;
  1314. lookup = fz_new_hash_table(ctx, 509, src_n, -1, NULL);
  1315. fz_find_color_converter(ctx, &cc, src_cs, dst_cs, NULL, is, params);
  1316. fz_try(ctx)
  1317. {
  1318. while (h--)
  1319. {
  1320. size_t ww = w;
  1321. while (ww--)
  1322. {
  1323. if (*s == *sold && memcmp(sold, s, src_n) == 0)
  1324. {
  1325. sold = s;
  1326. memcpy(d, dold, dst_n);
  1327. }
  1328. else
  1329. {
  1330. sold = s;
  1331. dold = d;
  1332. color = fz_hash_find(ctx, lookup, s);
  1333. if (color)
  1334. {
  1335. memcpy(d, color, dst_n);
  1336. }
  1337. else
  1338. {
  1339. if (sa)
  1340. {
  1341. alpha = s[src_c];
  1342. for (k = 0; k < src_c; k++)
  1343. srcv[k] = fz_div255(s[k], alpha) / 255.0f;
  1344. }
  1345. else
  1346. {
  1347. for (k = 0; k < src_c; k++)
  1348. srcv[k] = s[k] / 255.0f;
  1349. }
  1350. cc.convert(ctx, &cc, srcv, dstv);
  1351. if (da)
  1352. {
  1353. for (k = 0; k < dst_c; k++)
  1354. d[k] = fz_mul255(dstv[k] * 255, alpha);
  1355. d[k] = alpha;
  1356. }
  1357. else
  1358. {
  1359. for (k = 0; k < dst_c; k++)
  1360. d[k] = dstv[k] * 255;
  1361. }
  1362. fz_hash_insert(ctx, lookup, s, d);
  1363. }
  1364. }
  1365. s += src_n;
  1366. d += dst_n;
  1367. }
  1368. d += d_line_inc;
  1369. s += s_line_inc;
  1370. }
  1371. }
  1372. fz_always(ctx)
  1373. {
  1374. fz_drop_color_converter(ctx, &cc);
  1375. fz_drop_hash_table(ctx, lookup);
  1376. }
  1377. fz_catch(ctx)
  1378. fz_rethrow(ctx);
  1379. }
  1380. static void
  1381. memoize_spots(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params)
  1382. {
  1383. float srcv[FZ_MAX_COLORS];
  1384. float dstv[FZ_MAX_COLORS];
  1385. size_t w = src->w;
  1386. int h = src->h;
  1387. fz_colorspace *src_cs = src->colorspace;
  1388. fz_colorspace *dst_cs = dst->colorspace;
  1389. unsigned char *s = src->samples;
  1390. unsigned char *d = dst->samples;
  1391. int sa = src->alpha;
  1392. int src_s = src->s;
  1393. int src_n = src->n;
  1394. int src_c = src_n - src_s - sa;
  1395. int src_m = src_c + sa;
  1396. int da = dst->alpha;
  1397. int dst_s = dst->s;
  1398. int dst_n = dst->n;
  1399. int dst_c = dst_n - dst_s - da;
  1400. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1401. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1402. int k;
  1403. fz_hash_table *lookup;
  1404. unsigned char *color;
  1405. unsigned char sold[FZ_MAX_COLORS];
  1406. unsigned char dold[FZ_MAX_COLORS];
  1407. fz_color_converter cc;
  1408. int alpha = 255;
  1409. sold[0] = s[0] ^ 255;
  1410. lookup = fz_new_hash_table(ctx, 509, src_m, -1, NULL);
  1411. fz_find_color_converter(ctx, &cc, src_cs, dst_cs, NULL, is, params);
  1412. fz_try(ctx)
  1413. {
  1414. while (h--)
  1415. {
  1416. size_t ww = w;
  1417. while (ww--)
  1418. {
  1419. if (*s == *sold && memcmp(sold, s, src_m) == 0)
  1420. {
  1421. memcpy(d, dold, dst_c);
  1422. if (dst_s)
  1423. memset(d + dst_c, 0, dst_s);
  1424. if (da)
  1425. d[dst_n-1] = sold[src_m];
  1426. }
  1427. else
  1428. {
  1429. memcpy(sold, s, src_m);
  1430. if (sa)
  1431. sold[src_m] = s[src_n-1];
  1432. color = fz_hash_find(ctx, lookup, sold);
  1433. if (color)
  1434. {
  1435. memcpy(d, color, dst_n);
  1436. }
  1437. else
  1438. {
  1439. if (sa)
  1440. {
  1441. alpha = s[src_c];
  1442. for (k = 0; k < src_c; k++)
  1443. srcv[k] = fz_div255(s[k], alpha) / 255.0f;
  1444. }
  1445. else
  1446. {
  1447. for (k = 0; k < src_c; k++)
  1448. srcv[k] = s[k] / 255.0f;
  1449. }
  1450. cc.convert(ctx, &cc, srcv, dstv);
  1451. if (da)
  1452. {
  1453. for (k = 0; k < dst_c; k++)
  1454. d[k] = fz_mul255(dstv[k] * 255, alpha);
  1455. if (dst_s)
  1456. memset(d + dst_c, 0, dst_s);
  1457. dold[dst_c] = d[dst_n-1] = alpha;
  1458. }
  1459. else
  1460. {
  1461. for (k = 0; k < dst_c; k++)
  1462. d[k] = dstv[k] * 255;
  1463. if (dst_s)
  1464. memset(d + dst_c, 0, dst_s);
  1465. }
  1466. memcpy(dold, d, dst_c);
  1467. fz_hash_insert(ctx, lookup, sold, dold);
  1468. }
  1469. }
  1470. s += src_n;
  1471. d += dst_n;
  1472. }
  1473. d += d_line_inc;
  1474. s += s_line_inc;
  1475. }
  1476. }
  1477. fz_always(ctx)
  1478. {
  1479. fz_drop_color_converter(ctx, &cc);
  1480. fz_drop_hash_table(ctx, lookup);
  1481. }
  1482. fz_catch(ctx)
  1483. fz_rethrow(ctx);
  1484. }
  1485. void
  1486. fz_convert_slow_pixmap_samples(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst, fz_colorspace *is, fz_color_params params, int copy_spots)
  1487. {
  1488. int sa = src->alpha;
  1489. int src_s = src->s;
  1490. int src_c = src->n - src_s - sa;
  1491. int da = dst->alpha;
  1492. int dst_s = dst->s;
  1493. size_t w = src->w;
  1494. int h = src->h;
  1495. ptrdiff_t d_line_inc = dst->stride - w * dst->n;
  1496. ptrdiff_t s_line_inc = src->stride - w * src->n;
  1497. fz_colorspace *ss = src->colorspace;
  1498. if ((int)w < 0 || h < 0)
  1499. return;
  1500. assert(src->w == dst->w && src->h == dst->h);
  1501. if (d_line_inc == 0 && s_line_inc == 0)
  1502. {
  1503. w *= h;
  1504. h = 1;
  1505. }
  1506. if (src_s != 0 || dst_s != 0)
  1507. {
  1508. fz_warn(ctx, "Spots dropped during pixmap conversion");
  1509. }
  1510. /* Special case for Lab colorspace (scaling of components to float) */
  1511. if (ss->type == FZ_COLORSPACE_LAB)
  1512. {
  1513. if (src_s == 0 && dst_s == 0)
  1514. {
  1515. if (sa)
  1516. {
  1517. if (da)
  1518. convert_lab_sa_da(ctx, src, dst, is, params);
  1519. else
  1520. convert_lab_sa(ctx, src, dst, is, params);
  1521. }
  1522. else
  1523. {
  1524. if (da)
  1525. convert_lab_da(ctx, src, dst, is, params);
  1526. else
  1527. convert_lab(ctx, src, dst, is, params);
  1528. }
  1529. }
  1530. else
  1531. {
  1532. if (sa)
  1533. {
  1534. if (da)
  1535. convert_lab_sa_da_spots(ctx, src, dst, is, params);
  1536. else
  1537. convert_lab_sa_spots(ctx, src, dst, is, params);
  1538. }
  1539. else
  1540. {
  1541. if (da)
  1542. convert_lab_da_spots(ctx, src, dst, is, params);
  1543. else
  1544. convert_lab_spots(ctx, src, dst, is, params);
  1545. }
  1546. }
  1547. }
  1548. /* Brute-force for small images */
  1549. else if (w*h < 256)
  1550. {
  1551. if (src_s == 0 && dst_s == 0)
  1552. {
  1553. if (sa)
  1554. {
  1555. if (da)
  1556. brute_force_sa_da(ctx, src, dst, is, params);
  1557. else
  1558. brute_force_sa(ctx, src, dst, is, params);
  1559. }
  1560. else
  1561. {
  1562. if (da)
  1563. brute_force_da(ctx, src, dst, is, params);
  1564. else
  1565. brute_force(ctx, src, dst, is, params);
  1566. }
  1567. }
  1568. else
  1569. {
  1570. if (sa)
  1571. {
  1572. if (da)
  1573. brute_force_sa_da_spots(ctx, src, dst, is, params);
  1574. else
  1575. brute_force_sa_spots(ctx, src, dst, is, params);
  1576. }
  1577. else
  1578. {
  1579. if (da)
  1580. brute_force_da_spots(ctx, src, dst, is, params);
  1581. else
  1582. brute_force_spots(ctx, src, dst, is, params);
  1583. }
  1584. }
  1585. }
  1586. /* 1-d lookup table for single channel colorspaces */
  1587. else if (src_c == 1)
  1588. {
  1589. lookup_1d(ctx, src, dst, is, params);
  1590. }
  1591. /* Memoize colors using a hash table for the general case */
  1592. else
  1593. {
  1594. if (src_s == 0 && dst_s == 0)
  1595. memoize_nospots(ctx, src, dst, is, params);
  1596. else
  1597. memoize_spots(ctx, src, dst, is, params);
  1598. }
  1599. }
  1600. void
  1601. fz_convert_pixmap_samples(fz_context *ctx, const fz_pixmap *src, fz_pixmap *dst,
  1602. fz_colorspace *prf,
  1603. const fz_default_colorspaces *default_cs,
  1604. fz_color_params params,
  1605. int copy_spots)
  1606. {
  1607. #if FZ_ENABLE_ICC
  1608. fz_colorspace *ss = src->colorspace;
  1609. fz_colorspace *ds = dst->colorspace;
  1610. fz_pixmap *base_idx = NULL;
  1611. fz_pixmap *base_sep = NULL;
  1612. fz_icc_link *link = NULL;
  1613. fz_var(link);
  1614. fz_var(base_idx);
  1615. fz_var(base_sep);
  1616. if (!ds)
  1617. {
  1618. fz_fast_any_to_alpha(ctx, src, dst, copy_spots);
  1619. return;
  1620. }
  1621. fz_try(ctx)
  1622. {
  1623. /* Treat any alpha-only pixmap as being device gray here. */
  1624. if (!ss)
  1625. ss = fz_device_gray(ctx);
  1626. /* Convert indexed into base colorspace. */
  1627. if (ss->type == FZ_COLORSPACE_INDEXED)
  1628. {
  1629. src = base_idx = fz_convert_indexed_pixmap_to_base(ctx, src);
  1630. ss = src->colorspace;
  1631. }
  1632. /* Convert separation into base colorspace. */
  1633. if (ss->type == FZ_COLORSPACE_SEPARATION)
  1634. {
  1635. src = base_sep = fz_convert_separation_pixmap_to_base(ctx, src);
  1636. ss = src->colorspace;
  1637. }
  1638. /* Substitute Device colorspace with page Default colorspace: */
  1639. if (ss->flags & FZ_COLORSPACE_IS_DEVICE)
  1640. {
  1641. switch (ss->type)
  1642. {
  1643. default: break;
  1644. case FZ_COLORSPACE_GRAY: ss = fz_default_gray(ctx, default_cs); break;
  1645. case FZ_COLORSPACE_RGB: ss = fz_default_rgb(ctx, default_cs); break;
  1646. case FZ_COLORSPACE_CMYK: ss = fz_default_cmyk(ctx, default_cs); break;
  1647. }
  1648. }
  1649. if (!ctx->icc_enabled)
  1650. {
  1651. fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
  1652. }
  1653. /* Handle identity case. */
  1654. else if (ss == ds || (!memcmp(ss->u.icc.md5, ds->u.icc.md5, 16)))
  1655. {
  1656. fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
  1657. }
  1658. /* Handle DeviceGray to CMYK as K only. See note in Section 6.3 of PDF spec 1.7. */
  1659. else if ((ss->flags & FZ_COLORSPACE_IS_DEVICE) &&
  1660. (ss->type == FZ_COLORSPACE_GRAY) &&
  1661. (ds->type == FZ_COLORSPACE_CMYK))
  1662. {
  1663. fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
  1664. }
  1665. /* Use slow conversion path for indexed. */
  1666. else if (ss->type == FZ_COLORSPACE_INDEXED)
  1667. {
  1668. fz_convert_slow_pixmap_samples(ctx, src, dst, prf, params, copy_spots);
  1669. }
  1670. /* Use slow conversion path for separation. */
  1671. else if (ss->type == FZ_COLORSPACE_SEPARATION)
  1672. {
  1673. fz_convert_slow_pixmap_samples(ctx, src, dst, prf, params, copy_spots);
  1674. }
  1675. else
  1676. {
  1677. fz_try(ctx)
  1678. {
  1679. int sx = src->s + src->alpha;
  1680. int dx = dst->s + dst->alpha;
  1681. /* If there are no spots to copy, we might as well copy spots! */
  1682. int effectively_copying_spots = copy_spots || (src->s == 0 && dst->s == 0);
  1683. /* If we have alpha, we're preserving spots and we have the same number
  1684. * of 'extra' (non process, spots+alpha) channels (i.e. sx == dx), then
  1685. * we get lcms2 to do the premultiplication handling for us. If not,
  1686. * fz_icc_transform_pixmap will have to do it by steam. */
  1687. int premult = src->alpha && (sx == dx) && effectively_copying_spots;
  1688. link = fz_find_icc_link(ctx, ss, sx, ds, dx, prf, params, 0, effectively_copying_spots, premult);
  1689. fz_icc_transform_pixmap(ctx, link, src, dst, effectively_copying_spots);
  1690. }
  1691. fz_catch(ctx)
  1692. {
  1693. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  1694. fz_report_error(ctx);
  1695. fz_warn(ctx, "falling back to fast color conversion");
  1696. fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
  1697. }
  1698. }
  1699. }
  1700. fz_always(ctx)
  1701. {
  1702. fz_drop_icc_link(ctx, link);
  1703. fz_drop_pixmap(ctx, base_sep);
  1704. fz_drop_pixmap(ctx, base_idx);
  1705. }
  1706. fz_catch(ctx)
  1707. fz_rethrow(ctx);
  1708. #else
  1709. fz_convert_fast_pixmap_samples(ctx, src, dst, copy_spots);
  1710. #endif
  1711. }
  1712. void fz_colorspace_digest(fz_context *ctx, fz_colorspace *cs, unsigned char digest[16])
  1713. {
  1714. #if FZ_ENABLE_ICC
  1715. if (!fz_colorspace_is_icc(ctx, cs))
  1716. fz_throw(ctx, FZ_ERROR_ARGUMENT, "must have icc profile for colorspace digest");
  1717. memcpy(digest, cs->u.icc.md5, 16);
  1718. #else
  1719. fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "ICC support disabled");
  1720. #endif
  1721. }