pdf-shade.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. // Copyright (C) 2004-2021 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. /* Sample various functions into lookup tables */
  25. static void
  26. pdf_sample_composite_shade_function(fz_context *ctx, float *shade, int n, pdf_function *func, float t0, float t1)
  27. {
  28. int i;
  29. float t;
  30. for (i = 0; i < 256; i++)
  31. {
  32. t = t0 + (i / 255.0f) * (t1 - t0);
  33. pdf_eval_function(ctx, func, &t, 1, shade, n);
  34. shade += n;
  35. *shade++ = 1;
  36. }
  37. }
  38. static void
  39. pdf_sample_component_shade_function(fz_context *ctx, float *shade, int funcs, pdf_function **func, float t0, float t1)
  40. {
  41. int i, k;
  42. float t;
  43. for (i = 0; i < 256; i++)
  44. {
  45. t = t0 + (i / 255.0f) * (t1 - t0);
  46. for (k = 0; k < funcs; k++)
  47. pdf_eval_function(ctx, func[k], &t, 1, shade++, 1);
  48. *shade++ = 1;
  49. }
  50. }
  51. void
  52. pdf_sample_shade_function(fz_context *ctx, float *samples, int n, int funcs, pdf_function **func, float t0, float t1)
  53. {
  54. if (funcs == 1)
  55. pdf_sample_composite_shade_function(ctx, samples, n, func[0], t0, t1);
  56. else
  57. pdf_sample_component_shade_function(ctx, samples, funcs, func, t0, t1);
  58. }
  59. static void
  60. make_sampled_shade_function(fz_context *ctx, fz_shade *shade, int funcs, pdf_function **func, float t0, float t1)
  61. {
  62. int n = shade->colorspace->n;
  63. if (funcs != 1)
  64. n = funcs;
  65. shade->function_stride = n + 1;
  66. shade->function = Memento_label(fz_malloc(ctx, sizeof(float) * 256 * shade->function_stride), "shade samples");
  67. pdf_sample_shade_function(ctx, shade->function, n, funcs, func, t0, t1);
  68. }
  69. /* Type 1-3 -- Function-based, linear and radial shadings */
  70. #define FUNSEGS 64 /* size of sampled mesh for function-based shadings */
  71. static void
  72. pdf_load_function_based_shading(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  73. {
  74. pdf_obj *obj;
  75. float x0, y0, x1, y1;
  76. float fv[2];
  77. int xx, yy, zz;
  78. float *p;
  79. int n = fz_colorspace_n(ctx, shade->colorspace);
  80. x0 = y0 = 0;
  81. x1 = y1 = 1;
  82. obj = pdf_dict_get(ctx, dict, PDF_NAME(Domain));
  83. if (obj)
  84. {
  85. x0 = pdf_array_get_real(ctx, obj, 0);
  86. x1 = pdf_array_get_real(ctx, obj, 1);
  87. y0 = pdf_array_get_real(ctx, obj, 2);
  88. y1 = pdf_array_get_real(ctx, obj, 3);
  89. }
  90. shade->u.f.matrix = pdf_dict_get_matrix(ctx, dict, PDF_NAME(Matrix));
  91. shade->u.f.xdivs = FUNSEGS;
  92. shade->u.f.ydivs = FUNSEGS;
  93. shade->u.f.fn_vals = Memento_label(fz_malloc(ctx, (FUNSEGS+1)*(FUNSEGS+1)*n*sizeof(float)), "shade_fn_vals");
  94. shade->u.f.domain[0][0] = x0;
  95. shade->u.f.domain[0][1] = y0;
  96. shade->u.f.domain[1][0] = x1;
  97. shade->u.f.domain[1][1] = y1;
  98. p = shade->u.f.fn_vals;
  99. if (funcs == 1)
  100. {
  101. for (yy = 0; yy <= FUNSEGS; yy++)
  102. {
  103. fv[1] = y0 + (y1 - y0) * yy / FUNSEGS;
  104. for (xx = 0; xx <= FUNSEGS; xx++)
  105. {
  106. fv[0] = x0 + (x1 - x0) * xx / FUNSEGS;
  107. pdf_eval_function(ctx, func[0], fv, 2, p, n);
  108. p += n;
  109. }
  110. }
  111. }
  112. else
  113. {
  114. if (funcs != n)
  115. fz_throw(ctx, FZ_ERROR_SYNTAX, "Expected 1 2in, n-out function, or n 2 in, 1-out functions");
  116. for (yy = 0; yy <= FUNSEGS; yy++)
  117. {
  118. fv[1] = y0 + (y1 - y0) * yy / FUNSEGS;
  119. for (xx = 0; xx <= FUNSEGS; xx++)
  120. {
  121. fv[0] = x0 + (x1 - x0) * xx / FUNSEGS;
  122. for (zz = 0; zz < n; zz++)
  123. {
  124. pdf_eval_function(ctx, func[zz], fv, 2, p, 1);
  125. p ++;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. static void
  132. pdf_load_linear_shading(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  133. {
  134. pdf_obj *obj;
  135. float d0, d1;
  136. int e0, e1;
  137. obj = pdf_dict_get(ctx, dict, PDF_NAME(Coords));
  138. shade->u.l_or_r.coords[0][0] = pdf_array_get_real(ctx, obj, 0);
  139. shade->u.l_or_r.coords[0][1] = pdf_array_get_real(ctx, obj, 1);
  140. shade->u.l_or_r.coords[1][0] = pdf_array_get_real(ctx, obj, 2);
  141. shade->u.l_or_r.coords[1][1] = pdf_array_get_real(ctx, obj, 3);
  142. d0 = 0;
  143. d1 = 1;
  144. obj = pdf_dict_get(ctx, dict, PDF_NAME(Domain));
  145. if (obj)
  146. {
  147. d0 = pdf_array_get_real(ctx, obj, 0);
  148. d1 = pdf_array_get_real(ctx, obj, 1);
  149. }
  150. e0 = e1 = 0;
  151. obj = pdf_dict_get(ctx, dict, PDF_NAME(Extend));
  152. if (obj)
  153. {
  154. e0 = pdf_array_get_bool(ctx, obj, 0);
  155. e1 = pdf_array_get_bool(ctx, obj, 1);
  156. }
  157. make_sampled_shade_function(ctx, shade, funcs, func, d0, d1);
  158. shade->u.l_or_r.extend[0] = e0;
  159. shade->u.l_or_r.extend[1] = e1;
  160. }
  161. static void
  162. pdf_load_radial_shading(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  163. {
  164. pdf_obj *obj;
  165. float d0, d1;
  166. int e0, e1;
  167. obj = pdf_dict_get(ctx, dict, PDF_NAME(Coords));
  168. shade->u.l_or_r.coords[0][0] = pdf_array_get_real(ctx, obj, 0);
  169. shade->u.l_or_r.coords[0][1] = pdf_array_get_real(ctx, obj, 1);
  170. shade->u.l_or_r.coords[0][2] = pdf_array_get_real(ctx, obj, 2);
  171. shade->u.l_or_r.coords[1][0] = pdf_array_get_real(ctx, obj, 3);
  172. shade->u.l_or_r.coords[1][1] = pdf_array_get_real(ctx, obj, 4);
  173. shade->u.l_or_r.coords[1][2] = pdf_array_get_real(ctx, obj, 5);
  174. d0 = 0;
  175. d1 = 1;
  176. obj = pdf_dict_get(ctx, dict, PDF_NAME(Domain));
  177. if (obj)
  178. {
  179. d0 = pdf_array_get_real(ctx, obj, 0);
  180. d1 = pdf_array_get_real(ctx, obj, 1);
  181. }
  182. e0 = e1 = 0;
  183. obj = pdf_dict_get(ctx, dict, PDF_NAME(Extend));
  184. if (obj)
  185. {
  186. e0 = pdf_array_get_bool(ctx, obj, 0);
  187. e1 = pdf_array_get_bool(ctx, obj, 1);
  188. }
  189. make_sampled_shade_function(ctx, shade, funcs, func, d0, d1);
  190. shade->u.l_or_r.extend[0] = e0;
  191. shade->u.l_or_r.extend[1] = e1;
  192. }
  193. /* Type 4-7 -- Triangle and patch mesh shadings */
  194. struct mesh_params
  195. {
  196. int vprow;
  197. int bpflag;
  198. int bpcoord;
  199. int bpcomp;
  200. float x0, x1;
  201. float y0, y1;
  202. float c0[FZ_MAX_COLORS];
  203. float c1[FZ_MAX_COLORS];
  204. };
  205. static void
  206. pdf_load_mesh_params(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict)
  207. {
  208. pdf_obj *obj;
  209. int i, n;
  210. shade->u.m.x0 = shade->u.m.y0 = 0;
  211. shade->u.m.x1 = shade->u.m.y1 = 1;
  212. for (i = 0; i < FZ_MAX_COLORS; i++)
  213. {
  214. shade->u.m.c0[i] = 0;
  215. shade->u.m.c1[i] = 1;
  216. }
  217. shade->u.m.vprow = pdf_dict_get_int(ctx, dict, PDF_NAME(VerticesPerRow));
  218. shade->u.m.bpflag = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerFlag));
  219. shade->u.m.bpcoord = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerCoordinate));
  220. shade->u.m.bpcomp = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerComponent));
  221. obj = pdf_dict_get(ctx, dict, PDF_NAME(Decode));
  222. if (pdf_array_len(ctx, obj) >= 6)
  223. {
  224. n = fz_mini(FZ_MAX_COLORS, (pdf_array_len(ctx, obj) - 4) / 2);
  225. shade->u.m.x0 = pdf_array_get_real(ctx, obj, 0);
  226. shade->u.m.x1 = pdf_array_get_real(ctx, obj, 1);
  227. shade->u.m.y0 = pdf_array_get_real(ctx, obj, 2);
  228. shade->u.m.y1 = pdf_array_get_real(ctx, obj, 3);
  229. for (i = 0; i < n; i++)
  230. {
  231. shade->u.m.c0[i] = pdf_array_get_real(ctx, obj, 4 + i * 2);
  232. shade->u.m.c1[i] = pdf_array_get_real(ctx, obj, 5 + i * 2);
  233. }
  234. }
  235. if (shade->u.m.vprow < 2 && shade->type == 5)
  236. {
  237. fz_warn(ctx, "Too few vertices per row (%d)", shade->u.m.vprow);
  238. shade->u.m.vprow = 2;
  239. }
  240. if (shade->u.m.bpflag != 2 && shade->u.m.bpflag != 4 && shade->u.m.bpflag != 8 &&
  241. shade->type != 5)
  242. {
  243. fz_warn(ctx, "Invalid number of bits per flag (%d)", shade->u.m.bpflag);
  244. shade->u.m.bpflag = 8;
  245. }
  246. if (shade->u.m.bpcoord != 1 && shade->u.m.bpcoord != 2 && shade->u.m.bpcoord != 4 &&
  247. shade->u.m.bpcoord != 8 && shade->u.m.bpcoord != 12 && shade->u.m.bpcoord != 16 &&
  248. shade->u.m.bpcoord != 24 && shade->u.m.bpcoord != 32)
  249. {
  250. fz_warn(ctx, "Invalid number of bits per coordinate (%d)", shade->u.m.bpcoord);
  251. shade->u.m.bpcoord = 8;
  252. }
  253. if (shade->u.m.bpcomp != 1 && shade->u.m.bpcomp != 2 && shade->u.m.bpcomp != 4 &&
  254. shade->u.m.bpcomp != 8 && shade->u.m.bpcomp != 12 && shade->u.m.bpcomp != 16)
  255. {
  256. fz_warn(ctx, "Invalid number of bits per component (%d)", shade->u.m.bpcomp);
  257. shade->u.m.bpcomp = 8;
  258. }
  259. }
  260. static void
  261. pdf_load_type4_shade(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  262. {
  263. pdf_load_mesh_params(ctx, doc, shade, dict);
  264. if (funcs > 0)
  265. make_sampled_shade_function(ctx, shade, funcs, func, shade->u.m.c0[0], shade->u.m.c1[0]);
  266. shade->buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), 0);
  267. }
  268. static void
  269. pdf_load_type5_shade(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  270. {
  271. pdf_load_mesh_params(ctx, doc, shade, dict);
  272. if (funcs > 0)
  273. make_sampled_shade_function(ctx, shade, funcs, func, shade->u.m.c0[0], shade->u.m.c1[0]);
  274. shade->buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), 0);
  275. }
  276. /* Type 6 & 7 -- Patch mesh shadings */
  277. static void
  278. pdf_load_type6_shade(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  279. {
  280. pdf_load_mesh_params(ctx, doc, shade, dict);
  281. if (funcs > 0)
  282. make_sampled_shade_function(ctx, shade, funcs, func, shade->u.m.c0[0], shade->u.m.c1[0]);
  283. shade->buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), 0);
  284. }
  285. static void
  286. pdf_load_type7_shade(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict, int funcs, pdf_function **func)
  287. {
  288. pdf_load_mesh_params(ctx, doc, shade, dict);
  289. if (funcs > 0)
  290. make_sampled_shade_function(ctx, shade, funcs, func, shade->u.m.c0[0], shade->u.m.c1[0]);
  291. shade->buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), 0);
  292. }
  293. /* Load all of the shading dictionary parameters, then switch on the shading type. */
  294. static fz_shade *
  295. pdf_load_shading_dict(fz_context *ctx, pdf_document *doc, pdf_obj *dict, fz_matrix transform)
  296. {
  297. fz_shade *shade = NULL;
  298. pdf_function *func[FZ_MAX_COLORS] = { NULL };
  299. pdf_obj *obj;
  300. int funcs = 0;
  301. int type = 0;
  302. int i, in, out, n;
  303. fz_var(shade);
  304. fz_var(func);
  305. fz_var(funcs);
  306. fz_var(type);
  307. fz_try(ctx)
  308. {
  309. shade = fz_malloc_struct(ctx, fz_shade);
  310. FZ_INIT_STORABLE(shade, 1, fz_drop_shade_imp);
  311. shade->type = FZ_MESH_TYPE4;
  312. shade->use_background = 0;
  313. shade->function_stride = 0;
  314. shade->matrix = transform;
  315. shade->bbox = fz_infinite_rect;
  316. shade->colorspace = NULL;
  317. funcs = 0;
  318. obj = pdf_dict_get(ctx, dict, PDF_NAME(ShadingType));
  319. type = pdf_to_int(ctx, obj);
  320. obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace));
  321. if (!obj)
  322. fz_throw(ctx, FZ_ERROR_SYNTAX, "shading colorspace is missing");
  323. shade->colorspace = pdf_load_colorspace(ctx, obj);
  324. n = fz_colorspace_n(ctx, shade->colorspace);
  325. obj = pdf_dict_get(ctx, dict, PDF_NAME(Background));
  326. if (obj)
  327. {
  328. shade->use_background = 1;
  329. for (i = 0; i < n; i++)
  330. shade->background[i] = pdf_array_get_real(ctx, obj, i);
  331. }
  332. obj = pdf_dict_get(ctx, dict, PDF_NAME(BBox));
  333. if (pdf_is_array(ctx, obj))
  334. shade->bbox = pdf_to_rect(ctx, obj);
  335. obj = pdf_dict_get(ctx, dict, PDF_NAME(Function));
  336. if (pdf_is_dict(ctx, obj))
  337. {
  338. funcs = 1;
  339. if (type == 1)
  340. in = 2;
  341. else
  342. in = 1;
  343. out = n;
  344. func[0] = pdf_load_function(ctx, obj, in, out);
  345. if (!func[0])
  346. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  347. }
  348. else if (pdf_is_array(ctx, obj))
  349. {
  350. funcs = pdf_array_len(ctx, obj);
  351. if (funcs != 1 && funcs != n)
  352. {
  353. funcs = 0;
  354. fz_throw(ctx, FZ_ERROR_SYNTAX, "incorrect number of shading functions");
  355. }
  356. if (funcs > FZ_MAX_COLORS)
  357. {
  358. funcs = 0;
  359. fz_throw(ctx, FZ_ERROR_SYNTAX, "too many shading functions");
  360. }
  361. if (type == 1)
  362. in = 2;
  363. else
  364. in = 1;
  365. out = 1;
  366. for (i = 0; i < funcs; i++)
  367. {
  368. func[i] = pdf_load_function(ctx, pdf_array_get(ctx, obj, i), in, out);
  369. if (!func[i])
  370. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  371. }
  372. }
  373. else if (type < 4)
  374. {
  375. /* Functions are compulsory for types 1,2,3 */
  376. fz_throw(ctx, FZ_ERROR_SYNTAX, "cannot load shading function (%d 0 R)", pdf_to_num(ctx, obj));
  377. }
  378. shade->type = type;
  379. switch (type)
  380. {
  381. case 1: pdf_load_function_based_shading(ctx, doc, shade, dict, funcs, func); break;
  382. case 2: pdf_load_linear_shading(ctx, doc, shade, dict, funcs, func); break;
  383. case 3: pdf_load_radial_shading(ctx, doc, shade, dict, funcs, func); break;
  384. case 4: pdf_load_type4_shade(ctx, doc, shade, dict, funcs, func); break;
  385. case 5: pdf_load_type5_shade(ctx, doc, shade, dict, funcs, func); break;
  386. case 6: pdf_load_type6_shade(ctx, doc, shade, dict, funcs, func); break;
  387. case 7: pdf_load_type7_shade(ctx, doc, shade, dict, funcs, func); break;
  388. default:
  389. fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown shading type: %d", type);
  390. }
  391. }
  392. fz_always(ctx)
  393. {
  394. for (i = 0; i < funcs; i++)
  395. pdf_drop_function(ctx, func[i]);
  396. }
  397. fz_catch(ctx)
  398. {
  399. fz_drop_shade(ctx, shade);
  400. fz_rethrow(ctx);
  401. }
  402. return shade;
  403. }
  404. static size_t
  405. fz_shade_size(fz_context *ctx, fz_shade *s)
  406. {
  407. size_t f = 0;
  408. if (s == NULL)
  409. return 0;
  410. if (s->function_stride)
  411. f = sizeof(float) * s->function_stride * 256;
  412. if (s->type == FZ_FUNCTION_BASED)
  413. return sizeof(*s) + sizeof(float) * s->u.f.xdivs * s->u.f.ydivs * fz_colorspace_n(ctx, s->colorspace) + f;
  414. return sizeof(*s) + fz_compressed_buffer_size(s->buffer) + f;
  415. }
  416. fz_shade *
  417. pdf_load_shading(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
  418. {
  419. fz_matrix mat;
  420. pdf_obj *obj;
  421. fz_shade *shade;
  422. if ((shade = pdf_find_item(ctx, fz_drop_shade_imp, dict)) != NULL)
  423. {
  424. return shade;
  425. }
  426. /* Type 2 pattern dictionary */
  427. if (pdf_dict_get(ctx, dict, PDF_NAME(PatternType)))
  428. {
  429. mat = pdf_dict_get_matrix(ctx, dict, PDF_NAME(Matrix));
  430. obj = pdf_dict_get(ctx, dict, PDF_NAME(ExtGState));
  431. if (obj)
  432. {
  433. if (pdf_dict_get(ctx, obj, PDF_NAME(CA)) || pdf_dict_get(ctx, obj, PDF_NAME(ca)))
  434. {
  435. fz_warn(ctx, "shading with alpha not supported");
  436. }
  437. }
  438. obj = pdf_dict_get(ctx, dict, PDF_NAME(Shading));
  439. if (!obj)
  440. fz_throw(ctx, FZ_ERROR_SYNTAX, "missing shading dictionary");
  441. shade = pdf_load_shading_dict(ctx, doc, obj, mat);
  442. }
  443. /* Naked shading dictionary */
  444. else
  445. {
  446. shade = pdf_load_shading_dict(ctx, doc, dict, fz_identity);
  447. }
  448. pdf_store_item(ctx, dict, shade, fz_shade_size(ctx, shade));
  449. return shade;
  450. }