pdf-shade-recolor.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  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 "mupdf/pdf.h"
  24. #include <string.h>
  25. #include <math.h>
  26. #include <float.h>
  27. typedef struct
  28. {
  29. void *opaque;
  30. pdf_recolor_vertex *recolor;
  31. fz_colorspace *dst_cs;
  32. fz_colorspace *src_cs;
  33. int funcs;
  34. } recolor_details;
  35. #define FUNSEGS 64 /* size of sampled mesh for function-based shadings */
  36. #define FUNBPS 8 /* Bits per sample in output functions */
  37. static void
  38. fz_recolor_shade_type1(fz_context *ctx, pdf_obj *shade, pdf_function **func, recolor_details *rd)
  39. {
  40. float x0 = 0;
  41. float y0 = 0;
  42. float x1 = 1;
  43. float y1 = 1;
  44. float in[FZ_MAX_COLORS] = { 0 };
  45. float out[(FUNSEGS+1)*(FUNSEGS+1)*FZ_MAX_COLORS];
  46. float *p;
  47. float fv[2];
  48. int xx, yy;
  49. pdf_obj *obj;
  50. int n_in = rd->src_cs->n;
  51. int n_out = rd->dst_cs->n;
  52. pdf_obj *fun_obj = NULL;
  53. float range[FZ_MAX_COLORS];
  54. int i;
  55. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  56. pdf_obj *ref = NULL;
  57. fz_buffer *buf = NULL;
  58. fz_output *output = NULL;
  59. obj = pdf_dict_get(ctx, shade, PDF_NAME(Domain));
  60. if (obj)
  61. {
  62. x0 = pdf_array_get_real(ctx, obj, 0);
  63. x1 = pdf_array_get_real(ctx, obj, 1);
  64. y0 = pdf_array_get_real(ctx, obj, 2);
  65. y1 = pdf_array_get_real(ctx, obj, 3);
  66. }
  67. if (rd->funcs != 1 && rd->funcs != n_in)
  68. {
  69. fz_throw(ctx, FZ_ERROR_SYNTAX, "Unexpected function-arity.");
  70. }
  71. /* Sample the function, rewriting it. */
  72. for (i = 0; i < n_out; i++)
  73. {
  74. range[2 * i] = FLT_MAX;
  75. range[2 * i + 1] = -FLT_MAX;
  76. }
  77. p = out;
  78. for (yy = 0; yy <= FUNSEGS; yy++)
  79. {
  80. fv[1] = y0 + (y1 - y0) * yy / FUNSEGS;
  81. for (xx = 0; xx <= FUNSEGS; xx++)
  82. {
  83. fv[0] = x0 + (x1 - x0) * xx / FUNSEGS;
  84. if (rd->funcs == 1)
  85. pdf_eval_function(ctx, func[0], fv, 2, in, n_in);
  86. else
  87. {
  88. int zz;
  89. for (zz = 0; zz < n_in; zz++)
  90. pdf_eval_function(ctx, func[zz], fv, 2, &in[zz], 1);
  91. }
  92. rd->recolor(ctx, rd->opaque, rd->dst_cs, p, rd->src_cs, in);
  93. for (i = 0; i < n_out; i++)
  94. {
  95. if (range[2 * i] > p[i])
  96. range[2 * i] = p[i];
  97. if (range[2 * i + 1] < p[i])
  98. range[2 * i + 1] = p[i];
  99. }
  100. p += n_out;
  101. }
  102. }
  103. /* Now write the function out again. */
  104. fun_obj = pdf_new_dict(ctx, doc, 3);
  105. pdf_dict_put_int(ctx, fun_obj, PDF_NAME(FunctionType), 0);
  106. /* Domain */
  107. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Domain), 4);
  108. pdf_array_push_real(ctx, obj, x0);
  109. pdf_array_push_real(ctx, obj, x1);
  110. pdf_array_push_real(ctx, obj, y0);
  111. pdf_array_push_real(ctx, obj, y1);
  112. /* Range */
  113. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Range), 4);
  114. for (i = 0; i < 2*n_out; i++)
  115. pdf_array_push_real(ctx, obj, range[i]);
  116. /* Size */
  117. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Size), 2);
  118. pdf_array_push_int(ctx, obj, FUNSEGS+1);
  119. pdf_array_push_int(ctx, obj, FUNSEGS+1);
  120. /* BitsPerSample */
  121. pdf_dict_put_int(ctx, fun_obj, PDF_NAME(BitsPerSample), FUNBPS);
  122. buf = fz_new_buffer(ctx, 1);
  123. output = fz_new_output_with_buffer(ctx, buf);
  124. p = out;
  125. for (yy = 0; yy <= FUNSEGS; yy++)
  126. {
  127. for (xx = 0; xx <= FUNSEGS; xx++)
  128. {
  129. for (i = 0; i < n_out; i++)
  130. {
  131. float v = p[i];
  132. float d = range[2 * i + 1] - range[2 * i];
  133. int iv;
  134. v -= range[2 * i];
  135. if (d != 0)
  136. v = v * ((1<<FUNBPS)-1) / d;
  137. iv = (int)(v + 0.5f);
  138. fz_write_bits(ctx, output, iv, FUNBPS);
  139. }
  140. p += n_out;
  141. }
  142. }
  143. fz_write_bits_sync(ctx, output);
  144. fz_close_output(ctx, output);
  145. fz_drop_output(ctx, output);
  146. ref = pdf_add_object(ctx, doc, fun_obj);
  147. pdf_update_stream(ctx, doc, ref, buf, 0);
  148. fz_drop_buffer(ctx, buf);
  149. pdf_dict_put(ctx, shade, PDF_NAME(Function), ref);
  150. }
  151. static void
  152. fz_recolor_shade_function(fz_context *ctx, pdf_obj *shade, float *samples, int stride, recolor_details *rd)
  153. {
  154. int i;
  155. int n_in = fz_colorspace_n(ctx, rd->src_cs);
  156. int n_out = fz_colorspace_n(ctx, rd->dst_cs);
  157. float localp[256*FZ_MAX_COLORS];
  158. float *q = localp;
  159. float p[FZ_MAX_COLORS];
  160. pdf_obj *fun_obj = NULL;
  161. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  162. pdf_obj *obj;
  163. float t0 = 0;
  164. float t1 = 1;
  165. float range[FZ_MAX_COLORS];
  166. pdf_obj *ref = NULL;
  167. fz_buffer *buf = NULL;
  168. fz_output *output = NULL;
  169. int t;
  170. obj = pdf_dict_get(ctx, shade, PDF_NAME(Domain));
  171. if (obj)
  172. {
  173. t0 = pdf_array_get_real(ctx, obj, 0);
  174. t1 = pdf_array_get_real(ctx, obj, 1);
  175. }
  176. for (i = 0; i < n_out; i++)
  177. {
  178. range[2 * i] = FLT_MAX;
  179. range[2 * i + 1] = -FLT_MAX;
  180. }
  181. for (t = 0; t < 256; t++)
  182. {
  183. for (i = 0; i < n_in; i++)
  184. p[i] = samples[t*stride+i];
  185. rd->recolor(ctx, rd->opaque, rd->dst_cs, q, rd->src_cs, p);
  186. for (i = 0; i < n_out; i++)
  187. {
  188. if (range[2 * i] > q[i])
  189. range[2 * i] = q[i];
  190. if (range[2 * i + 1] < q[i])
  191. range[2 * i + 1] = q[i];
  192. }
  193. q += n_out;
  194. }
  195. fz_var(ref);
  196. fz_var(output);
  197. /* Now write the function out again. */
  198. fun_obj = pdf_new_dict(ctx, doc, 3);
  199. fz_try(ctx)
  200. {
  201. pdf_dict_put_int(ctx, fun_obj, PDF_NAME(FunctionType), 0);
  202. /* Domain */
  203. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Domain), 2);
  204. pdf_array_push_real(ctx, obj, t0);
  205. pdf_array_push_real(ctx, obj, t1);
  206. /* Range */
  207. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Range), 2 * n_out);
  208. for (i = 0; i < 2 * n_out; i++)
  209. pdf_array_push_real(ctx, obj, range[i]);
  210. obj = pdf_dict_put_array(ctx, fun_obj, PDF_NAME(Size), 1);
  211. pdf_array_push_int(ctx, obj, 256);
  212. pdf_dict_put_int(ctx, fun_obj, PDF_NAME(BitsPerSample), FUNBPS);
  213. buf = fz_new_buffer(ctx, 1);
  214. output = fz_new_output_with_buffer(ctx, buf);
  215. q = localp;
  216. for (t = 0; t < 256; t++)
  217. {
  218. for (i = 0; i < n_out; i++)
  219. {
  220. float v = q[i];
  221. float d = range[2 * i + 1] - range[2 * i];
  222. int iv;
  223. v -= range[2 * i];
  224. if (d != 0)
  225. v = v * ((1<<FUNBPS)-1) / d;
  226. iv = (int)(v + 0.5f);
  227. fz_write_bits(ctx, output, iv, FUNBPS);
  228. }
  229. q += n_out;
  230. }
  231. fz_write_bits_sync(ctx, output);
  232. fz_close_output(ctx, output);
  233. ref = pdf_add_object(ctx, doc, fun_obj);
  234. pdf_update_stream(ctx, doc, ref, buf, 0);
  235. pdf_dict_put(ctx, shade, PDF_NAME(Function), ref);
  236. }
  237. fz_always(ctx)
  238. {
  239. fz_drop_output(ctx, output);
  240. fz_drop_buffer(ctx, buf);
  241. pdf_drop_obj(ctx, fun_obj);
  242. pdf_drop_obj(ctx, ref);
  243. }
  244. fz_catch(ctx)
  245. fz_rethrow(ctx);
  246. }
  247. static inline float read_sample(fz_context *ctx, fz_stream *stream, int bits, float min, float max)
  248. {
  249. /* we use pow(2,x) because (1<<x) would overflow the math on 32-bit samples */
  250. float bitscale = 1 / (powf(2, bits) - 1);
  251. return min + fz_read_bits(ctx, stream, bits) * (max - min) * bitscale;
  252. }
  253. static inline void write_sample(fz_context *ctx, fz_output *out, int bits, float min, float max, float val)
  254. {
  255. /* we use pow(2,x) because (1<<x) would overflow the math on 32-bit samples */
  256. float bitscale = (powf(2, bits) - 1);
  257. if (val < min)
  258. val = min;
  259. else if (val > max)
  260. val = max;
  261. val -= min;
  262. if (max != min)
  263. val /= (max - min);
  264. /* Now 0 <= val <= 1 */
  265. fz_write_bits(ctx, out, (int)(val * bitscale), bits);
  266. }
  267. typedef struct
  268. {
  269. float *p;
  270. int len;
  271. int max;
  272. int pos;
  273. } float_queue;
  274. static void
  275. float_queue_push(fz_context *ctx, float_queue *p, float f)
  276. {
  277. if (p->len == p->max)
  278. {
  279. int new_max = p->max * 2;
  280. if (new_max == 0)
  281. new_max = 32;
  282. p->p = fz_realloc(ctx, p->p, sizeof(float) * new_max);
  283. p->max = new_max;
  284. }
  285. p->p[p->len++] = f;
  286. }
  287. static float
  288. float_queue_pop(fz_context *ctx, float_queue *p)
  289. {
  290. return p->p[p->pos++];
  291. }
  292. static void
  293. float_queue_drop(fz_context *ctx, float_queue *p)
  294. {
  295. fz_free(ctx, p->p);
  296. }
  297. static void
  298. read_decode(fz_context *ctx, pdf_obj *shade, int n_in, float *c_min, float *c_max, int n_out, float *d_min, float *d_max)
  299. {
  300. int i;
  301. pdf_obj *obj = pdf_dict_get(ctx, shade, PDF_NAME(Decode));
  302. for (i = 0; i < n_in; i++)
  303. {
  304. c_min[i] = pdf_array_get_int(ctx, obj, 2 * i + 4);
  305. c_max[i] = pdf_array_get_int(ctx, obj, 2 * i + 5);
  306. }
  307. for (i = 0; i < n_out; i++)
  308. {
  309. d_min[i] = FLT_MAX;
  310. d_max[i] = -FLT_MAX;
  311. }
  312. }
  313. static void
  314. rewrite_decode(fz_context *ctx, pdf_obj *shade, int n_out, float *d_min, float *d_max)
  315. {
  316. int i;
  317. pdf_obj *obj = pdf_keep_obj(ctx, pdf_dict_get(ctx, shade, PDF_NAME(Decode)));
  318. pdf_obj *obj2;
  319. fz_try(ctx)
  320. {
  321. obj2 = pdf_dict_put_array(ctx, shade, PDF_NAME(Decode), 4);
  322. for (i = 0; i < 4; i++)
  323. {
  324. pdf_array_push(ctx, obj2, pdf_array_get(ctx, obj, i));
  325. }
  326. for (i = 0; i < n_out; i++)
  327. {
  328. pdf_array_push_real(ctx, obj2, d_min[i]);
  329. pdf_array_push_real(ctx, obj2, d_max[i]);
  330. }
  331. }
  332. fz_always(ctx)
  333. pdf_drop_obj(ctx, obj);
  334. fz_catch(ctx)
  335. fz_rethrow(ctx);
  336. }
  337. static void
  338. fz_recolor_shade_type4(fz_context *ctx, pdf_obj *shade, recolor_details *rd)
  339. {
  340. fz_stream *stream;
  341. int i, n_in = rd->src_cs->n;
  342. int n_out = rd->dst_cs->n;
  343. int bpflag = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerFlag));
  344. int bpcoord = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerCoordinate));
  345. int bpcomp = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerComponent));
  346. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  347. float c[FZ_MAX_COLORS];
  348. float d[FZ_MAX_COLORS];
  349. float c_min[FZ_MAX_COLORS];
  350. float c_max[FZ_MAX_COLORS];
  351. float d_min[FZ_MAX_COLORS];
  352. float d_max[FZ_MAX_COLORS];
  353. fz_buffer *outbuf = NULL;
  354. fz_output *out = NULL;
  355. float_queue fq = { 0 };
  356. fz_var(outbuf);
  357. fz_var(out);
  358. fz_var(stream);
  359. read_decode(ctx, shade, n_in, c_min, c_max, n_out, d_min, d_max);
  360. stream = pdf_open_stream(ctx, shade);
  361. fz_try(ctx)
  362. {
  363. while (!fz_is_eof_bits(ctx, stream))
  364. {
  365. /* flag */ (void)fz_read_bits(ctx, stream, bpflag);
  366. /* x_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  367. /* y_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  368. for (i = 0; i < n_in; i++)
  369. c[i] = read_sample(ctx, stream, bpcomp, c_min[i], c_max[i]);
  370. rd->recolor(ctx, rd->opaque, rd->dst_cs, d, rd->src_cs, c);
  371. for (i = 0; i < n_out; i++)
  372. {
  373. if (d[i] < d_min[i])
  374. d_min[i] = d[i];
  375. if (d[i] > d_max[i])
  376. d_max[i] = d[i];
  377. float_queue_push(ctx, &fq, d[i]);
  378. }
  379. }
  380. fz_drop_stream(ctx, stream);
  381. stream = NULL;
  382. rewrite_decode(ctx, shade, n_out, d_min, d_max);
  383. stream = pdf_open_stream(ctx, shade);
  384. outbuf = fz_new_buffer(ctx, 1);
  385. out = fz_new_output_with_buffer(ctx, outbuf);
  386. while (!fz_is_eof_bits(ctx, stream))
  387. {
  388. unsigned int flag = fz_read_bits(ctx, stream, bpflag);
  389. unsigned int x_bits = fz_read_bits(ctx, stream, bpcoord);
  390. unsigned int y_bits = fz_read_bits(ctx, stream, bpcoord);
  391. for (i = 0; i < n_in; i++)
  392. (void)fz_read_bits(ctx, stream, bpcomp);
  393. fz_write_bits(ctx, out, flag, bpflag);
  394. fz_write_bits(ctx, out, x_bits, bpcoord);
  395. fz_write_bits(ctx, out, y_bits, bpcoord);
  396. for (i = 0; i < n_out; i++)
  397. {
  398. float f = float_queue_pop(ctx, &fq);
  399. write_sample(ctx, out, 8, d_min[i], d_max[i], f);
  400. }
  401. }
  402. fz_write_bits_sync(ctx, out);
  403. fz_close_output(ctx, out);
  404. pdf_dict_put_int(ctx, shade, PDF_NAME(BitsPerComponent), 8);
  405. pdf_update_stream(ctx, doc, shade, outbuf, 0);
  406. }
  407. fz_always(ctx)
  408. {
  409. float_queue_drop(ctx, &fq);
  410. fz_drop_stream(ctx, stream);
  411. fz_drop_output(ctx, out);
  412. fz_drop_buffer(ctx, outbuf);
  413. }
  414. fz_catch(ctx)
  415. {
  416. fz_rethrow(ctx);
  417. }
  418. }
  419. static void
  420. fz_recolor_shade_type5(fz_context *ctx, pdf_obj *shade, recolor_details *rd)
  421. {
  422. fz_stream *stream;
  423. int i, k, n_in = rd->src_cs->n;
  424. int n_out = rd->dst_cs->n;
  425. int bpcoord = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerCoordinate));
  426. int bpcomp = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerComponent));
  427. int vprow = pdf_dict_get_int(ctx, shade, PDF_NAME(VerticesPerRow));
  428. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  429. float c[FZ_MAX_COLORS];
  430. float d[FZ_MAX_COLORS];
  431. float c_min[FZ_MAX_COLORS];
  432. float c_max[FZ_MAX_COLORS];
  433. float d_min[FZ_MAX_COLORS];
  434. float d_max[FZ_MAX_COLORS];
  435. fz_buffer *outbuf = NULL;
  436. fz_output *out = NULL;
  437. float_queue fq = { 0 };
  438. fz_var(outbuf);
  439. fz_var(out);
  440. fz_var(stream);
  441. read_decode(ctx, shade, n_in, c_min, c_max, n_out, d_min, d_max);
  442. stream = pdf_open_stream(ctx, shade);
  443. fz_try(ctx)
  444. {
  445. while (!fz_is_eof_bits(ctx, stream))
  446. {
  447. for (i = 0; i < vprow; i++)
  448. {
  449. /* x_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  450. /* y_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  451. for (k = 0; k < n_in; k++)
  452. c[k] = read_sample(ctx, stream, bpcomp, c_min[k], c_max[k]);
  453. rd->recolor(ctx, rd->opaque, rd->dst_cs, d, rd->src_cs, c);
  454. for (k = 0; k < n_out; k++)
  455. {
  456. if (d[k] < d_min[k])
  457. d_min[k] = d[k];
  458. if (d[k] > d_max[k])
  459. d_max[k] = d[k];
  460. float_queue_push(ctx, &fq, d[k]);
  461. }
  462. }
  463. }
  464. fz_drop_stream(ctx, stream);
  465. stream = NULL;
  466. rewrite_decode(ctx, shade, n_out, d_min, d_max);
  467. stream = pdf_open_stream(ctx, shade);
  468. outbuf = fz_new_buffer(ctx, 1);
  469. out = fz_new_output_with_buffer(ctx, outbuf);
  470. while (!fz_is_eof_bits(ctx, stream))
  471. {
  472. for (i = 0; i < vprow; i++)
  473. {
  474. unsigned int x_bits = fz_read_bits(ctx, stream, bpcoord);
  475. unsigned int y_bits = fz_read_bits(ctx, stream, bpcoord);
  476. for (k = 0; k < n_in; k++)
  477. (void)fz_read_bits(ctx, stream, bpcomp);
  478. fz_write_bits(ctx, out, x_bits, bpcoord);
  479. fz_write_bits(ctx, out, y_bits, bpcoord);
  480. for (k = 0; k < n_out; k++)
  481. {
  482. float f = float_queue_pop(ctx, &fq);
  483. write_sample(ctx, out, 8, d_min[k], d_max[k], f);
  484. }
  485. }
  486. }
  487. fz_write_bits_sync(ctx, out);
  488. fz_close_output(ctx, out);
  489. pdf_dict_put_int(ctx, shade, PDF_NAME(BitsPerComponent), 8);
  490. pdf_update_stream(ctx, doc, shade, outbuf, 0);
  491. }
  492. fz_always(ctx)
  493. {
  494. float_queue_drop(ctx, &fq);
  495. fz_drop_stream(ctx, stream);
  496. fz_drop_output(ctx, out);
  497. fz_drop_buffer(ctx, outbuf);
  498. }
  499. fz_catch(ctx)
  500. {
  501. fz_rethrow(ctx);
  502. }
  503. }
  504. static void
  505. fz_recolor_shade_type6(fz_context *ctx, pdf_obj *shade, recolor_details *rd)
  506. {
  507. fz_stream *stream;
  508. int i, k, n_in = rd->src_cs->n;
  509. int n_out = rd->dst_cs->n;
  510. int bpflag = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerFlag));
  511. int bpcoord = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerCoordinate));
  512. int bpcomp = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerComponent));
  513. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  514. float c[FZ_MAX_COLORS];
  515. float d[FZ_MAX_COLORS];
  516. float c_min[FZ_MAX_COLORS];
  517. float c_max[FZ_MAX_COLORS];
  518. float d_min[FZ_MAX_COLORS];
  519. float d_max[FZ_MAX_COLORS];
  520. fz_buffer *outbuf = NULL;
  521. fz_output *out = NULL;
  522. float_queue fq = { 0 };
  523. fz_var(outbuf);
  524. fz_var(out);
  525. fz_var(stream);
  526. read_decode(ctx, shade, n_in, c_min, c_max, n_out, d_min, d_max);
  527. stream = pdf_open_stream(ctx, shade);
  528. fz_try(ctx)
  529. {
  530. while (!fz_is_eof_bits(ctx, stream))
  531. {
  532. int startcolor;
  533. int startpt;
  534. int flag = fz_read_bits(ctx, stream, bpflag);
  535. if (flag == 0)
  536. {
  537. startpt = 0;
  538. startcolor = 0;
  539. }
  540. else
  541. {
  542. startpt = 4;
  543. startcolor = 2;
  544. }
  545. for (i = startpt; i < 12; i++)
  546. {
  547. unsigned int x_bits = fz_read_bits(ctx, stream, bpcoord);
  548. unsigned int y_bits = fz_read_bits(ctx, stream, bpcoord);
  549. fz_write_bits(ctx, out, x_bits, bpcoord);
  550. fz_write_bits(ctx, out, y_bits, bpcoord);
  551. }
  552. for (i = startcolor; i < 4; i++)
  553. {
  554. for (k = 0; k < n_in; k++)
  555. c[k] = read_sample(ctx, stream, bpcomp, c_min[k], c_max[k]);
  556. rd->recolor(ctx, rd->opaque, rd->dst_cs, d, rd->src_cs, c);
  557. for (k = 0; k < n_out; k++)
  558. {
  559. if (d[k] < d_min[k])
  560. d_min[k] = d[k];
  561. if (d[k] > d_max[k])
  562. d_max[k] = d[k];
  563. float_queue_push(ctx, &fq, d[k]);
  564. }
  565. }
  566. }
  567. fz_drop_stream(ctx, stream);
  568. stream = NULL;
  569. rewrite_decode(ctx, shade, n_out, d_min, d_max);
  570. stream = pdf_open_stream(ctx, shade);
  571. outbuf = fz_new_buffer(ctx, 1);
  572. out = fz_new_output_with_buffer(ctx, outbuf);
  573. while (!fz_is_eof_bits(ctx, stream))
  574. {
  575. int startcolor;
  576. int startpt;
  577. int flag = fz_read_bits(ctx, stream, bpflag);
  578. fz_write_bits(ctx, out, flag, bpflag);
  579. if (flag == 0)
  580. {
  581. startpt = 0;
  582. startcolor = 0;
  583. }
  584. else
  585. {
  586. startpt = 4;
  587. startcolor = 2;
  588. }
  589. for (i = startpt; i < 12; i++)
  590. {
  591. unsigned int x_bits = fz_read_bits(ctx, stream, bpcoord);
  592. unsigned int y_bits = fz_read_bits(ctx, stream, bpcoord);
  593. fz_write_bits(ctx, out, x_bits, bpcoord);
  594. fz_write_bits(ctx, out, y_bits, bpcoord);
  595. }
  596. for (i = startcolor; i < 4; i++)
  597. {
  598. for (k = 0; k < n_in; k++)
  599. (void)fz_read_bits(ctx, stream, bpcomp);
  600. for (k = 0; k < n_out; k++)
  601. {
  602. float f = float_queue_pop(ctx, &fq);
  603. write_sample(ctx, out, 8, d_min[k], d_max[k], f);
  604. }
  605. }
  606. }
  607. fz_write_bits_sync(ctx, out);
  608. fz_close_output(ctx, out);
  609. pdf_dict_put_int(ctx, shade, PDF_NAME(BitsPerComponent), 8);
  610. pdf_update_stream(ctx, doc, shade, outbuf, 0);
  611. }
  612. fz_always(ctx)
  613. {
  614. float_queue_drop(ctx, &fq);
  615. fz_drop_stream(ctx, stream);
  616. fz_drop_output(ctx, out);
  617. fz_drop_buffer(ctx, outbuf);
  618. }
  619. fz_catch(ctx)
  620. {
  621. fz_rethrow(ctx);
  622. }
  623. }
  624. static void
  625. fz_recolor_shade_type7(fz_context *ctx, pdf_obj *shade, recolor_details *rd)
  626. {
  627. fz_stream *stream;
  628. int i, k, n_in = rd->src_cs->n;
  629. int n_out = rd->dst_cs->n;
  630. int bpflag = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerFlag));
  631. int bpcoord = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerCoordinate));
  632. int bpcomp = pdf_dict_get_int(ctx, shade, PDF_NAME(BitsPerComponent));
  633. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  634. float c[FZ_MAX_COLORS];
  635. float d[FZ_MAX_COLORS];
  636. float c_min[FZ_MAX_COLORS];
  637. float c_max[FZ_MAX_COLORS];
  638. float d_min[FZ_MAX_COLORS];
  639. float d_max[FZ_MAX_COLORS];
  640. fz_buffer *outbuf = NULL;
  641. fz_output *out = NULL;
  642. float_queue fq = { 0 };
  643. fz_var(outbuf);
  644. fz_var(out);
  645. fz_var(stream);
  646. read_decode(ctx, shade, n_in, c_min, c_max, n_out, d_min, d_max);
  647. stream = pdf_open_stream(ctx, shade);
  648. fz_try(ctx)
  649. {
  650. while (!fz_is_eof_bits(ctx, stream))
  651. {
  652. int startcolor;
  653. int startpt;
  654. int flag = fz_read_bits(ctx, stream, bpflag);
  655. if (flag == 0)
  656. {
  657. startpt = 0;
  658. startcolor = 0;
  659. }
  660. else
  661. {
  662. startpt = 4;
  663. startcolor = 2;
  664. }
  665. for (i = startpt; i < 16; i++)
  666. {
  667. /* x_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  668. /* y_bits */ (void)fz_read_bits(ctx, stream, bpcoord);
  669. }
  670. for (i = startcolor; i < 4; i++)
  671. {
  672. for (k = 0; k < n_in; k++)
  673. c[k] = read_sample(ctx, stream, bpcomp, c_min[k], c_max[k]);
  674. rd->recolor(ctx, rd->opaque, rd->dst_cs, d, rd->src_cs, c);
  675. for (k = 0; k < n_out; k++)
  676. {
  677. if (d[k] < d_min[k])
  678. d_min[k] = d[k];
  679. if (d[k] > d_max[k])
  680. d_max[k] = d[k];
  681. float_queue_push(ctx, &fq, d[k]);
  682. }
  683. }
  684. }
  685. fz_drop_stream(ctx, stream);
  686. stream = NULL;
  687. rewrite_decode(ctx, shade, n_out, d_min, d_max);
  688. stream = pdf_open_stream(ctx, shade);
  689. outbuf = fz_new_buffer(ctx, 1);
  690. out = fz_new_output_with_buffer(ctx, outbuf);
  691. while (!fz_is_eof_bits(ctx, stream))
  692. {
  693. int startcolor;
  694. int startpt;
  695. int flag = fz_read_bits(ctx, stream, bpflag);
  696. fz_write_bits(ctx, out, flag, bpflag);
  697. if (flag == 0)
  698. {
  699. startpt = 0;
  700. startcolor = 0;
  701. }
  702. else
  703. {
  704. startpt = 4;
  705. startcolor = 2;
  706. }
  707. for (i = startpt; i < 16; i++)
  708. {
  709. unsigned int x_bits = fz_read_bits(ctx, stream, bpcoord);
  710. unsigned int y_bits = fz_read_bits(ctx, stream, bpcoord);
  711. fz_write_bits(ctx, out, x_bits, bpcoord);
  712. fz_write_bits(ctx, out, y_bits, bpcoord);
  713. }
  714. for (i = startcolor; i < 4; i++)
  715. {
  716. for (k = 0; k < n_in; k++)
  717. (void)fz_read_bits(ctx, stream, bpcomp);
  718. for (k = 0; k < n_out; k++)
  719. {
  720. float f = float_queue_pop(ctx, &fq);
  721. write_sample(ctx, out, 8, d_min[k], d_max[k], f);
  722. }
  723. }
  724. }
  725. fz_write_bits_sync(ctx, out);
  726. fz_close_output(ctx, out);
  727. pdf_dict_put_int(ctx, shade, PDF_NAME(BitsPerComponent), 8);
  728. pdf_update_stream(ctx, doc, shade, outbuf, 0);
  729. }
  730. fz_always(ctx)
  731. {
  732. float_queue_drop(ctx, &fq);
  733. fz_drop_stream(ctx, stream);
  734. fz_drop_output(ctx, out);
  735. fz_drop_buffer(ctx, outbuf);
  736. }
  737. fz_catch(ctx)
  738. {
  739. fz_rethrow(ctx);
  740. }
  741. }
  742. pdf_obj *
  743. pdf_new_colorspace(fz_context *ctx, fz_colorspace *cs)
  744. {
  745. switch (fz_colorspace_type(ctx, cs))
  746. {
  747. case FZ_COLORSPACE_GRAY:
  748. return PDF_NAME(DeviceGray);
  749. case FZ_COLORSPACE_RGB:
  750. return PDF_NAME(DeviceRGB);
  751. case FZ_COLORSPACE_CMYK:
  752. return PDF_NAME(DeviceCMYK);
  753. default:
  754. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unimplemented colorspace");
  755. }
  756. }
  757. pdf_obj *
  758. pdf_recolor_shade(fz_context *ctx, pdf_obj *shade, pdf_shade_recolorer *reshade, void *opaque)
  759. {
  760. recolor_details rd;
  761. fz_colorspace *src_cs;
  762. pdf_obj *background, *new_bg = NULL;
  763. pdf_obj *function;
  764. pdf_obj *rewritten = NULL;
  765. pdf_obj *obj;
  766. int type, i;
  767. pdf_function *func[FZ_MAX_COLORS] = { NULL };
  768. float d0, d1;
  769. float samples[256*(FZ_MAX_COLORS + 1)];
  770. pdf_document *doc = pdf_get_bound_document(ctx, shade);
  771. src_cs = pdf_load_colorspace(ctx, pdf_dict_get(ctx, shade, PDF_NAME(ColorSpace)));
  772. fz_var(rewritten);
  773. rd.funcs = 0;
  774. fz_try(ctx)
  775. {
  776. rd.recolor = reshade(ctx, opaque, src_cs, &rd.dst_cs);
  777. if (rd.recolor == NULL)
  778. break;
  779. rd.src_cs = src_cs;
  780. rd.opaque = opaque;
  781. rewritten = pdf_deep_copy_obj(ctx, shade);
  782. type = pdf_dict_get_int(ctx, shade, PDF_NAME(ShadingType));
  783. pdf_dict_put_drop(ctx, rewritten, PDF_NAME(ColorSpace), pdf_new_colorspace(ctx, rd.dst_cs));
  784. background = pdf_dict_get(ctx, shade, PDF_NAME(Background));
  785. if (background)
  786. {
  787. int n = pdf_array_len(ctx, background);
  788. float bg[FZ_MAX_COLORS];
  789. float nbg[FZ_MAX_COLORS];
  790. if (n > FZ_MAX_COLORS)
  791. fz_throw(ctx, FZ_ERROR_SYNTAX, "Too many background components");
  792. if (n != src_cs->n)
  793. fz_throw(ctx, FZ_ERROR_SYNTAX, "Wrong background dimension");
  794. for (i = 0; i < n; i++)
  795. bg[i] = pdf_array_get_real(ctx, background, i);
  796. rd.recolor(ctx, rd.opaque, rd.dst_cs, nbg, src_cs, bg);
  797. new_bg = pdf_dict_put_array(ctx, rewritten, PDF_NAME(Background), rd.dst_cs->n);
  798. for (i = 0; i < n; i++)
  799. pdf_array_put_real(ctx, new_bg, i, bg[i]);
  800. pdf_dict_put(ctx, rewritten, PDF_NAME(Background), new_bg);
  801. }
  802. d0 = 0;
  803. d1 = 1;
  804. obj = pdf_dict_get(ctx, shade, PDF_NAME(Domain));
  805. if (obj)
  806. {
  807. d0 = pdf_array_get_real(ctx, obj, 0);
  808. d1 = pdf_array_get_real(ctx, obj, 1);
  809. }
  810. function = pdf_dict_get(ctx, shade, PDF_NAME(Function));
  811. if (pdf_is_dict(ctx, function))
  812. {
  813. rd.funcs = 1;
  814. func[0] = pdf_load_function(ctx, function, type == 1 ? 2 : 1, src_cs->n);
  815. if (!func[0])
  816. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  817. if (type != 1)
  818. pdf_sample_shade_function(ctx, samples, src_cs->n, 1, func, d0, d1);
  819. }
  820. else if (pdf_is_array(ctx, function))
  821. {
  822. int in;
  823. rd.funcs = pdf_array_len(ctx, function);
  824. if (rd.funcs != 1 && rd.funcs != src_cs->n)
  825. fz_throw(ctx, FZ_ERROR_SYNTAX, "incorrect number of shading functions");
  826. if (rd.funcs > FZ_MAX_COLORS)
  827. fz_throw(ctx, FZ_ERROR_SYNTAX, "too many shading functions");
  828. if (type == 1)
  829. in = 2;
  830. else
  831. in = 1;
  832. for (i = 0; i < rd.funcs; i++)
  833. {
  834. func[i] = pdf_load_function(ctx, pdf_array_get(ctx, function, i), in, 1);
  835. if (!func[i])
  836. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  837. }
  838. if (type != 1)
  839. pdf_sample_shade_function(ctx, samples, src_cs->n, rd.funcs, func, d0, d1);
  840. }
  841. else if (type < 4)
  842. {
  843. /* Functions are compulsory for types 1,2,3 */
  844. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  845. }
  846. /* For function based shadings, we rewrite the 2d function. */
  847. if (type == 1)
  848. {
  849. fz_recolor_shade_type1(ctx, rewritten, func, &rd);
  850. break;
  851. }
  852. /* For all other function based shadings, we just rewrite the 1d function. */
  853. if (rd.funcs)
  854. {
  855. fz_recolor_shade_function(ctx, rewritten, samples, src_cs->n+1, &rd);
  856. break;
  857. }
  858. /* From here on in, we're changing the mesh, which means altering a stream.
  859. * We'll need to be an indirect for that to work. */
  860. obj = pdf_add_object(ctx, doc, rewritten);
  861. pdf_drop_obj(ctx, rewritten);
  862. rewritten = obj;
  863. switch (type)
  864. {
  865. case FZ_FUNCTION_BASED:
  866. /* Can never reach here. */
  867. break;
  868. case FZ_LINEAR:
  869. case FZ_RADIAL:
  870. fz_throw(ctx, FZ_ERROR_SYNTAX, "Linear/Radial shadings must use functions");
  871. break;
  872. case FZ_MESH_TYPE4:
  873. fz_recolor_shade_type4(ctx, rewritten, &rd);
  874. break;
  875. case FZ_MESH_TYPE5:
  876. fz_recolor_shade_type5(ctx, rewritten, &rd);
  877. break;
  878. case FZ_MESH_TYPE6:
  879. fz_recolor_shade_type6(ctx, rewritten, &rd);
  880. break;
  881. case FZ_MESH_TYPE7:
  882. fz_recolor_shade_type7(ctx, rewritten, &rd);
  883. break;
  884. default:
  885. fz_throw(ctx, FZ_ERROR_SYNTAX, "Unexpected mesh type %d\n", type);
  886. }
  887. }
  888. fz_always(ctx)
  889. {
  890. for (i = 0; i < rd.funcs; i++)
  891. pdf_drop_function(ctx, func[i]);
  892. fz_drop_colorspace(ctx, src_cs);
  893. }
  894. fz_catch(ctx)
  895. {
  896. pdf_drop_obj(ctx, rewritten);
  897. fz_rethrow(ctx);
  898. }
  899. return rewritten ? rewritten : shade;
  900. }