pdf-page.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995
  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 "pdf-annot-imp.h"
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <limits.h>
  27. static void pdf_adjust_page_labels(fz_context *ctx, pdf_document *doc, int index, int adjust);
  28. int
  29. pdf_count_pages(fz_context *ctx, pdf_document *doc)
  30. {
  31. int pages;
  32. if (doc->is_fdf)
  33. return 0;
  34. /* FIXME: We should reset linear_page_count to 0 when editing starts
  35. * (or when linear loading ends) */
  36. if (doc->linear_page_count != 0)
  37. pages = doc->linear_page_count;
  38. else
  39. pages = pdf_to_int(ctx, pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/Pages/Count"));
  40. if (pages < 0)
  41. fz_throw(ctx, FZ_ERROR_FORMAT, "Invalid number of pages");
  42. return pages;
  43. }
  44. int pdf_count_pages_imp(fz_context *ctx, fz_document *doc, int chapter)
  45. {
  46. return pdf_count_pages(ctx, (pdf_document*)doc);
  47. }
  48. static int
  49. pdf_load_page_tree_imp(fz_context *ctx, pdf_document *doc, pdf_obj *node, int idx, pdf_cycle_list *cycle_up)
  50. {
  51. pdf_cycle_list cycle;
  52. pdf_obj *type = pdf_dict_get(ctx, node, PDF_NAME(Type));
  53. if (pdf_name_eq(ctx, type, PDF_NAME(Pages)))
  54. {
  55. pdf_obj *kids = pdf_dict_get(ctx, node, PDF_NAME(Kids));
  56. int i, n = pdf_array_len(ctx, kids);
  57. if (pdf_cycle(ctx, &cycle, cycle_up, node))
  58. fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in page tree");
  59. for (i = 0; i < n; ++i)
  60. idx = pdf_load_page_tree_imp(ctx, doc, pdf_array_get(ctx, kids, i), idx, &cycle);
  61. }
  62. else if (pdf_name_eq(ctx, type, PDF_NAME(Page)))
  63. {
  64. if (idx >= doc->map_page_count)
  65. fz_throw(ctx, FZ_ERROR_FORMAT, "too many kids in page tree");
  66. doc->rev_page_map[idx].page = idx;
  67. doc->rev_page_map[idx].object = pdf_to_num(ctx, node);
  68. doc->fwd_page_map[idx] = pdf_keep_obj(ctx, node);
  69. ++idx;
  70. }
  71. else
  72. {
  73. fz_throw(ctx, FZ_ERROR_FORMAT, "non-page object in page tree");
  74. }
  75. return idx;
  76. }
  77. static int
  78. cmp_rev_page_map(const void *va, const void *vb)
  79. {
  80. const pdf_rev_page_map *a = va;
  81. const pdf_rev_page_map *b = vb;
  82. return a->object - b->object;
  83. }
  84. void
  85. pdf_load_page_tree(fz_context *ctx, pdf_document *doc)
  86. {
  87. /* Noop now. */
  88. }
  89. void
  90. pdf_drop_page_tree_internal(fz_context *ctx, pdf_document *doc)
  91. {
  92. int i;
  93. fz_free(ctx, doc->rev_page_map);
  94. doc->rev_page_map = NULL;
  95. if (doc->fwd_page_map)
  96. for (i = 0; i < doc->map_page_count; i++)
  97. pdf_drop_obj(ctx, doc->fwd_page_map[i]);
  98. fz_free(ctx, doc->fwd_page_map);
  99. doc->fwd_page_map = NULL;
  100. doc->map_page_count = 0;
  101. }
  102. static void
  103. pdf_load_page_tree_internal(fz_context *ctx, pdf_document *doc)
  104. {
  105. /* Check we're not already loaded. */
  106. if (doc->fwd_page_map != NULL)
  107. return;
  108. /* At this point we're trusting that only 1 thread should be doing
  109. * stuff that hits the document at a time. */
  110. fz_try(ctx)
  111. {
  112. int idx;
  113. doc->map_page_count = pdf_count_pages(ctx, doc);
  114. while (1)
  115. {
  116. doc->rev_page_map = Memento_label(fz_calloc(ctx, doc->map_page_count, sizeof(pdf_rev_page_map)), "pdf_rev_page_map");
  117. doc->fwd_page_map = Memento_label(fz_calloc(ctx, doc->map_page_count, sizeof(pdf_obj *)), "pdf_fwd_page_map");
  118. idx = pdf_load_page_tree_imp(ctx, doc, pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/Pages"), 0, NULL);
  119. if (idx < doc->map_page_count)
  120. {
  121. /* The document claims more pages that it has. Fix that. */
  122. fz_warn(ctx, "Document claims to have %d pages, but only has %d.", doc->map_page_count, idx);
  123. /* This put drops the page tree! */
  124. pdf_dict_putp_drop(ctx, pdf_trailer(ctx, doc), "Root/Pages/Count", pdf_new_int(ctx, idx));
  125. doc->map_page_count = idx;
  126. continue;
  127. }
  128. break;
  129. }
  130. qsort(doc->rev_page_map, doc->map_page_count, sizeof *doc->rev_page_map, cmp_rev_page_map);
  131. }
  132. fz_catch(ctx)
  133. {
  134. pdf_drop_page_tree_internal(ctx, doc);
  135. fz_rethrow(ctx);
  136. }
  137. }
  138. void
  139. pdf_drop_page_tree(fz_context *ctx, pdf_document *doc)
  140. {
  141. /* Historical entry point. Now does nothing. We drop 'just in time'. */
  142. }
  143. static pdf_obj *
  144. pdf_lookup_page_loc_imp(fz_context *ctx, pdf_document *doc, pdf_obj *node, int *skip, pdf_obj **parentp, int *indexp)
  145. {
  146. pdf_mark_list mark_list;
  147. pdf_obj *kids;
  148. pdf_obj *hit = NULL;
  149. int i, len;
  150. pdf_mark_list_init(ctx, &mark_list);
  151. fz_try(ctx)
  152. {
  153. do
  154. {
  155. kids = pdf_dict_get(ctx, node, PDF_NAME(Kids));
  156. len = pdf_array_len(ctx, kids);
  157. if (len == 0)
  158. fz_throw(ctx, FZ_ERROR_FORMAT, "malformed page tree");
  159. if (pdf_mark_list_push(ctx, &mark_list, node))
  160. fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in page tree");
  161. for (i = 0; i < len; i++)
  162. {
  163. pdf_obj *kid = pdf_array_get(ctx, kids, i);
  164. pdf_obj *type = pdf_dict_get(ctx, kid, PDF_NAME(Type));
  165. if (type ? pdf_name_eq(ctx, type, PDF_NAME(Pages)) : pdf_dict_get(ctx, kid, PDF_NAME(Kids)) && !pdf_dict_get(ctx, kid, PDF_NAME(MediaBox)))
  166. {
  167. int count = pdf_dict_get_int(ctx, kid, PDF_NAME(Count));
  168. if (*skip < count)
  169. {
  170. node = kid;
  171. break;
  172. }
  173. else
  174. {
  175. *skip -= count;
  176. }
  177. }
  178. else
  179. {
  180. if (type ? !pdf_name_eq(ctx, type, PDF_NAME(Page)) : !pdf_dict_get(ctx, kid, PDF_NAME(MediaBox)))
  181. fz_warn(ctx, "non-page object in page tree (%s)", pdf_to_name(ctx, type));
  182. if (*skip == 0)
  183. {
  184. if (parentp) *parentp = node;
  185. if (indexp) *indexp = i;
  186. hit = kid;
  187. break;
  188. }
  189. else
  190. {
  191. (*skip)--;
  192. }
  193. }
  194. }
  195. }
  196. /* If i < len && hit != NULL the desired page was found in the
  197. Kids array, done. If i < len && hit == NULL the found page tree
  198. node contains a Kids array that contains the desired page, loop
  199. back to top to extract it. When i == len the Kids array has been
  200. exhausted without finding the desired page, give up.
  201. */
  202. while (hit == NULL && i < len);
  203. }
  204. fz_always(ctx)
  205. {
  206. pdf_mark_list_free(ctx, &mark_list);
  207. }
  208. fz_catch(ctx)
  209. {
  210. fz_rethrow(ctx);
  211. }
  212. return hit;
  213. }
  214. pdf_obj *
  215. pdf_lookup_page_loc(fz_context *ctx, pdf_document *doc, int needle, pdf_obj **parentp, int *indexp)
  216. {
  217. pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
  218. pdf_obj *node = pdf_dict_get(ctx, root, PDF_NAME(Pages));
  219. int skip = needle;
  220. pdf_obj *hit;
  221. if (!node)
  222. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find page tree");
  223. hit = pdf_lookup_page_loc_imp(ctx, doc, node, &skip, parentp, indexp);
  224. if (!hit)
  225. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find page %d in page tree", needle+1);
  226. return hit;
  227. }
  228. pdf_obj *
  229. pdf_lookup_page_obj(fz_context *ctx, pdf_document *doc, int needle)
  230. {
  231. if (doc->fwd_page_map == NULL && !doc->page_tree_broken)
  232. {
  233. fz_try(ctx)
  234. pdf_load_page_tree_internal(ctx, doc);
  235. fz_catch(ctx)
  236. {
  237. doc->page_tree_broken = 1;
  238. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  239. fz_report_error(ctx);
  240. fz_warn(ctx, "Page tree load failed. Falling back to slow lookup");
  241. }
  242. }
  243. if (doc->fwd_page_map)
  244. {
  245. if (needle < 0 || needle >= doc->map_page_count)
  246. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find page %d in page tree", needle+1);
  247. if (doc->fwd_page_map[needle] != NULL)
  248. return doc->fwd_page_map[needle];
  249. }
  250. return pdf_lookup_page_loc(ctx, doc, needle, NULL, NULL);
  251. }
  252. static int
  253. pdf_count_pages_before_kid(fz_context *ctx, pdf_document *doc, pdf_obj *parent, int kid_num)
  254. {
  255. pdf_obj *kids = pdf_dict_get(ctx, parent, PDF_NAME(Kids));
  256. int i, total = 0, len = pdf_array_len(ctx, kids);
  257. for (i = 0; i < len; i++)
  258. {
  259. pdf_obj *kid = pdf_array_get(ctx, kids, i);
  260. if (pdf_to_num(ctx, kid) == kid_num)
  261. return total;
  262. if (pdf_name_eq(ctx, pdf_dict_get(ctx, kid, PDF_NAME(Type)), PDF_NAME(Pages)))
  263. {
  264. pdf_obj *count = pdf_dict_get(ctx, kid, PDF_NAME(Count));
  265. int n = pdf_to_int(ctx, count);
  266. if (!pdf_is_int(ctx, count) || n < 0 || INT_MAX - total <= n)
  267. fz_throw(ctx, FZ_ERROR_FORMAT, "illegal or missing count in pages tree");
  268. total += n;
  269. }
  270. else
  271. total++;
  272. }
  273. return -1; // the page we're looking for is not in the page tree (it has been deleted)
  274. }
  275. static int
  276. pdf_lookup_page_number_slow(fz_context *ctx, pdf_document *doc, pdf_obj *node)
  277. {
  278. pdf_mark_list mark_list;
  279. int needle = pdf_to_num(ctx, node);
  280. int total = 0;
  281. int n;
  282. pdf_obj *parent;
  283. if (!pdf_name_eq(ctx, pdf_dict_get(ctx, node, PDF_NAME(Type)), PDF_NAME(Page)))
  284. {
  285. fz_warn(ctx, "invalid page object");
  286. return -1;
  287. }
  288. pdf_mark_list_init(ctx, &mark_list);
  289. parent = pdf_dict_get(ctx, node, PDF_NAME(Parent));
  290. fz_try(ctx)
  291. {
  292. while (pdf_is_dict(ctx, parent))
  293. {
  294. if (pdf_mark_list_push(ctx, &mark_list, parent))
  295. fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in page tree (parents)");
  296. n = pdf_count_pages_before_kid(ctx, doc, parent, needle);
  297. // Page was not found in page tree!
  298. if (n < 0)
  299. {
  300. total = -1;
  301. break;
  302. }
  303. if (INT_MAX - total <= n)
  304. fz_throw(ctx, FZ_ERROR_FORMAT, "illegal or missing count in pages tree");
  305. total += n;
  306. needle = pdf_to_num(ctx, parent);
  307. parent = pdf_dict_get(ctx, parent, PDF_NAME(Parent));
  308. }
  309. }
  310. fz_always(ctx)
  311. pdf_mark_list_free(ctx, &mark_list);
  312. fz_catch(ctx)
  313. fz_rethrow(ctx);
  314. return total;
  315. }
  316. static int
  317. pdf_lookup_page_number_fast(fz_context *ctx, pdf_document *doc, int needle)
  318. {
  319. int l = 0;
  320. int r = doc->map_page_count - 1;
  321. while (l <= r)
  322. {
  323. int m = (l + r) >> 1;
  324. int c = needle - doc->rev_page_map[m].object;
  325. if (c < 0)
  326. r = m - 1;
  327. else if (c > 0)
  328. l = m + 1;
  329. else
  330. return doc->rev_page_map[m].page;
  331. }
  332. return -1;
  333. }
  334. int
  335. pdf_lookup_page_number(fz_context *ctx, pdf_document *doc, pdf_obj *page)
  336. {
  337. if (doc->rev_page_map == NULL && !doc->page_tree_broken)
  338. {
  339. fz_try(ctx)
  340. pdf_load_page_tree_internal(ctx, doc);
  341. fz_catch(ctx)
  342. {
  343. doc->page_tree_broken = 1;
  344. fz_report_error(ctx);
  345. fz_warn(ctx, "Page tree load failed. Falling back to slow lookup.");
  346. }
  347. }
  348. if (doc->rev_page_map)
  349. return pdf_lookup_page_number_fast(ctx, doc, pdf_to_num(ctx, page));
  350. else
  351. return pdf_lookup_page_number_slow(ctx, doc, page);
  352. }
  353. static void
  354. pdf_flatten_inheritable_page_item(fz_context *ctx, pdf_obj *page, pdf_obj *key)
  355. {
  356. pdf_obj *val = pdf_dict_get_inheritable(ctx, page, key);
  357. if (val)
  358. pdf_dict_put(ctx, page, key, val);
  359. }
  360. void
  361. pdf_flatten_inheritable_page_items(fz_context *ctx, pdf_obj *page)
  362. {
  363. pdf_flatten_inheritable_page_item(ctx, page, PDF_NAME(MediaBox));
  364. pdf_flatten_inheritable_page_item(ctx, page, PDF_NAME(CropBox));
  365. pdf_flatten_inheritable_page_item(ctx, page, PDF_NAME(Rotate));
  366. pdf_flatten_inheritable_page_item(ctx, page, PDF_NAME(Resources));
  367. }
  368. /* We need to know whether to install a page-level transparency group */
  369. /*
  370. * Object memo flags - allows us to secretly remember "a memo" (a bool) in an
  371. * object, and to read back whether there was a memo, and if so, what it was.
  372. */
  373. enum
  374. {
  375. PDF_FLAGS_MEMO_BM = 0,
  376. PDF_FLAGS_MEMO_OP = 1
  377. };
  378. static int pdf_resources_use_blending(fz_context *ctx, pdf_obj *rdb, pdf_cycle_list *cycle_up);
  379. static int
  380. pdf_extgstate_uses_blending(fz_context *ctx, pdf_obj *dict)
  381. {
  382. pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME(BM));
  383. if (obj && !pdf_name_eq(ctx, obj, PDF_NAME(Normal)))
  384. return 1;
  385. return 0;
  386. }
  387. static int
  388. pdf_pattern_uses_blending(fz_context *ctx, pdf_obj *dict, pdf_cycle_list *cycle_up)
  389. {
  390. pdf_obj *obj;
  391. pdf_cycle_list cycle;
  392. if (pdf_cycle(ctx, &cycle, cycle_up, dict))
  393. return 0;
  394. obj = pdf_dict_get(ctx, dict, PDF_NAME(Resources));
  395. if (pdf_resources_use_blending(ctx, obj, &cycle))
  396. return 1;
  397. obj = pdf_dict_get(ctx, dict, PDF_NAME(ExtGState));
  398. return pdf_extgstate_uses_blending(ctx, obj);
  399. }
  400. static int
  401. pdf_xobject_uses_blending(fz_context *ctx, pdf_obj *dict, pdf_cycle_list *cycle_up)
  402. {
  403. pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME(Resources));
  404. pdf_cycle_list cycle;
  405. if (pdf_cycle(ctx, &cycle, cycle_up, dict))
  406. return 0;
  407. if (pdf_name_eq(ctx, pdf_dict_getp(ctx, dict, "Group/S"), PDF_NAME(Transparency)))
  408. return 1;
  409. if (pdf_name_eq(ctx, pdf_dict_get(ctx, dict, PDF_NAME(Subtype)), PDF_NAME(Image)) &&
  410. pdf_dict_get(ctx, dict, PDF_NAME(SMask)) != NULL)
  411. return 1;
  412. return pdf_resources_use_blending(ctx, obj, &cycle);
  413. }
  414. static int
  415. pdf_resources_use_blending(fz_context *ctx, pdf_obj *rdb, pdf_cycle_list *cycle_up)
  416. {
  417. pdf_cycle_list cycle;
  418. pdf_obj *obj;
  419. int i, n, useBM = 0;
  420. if (!rdb)
  421. return 0;
  422. /* Have we been here before and remembered an answer? */
  423. if (pdf_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_BM, &useBM))
  424. return useBM;
  425. /* stop on cyclic resource dependencies */
  426. if (pdf_cycle(ctx, &cycle, cycle_up, rdb))
  427. return 0;
  428. obj = pdf_dict_get(ctx, rdb, PDF_NAME(ExtGState));
  429. n = pdf_dict_len(ctx, obj);
  430. for (i = 0; i < n; i++)
  431. if (pdf_extgstate_uses_blending(ctx, pdf_dict_get_val(ctx, obj, i)))
  432. goto found;
  433. obj = pdf_dict_get(ctx, rdb, PDF_NAME(Pattern));
  434. n = pdf_dict_len(ctx, obj);
  435. for (i = 0; i < n; i++)
  436. if (pdf_pattern_uses_blending(ctx, pdf_dict_get_val(ctx, obj, i), &cycle))
  437. goto found;
  438. obj = pdf_dict_get(ctx, rdb, PDF_NAME(XObject));
  439. n = pdf_dict_len(ctx, obj);
  440. for (i = 0; i < n; i++)
  441. if (pdf_xobject_uses_blending(ctx, pdf_dict_get_val(ctx, obj, i), &cycle))
  442. goto found;
  443. if (0)
  444. {
  445. found:
  446. useBM = 1;
  447. }
  448. pdf_set_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_BM, useBM);
  449. return useBM;
  450. }
  451. static int pdf_resources_use_overprint(fz_context *ctx, pdf_obj *rdb, pdf_cycle_list *cycle_up);
  452. static int
  453. pdf_extgstate_uses_overprint(fz_context *ctx, pdf_obj *dict)
  454. {
  455. pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME(OP));
  456. if (obj && pdf_to_bool(ctx, obj))
  457. return 1;
  458. return 0;
  459. }
  460. static int
  461. pdf_pattern_uses_overprint(fz_context *ctx, pdf_obj *dict, pdf_cycle_list *cycle_up)
  462. {
  463. pdf_obj *obj;
  464. pdf_cycle_list cycle;
  465. if (pdf_cycle(ctx, &cycle, cycle_up, dict))
  466. return 0;
  467. obj = pdf_dict_get(ctx, dict, PDF_NAME(Resources));
  468. if (pdf_resources_use_overprint(ctx, obj, &cycle))
  469. return 1;
  470. obj = pdf_dict_get(ctx, dict, PDF_NAME(ExtGState));
  471. return pdf_extgstate_uses_overprint(ctx, obj);
  472. }
  473. static int
  474. pdf_xobject_uses_overprint(fz_context *ctx, pdf_obj *dict, pdf_cycle_list *cycle_up)
  475. {
  476. pdf_obj *obj = pdf_dict_get(ctx, dict, PDF_NAME(Resources));
  477. pdf_cycle_list cycle;
  478. if (pdf_cycle(ctx, &cycle, cycle_up, dict))
  479. return 0;
  480. return pdf_resources_use_overprint(ctx, obj, &cycle);
  481. }
  482. static int
  483. pdf_resources_use_overprint(fz_context *ctx, pdf_obj *rdb, pdf_cycle_list *cycle_up)
  484. {
  485. pdf_cycle_list cycle;
  486. pdf_obj *obj;
  487. int i, n, useOP = 0;
  488. if (!rdb)
  489. return 0;
  490. /* Have we been here before and remembered an answer? */
  491. if (pdf_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_OP, &useOP))
  492. return useOP;
  493. /* stop on cyclic resource dependencies */
  494. if (pdf_cycle(ctx, &cycle, cycle_up, rdb))
  495. return 0;
  496. obj = pdf_dict_get(ctx, rdb, PDF_NAME(ExtGState));
  497. n = pdf_dict_len(ctx, obj);
  498. for (i = 0; i < n; i++)
  499. if (pdf_extgstate_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i)))
  500. goto found;
  501. obj = pdf_dict_get(ctx, rdb, PDF_NAME(Pattern));
  502. n = pdf_dict_len(ctx, obj);
  503. for (i = 0; i < n; i++)
  504. if (pdf_pattern_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i), &cycle))
  505. goto found;
  506. obj = pdf_dict_get(ctx, rdb, PDF_NAME(XObject));
  507. n = pdf_dict_len(ctx, obj);
  508. for (i = 0; i < n; i++)
  509. if (pdf_xobject_uses_overprint(ctx, pdf_dict_get_val(ctx, obj, i), &cycle))
  510. goto found;
  511. if (0)
  512. {
  513. found:
  514. useOP = 1;
  515. }
  516. pdf_set_obj_memo(ctx, rdb, PDF_FLAGS_MEMO_OP, useOP);
  517. return useOP;
  518. }
  519. fz_transition *
  520. pdf_page_presentation(fz_context *ctx, pdf_page *page, fz_transition *transition, float *duration)
  521. {
  522. pdf_obj *obj, *transdict;
  523. *duration = pdf_dict_get_real(ctx, page->obj, PDF_NAME(Dur));
  524. transdict = pdf_dict_get(ctx, page->obj, PDF_NAME(Trans));
  525. if (!transdict)
  526. return NULL;
  527. obj = pdf_dict_get(ctx, transdict, PDF_NAME(D));
  528. transition->duration = pdf_to_real_default(ctx, obj, 1);
  529. transition->vertical = !pdf_name_eq(ctx, pdf_dict_get(ctx, transdict, PDF_NAME(Dm)), PDF_NAME(H));
  530. transition->outwards = !pdf_name_eq(ctx, pdf_dict_get(ctx, transdict, PDF_NAME(M)), PDF_NAME(I));
  531. /* FIXME: If 'Di' is None, it should be handled differently, but
  532. * this only affects Fly, and we don't implement that currently. */
  533. transition->direction = (pdf_dict_get_int(ctx, transdict, PDF_NAME(Di)));
  534. /* FIXME: Read SS for Fly when we implement it */
  535. /* FIXME: Read B for Fly when we implement it */
  536. obj = pdf_dict_get(ctx, transdict, PDF_NAME(S));
  537. if (pdf_name_eq(ctx, obj, PDF_NAME(Split)))
  538. transition->type = FZ_TRANSITION_SPLIT;
  539. else if (pdf_name_eq(ctx, obj, PDF_NAME(Blinds)))
  540. transition->type = FZ_TRANSITION_BLINDS;
  541. else if (pdf_name_eq(ctx, obj, PDF_NAME(Box)))
  542. transition->type = FZ_TRANSITION_BOX;
  543. else if (pdf_name_eq(ctx, obj, PDF_NAME(Wipe)))
  544. transition->type = FZ_TRANSITION_WIPE;
  545. else if (pdf_name_eq(ctx, obj, PDF_NAME(Dissolve)))
  546. transition->type = FZ_TRANSITION_DISSOLVE;
  547. else if (pdf_name_eq(ctx, obj, PDF_NAME(Glitter)))
  548. transition->type = FZ_TRANSITION_GLITTER;
  549. else if (pdf_name_eq(ctx, obj, PDF_NAME(Fly)))
  550. transition->type = FZ_TRANSITION_FLY;
  551. else if (pdf_name_eq(ctx, obj, PDF_NAME(Push)))
  552. transition->type = FZ_TRANSITION_PUSH;
  553. else if (pdf_name_eq(ctx, obj, PDF_NAME(Cover)))
  554. transition->type = FZ_TRANSITION_COVER;
  555. else if (pdf_name_eq(ctx, obj, PDF_NAME(Uncover)))
  556. transition->type = FZ_TRANSITION_UNCOVER;
  557. else if (pdf_name_eq(ctx, obj, PDF_NAME(Fade)))
  558. transition->type = FZ_TRANSITION_FADE;
  559. else
  560. transition->type = FZ_TRANSITION_NONE;
  561. return transition;
  562. }
  563. fz_rect
  564. pdf_bound_page(fz_context *ctx, pdf_page *page, fz_box_type box)
  565. {
  566. fz_matrix page_ctm;
  567. fz_rect rect;
  568. pdf_page_transform_box(ctx, page, &rect, &page_ctm, box);
  569. return fz_transform_rect(rect, page_ctm);
  570. }
  571. static fz_rect
  572. pdf_bound_page_imp(fz_context *ctx, fz_page *page, fz_box_type box)
  573. {
  574. return pdf_bound_page(ctx, (pdf_page*)page, box);
  575. }
  576. void
  577. pdf_set_page_box(fz_context *ctx, pdf_page *page, fz_box_type box, fz_rect rect)
  578. {
  579. fz_matrix page_ctm, inv_page_ctm;
  580. fz_rect page_rect;
  581. pdf_page_transform_box(ctx, page, NULL, &page_ctm, box);
  582. inv_page_ctm = fz_invert_matrix(page_ctm);
  583. page_rect = fz_transform_rect(rect, inv_page_ctm);
  584. switch (box)
  585. {
  586. case FZ_MEDIA_BOX:
  587. pdf_dict_put_rect(ctx, page->obj, PDF_NAME(MediaBox), page_rect);
  588. break;
  589. case FZ_CROP_BOX:
  590. pdf_dict_put_rect(ctx, page->obj, PDF_NAME(CropBox), page_rect);
  591. break;
  592. case FZ_BLEED_BOX:
  593. pdf_dict_put_rect(ctx, page->obj, PDF_NAME(BleedBox), page_rect);
  594. break;
  595. case FZ_TRIM_BOX:
  596. pdf_dict_put_rect(ctx, page->obj, PDF_NAME(TrimBox), page_rect);
  597. break;
  598. case FZ_ART_BOX:
  599. pdf_dict_put_rect(ctx, page->obj, PDF_NAME(ArtBox), page_rect);
  600. break;
  601. case FZ_UNKNOWN_BOX:
  602. fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "unknown page box type: %d", box);
  603. }
  604. }
  605. fz_link *
  606. pdf_load_links(fz_context *ctx, pdf_page *page)
  607. {
  608. return fz_keep_link(ctx, page->links);
  609. }
  610. static fz_link *
  611. pdf_load_links_imp(fz_context *ctx, fz_page *page)
  612. {
  613. return pdf_load_links(ctx, (pdf_page*)page);
  614. }
  615. pdf_obj *
  616. pdf_page_resources(fz_context *ctx, pdf_page *page)
  617. {
  618. return pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Resources));
  619. }
  620. pdf_obj *
  621. pdf_page_contents(fz_context *ctx, pdf_page *page)
  622. {
  623. return pdf_dict_get(ctx, page->obj, PDF_NAME(Contents));
  624. }
  625. pdf_obj *
  626. pdf_page_group(fz_context *ctx, pdf_page *page)
  627. {
  628. return pdf_dict_get(ctx, page->obj, PDF_NAME(Group));
  629. }
  630. void
  631. pdf_page_obj_transform_box(fz_context *ctx, pdf_obj *pageobj, fz_rect *outbox, fz_matrix *page_ctm, fz_box_type box)
  632. {
  633. pdf_obj *obj;
  634. fz_rect usedbox, tempbox, cropbox, mediabox;
  635. float userunit = 1;
  636. int rotate;
  637. if (!outbox)
  638. outbox = &tempbox;
  639. userunit = pdf_dict_get_real_default(ctx, pageobj, PDF_NAME(UserUnit), 1);
  640. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(MediaBox));
  641. mediabox = pdf_to_rect(ctx, obj);
  642. obj = NULL;
  643. if (box == FZ_ART_BOX)
  644. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(ArtBox));
  645. if (box == FZ_TRIM_BOX)
  646. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(TrimBox));
  647. if (box == FZ_BLEED_BOX)
  648. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(BleedBox));
  649. if (box == FZ_CROP_BOX || !obj)
  650. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(CropBox));
  651. if (box == FZ_MEDIA_BOX || !obj)
  652. usedbox = mediabox;
  653. else
  654. {
  655. // never use a box larger than fits the paper (mediabox)
  656. usedbox = fz_intersect_rect(mediabox, pdf_to_rect(ctx, obj));
  657. }
  658. if (fz_is_empty_rect(usedbox))
  659. usedbox = fz_make_rect(0, 0, 612, 792);
  660. usedbox.x0 = fz_min(usedbox.x0, usedbox.x1);
  661. usedbox.y0 = fz_min(usedbox.y0, usedbox.y1);
  662. usedbox.x1 = fz_max(usedbox.x0, usedbox.x1);
  663. usedbox.y1 = fz_max(usedbox.y0, usedbox.y1);
  664. if (usedbox.x1 - usedbox.x0 < 1 || usedbox.y1 - usedbox.y0 < 1)
  665. usedbox = fz_unit_rect;
  666. *outbox = usedbox;
  667. /* Snap page rotation to 0, 90, 180 or 270 */
  668. rotate = pdf_dict_get_inheritable_int(ctx, pageobj, PDF_NAME(Rotate));
  669. if (rotate < 0)
  670. rotate = 360 - ((-rotate) % 360);
  671. if (rotate >= 360)
  672. rotate = rotate % 360;
  673. rotate = 90*((rotate + 45)/90);
  674. if (rotate >= 360)
  675. rotate = 0;
  676. /* Compute transform from fitz' page space (upper left page origin, y descending, 72 dpi)
  677. * to PDF user space (arbitrary page origin, y ascending, UserUnit dpi). */
  678. /* Make left-handed and scale by UserUnit */
  679. *page_ctm = fz_scale(userunit, -userunit);
  680. /* Rotate */
  681. *page_ctm = fz_pre_rotate(*page_ctm, -rotate);
  682. /* Always use CropBox to set origin to top left */
  683. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(CropBox));
  684. if (!pdf_is_array(ctx, obj))
  685. obj = pdf_dict_get_inheritable(ctx, pageobj, PDF_NAME(MediaBox));
  686. cropbox = pdf_to_rect(ctx, obj);
  687. cropbox = fz_intersect_rect(cropbox, mediabox);
  688. if (fz_is_empty_rect(cropbox))
  689. cropbox = fz_make_rect(0, 0, 612, 792);
  690. cropbox.x0 = fz_min(cropbox.x0, cropbox.x1);
  691. cropbox.y0 = fz_min(cropbox.y0, cropbox.y1);
  692. cropbox.x1 = fz_max(cropbox.x0, cropbox.x1);
  693. cropbox.y1 = fz_max(cropbox.y0, cropbox.y1);
  694. if (cropbox.x1 - cropbox.x0 < 1 || cropbox.y1 - cropbox.y0 < 1)
  695. cropbox = fz_unit_rect;
  696. /* Translate page origin of CropBox to 0,0 */
  697. cropbox = fz_transform_rect(cropbox, *page_ctm);
  698. *page_ctm = fz_concat(*page_ctm, fz_translate(-cropbox.x0, -cropbox.y0));
  699. }
  700. void
  701. pdf_page_obj_transform(fz_context *ctx, pdf_obj *pageobj, fz_rect *page_cropbox, fz_matrix *page_ctm)
  702. {
  703. pdf_page_obj_transform_box(ctx, pageobj, page_cropbox, page_ctm, FZ_CROP_BOX);
  704. }
  705. void
  706. pdf_page_transform_box(fz_context *ctx, pdf_page *page, fz_rect *page_cropbox, fz_matrix *page_ctm, fz_box_type box)
  707. {
  708. pdf_page_obj_transform_box(ctx, page->obj, page_cropbox, page_ctm, box);
  709. }
  710. void
  711. pdf_page_transform(fz_context *ctx, pdf_page *page, fz_rect *cropbox, fz_matrix *ctm)
  712. {
  713. pdf_page_transform_box(ctx, page, cropbox, ctm, FZ_CROP_BOX);
  714. }
  715. static void
  716. find_seps(fz_context *ctx, fz_separations **seps, pdf_obj *obj, pdf_mark_list *clearme)
  717. {
  718. int i, n;
  719. pdf_obj *nameobj, *cols;
  720. if (!obj)
  721. return;
  722. // Already seen this ColorSpace...
  723. if (pdf_mark_list_push(ctx, clearme, obj))
  724. return;
  725. nameobj = pdf_array_get(ctx, obj, 0);
  726. if (pdf_name_eq(ctx, nameobj, PDF_NAME(Separation)))
  727. {
  728. fz_colorspace *cs;
  729. const char *name = pdf_array_get_name(ctx, obj, 1);
  730. /* Skip 'special' colorants. */
  731. if (!strcmp(name, "Black") ||
  732. !strcmp(name, "Cyan") ||
  733. !strcmp(name, "Magenta") ||
  734. !strcmp(name, "Yellow") ||
  735. !strcmp(name, "All") ||
  736. !strcmp(name, "None"))
  737. return;
  738. n = fz_count_separations(ctx, *seps);
  739. for (i = 0; i < n; i++)
  740. {
  741. if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
  742. return; /* Got that one already */
  743. }
  744. fz_try(ctx)
  745. cs = pdf_load_colorspace(ctx, obj);
  746. fz_catch(ctx)
  747. {
  748. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  749. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  750. fz_report_error(ctx);
  751. return; /* ignore broken colorspace */
  752. }
  753. fz_try(ctx)
  754. {
  755. if (!*seps)
  756. *seps = fz_new_separations(ctx, 0);
  757. fz_add_separation(ctx, *seps, name, cs, 0);
  758. }
  759. fz_always(ctx)
  760. fz_drop_colorspace(ctx, cs);
  761. fz_catch(ctx)
  762. fz_rethrow(ctx);
  763. }
  764. else if (pdf_name_eq(ctx, nameobj, PDF_NAME(Indexed)))
  765. {
  766. find_seps(ctx, seps, pdf_array_get(ctx, obj, 1), clearme);
  767. }
  768. else if (pdf_name_eq(ctx, nameobj, PDF_NAME(DeviceN)))
  769. {
  770. /* If the separation colorants exists for this DeviceN color space
  771. * add those prior to our search for DeviceN color */
  772. cols = pdf_dict_get(ctx, pdf_array_get(ctx, obj, 4), PDF_NAME(Colorants));
  773. n = pdf_dict_len(ctx, cols);
  774. for (i = 0; i < n; i++)
  775. find_seps(ctx, seps, pdf_dict_get_val(ctx, cols, i), clearme);
  776. }
  777. }
  778. static void
  779. find_devn(fz_context *ctx, fz_separations **seps, pdf_obj *obj, pdf_mark_list *clearme)
  780. {
  781. int i, j, n, m;
  782. pdf_obj *arr;
  783. pdf_obj *nameobj = pdf_array_get(ctx, obj, 0);
  784. if (!obj)
  785. return;
  786. // Already seen this ColorSpace...
  787. if (pdf_mark_list_push(ctx, clearme, obj))
  788. return;
  789. if (!pdf_name_eq(ctx, nameobj, PDF_NAME(DeviceN)))
  790. return;
  791. arr = pdf_array_get(ctx, obj, 1);
  792. m = pdf_array_len(ctx, arr);
  793. for (j = 0; j < m; j++)
  794. {
  795. fz_colorspace *cs;
  796. const char *name = pdf_array_get_name(ctx, arr, j);
  797. /* Skip 'special' colorants. */
  798. if (!strcmp(name, "Black") ||
  799. !strcmp(name, "Cyan") ||
  800. !strcmp(name, "Magenta") ||
  801. !strcmp(name, "Yellow") ||
  802. !strcmp(name, "All") ||
  803. !strcmp(name, "None"))
  804. continue;
  805. n = fz_count_separations(ctx, *seps);
  806. for (i = 0; i < n; i++)
  807. {
  808. if (!strcmp(name, fz_separation_name(ctx, *seps, i)))
  809. break; /* Got that one already */
  810. }
  811. if (i == n)
  812. {
  813. fz_try(ctx)
  814. cs = pdf_load_colorspace(ctx, obj);
  815. fz_catch(ctx)
  816. {
  817. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  818. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  819. fz_report_error(ctx);
  820. continue; /* ignore broken colorspace */
  821. }
  822. fz_try(ctx)
  823. {
  824. if (!*seps)
  825. *seps = fz_new_separations(ctx, 0);
  826. fz_add_separation(ctx, *seps, name, cs, j);
  827. }
  828. fz_always(ctx)
  829. fz_drop_colorspace(ctx, cs);
  830. fz_catch(ctx)
  831. fz_rethrow(ctx);
  832. }
  833. }
  834. }
  835. typedef void (res_finder_fn)(fz_context *ctx, fz_separations **seps, pdf_obj *obj, pdf_mark_list *clearme);
  836. static void
  837. scan_page_seps(fz_context *ctx, pdf_obj *res, fz_separations **seps, res_finder_fn *fn, pdf_mark_list *clearme)
  838. {
  839. pdf_obj *dict;
  840. pdf_obj *obj;
  841. int i, n;
  842. if (!res)
  843. return;
  844. // Already seen this Resources...
  845. if (pdf_mark_list_push(ctx, clearme, res))
  846. return;
  847. dict = pdf_dict_get(ctx, res, PDF_NAME(ColorSpace));
  848. n = pdf_dict_len(ctx, dict);
  849. for (i = 0; i < n; i++)
  850. {
  851. obj = pdf_dict_get_val(ctx, dict, i);
  852. fn(ctx, seps, obj, clearme);
  853. }
  854. dict = pdf_dict_get(ctx, res, PDF_NAME(Shading));
  855. n = pdf_dict_len(ctx, dict);
  856. for (i = 0; i < n; i++)
  857. {
  858. obj = pdf_dict_get_val(ctx, dict, i);
  859. fn(ctx, seps, pdf_dict_get(ctx, obj, PDF_NAME(ColorSpace)), clearme);
  860. }
  861. dict = pdf_dict_get(ctx, res, PDF_NAME(Pattern));
  862. n = pdf_dict_len(ctx, dict);
  863. for (i = 0; i < n; i++)
  864. {
  865. pdf_obj *obj2;
  866. obj = pdf_dict_get_val(ctx, dict, i);
  867. obj2 = pdf_dict_get(ctx, obj, PDF_NAME(Shading));
  868. fn(ctx, seps, pdf_dict_get(ctx, obj2, PDF_NAME(ColorSpace)), clearme);
  869. }
  870. dict = pdf_dict_get(ctx, res, PDF_NAME(XObject));
  871. n = pdf_dict_len(ctx, dict);
  872. for (i = 0; i < n; i++)
  873. {
  874. obj = pdf_dict_get_val(ctx, dict, i);
  875. // Already seen this XObject...
  876. if (!pdf_mark_list_push(ctx, clearme, obj))
  877. {
  878. fn(ctx, seps, pdf_dict_get(ctx, obj, PDF_NAME(ColorSpace)), clearme);
  879. /* Recurse on XObject forms. */
  880. scan_page_seps(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Resources)), seps, fn, clearme);
  881. }
  882. }
  883. }
  884. fz_separations *
  885. pdf_page_separations(fz_context *ctx, pdf_page *page)
  886. {
  887. pdf_obj *res = pdf_page_resources(ctx, page);
  888. pdf_mark_list clearme;
  889. fz_separations *seps = NULL;
  890. pdf_mark_list_init(ctx, &clearme);
  891. fz_try(ctx)
  892. {
  893. /* Run through and look for separations first. This is
  894. * because separations are simplest to deal with, and
  895. * because DeviceN may be implemented on top of separations.
  896. */
  897. scan_page_seps(ctx, res, &seps, find_seps, &clearme);
  898. }
  899. fz_always(ctx)
  900. pdf_mark_list_free(ctx, &clearme);
  901. fz_catch(ctx)
  902. {
  903. fz_drop_separations(ctx, seps);
  904. fz_rethrow(ctx);
  905. }
  906. pdf_mark_list_init(ctx, &clearme);
  907. fz_try(ctx)
  908. {
  909. /* Now run through again, and look for DeviceNs. These may
  910. * have spot colors in that aren't defined in terms of
  911. * separations. */
  912. scan_page_seps(ctx, res, &seps, find_devn, &clearme);
  913. }
  914. fz_always(ctx)
  915. pdf_mark_list_free(ctx, &clearme);
  916. fz_catch(ctx)
  917. {
  918. fz_drop_separations(ctx, seps);
  919. fz_rethrow(ctx);
  920. }
  921. return seps;
  922. }
  923. int
  924. pdf_page_uses_overprint(fz_context *ctx, pdf_page *page)
  925. {
  926. return page ? page->overprint : 0;
  927. }
  928. static void
  929. pdf_drop_page_imp(fz_context *ctx, fz_page *page_)
  930. {
  931. pdf_page *page = (pdf_page*)page_;
  932. pdf_annot *widget;
  933. pdf_annot *annot;
  934. pdf_link *link;
  935. link = (pdf_link *) page->links;
  936. while (link)
  937. {
  938. link->page = NULL;
  939. link = (pdf_link *) link->super.next;
  940. }
  941. fz_drop_link(ctx, page->links);
  942. page->links = NULL;
  943. annot = page->annots;
  944. while (annot)
  945. {
  946. annot->page = NULL;
  947. annot = annot->next;
  948. }
  949. pdf_drop_annots(ctx, page->annots);
  950. page->annots = NULL;
  951. widget = page->widgets;
  952. while (widget)
  953. {
  954. widget->page = NULL;
  955. widget = widget->next;
  956. }
  957. pdf_drop_widgets(ctx, page->widgets);
  958. page->widgets = NULL;
  959. pdf_drop_obj(ctx, page->obj);
  960. page->obj = NULL;
  961. page->doc = NULL;
  962. }
  963. static void pdf_run_page_contents_imp(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
  964. {
  965. pdf_run_page_contents(ctx, (pdf_page*)page, dev, ctm, cookie);
  966. }
  967. static void pdf_run_page_annots_imp(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
  968. {
  969. pdf_run_page_annots(ctx, (pdf_page*)page, dev, ctm, cookie);
  970. }
  971. static void pdf_run_page_widgets_imp(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
  972. {
  973. pdf_run_page_widgets(ctx, (pdf_page*)page, dev, ctm, cookie);
  974. }
  975. static fz_transition * pdf_page_presentation_imp(fz_context *ctx, fz_page *page, fz_transition *transition, float *duration)
  976. {
  977. return pdf_page_presentation(ctx, (pdf_page*)page, transition, duration);
  978. }
  979. static fz_separations * pdf_page_separations_imp(fz_context *ctx, fz_page *page)
  980. {
  981. return pdf_page_separations(ctx, (pdf_page*)page);
  982. }
  983. static int pdf_page_uses_overprint_imp(fz_context *ctx, fz_page *page)
  984. {
  985. return pdf_page_uses_overprint(ctx, (pdf_page*)page);
  986. }
  987. static fz_link * pdf_create_link_imp(fz_context *ctx, fz_page *page, fz_rect bbox, const char *uri)
  988. {
  989. return pdf_create_link(ctx, (pdf_page*)page, bbox, uri);
  990. }
  991. static void pdf_delete_link_imp(fz_context *ctx, fz_page *page, fz_link *link)
  992. {
  993. pdf_delete_link(ctx, (pdf_page*)page, link);
  994. }
  995. static pdf_page *
  996. pdf_new_page(fz_context *ctx, pdf_document *doc)
  997. {
  998. pdf_page *page = fz_new_derived_page(ctx, pdf_page, (fz_document*) doc);
  999. page->doc = doc; /* typecast alias for page->super.doc */
  1000. page->super.drop_page = pdf_drop_page_imp;
  1001. page->super.load_links = pdf_load_links_imp;
  1002. page->super.bound_page = pdf_bound_page_imp;
  1003. page->super.run_page_contents = pdf_run_page_contents_imp;
  1004. page->super.run_page_annots = pdf_run_page_annots_imp;
  1005. page->super.run_page_widgets = pdf_run_page_widgets_imp;
  1006. page->super.page_presentation = pdf_page_presentation_imp;
  1007. page->super.separations = pdf_page_separations_imp;
  1008. page->super.overprint = pdf_page_uses_overprint_imp;
  1009. page->super.create_link = pdf_create_link_imp;
  1010. page->super.delete_link = pdf_delete_link_imp;
  1011. page->obj = NULL;
  1012. page->transparency = 0;
  1013. page->links = NULL;
  1014. page->annots = NULL;
  1015. page->annot_tailp = &page->annots;
  1016. page->widgets = NULL;
  1017. page->widget_tailp = &page->widgets;
  1018. return page;
  1019. }
  1020. static void
  1021. pdf_load_default_colorspaces_imp(fz_context *ctx, fz_default_colorspaces *default_cs, pdf_obj *obj)
  1022. {
  1023. pdf_obj *cs_obj;
  1024. /* The spec says to ignore any colors we can't understand */
  1025. cs_obj = pdf_dict_get(ctx, obj, PDF_NAME(DefaultGray));
  1026. if (cs_obj)
  1027. {
  1028. fz_try(ctx)
  1029. {
  1030. fz_colorspace *cs = pdf_load_colorspace(ctx, cs_obj);
  1031. fz_set_default_gray(ctx, default_cs, cs);
  1032. fz_drop_colorspace(ctx, cs);
  1033. }
  1034. fz_catch(ctx)
  1035. {
  1036. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  1037. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  1038. fz_report_error(ctx);
  1039. }
  1040. }
  1041. cs_obj = pdf_dict_get(ctx, obj, PDF_NAME(DefaultRGB));
  1042. if (cs_obj)
  1043. {
  1044. fz_try(ctx)
  1045. {
  1046. fz_colorspace *cs = pdf_load_colorspace(ctx, cs_obj);
  1047. fz_set_default_rgb(ctx, default_cs, cs);
  1048. fz_drop_colorspace(ctx, cs);
  1049. }
  1050. fz_catch(ctx)
  1051. {
  1052. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  1053. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  1054. fz_report_error(ctx);
  1055. }
  1056. }
  1057. cs_obj = pdf_dict_get(ctx, obj, PDF_NAME(DefaultCMYK));
  1058. if (cs_obj)
  1059. {
  1060. fz_try(ctx)
  1061. {
  1062. fz_colorspace *cs = pdf_load_colorspace(ctx, cs_obj);
  1063. fz_set_default_cmyk(ctx, default_cs, cs);
  1064. fz_drop_colorspace(ctx, cs);
  1065. }
  1066. fz_catch(ctx)
  1067. {
  1068. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  1069. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  1070. fz_report_error(ctx);
  1071. }
  1072. }
  1073. }
  1074. fz_default_colorspaces *
  1075. pdf_load_default_colorspaces(fz_context *ctx, pdf_document *doc, pdf_page *page)
  1076. {
  1077. pdf_obj *res;
  1078. pdf_obj *obj;
  1079. fz_default_colorspaces *default_cs;
  1080. fz_colorspace *oi;
  1081. default_cs = fz_new_default_colorspaces(ctx);
  1082. fz_try(ctx)
  1083. {
  1084. res = pdf_page_resources(ctx, page);
  1085. obj = pdf_dict_get(ctx, res, PDF_NAME(ColorSpace));
  1086. if (obj)
  1087. pdf_load_default_colorspaces_imp(ctx, default_cs, obj);
  1088. oi = pdf_document_output_intent(ctx, doc);
  1089. if (oi)
  1090. fz_set_default_output_intent(ctx, default_cs, oi);
  1091. }
  1092. fz_catch(ctx)
  1093. {
  1094. if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
  1095. {
  1096. fz_drop_default_colorspaces(ctx, default_cs);
  1097. fz_rethrow(ctx);
  1098. }
  1099. fz_ignore_error(ctx);
  1100. page->super.incomplete = 1;
  1101. }
  1102. return default_cs;
  1103. }
  1104. fz_default_colorspaces *
  1105. pdf_update_default_colorspaces(fz_context *ctx, fz_default_colorspaces *old_cs, pdf_obj *res)
  1106. {
  1107. pdf_obj *obj;
  1108. fz_default_colorspaces *new_cs;
  1109. obj = pdf_dict_get(ctx, res, PDF_NAME(ColorSpace));
  1110. if (!obj)
  1111. return fz_keep_default_colorspaces(ctx, old_cs);
  1112. new_cs = fz_clone_default_colorspaces(ctx, old_cs);
  1113. fz_try(ctx)
  1114. pdf_load_default_colorspaces_imp(ctx, new_cs, obj);
  1115. fz_catch(ctx)
  1116. {
  1117. fz_drop_default_colorspaces(ctx, new_cs);
  1118. fz_rethrow(ctx);
  1119. }
  1120. return new_cs;
  1121. }
  1122. void pdf_nuke_page(fz_context *ctx, pdf_page *page)
  1123. {
  1124. pdf_nuke_links(ctx, page);
  1125. pdf_nuke_annots(ctx, page);
  1126. pdf_drop_obj(ctx, page->obj);
  1127. page->obj = NULL;
  1128. page->super.in_doc = 0;
  1129. }
  1130. void pdf_sync_page(fz_context *ctx, pdf_page *page)
  1131. {
  1132. pdf_sync_links(ctx, page);
  1133. pdf_sync_annots(ctx, page);
  1134. }
  1135. void pdf_sync_open_pages(fz_context *ctx, pdf_document *doc)
  1136. {
  1137. fz_page *page, *next;
  1138. pdf_page *ppage;
  1139. int number;
  1140. for (page = doc->super.open; page != NULL; page = next)
  1141. {
  1142. next = page->next;
  1143. if (page->doc == NULL)
  1144. continue;
  1145. ppage = (pdf_page*)page;
  1146. number = pdf_lookup_page_number(ctx, doc, ppage->obj);
  1147. if (number < 0)
  1148. {
  1149. pdf_nuke_page(ctx, ppage);
  1150. if (next)
  1151. next->prev = page->prev;
  1152. if (page->prev)
  1153. *page->prev = page->next;
  1154. }
  1155. else
  1156. {
  1157. pdf_sync_page(ctx, ppage);
  1158. page->number = number;
  1159. }
  1160. }
  1161. }
  1162. pdf_page *
  1163. pdf_load_page(fz_context *ctx, pdf_document *doc, int number)
  1164. {
  1165. return (pdf_page*)fz_load_page(ctx, (fz_document*)doc, number);
  1166. }
  1167. int
  1168. pdf_page_has_transparency(fz_context *ctx, pdf_page *page)
  1169. {
  1170. return page->transparency;
  1171. }
  1172. fz_page *
  1173. pdf_load_page_imp(fz_context *ctx, fz_document *doc_, int chapter, int number)
  1174. {
  1175. pdf_document *doc = (pdf_document*)doc_;
  1176. pdf_page *page;
  1177. pdf_annot *annot;
  1178. pdf_obj *pageobj, *obj;
  1179. if (doc->is_fdf)
  1180. fz_throw(ctx, FZ_ERROR_FORMAT, "FDF documents have no pages");
  1181. if (chapter != 0)
  1182. fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid chapter number: %d", chapter);
  1183. if (number < 0 || number >= pdf_count_pages(ctx, doc))
  1184. fz_throw(ctx, FZ_ERROR_ARGUMENT, "invalid page number: %d", number);
  1185. if (doc->file_reading_linearly)
  1186. {
  1187. pageobj = pdf_progressive_advance(ctx, doc, number);
  1188. if (pageobj == NULL)
  1189. fz_throw(ctx, FZ_ERROR_TRYLATER, "page %d not available yet", number);
  1190. }
  1191. else
  1192. pageobj = pdf_lookup_page_obj(ctx, doc, number);
  1193. page = pdf_new_page(ctx, doc);
  1194. page->obj = pdf_keep_obj(ctx, pageobj);
  1195. /* Pre-load annotations and links */
  1196. fz_try(ctx)
  1197. {
  1198. obj = pdf_dict_get(ctx, pageobj, PDF_NAME(Annots));
  1199. if (obj)
  1200. {
  1201. fz_rect page_cropbox;
  1202. fz_matrix page_ctm;
  1203. pdf_page_transform(ctx, page, &page_cropbox, &page_ctm);
  1204. page->links = pdf_load_link_annots(ctx, doc, page, obj, number, page_ctm);
  1205. pdf_load_annots(ctx, page);
  1206. }
  1207. }
  1208. fz_catch(ctx)
  1209. {
  1210. if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
  1211. {
  1212. fz_drop_page(ctx, &page->super);
  1213. fz_rethrow(ctx);
  1214. }
  1215. fz_ignore_error(ctx);
  1216. page->super.incomplete = 1;
  1217. fz_drop_link(ctx, page->links);
  1218. page->links = NULL;
  1219. }
  1220. /* Scan for transparency and overprint */
  1221. fz_try(ctx)
  1222. {
  1223. pdf_obj *resources = pdf_page_resources(ctx, page);
  1224. if (pdf_name_eq(ctx, pdf_dict_getp(ctx, pageobj, "Group/S"), PDF_NAME(Transparency)))
  1225. page->transparency = 1;
  1226. else if (pdf_resources_use_blending(ctx, resources, NULL))
  1227. page->transparency = 1;
  1228. if (pdf_resources_use_overprint(ctx, resources, NULL))
  1229. page->overprint = 1;
  1230. for (annot = page->annots; annot && !page->transparency; annot = annot->next)
  1231. {
  1232. fz_try(ctx)
  1233. {
  1234. pdf_obj *ap;
  1235. pdf_obj *res;
  1236. pdf_annot_push_local_xref(ctx, annot);
  1237. ap = pdf_annot_ap(ctx, annot);
  1238. if (!ap)
  1239. break;
  1240. res = pdf_xobject_resources(ctx, ap);
  1241. if (pdf_resources_use_blending(ctx, res, NULL))
  1242. page->transparency = 1;
  1243. if (pdf_resources_use_overprint(ctx, pdf_xobject_resources(ctx, res), NULL))
  1244. page->overprint = 1;
  1245. }
  1246. fz_always(ctx)
  1247. pdf_annot_pop_local_xref(ctx, annot);
  1248. fz_catch(ctx)
  1249. fz_rethrow(ctx);
  1250. }
  1251. for (annot = page->widgets; annot && !page->transparency; annot = annot->next)
  1252. {
  1253. fz_try(ctx)
  1254. {
  1255. pdf_obj *ap;
  1256. pdf_obj *res;
  1257. pdf_annot_push_local_xref(ctx, annot);
  1258. ap = pdf_annot_ap(ctx, annot);
  1259. if (!ap)
  1260. break;
  1261. res = pdf_xobject_resources(ctx, ap);
  1262. if (pdf_resources_use_blending(ctx, res, NULL))
  1263. page->transparency = 1;
  1264. if (pdf_resources_use_overprint(ctx, pdf_xobject_resources(ctx, res), NULL))
  1265. page->overprint = 1;
  1266. }
  1267. fz_always(ctx)
  1268. pdf_annot_pop_local_xref(ctx, annot);
  1269. fz_catch(ctx)
  1270. fz_rethrow(ctx);
  1271. }
  1272. }
  1273. fz_catch(ctx)
  1274. {
  1275. if (fz_caught(ctx) != FZ_ERROR_TRYLATER)
  1276. {
  1277. fz_drop_page(ctx, &page->super);
  1278. fz_rethrow(ctx);
  1279. }
  1280. fz_ignore_error(ctx);
  1281. page->super.incomplete = 1;
  1282. }
  1283. return (fz_page*)page;
  1284. }
  1285. void
  1286. pdf_delete_page(fz_context *ctx, pdf_document *doc, int at)
  1287. {
  1288. pdf_obj *parent, *kids;
  1289. int i;
  1290. pdf_begin_operation(ctx, doc, "Delete page");
  1291. fz_try(ctx)
  1292. {
  1293. pdf_lookup_page_loc(ctx, doc, at, &parent, &i);
  1294. kids = pdf_dict_get(ctx, parent, PDF_NAME(Kids));
  1295. pdf_array_delete(ctx, kids, i);
  1296. while (parent)
  1297. {
  1298. int count = pdf_dict_get_int(ctx, parent, PDF_NAME(Count));
  1299. pdf_dict_put_int(ctx, parent, PDF_NAME(Count), count - 1);
  1300. parent = pdf_dict_get(ctx, parent, PDF_NAME(Parent));
  1301. }
  1302. /* Adjust page labels */
  1303. pdf_adjust_page_labels(ctx, doc, at, -1);
  1304. pdf_end_operation(ctx, doc);
  1305. }
  1306. fz_catch(ctx)
  1307. {
  1308. pdf_abandon_operation(ctx, doc);
  1309. pdf_sync_open_pages(ctx, doc);
  1310. fz_rethrow(ctx);
  1311. }
  1312. pdf_sync_open_pages(ctx, doc);
  1313. }
  1314. void
  1315. pdf_delete_page_range(fz_context *ctx, pdf_document *doc, int start, int end)
  1316. {
  1317. int count = pdf_count_pages(ctx, doc);
  1318. if (end < 0)
  1319. end = count;
  1320. start = fz_clampi(start, 0, count);
  1321. end = fz_clampi(end, 0, count);
  1322. while (start < end)
  1323. {
  1324. pdf_delete_page(ctx, doc, start);
  1325. end--;
  1326. }
  1327. }
  1328. pdf_obj *
  1329. pdf_add_page(fz_context *ctx, pdf_document *doc, fz_rect mediabox, int rotate, pdf_obj *resources, fz_buffer *contents)
  1330. {
  1331. pdf_obj *page_obj = NULL;
  1332. pdf_obj *page_ref = NULL;
  1333. fz_var(page_obj);
  1334. fz_var(page_ref);
  1335. pdf_begin_operation(ctx, doc, "Add page");
  1336. fz_try(ctx)
  1337. {
  1338. page_obj = pdf_new_dict(ctx, doc, 5);
  1339. pdf_dict_put(ctx, page_obj, PDF_NAME(Type), PDF_NAME(Page));
  1340. pdf_dict_put_rect(ctx, page_obj, PDF_NAME(MediaBox), mediabox);
  1341. pdf_dict_put_int(ctx, page_obj, PDF_NAME(Rotate), rotate);
  1342. if (pdf_is_indirect(ctx, resources))
  1343. pdf_dict_put(ctx, page_obj, PDF_NAME(Resources), resources);
  1344. else if (pdf_is_dict(ctx, resources))
  1345. pdf_dict_put_drop(ctx, page_obj, PDF_NAME(Resources), pdf_add_object(ctx, doc, resources));
  1346. else
  1347. pdf_dict_put_dict(ctx, page_obj, PDF_NAME(Resources), 1);
  1348. if (contents && contents->len > 0)
  1349. pdf_dict_put_drop(ctx, page_obj, PDF_NAME(Contents), pdf_add_stream(ctx, doc, contents, NULL, 0));
  1350. page_ref = pdf_add_object_drop(ctx, doc, page_obj);
  1351. pdf_end_operation(ctx, doc);
  1352. }
  1353. fz_catch(ctx)
  1354. {
  1355. pdf_drop_obj(ctx, page_obj);
  1356. pdf_abandon_operation(ctx, doc);
  1357. fz_rethrow(ctx);
  1358. }
  1359. return page_ref;
  1360. }
  1361. void
  1362. pdf_insert_page(fz_context *ctx, pdf_document *doc, int at, pdf_obj *page_ref)
  1363. {
  1364. int count = pdf_count_pages(ctx, doc);
  1365. pdf_obj *parent, *kids;
  1366. int i;
  1367. if (at < 0)
  1368. at = count;
  1369. if (at == INT_MAX)
  1370. at = count;
  1371. if (at > count)
  1372. fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot insert page beyond end of page tree");
  1373. pdf_begin_operation(ctx, doc, "Insert page");
  1374. fz_try(ctx)
  1375. {
  1376. if (count == 0)
  1377. {
  1378. pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
  1379. parent = pdf_dict_get(ctx, root, PDF_NAME(Pages));
  1380. if (!parent)
  1381. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find page tree");
  1382. kids = pdf_dict_get(ctx, parent, PDF_NAME(Kids));
  1383. if (!kids)
  1384. fz_throw(ctx, FZ_ERROR_FORMAT, "malformed page tree");
  1385. pdf_array_insert(ctx, kids, page_ref, 0);
  1386. }
  1387. else if (at == count)
  1388. {
  1389. /* append after last page */
  1390. pdf_lookup_page_loc(ctx, doc, count - 1, &parent, &i);
  1391. kids = pdf_dict_get(ctx, parent, PDF_NAME(Kids));
  1392. pdf_array_insert(ctx, kids, page_ref, i + 1);
  1393. }
  1394. else
  1395. {
  1396. /* insert before found page */
  1397. pdf_lookup_page_loc(ctx, doc, at, &parent, &i);
  1398. kids = pdf_dict_get(ctx, parent, PDF_NAME(Kids));
  1399. pdf_array_insert(ctx, kids, page_ref, i);
  1400. }
  1401. pdf_dict_put(ctx, page_ref, PDF_NAME(Parent), parent);
  1402. /* Adjust page counts */
  1403. while (parent)
  1404. {
  1405. count = pdf_dict_get_int(ctx, parent, PDF_NAME(Count));
  1406. pdf_dict_put_int(ctx, parent, PDF_NAME(Count), count + 1);
  1407. parent = pdf_dict_get(ctx, parent, PDF_NAME(Parent));
  1408. }
  1409. /* Adjust page labels */
  1410. pdf_adjust_page_labels(ctx, doc, at, 1);
  1411. pdf_end_operation(ctx, doc);
  1412. }
  1413. fz_catch(ctx)
  1414. {
  1415. pdf_abandon_operation(ctx, doc);
  1416. pdf_sync_open_pages(ctx, doc);
  1417. fz_rethrow(ctx);
  1418. }
  1419. pdf_sync_open_pages(ctx, doc);
  1420. }
  1421. /*
  1422. * Page Labels
  1423. */
  1424. struct page_label_range {
  1425. int offset;
  1426. pdf_obj *label;
  1427. int nums_ix;
  1428. pdf_obj *nums;
  1429. };
  1430. static void
  1431. pdf_lookup_page_label_imp(fz_context *ctx, pdf_obj *node, int index, struct page_label_range *range)
  1432. {
  1433. pdf_obj *kids = pdf_dict_get(ctx, node, PDF_NAME(Kids));
  1434. pdf_obj *nums = pdf_dict_get(ctx, node, PDF_NAME(Nums));
  1435. int i;
  1436. if (pdf_is_array(ctx, kids))
  1437. {
  1438. for (i = 0; i < pdf_array_len(ctx, kids); ++i)
  1439. {
  1440. pdf_obj *kid = pdf_array_get(ctx, kids, i);
  1441. pdf_lookup_page_label_imp(ctx, kid, index, range);
  1442. }
  1443. }
  1444. if (pdf_is_array(ctx, nums))
  1445. {
  1446. for (i = 0; i < pdf_array_len(ctx, nums); i += 2)
  1447. {
  1448. int k = pdf_array_get_int(ctx, nums, i);
  1449. if (k <= index)
  1450. {
  1451. range->offset = k;
  1452. range->label = pdf_array_get(ctx, nums, i + 1);
  1453. range->nums_ix = i;
  1454. range->nums = nums;
  1455. }
  1456. else
  1457. {
  1458. /* stop looking if we've already passed the index */
  1459. return;
  1460. }
  1461. }
  1462. }
  1463. }
  1464. static struct page_label_range
  1465. pdf_lookup_page_label(fz_context *ctx, pdf_document *doc, int index)
  1466. {
  1467. struct page_label_range range = { 0, NULL };
  1468. pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
  1469. pdf_obj *labels = pdf_dict_get(ctx, root, PDF_NAME(PageLabels));
  1470. pdf_lookup_page_label_imp(ctx, labels, index, &range);
  1471. return range;
  1472. }
  1473. static void
  1474. pdf_flatten_page_label_tree_imp(fz_context *ctx, pdf_obj *node, pdf_obj *new_nums)
  1475. {
  1476. pdf_obj *kids = pdf_dict_get(ctx, node, PDF_NAME(Kids));
  1477. pdf_obj *nums = pdf_dict_get(ctx, node, PDF_NAME(Nums));
  1478. int i;
  1479. if (pdf_is_array(ctx, kids))
  1480. {
  1481. for (i = 0; i < pdf_array_len(ctx, kids); ++i)
  1482. {
  1483. pdf_obj *kid = pdf_array_get(ctx, kids, i);
  1484. pdf_flatten_page_label_tree_imp(ctx, kid, new_nums);
  1485. }
  1486. }
  1487. if (pdf_is_array(ctx, nums))
  1488. {
  1489. for (i = 0; i < pdf_array_len(ctx, nums); i += 2)
  1490. {
  1491. pdf_array_push(ctx, new_nums, pdf_array_get(ctx, nums, i));
  1492. pdf_array_push(ctx, new_nums, pdf_array_get(ctx, nums, i + 1));
  1493. }
  1494. }
  1495. }
  1496. static void
  1497. pdf_flatten_page_label_tree(fz_context *ctx, pdf_document *doc)
  1498. {
  1499. pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
  1500. pdf_obj *labels = pdf_dict_get(ctx, root, PDF_NAME(PageLabels));
  1501. pdf_obj *nums = pdf_dict_get(ctx, labels, PDF_NAME(Nums));
  1502. // Already flat...
  1503. if (pdf_is_array(ctx, nums) && pdf_array_len(ctx, nums) >= 2)
  1504. return;
  1505. nums = pdf_new_array(ctx, doc, 8);
  1506. fz_try(ctx)
  1507. {
  1508. if (!labels)
  1509. labels = pdf_dict_put_dict(ctx, root, PDF_NAME(PageLabels), 1);
  1510. pdf_flatten_page_label_tree_imp(ctx, labels, nums);
  1511. pdf_dict_del(ctx, labels, PDF_NAME(Kids));
  1512. pdf_dict_del(ctx, labels, PDF_NAME(Limits));
  1513. pdf_dict_put(ctx, labels, PDF_NAME(Nums), nums);
  1514. /* No Page Label tree found - insert one with default values */
  1515. if (pdf_array_len(ctx, nums) == 0)
  1516. {
  1517. pdf_obj *obj;
  1518. pdf_array_push_int(ctx, nums, 0);
  1519. obj = pdf_array_push_dict(ctx, nums, 1);
  1520. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(D));
  1521. }
  1522. }
  1523. fz_always(ctx)
  1524. pdf_drop_obj(ctx, nums);
  1525. fz_catch(ctx)
  1526. fz_rethrow(ctx);
  1527. }
  1528. static pdf_obj *
  1529. pdf_create_page_label(fz_context *ctx, pdf_document *doc, pdf_page_label_style style, const char *prefix, int start)
  1530. {
  1531. pdf_obj *obj = pdf_new_dict(ctx, doc, 3);
  1532. fz_try(ctx)
  1533. {
  1534. switch (style)
  1535. {
  1536. default:
  1537. case PDF_PAGE_LABEL_NONE:
  1538. break;
  1539. case PDF_PAGE_LABEL_DECIMAL:
  1540. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(D));
  1541. break;
  1542. case PDF_PAGE_LABEL_ROMAN_UC:
  1543. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(R));
  1544. break;
  1545. case PDF_PAGE_LABEL_ROMAN_LC:
  1546. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(r));
  1547. break;
  1548. case PDF_PAGE_LABEL_ALPHA_UC:
  1549. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(A));
  1550. break;
  1551. case PDF_PAGE_LABEL_ALPHA_LC:
  1552. pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(a));
  1553. break;
  1554. }
  1555. if (prefix && strlen(prefix) > 0)
  1556. pdf_dict_put_text_string(ctx, obj, PDF_NAME(P), prefix);
  1557. if (start > 1)
  1558. pdf_dict_put_int(ctx, obj, PDF_NAME(St), start);
  1559. }
  1560. fz_catch(ctx)
  1561. {
  1562. pdf_drop_obj(ctx, obj);
  1563. fz_rethrow(ctx);
  1564. }
  1565. return obj;
  1566. }
  1567. static void
  1568. pdf_adjust_page_labels(fz_context *ctx, pdf_document *doc, int index, int adjust)
  1569. {
  1570. pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root));
  1571. pdf_obj *labels = pdf_dict_get(ctx, root, PDF_NAME(PageLabels));
  1572. // Skip the adjustment step if there are no page labels.
  1573. // Exception: If we would adjust the label for page 0, we must create one!
  1574. // Exception: If the document only has one page!
  1575. if (labels || (adjust > 0 && index == 0 && pdf_count_pages(ctx, doc) > 1))
  1576. {
  1577. struct page_label_range range;
  1578. int i;
  1579. // Ensure we have a flat page label tree with at least one entry.
  1580. pdf_flatten_page_label_tree(ctx, doc);
  1581. // Find page label affecting the page that triggered adjustment
  1582. range = pdf_lookup_page_label(ctx, doc, index);
  1583. // Shift all page labels on and after the inserted index
  1584. if (adjust > 0)
  1585. {
  1586. if (range.offset == index)
  1587. i = range.nums_ix;
  1588. else
  1589. i = range.nums_ix + 2;
  1590. }
  1591. // Shift all page labels after the removed index
  1592. else
  1593. {
  1594. i = range.nums_ix + 2;
  1595. }
  1596. // Increase/decrease the indices in the name tree
  1597. for (; i < pdf_array_len(ctx, range.nums); i += 2)
  1598. pdf_array_put_int(ctx, range.nums, i, pdf_array_get_int(ctx, range.nums, i) + adjust);
  1599. // TODO: delete page labels that have no effect (zero range)
  1600. // Make sure the number tree always has an entry for page 0
  1601. if (adjust > 0 && index == 0)
  1602. {
  1603. pdf_array_insert_drop(ctx, range.nums, pdf_new_int(ctx, index), 0);
  1604. pdf_array_insert_drop(ctx, range.nums, pdf_create_page_label(ctx, doc, PDF_PAGE_LABEL_DECIMAL, NULL, 1), 1);
  1605. }
  1606. }
  1607. }
  1608. void
  1609. pdf_set_page_labels(fz_context *ctx, pdf_document *doc,
  1610. int index,
  1611. pdf_page_label_style style, const char *prefix, int start)
  1612. {
  1613. struct page_label_range range;
  1614. pdf_begin_operation(ctx, doc, "Set page label");
  1615. fz_try(ctx)
  1616. {
  1617. // Ensure we have a flat page label tree with at least one entry.
  1618. pdf_flatten_page_label_tree(ctx, doc);
  1619. range = pdf_lookup_page_label(ctx, doc, index);
  1620. if (range.offset == index)
  1621. {
  1622. // Replace label
  1623. pdf_array_put_drop(ctx, range.nums,
  1624. range.nums_ix + 1,
  1625. pdf_create_page_label(ctx, doc, style, prefix, start));
  1626. }
  1627. else
  1628. {
  1629. // Insert new label
  1630. pdf_array_insert_drop(ctx, range.nums,
  1631. pdf_new_int(ctx, index),
  1632. range.nums_ix + 2);
  1633. pdf_array_insert_drop(ctx, range.nums,
  1634. pdf_create_page_label(ctx, doc, style, prefix, start),
  1635. range.nums_ix + 3);
  1636. }
  1637. pdf_end_operation(ctx, doc);
  1638. }
  1639. fz_catch(ctx)
  1640. {
  1641. pdf_abandon_operation(ctx, doc);
  1642. fz_rethrow(ctx);
  1643. }
  1644. }
  1645. void
  1646. pdf_delete_page_labels(fz_context *ctx, pdf_document *doc, int index)
  1647. {
  1648. struct page_label_range range;
  1649. if (index == 0)
  1650. {
  1651. pdf_set_page_labels(ctx, doc, 0, PDF_PAGE_LABEL_DECIMAL, NULL, 1);
  1652. return;
  1653. }
  1654. pdf_begin_operation(ctx, doc, "Delete page label");
  1655. fz_try(ctx)
  1656. {
  1657. // Ensure we have a flat page label tree with at least one entry.
  1658. pdf_flatten_page_label_tree(ctx, doc);
  1659. range = pdf_lookup_page_label(ctx, doc, index);
  1660. if (range.offset == index)
  1661. {
  1662. // Delete label
  1663. pdf_array_delete(ctx, range.nums, range.nums_ix);
  1664. pdf_array_delete(ctx, range.nums, range.nums_ix);
  1665. }
  1666. pdf_end_operation(ctx, doc);
  1667. }
  1668. fz_catch(ctx)
  1669. {
  1670. pdf_abandon_operation(ctx, doc);
  1671. fz_rethrow(ctx);
  1672. }
  1673. }
  1674. static const char *roman_uc[3][10] = {
  1675. { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" },
  1676. { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" },
  1677. { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" },
  1678. };
  1679. static const char *roman_lc[3][10] = {
  1680. { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" },
  1681. { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" },
  1682. { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" },
  1683. };
  1684. static void pdf_format_roman_page_label(char *buf, int size, int n, const char *sym[3][10], const char *sym_m)
  1685. {
  1686. int I = n % 10;
  1687. int X = (n / 10) % 10;
  1688. int C = (n / 100) % 10;
  1689. int M = (n / 1000);
  1690. fz_strlcpy(buf, "", size);
  1691. while (M--)
  1692. fz_strlcat(buf, sym_m, size);
  1693. fz_strlcat(buf, sym[2][C], size);
  1694. fz_strlcat(buf, sym[1][X], size);
  1695. fz_strlcat(buf, sym[0][I], size);
  1696. }
  1697. static void pdf_format_alpha_page_label(char *buf, int size, int n, int alpha)
  1698. {
  1699. int reps = (n - 1) / 26 + 1;
  1700. if (reps > size - 1)
  1701. reps = size - 1;
  1702. memset(buf, (n - 1) % 26 + alpha, reps);
  1703. buf[reps] = '\0';
  1704. }
  1705. static void
  1706. pdf_format_page_label(fz_context *ctx, int index, pdf_obj *dict, char *buf, size_t size)
  1707. {
  1708. pdf_obj *style = pdf_dict_get(ctx, dict, PDF_NAME(S));
  1709. const char *prefix = pdf_dict_get_text_string(ctx, dict, PDF_NAME(P));
  1710. int start = pdf_dict_get_int(ctx, dict, PDF_NAME(St));
  1711. size_t n;
  1712. // St must be >= 1; default is 1.
  1713. if (start < 1)
  1714. start = 1;
  1715. // Add prefix (optional; may be empty)
  1716. fz_strlcpy(buf, prefix, size);
  1717. n = strlen(buf);
  1718. buf += n;
  1719. size -= n;
  1720. // Append number using style (optional)
  1721. if (style == PDF_NAME(D))
  1722. fz_snprintf(buf, size, "%d", index + start);
  1723. else if (style == PDF_NAME(R))
  1724. pdf_format_roman_page_label(buf, (int)size, index + start, roman_uc, "M");
  1725. else if (style == PDF_NAME(r))
  1726. pdf_format_roman_page_label(buf, (int)size, index + start, roman_lc, "m");
  1727. else if (style == PDF_NAME(A))
  1728. pdf_format_alpha_page_label(buf, (int)size, index + start, 'A');
  1729. else if (style == PDF_NAME(a))
  1730. pdf_format_alpha_page_label(buf, (int)size, index + start, 'a');
  1731. }
  1732. void
  1733. pdf_page_label(fz_context *ctx, pdf_document *doc, int index, char *buf, size_t size)
  1734. {
  1735. struct page_label_range range = pdf_lookup_page_label(ctx, doc, index);
  1736. if (range.label)
  1737. pdf_format_page_label(ctx, index - range.offset, range.label, buf, size);
  1738. else
  1739. fz_snprintf(buf, size, "%z", index + 1);
  1740. }
  1741. void
  1742. pdf_page_label_imp(fz_context *ctx, fz_document *doc, int chapter, int page, char *buf, size_t size)
  1743. {
  1744. pdf_page_label(ctx, pdf_document_from_fz_document(ctx, doc), page, buf, size);
  1745. }
  1746. pdf_page *
  1747. pdf_keep_page(fz_context *ctx, pdf_page *page)
  1748. {
  1749. return (pdf_page *) fz_keep_page(ctx, &page->super);
  1750. }
  1751. void
  1752. pdf_drop_page(fz_context *ctx, pdf_page *page)
  1753. {
  1754. fz_drop_page(ctx, &page->super);
  1755. }