Mercurial > hgrepos > Python2 > PyMuPDF
comparison src_classic/helper-annot.i @ 1:1d09e1dec1d9 upstream
ADD: PyMuPDF v1.26.4: the original sdist.
It does not yet contain MuPDF. This normally will be downloaded when
building PyMuPDF.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:37:51 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 1:1d09e1dec1d9 |
|---|---|
| 1 %{ | |
| 2 /* | |
| 3 # ------------------------------------------------------------------------ | |
| 4 # Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com | |
| 5 # License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html | |
| 6 # | |
| 7 # Part of "PyMuPDF", a Python binding for "MuPDF" (http://mupdf.com), a | |
| 8 # lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is | |
| 9 # maintained and developed by Artifex Software, Inc. https://artifex.com. | |
| 10 # ------------------------------------------------------------------------ | |
| 11 */ | |
| 12 //------------------------------------------------------------------------ | |
| 13 // return pdf_obj "border style" from Python str | |
| 14 //------------------------------------------------------------------------ | |
| 15 pdf_obj *JM_get_border_style(fz_context *ctx, PyObject *style) | |
| 16 { | |
| 17 pdf_obj *val = PDF_NAME(S); | |
| 18 if (!style) return val; | |
| 19 char *s = JM_StrAsChar(style); | |
| 20 JM_PyErr_Clear; | |
| 21 if (!s) return val; | |
| 22 if (!strncmp(s, "b", 1) || !strncmp(s, "B", 1)) val = PDF_NAME(B); | |
| 23 else if (!strncmp(s, "d", 1) || !strncmp(s, "D", 1)) val = PDF_NAME(D); | |
| 24 else if (!strncmp(s, "i", 1) || !strncmp(s, "I", 1)) val = PDF_NAME(I); | |
| 25 else if (!strncmp(s, "u", 1) || !strncmp(s, "U", 1)) val = PDF_NAME(U); | |
| 26 else if (!strncmp(s, "s", 1) || !strncmp(s, "S", 1)) val = PDF_NAME(S); | |
| 27 return val; | |
| 28 } | |
| 29 | |
| 30 //------------------------------------------------------------------------ | |
| 31 // Make /DA string of annotation | |
| 32 //------------------------------------------------------------------------ | |
| 33 const char *JM_expand_fname(const char **name) | |
| 34 { | |
| 35 if (!*name) return "Helv"; | |
| 36 if (!strncmp(*name, "Co", 2)) return "Cour"; | |
| 37 if (!strncmp(*name, "co", 2)) return "Cour"; | |
| 38 if (!strncmp(*name, "Ti", 2)) return "TiRo"; | |
| 39 if (!strncmp(*name, "ti", 2)) return "TiRo"; | |
| 40 if (!strncmp(*name, "Sy", 2)) return "Symb"; | |
| 41 if (!strncmp(*name, "sy", 2)) return "Symb"; | |
| 42 if (!strncmp(*name, "Za", 2)) return "ZaDb"; | |
| 43 if (!strncmp(*name, "za", 2)) return "ZaDb"; | |
| 44 return "Helv"; | |
| 45 } | |
| 46 | |
| 47 void JM_make_annot_DA(fz_context *ctx, pdf_annot *annot, int ncol, float col[4], const char *fontname, float fontsize) | |
| 48 { | |
| 49 fz_buffer *buf = NULL; | |
| 50 fz_try(ctx) | |
| 51 { | |
| 52 buf = fz_new_buffer(ctx, 50); | |
| 53 if (ncol <= 1) | |
| 54 fz_append_printf(ctx, buf, "%g g ", col[0]); | |
| 55 else if (ncol < 4) | |
| 56 fz_append_printf(ctx, buf, "%g %g %g rg ", col[0], col[1], col[2]); | |
| 57 else | |
| 58 fz_append_printf(ctx, buf, "%g %g %g %g k ", col[0], col[1], col[2], col[3]); | |
| 59 fz_append_printf(ctx, buf, "/%s %g Tf", JM_expand_fname(&fontname), fontsize); | |
| 60 unsigned char *da = NULL; | |
| 61 size_t len = fz_buffer_storage(ctx, buf, &da); | |
| 62 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 63 pdf_dict_put_string(ctx, annot_obj, PDF_NAME(DA), (const char *) da, len); | |
| 64 } | |
| 65 fz_always(ctx) fz_drop_buffer(ctx, buf); | |
| 66 fz_catch(ctx) fz_rethrow(ctx); | |
| 67 return; | |
| 68 } | |
| 69 | |
| 70 //------------------------------------------------------------------------ | |
| 71 // refreshes the link and annotation tables of a page | |
| 72 //------------------------------------------------------------------------ | |
| 73 void JM_refresh_links(fz_context *ctx, pdf_page *page) | |
| 74 { | |
| 75 if (!page) return; | |
| 76 fz_try(ctx) { | |
| 77 pdf_obj *obj = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 78 if (obj) | |
| 79 { | |
| 80 pdf_document *pdf = page->doc; | |
| 81 int number = pdf_lookup_page_number(ctx, pdf, page->obj); | |
| 82 fz_rect page_mediabox; | |
| 83 fz_matrix page_ctm; | |
| 84 pdf_page_transform(ctx, page, &page_mediabox, &page_ctm); | |
| 85 page->links = pdf_load_link_annots(ctx, pdf, page, obj, number, page_ctm); | |
| 86 } | |
| 87 } | |
| 88 fz_catch(ctx) { | |
| 89 fz_rethrow(ctx); | |
| 90 } | |
| 91 return; | |
| 92 } | |
| 93 | |
| 94 | |
| 95 PyObject *JM_annot_border(fz_context *ctx, pdf_obj *annot_obj) | |
| 96 { | |
| 97 PyObject *res = PyDict_New(); | |
| 98 PyObject *dash_py = PyList_New(0); | |
| 99 PyObject *val; | |
| 100 int i; | |
| 101 const char *style = NULL; | |
| 102 float width = -1.0f; | |
| 103 int clouds = -1; | |
| 104 pdf_obj *obj = NULL; | |
| 105 | |
| 106 obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(Border)); | |
| 107 if (pdf_is_array(ctx, obj)) { | |
| 108 width = pdf_to_real(ctx, pdf_array_get(ctx, obj, 2)); | |
| 109 if (pdf_array_len(ctx, obj) == 4) { | |
| 110 pdf_obj *dash = pdf_array_get(ctx, obj, 3); | |
| 111 for (i = 0; i < pdf_array_len(ctx, dash); i++) { | |
| 112 val = Py_BuildValue("i", pdf_to_int(ctx, pdf_array_get(ctx, dash, i))); | |
| 113 LIST_APPEND_DROP(dash_py, val); | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 pdf_obj *bs_o = pdf_dict_get(ctx, annot_obj, PDF_NAME(BS)); | |
| 119 if (bs_o) { | |
| 120 width = pdf_to_real(ctx, pdf_dict_get(ctx, bs_o, PDF_NAME(W))); | |
| 121 style = pdf_to_name(ctx, pdf_dict_get(ctx, bs_o, PDF_NAME(S))); | |
| 122 if (style && strcmp(style, "") == 0) { | |
| 123 style = NULL; | |
| 124 } | |
| 125 obj = pdf_dict_get(ctx, bs_o, PDF_NAME(D)); | |
| 126 if (obj) { | |
| 127 for (i = 0; i < pdf_array_len(ctx, obj); i++) { | |
| 128 val = Py_BuildValue("i", pdf_to_int(ctx, pdf_array_get(ctx, obj, i))); | |
| 129 LIST_APPEND_DROP(dash_py, val); | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(BE)); | |
| 135 if (obj) { | |
| 136 clouds = pdf_to_int(ctx, pdf_dict_get(ctx, obj, PDF_NAME(I))); | |
| 137 } | |
| 138 val = PySequence_Tuple(dash_py); | |
| 139 Py_CLEAR(dash_py); | |
| 140 DICT_SETITEM_DROP(res, dictkey_width, Py_BuildValue("f", width)); | |
| 141 DICT_SETITEM_DROP(res, dictkey_dashes, val); | |
| 142 DICT_SETITEM_DROP(res, dictkey_style, Py_BuildValue("s", style)); | |
| 143 DICT_SETITEMSTR_DROP(res, "clouds", Py_BuildValue("i", clouds)); | |
| 144 return res; | |
| 145 } | |
| 146 | |
| 147 PyObject *JM_annot_set_border(fz_context *ctx, PyObject *border, pdf_document *doc, pdf_obj *annot_obj) | |
| 148 { | |
| 149 if (!PyDict_Check(border)) { | |
| 150 JM_Warning("arg must be a dict"); | |
| 151 Py_RETURN_NONE; // not a dict | |
| 152 } | |
| 153 pdf_obj *obj = NULL; | |
| 154 Py_ssize_t i = 0, dashlen = 0; | |
| 155 int d; | |
| 156 double nwidth = PyFloat_AsDouble(PyDict_GetItem(border, dictkey_width)); // new width | |
| 157 PyObject *ndashes = PyDict_GetItem(border, dictkey_dashes); // new dashes | |
| 158 PyObject *nstyle = PyDict_GetItem(border, dictkey_style); // new style | |
| 159 int nclouds = (int) PyLong_AsLong(PyDict_GetItemString(border, "clouds")); // new clouds value | |
| 160 | |
| 161 // get old border properties | |
| 162 PyObject *oborder = JM_annot_border(ctx, annot_obj); | |
| 163 | |
| 164 // delete border-related entries | |
| 165 pdf_dict_del(ctx, annot_obj, PDF_NAME(BS)); | |
| 166 pdf_dict_del(ctx, annot_obj, PDF_NAME(BE)); | |
| 167 pdf_dict_del(ctx, annot_obj, PDF_NAME(Border)); | |
| 168 | |
| 169 // populate border items: keep old values for any omitted new ones | |
| 170 if (nwidth < 0) nwidth = PyFloat_AsDouble(PyDict_GetItem(oborder, dictkey_width)); // no new width: keep current | |
| 171 if (ndashes == Py_None) ndashes = PyDict_GetItem(oborder, dictkey_dashes); // no new dashes: keep old | |
| 172 if (nstyle == Py_None) nstyle = PyDict_GetItem(oborder, dictkey_style); // no new style: keep old | |
| 173 if (nclouds < 0) nclouds = (int) PyLong_AsLong(PyDict_GetItemString(oborder, "clouds")); // no new clouds: keep old | |
| 174 | |
| 175 if (ndashes && PyTuple_Check(ndashes) && PyTuple_Size(ndashes) > 0) { | |
| 176 dashlen = PyTuple_Size(ndashes); | |
| 177 pdf_obj *darr = pdf_new_array(ctx, doc, dashlen); | |
| 178 for (i = 0; i < dashlen; i++) { | |
| 179 d = (int) PyLong_AsLong(PyTuple_GetItem(ndashes, i)); | |
| 180 pdf_array_push_int(ctx, darr, (int64_t) d); | |
| 181 } | |
| 182 pdf_dict_putl_drop(ctx, annot_obj, darr, PDF_NAME(BS), PDF_NAME(D), NULL); | |
| 183 } | |
| 184 | |
| 185 pdf_dict_putl_drop(ctx, annot_obj, pdf_new_real(ctx, (float) nwidth), | |
| 186 PDF_NAME(BS), PDF_NAME(W), NULL); | |
| 187 | |
| 188 if (dashlen == 0) { | |
| 189 obj = JM_get_border_style(ctx, nstyle); | |
| 190 } else { | |
| 191 obj = PDF_NAME(D); | |
| 192 } | |
| 193 pdf_dict_putl_drop(ctx, annot_obj, obj, PDF_NAME(BS), PDF_NAME(S), NULL); | |
| 194 | |
| 195 if (nclouds > 0) { | |
| 196 pdf_dict_put_dict(ctx, annot_obj, PDF_NAME(BE), 2); | |
| 197 pdf_obj *obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(BE)); | |
| 198 pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(C)); | |
| 199 pdf_dict_put_int(ctx, obj, PDF_NAME(I), (int64_t) nclouds); | |
| 200 } | |
| 201 | |
| 202 PyErr_Clear(); | |
| 203 Py_RETURN_NONE; | |
| 204 } | |
| 205 | |
| 206 PyObject *JM_annot_colors(fz_context *ctx, pdf_obj *annot_obj) | |
| 207 { | |
| 208 PyObject *res = PyDict_New(); | |
| 209 PyObject *color = NULL; | |
| 210 int i, n; | |
| 211 float col; | |
| 212 pdf_obj *o = NULL; | |
| 213 | |
| 214 o = pdf_dict_get(ctx, annot_obj, PDF_NAME(C)); | |
| 215 if (pdf_is_array(ctx, o)) { | |
| 216 n = pdf_array_len(ctx, o); | |
| 217 color = PyTuple_New((Py_ssize_t) n); | |
| 218 for (i = 0; i < n; i++) { | |
| 219 col = pdf_to_real(ctx, pdf_array_get(ctx, o, i)); | |
| 220 PyTuple_SET_ITEM(color, i, Py_BuildValue("f", col)); | |
| 221 } | |
| 222 DICT_SETITEM_DROP(res, dictkey_stroke, color); | |
| 223 } else { | |
| 224 DICT_SETITEM_DROP(res, dictkey_stroke, Py_BuildValue("s", NULL)); | |
| 225 } | |
| 226 | |
| 227 o = pdf_dict_get(ctx, annot_obj, PDF_NAME(IC)); | |
| 228 if (pdf_is_array(ctx, o)) { | |
| 229 n = pdf_array_len(ctx, o); | |
| 230 color = PyTuple_New((Py_ssize_t) n); | |
| 231 for (i = 0; i < n; i++) { | |
| 232 col = pdf_to_real(ctx, pdf_array_get(ctx, o, i)); | |
| 233 PyTuple_SET_ITEM(color, i, Py_BuildValue("f", col)); | |
| 234 } | |
| 235 DICT_SETITEM_DROP(res, dictkey_fill, color); | |
| 236 } else { | |
| 237 DICT_SETITEM_DROP(res, dictkey_fill, Py_BuildValue("s", NULL)); | |
| 238 } | |
| 239 | |
| 240 return res; | |
| 241 } | |
| 242 | |
| 243 | |
| 244 //------------------------------------------------------------------------ | |
| 245 // Return the first annotation whose /IRT key ("In Response To") points to | |
| 246 // annot. Used to remove the response chain of a given annotation. | |
| 247 //------------------------------------------------------------------------ | |
| 248 pdf_annot *JM_find_annot_irt(fz_context *ctx, pdf_annot *annot) | |
| 249 { | |
| 250 pdf_annot *irt_annot = NULL; // returning this | |
| 251 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 252 pdf_obj *o = NULL; | |
| 253 int found = 0; | |
| 254 fz_try(ctx) { // loop thru MuPDF's internal annots array | |
| 255 pdf_page *page = pdf_annot_page(ctx, annot); | |
| 256 irt_annot = pdf_first_annot(ctx, page); | |
| 257 while (irt_annot) { | |
| 258 pdf_obj *irt_annot_obj = pdf_annot_obj(ctx, irt_annot); | |
| 259 o = pdf_dict_gets(ctx, irt_annot_obj, "IRT"); | |
| 260 if (o) { | |
| 261 if (!pdf_objcmp(ctx, o, annot_obj)) { | |
| 262 found = 1; | |
| 263 break; | |
| 264 } | |
| 265 } | |
| 266 irt_annot = pdf_next_annot(ctx, irt_annot); | |
| 267 } | |
| 268 } | |
| 269 fz_catch(ctx) {;} | |
| 270 if (found) return pdf_keep_annot(ctx, irt_annot); | |
| 271 return NULL; | |
| 272 } | |
| 273 | |
| 274 //------------------------------------------------------------------------ | |
| 275 // return the annotation names (list of /NM entries) | |
| 276 //------------------------------------------------------------------------ | |
| 277 PyObject *JM_get_annot_id_list(fz_context *ctx, pdf_page *page) | |
| 278 { | |
| 279 PyObject *names = PyList_New(0); | |
| 280 pdf_obj *annot_obj = NULL; | |
| 281 pdf_obj *annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots)); | |
| 282 pdf_obj *name = NULL; | |
| 283 if (!annots) return names; | |
| 284 fz_try(ctx) { | |
| 285 int i, n = pdf_array_len(ctx, annots); | |
| 286 for (i = 0; i < n; i++) { | |
| 287 annot_obj = pdf_array_get(ctx, annots, i); | |
| 288 name = pdf_dict_gets(ctx, annot_obj, "NM"); | |
| 289 if (name) { | |
| 290 LIST_APPEND_DROP(names, Py_BuildValue("s", pdf_to_text_string(ctx, name))); | |
| 291 } | |
| 292 } | |
| 293 } | |
| 294 fz_catch(ctx) { | |
| 295 return names; | |
| 296 } | |
| 297 return names; | |
| 298 } | |
| 299 | |
| 300 | |
| 301 //------------------------------------------------------------------------ | |
| 302 // return the xrefs and /NM ids of a page's annots, links and fields | |
| 303 //------------------------------------------------------------------------ | |
| 304 PyObject *JM_get_annot_xref_list(fz_context *ctx, pdf_obj *page_obj) | |
| 305 { | |
| 306 PyObject *names = PyList_New(0); | |
| 307 pdf_obj *id, *subtype, *annots, *annot_obj; | |
| 308 int xref, type, i, n; | |
| 309 fz_try(ctx) { | |
| 310 annots = pdf_dict_get(ctx, page_obj, PDF_NAME(Annots)); | |
| 311 n = pdf_array_len(ctx, annots); | |
| 312 for (i = 0; i < n; i++) { | |
| 313 annot_obj = pdf_array_get(ctx, annots, i); | |
| 314 xref = pdf_to_num(ctx, annot_obj); | |
| 315 subtype = pdf_dict_get(ctx, annot_obj, PDF_NAME(Subtype)); | |
| 316 if (!subtype) { | |
| 317 continue; // subtype is required | |
| 318 } | |
| 319 type = pdf_annot_type_from_string(ctx, pdf_to_name(ctx, subtype)); | |
| 320 if (type == PDF_ANNOT_UNKNOWN) { | |
| 321 continue; // only accept valid annot types | |
| 322 } | |
| 323 id = pdf_dict_gets(ctx, annot_obj, "NM"); | |
| 324 LIST_APPEND_DROP(names, Py_BuildValue("iis", xref, type, pdf_to_text_string(ctx, id))); | |
| 325 } | |
| 326 } | |
| 327 fz_catch(ctx) { | |
| 328 return names; | |
| 329 } | |
| 330 return names; | |
| 331 } | |
| 332 | |
| 333 | |
| 334 //------------------------------------------------------------------------ | |
| 335 // Add a unique /NM key to an annotation or widget. | |
| 336 // Append a number to 'stem' such that the result is a unique name. | |
| 337 //------------------------------------------------------------------------ | |
| 338 static char JM_annot_id_stem[50] = "fitz"; | |
| 339 void JM_add_annot_id(fz_context *ctx, pdf_annot *annot, char *stem) | |
| 340 { | |
| 341 fz_try(ctx) { | |
| 342 PyObject *names = NULL; | |
| 343 pdf_page *page = pdf_annot_page(ctx, annot); | |
| 344 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 345 names = JM_get_annot_id_list(ctx, page); | |
| 346 int i = 0; | |
| 347 PyObject *stem_id = NULL; | |
| 348 while (1) { | |
| 349 stem_id = PyUnicode_FromFormat("%s-%s%d", JM_annot_id_stem, stem, i); | |
| 350 if (!PySequence_Contains(names, stem_id)) break; | |
| 351 i += 1; | |
| 352 Py_DECREF(stem_id); | |
| 353 } | |
| 354 char *response = JM_StrAsChar(stem_id); | |
| 355 pdf_obj *name = pdf_new_string(ctx, (const char *) response, strlen(response)); | |
| 356 pdf_dict_puts_drop(ctx, annot_obj, "NM", name); | |
| 357 Py_CLEAR(stem_id); | |
| 358 Py_CLEAR(names); | |
| 359 page->doc->resynth_required = 0; | |
| 360 } | |
| 361 fz_catch(ctx) { | |
| 362 fz_rethrow(ctx); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 //------------------------------------------------------------------------ | |
| 367 // retrieve annot by name (/NM key) | |
| 368 //------------------------------------------------------------------------ | |
| 369 pdf_annot *JM_get_annot_by_name(fz_context *ctx, pdf_page *page, char *name) | |
| 370 { | |
| 371 if (!name || strlen(name) == 0) { | |
| 372 return NULL; | |
| 373 } | |
| 374 pdf_annot *annot = NULL; | |
| 375 int found = 0; | |
| 376 size_t len = 0; | |
| 377 | |
| 378 fz_try(ctx) { // loop thru MuPDF's internal annots and widget arrays | |
| 379 annot = pdf_first_annot(ctx, page); | |
| 380 while (annot) { | |
| 381 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 382 const char *response = pdf_to_string(ctx, pdf_dict_gets(ctx, annot_obj, "NM"), &len); | |
| 383 if (strcmp(name, response) == 0) { | |
| 384 found = 1; | |
| 385 break; | |
| 386 } | |
| 387 annot = pdf_next_annot(ctx, annot); | |
| 388 } | |
| 389 if (!found) { | |
| 390 fz_throw(ctx, FZ_ERROR_GENERIC, "'%s' is not an annot of this page", name); | |
| 391 } | |
| 392 } | |
| 393 fz_catch(ctx) { | |
| 394 fz_rethrow(ctx); | |
| 395 } | |
| 396 return pdf_keep_annot(ctx, annot); | |
| 397 } | |
| 398 | |
| 399 //------------------------------------------------------------------------ | |
| 400 // retrieve annot by its xref | |
| 401 //------------------------------------------------------------------------ | |
| 402 pdf_annot *JM_get_annot_by_xref(fz_context *ctx, pdf_page *page, int xref) | |
| 403 { | |
| 404 pdf_annot *annot = NULL; | |
| 405 int found = 0; | |
| 406 | |
| 407 fz_try(ctx) { // loop thru MuPDF's internal annots array | |
| 408 annot = pdf_first_annot(ctx, page); | |
| 409 while (annot) { | |
| 410 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 411 if (xref == pdf_to_num(ctx, annot_obj)) { | |
| 412 found = 1; | |
| 413 break; | |
| 414 } | |
| 415 annot = pdf_next_annot(ctx, annot); | |
| 416 } | |
| 417 if (!found) { | |
| 418 fz_throw(ctx, FZ_ERROR_GENERIC, "xref %d is not an annot of this page", xref); | |
| 419 } | |
| 420 } | |
| 421 fz_catch(ctx) { | |
| 422 fz_rethrow(ctx); | |
| 423 } | |
| 424 return pdf_keep_annot(ctx, annot); | |
| 425 } | |
| 426 | |
| 427 //------------------------------------------------------------------------ | |
| 428 // retrieve widget by its xref | |
| 429 //------------------------------------------------------------------------ | |
| 430 pdf_annot *JM_get_widget_by_xref(fz_context *ctx, pdf_page *page, int xref) | |
| 431 { | |
| 432 pdf_annot *annot = NULL; | |
| 433 int found = 0; | |
| 434 | |
| 435 fz_try(ctx) { // loop thru MuPDF's internal annots array | |
| 436 annot = pdf_first_widget(ctx, page); | |
| 437 while (annot) { | |
| 438 pdf_obj *annot_obj = pdf_annot_obj(ctx, annot); | |
| 439 if (xref == pdf_to_num(ctx, annot_obj)) { | |
| 440 found = 1; | |
| 441 break; | |
| 442 } | |
| 443 annot = pdf_next_widget(ctx, annot); | |
| 444 } | |
| 445 if (!found) { | |
| 446 fz_throw(ctx, FZ_ERROR_GENERIC, "xref %d is not a widget of this page", xref); | |
| 447 } | |
| 448 } | |
| 449 fz_catch(ctx) { | |
| 450 fz_rethrow(ctx); | |
| 451 } | |
| 452 return pdf_keep_annot(ctx, annot); | |
| 453 } | |
| 454 | |
| 455 %} |
