Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/util.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2022 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 | |
| 23 #include "mupdf/fitz.h" | |
| 24 | |
| 25 #include <float.h> | |
| 26 | |
| 27 fz_display_list * | |
| 28 fz_new_display_list_from_page(fz_context *ctx, fz_page *page) | |
| 29 { | |
| 30 fz_display_list *list; | |
| 31 fz_device *dev = NULL; | |
| 32 | |
| 33 fz_var(dev); | |
| 34 | |
| 35 list = fz_new_display_list(ctx, fz_bound_page(ctx, page)); | |
| 36 fz_try(ctx) | |
| 37 { | |
| 38 dev = fz_new_list_device(ctx, list); | |
| 39 fz_run_page(ctx, page, dev, fz_identity, NULL); | |
| 40 fz_close_device(ctx, dev); | |
| 41 } | |
| 42 fz_always(ctx) | |
| 43 { | |
| 44 fz_drop_device(ctx, dev); | |
| 45 } | |
| 46 fz_catch(ctx) | |
| 47 { | |
| 48 fz_drop_display_list(ctx, list); | |
| 49 fz_rethrow(ctx); | |
| 50 } | |
| 51 | |
| 52 return list; | |
| 53 } | |
| 54 | |
| 55 fz_display_list * | |
| 56 fz_new_display_list_from_page_number(fz_context *ctx, fz_document *doc, int number) | |
| 57 { | |
| 58 fz_page *page; | |
| 59 fz_display_list *list = NULL; | |
| 60 | |
| 61 page = fz_load_page(ctx, doc, number); | |
| 62 fz_try(ctx) | |
| 63 list = fz_new_display_list_from_page(ctx, page); | |
| 64 fz_always(ctx) | |
| 65 fz_drop_page(ctx, page); | |
| 66 fz_catch(ctx) | |
| 67 fz_rethrow(ctx); | |
| 68 return list; | |
| 69 } | |
| 70 | |
| 71 fz_display_list * | |
| 72 fz_new_display_list_from_page_contents(fz_context *ctx, fz_page *page) | |
| 73 { | |
| 74 fz_display_list *list; | |
| 75 fz_device *dev = NULL; | |
| 76 | |
| 77 fz_var(dev); | |
| 78 | |
| 79 list = fz_new_display_list(ctx, fz_bound_page(ctx, page)); | |
| 80 fz_try(ctx) | |
| 81 { | |
| 82 dev = fz_new_list_device(ctx, list); | |
| 83 fz_run_page_contents(ctx, page, dev, fz_identity, NULL); | |
| 84 fz_close_device(ctx, dev); | |
| 85 } | |
| 86 fz_always(ctx) | |
| 87 { | |
| 88 fz_drop_device(ctx, dev); | |
| 89 } | |
| 90 fz_catch(ctx) | |
| 91 { | |
| 92 fz_drop_display_list(ctx, list); | |
| 93 fz_rethrow(ctx); | |
| 94 } | |
| 95 | |
| 96 return list; | |
| 97 } | |
| 98 | |
| 99 fz_pixmap * | |
| 100 fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, int alpha) | |
| 101 { | |
| 102 return fz_new_pixmap_from_display_list_with_separations(ctx, list, ctm, cs, NULL, alpha); | |
| 103 } | |
| 104 | |
| 105 fz_pixmap * | |
| 106 fz_new_pixmap_from_display_list_with_separations(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) | |
| 107 { | |
| 108 fz_rect rect; | |
| 109 fz_irect bbox; | |
| 110 fz_pixmap *pix; | |
| 111 | |
| 112 rect = fz_bound_display_list(ctx, list); | |
| 113 rect = fz_transform_rect(rect, ctm); | |
| 114 bbox = fz_round_rect(rect); | |
| 115 | |
| 116 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); | |
| 117 if (alpha) | |
| 118 fz_clear_pixmap(ctx, pix); | |
| 119 else | |
| 120 fz_clear_pixmap_with_value(ctx, pix, 0xFF); | |
| 121 | |
| 122 return fz_fill_pixmap_from_display_list(ctx, list, ctm, pix); | |
| 123 } | |
| 124 | |
| 125 fz_pixmap * | |
| 126 fz_fill_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_pixmap *pix) | |
| 127 { | |
| 128 fz_device *dev = NULL; | |
| 129 | |
| 130 fz_var(dev); | |
| 131 | |
| 132 fz_try(ctx) | |
| 133 { | |
| 134 dev = fz_new_draw_device(ctx, ctm, pix); | |
| 135 fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL); | |
| 136 fz_close_device(ctx, dev); | |
| 137 } | |
| 138 fz_always(ctx) | |
| 139 { | |
| 140 fz_drop_device(ctx, dev); | |
| 141 } | |
| 142 fz_catch(ctx) | |
| 143 { | |
| 144 fz_drop_pixmap(ctx, pix); | |
| 145 fz_rethrow(ctx); | |
| 146 } | |
| 147 | |
| 148 return pix; | |
| 149 } | |
| 150 | |
| 151 fz_pixmap * | |
| 152 fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha) | |
| 153 { | |
| 154 return fz_new_pixmap_from_page_contents_with_separations(ctx, page, ctm, cs, NULL, alpha); | |
| 155 } | |
| 156 | |
| 157 fz_pixmap * | |
| 158 fz_new_pixmap_from_page_contents_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) | |
| 159 { | |
| 160 fz_rect rect; | |
| 161 fz_irect bbox; | |
| 162 fz_pixmap *pix; | |
| 163 fz_device *dev = NULL; | |
| 164 | |
| 165 fz_var(dev); | |
| 166 | |
| 167 rect = fz_bound_page(ctx, page); | |
| 168 rect = fz_transform_rect(rect, ctm); | |
| 169 bbox = fz_round_rect(rect); | |
| 170 | |
| 171 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); | |
| 172 if (alpha) | |
| 173 fz_clear_pixmap(ctx, pix); | |
| 174 else | |
| 175 fz_clear_pixmap_with_value(ctx, pix, 0xFF); | |
| 176 | |
| 177 fz_try(ctx) | |
| 178 { | |
| 179 dev = fz_new_draw_device(ctx, ctm, pix); | |
| 180 fz_run_page_contents(ctx, page, dev, fz_identity, NULL); | |
| 181 fz_close_device(ctx, dev); | |
| 182 } | |
| 183 fz_always(ctx) | |
| 184 { | |
| 185 fz_drop_device(ctx, dev); | |
| 186 } | |
| 187 fz_catch(ctx) | |
| 188 { | |
| 189 fz_drop_pixmap(ctx, pix); | |
| 190 fz_rethrow(ctx); | |
| 191 } | |
| 192 | |
| 193 return pix; | |
| 194 } | |
| 195 | |
| 196 fz_pixmap * | |
| 197 fz_new_pixmap_from_page(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha) | |
| 198 { | |
| 199 return fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, NULL, alpha); | |
| 200 } | |
| 201 | |
| 202 fz_pixmap * | |
| 203 fz_new_pixmap_from_page_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) | |
| 204 { | |
| 205 fz_rect rect; | |
| 206 fz_irect bbox; | |
| 207 fz_pixmap *pix; | |
| 208 fz_device *dev = NULL; | |
| 209 | |
| 210 fz_var(dev); | |
| 211 | |
| 212 rect = fz_bound_page(ctx, page); | |
| 213 rect = fz_transform_rect(rect, ctm); | |
| 214 bbox = fz_round_rect(rect); | |
| 215 | |
| 216 pix = fz_new_pixmap_with_bbox(ctx, cs, bbox, seps, alpha); | |
| 217 | |
| 218 fz_try(ctx) | |
| 219 { | |
| 220 if (alpha) | |
| 221 fz_clear_pixmap(ctx, pix); | |
| 222 else | |
| 223 fz_clear_pixmap_with_value(ctx, pix, 0xFF); | |
| 224 | |
| 225 dev = fz_new_draw_device(ctx, ctm, pix); | |
| 226 fz_run_page(ctx, page, dev, fz_identity, NULL); | |
| 227 fz_close_device(ctx, dev); | |
| 228 } | |
| 229 fz_always(ctx) | |
| 230 { | |
| 231 fz_drop_device(ctx, dev); | |
| 232 } | |
| 233 fz_catch(ctx) | |
| 234 { | |
| 235 fz_drop_pixmap(ctx, pix); | |
| 236 fz_rethrow(ctx); | |
| 237 } | |
| 238 | |
| 239 return pix; | |
| 240 } | |
| 241 | |
| 242 fz_pixmap * | |
| 243 fz_new_pixmap_from_page_number(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, int alpha) | |
| 244 { | |
| 245 return fz_new_pixmap_from_page_number_with_separations(ctx, doc, number, ctm, cs, NULL, alpha); | |
| 246 } | |
| 247 | |
| 248 fz_pixmap * | |
| 249 fz_new_pixmap_from_page_number_with_separations(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha) | |
| 250 { | |
| 251 fz_page *page; | |
| 252 fz_pixmap *pix = NULL; | |
| 253 | |
| 254 page = fz_load_page(ctx, doc, number); | |
| 255 fz_try(ctx) | |
| 256 pix = fz_new_pixmap_from_page_with_separations(ctx, page, ctm, cs, seps, alpha); | |
| 257 fz_always(ctx) | |
| 258 fz_drop_page(ctx, page); | |
| 259 fz_catch(ctx) | |
| 260 fz_rethrow(ctx); | |
| 261 return pix; | |
| 262 } | |
| 263 | |
| 264 fz_stext_page * | |
| 265 fz_new_stext_page_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options) | |
| 266 { | |
| 267 fz_stext_page *text; | |
| 268 fz_device *dev = NULL; | |
| 269 | |
| 270 fz_var(dev); | |
| 271 | |
| 272 if (list == NULL) | |
| 273 return NULL; | |
| 274 | |
| 275 text = fz_new_stext_page(ctx, fz_bound_display_list(ctx, list)); | |
| 276 fz_try(ctx) | |
| 277 { | |
| 278 dev = fz_new_stext_device(ctx, text, options); | |
| 279 fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL); | |
| 280 fz_close_device(ctx, dev); | |
| 281 } | |
| 282 fz_always(ctx) | |
| 283 { | |
| 284 fz_drop_device(ctx, dev); | |
| 285 } | |
| 286 fz_catch(ctx) | |
| 287 { | |
| 288 fz_drop_stext_page(ctx, text); | |
| 289 fz_rethrow(ctx); | |
| 290 } | |
| 291 | |
| 292 return text; | |
| 293 } | |
| 294 | |
| 295 fz_stext_page * | |
| 296 fz_new_stext_page_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options) | |
| 297 { | |
| 298 fz_stext_page *text; | |
| 299 fz_device *dev = NULL; | |
| 300 | |
| 301 fz_var(dev); | |
| 302 | |
| 303 if (page == NULL) | |
| 304 return NULL; | |
| 305 | |
| 306 text = fz_new_stext_page(ctx, fz_bound_page(ctx, page)); | |
| 307 fz_try(ctx) | |
| 308 { | |
| 309 dev = fz_new_stext_device(ctx, text, options); | |
| 310 fz_run_page_contents(ctx, page, dev, fz_identity, NULL); | |
| 311 fz_close_device(ctx, dev); | |
| 312 } | |
| 313 fz_always(ctx) | |
| 314 { | |
| 315 fz_drop_device(ctx, dev); | |
| 316 } | |
| 317 fz_catch(ctx) | |
| 318 { | |
| 319 fz_drop_stext_page(ctx, text); | |
| 320 fz_rethrow(ctx); | |
| 321 } | |
| 322 | |
| 323 return text; | |
| 324 } | |
| 325 | |
| 326 fz_stext_page * | |
| 327 fz_new_stext_page_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options) | |
| 328 { | |
| 329 fz_page *page; | |
| 330 fz_stext_page *text = NULL; | |
| 331 | |
| 332 page = fz_load_page(ctx, doc, number); | |
| 333 fz_try(ctx) | |
| 334 text = fz_new_stext_page_from_page(ctx, page, options); | |
| 335 fz_always(ctx) | |
| 336 fz_drop_page(ctx, page); | |
| 337 fz_catch(ctx) | |
| 338 fz_rethrow(ctx); | |
| 339 return text; | |
| 340 } | |
| 341 | |
| 342 fz_stext_page * | |
| 343 fz_new_stext_page_from_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const fz_stext_options *options) | |
| 344 { | |
| 345 fz_page *page; | |
| 346 fz_stext_page *text = NULL; | |
| 347 | |
| 348 page = fz_load_chapter_page(ctx, doc, chapter, number); | |
| 349 fz_try(ctx) | |
| 350 text = fz_new_stext_page_from_page(ctx, page, options); | |
| 351 fz_always(ctx) | |
| 352 fz_drop_page(ctx, page); | |
| 353 fz_catch(ctx) | |
| 354 fz_rethrow(ctx); | |
| 355 return text; | |
| 356 } | |
| 357 | |
| 358 int | |
| 359 fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) | |
| 360 { | |
| 361 fz_stext_page *text; | |
| 362 int count = 0; | |
| 363 | |
| 364 text = fz_new_stext_page_from_display_list(ctx, list, NULL); | |
| 365 fz_try(ctx) | |
| 366 count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max); | |
| 367 fz_always(ctx) | |
| 368 fz_drop_stext_page(ctx, text); | |
| 369 fz_catch(ctx) | |
| 370 fz_rethrow(ctx); | |
| 371 return count; | |
| 372 } | |
| 373 | |
| 374 int | |
| 375 fz_search_display_list_cb(fz_context *ctx, fz_display_list *list, const char *needle, fz_search_callback_fn *cb, void *opaque) | |
| 376 { | |
| 377 fz_stext_page *text; | |
| 378 int count = 0; | |
| 379 | |
| 380 text = fz_new_stext_page_from_display_list(ctx, list, NULL); | |
| 381 fz_try(ctx) | |
| 382 count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque); | |
| 383 fz_always(ctx) | |
| 384 fz_drop_stext_page(ctx, text); | |
| 385 fz_catch(ctx) | |
| 386 fz_rethrow(ctx); | |
| 387 return count; | |
| 388 } | |
| 389 | |
| 390 int | |
| 391 fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) | |
| 392 { | |
| 393 fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; | |
| 394 fz_stext_page *text; | |
| 395 int count = 0; | |
| 396 | |
| 397 text = fz_new_stext_page_from_page(ctx, page, &opts); | |
| 398 fz_try(ctx) | |
| 399 count = fz_search_stext_page(ctx, text, needle, hit_mark, hit_bbox, hit_max); | |
| 400 fz_always(ctx) | |
| 401 fz_drop_stext_page(ctx, text); | |
| 402 fz_catch(ctx) | |
| 403 fz_rethrow(ctx); | |
| 404 return count; | |
| 405 } | |
| 406 | |
| 407 int | |
| 408 fz_search_page_cb(fz_context *ctx, fz_page *page, const char *needle, fz_search_callback_fn *cb, void *opaque) | |
| 409 { | |
| 410 fz_stext_options opts = { FZ_STEXT_DEHYPHENATE }; | |
| 411 fz_stext_page *text; | |
| 412 int count = 0; | |
| 413 | |
| 414 text = fz_new_stext_page_from_page(ctx, page, &opts); | |
| 415 fz_try(ctx) | |
| 416 count = fz_search_stext_page_cb(ctx, text, needle, cb, opaque); | |
| 417 fz_always(ctx) | |
| 418 fz_drop_stext_page(ctx, text); | |
| 419 fz_catch(ctx) | |
| 420 fz_rethrow(ctx); | |
| 421 return count; | |
| 422 } | |
| 423 | |
| 424 int | |
| 425 fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) | |
| 426 { | |
| 427 fz_page *page; | |
| 428 int count = 0; | |
| 429 | |
| 430 page = fz_load_page(ctx, doc, number); | |
| 431 fz_try(ctx) | |
| 432 count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max); | |
| 433 fz_always(ctx) | |
| 434 fz_drop_page(ctx, page); | |
| 435 fz_catch(ctx) | |
| 436 fz_rethrow(ctx); | |
| 437 return count; | |
| 438 } | |
| 439 | |
| 440 int | |
| 441 fz_search_page_number_cb(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_search_callback_fn *cb, void *opaque) | |
| 442 { | |
| 443 fz_page *page; | |
| 444 int count = 0; | |
| 445 | |
| 446 page = fz_load_page(ctx, doc, number); | |
| 447 fz_try(ctx) | |
| 448 count = fz_search_page_cb(ctx, page, needle, cb, opaque); | |
| 449 fz_always(ctx) | |
| 450 fz_drop_page(ctx, page); | |
| 451 fz_catch(ctx) | |
| 452 fz_rethrow(ctx); | |
| 453 return count; | |
| 454 } | |
| 455 | |
| 456 int | |
| 457 fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max) | |
| 458 { | |
| 459 fz_page *page; | |
| 460 int count = 0; | |
| 461 | |
| 462 page = fz_load_chapter_page(ctx, doc, chapter, number); | |
| 463 fz_try(ctx) | |
| 464 count = fz_search_page(ctx, page, needle, hit_mark, hit_bbox, hit_max); | |
| 465 fz_always(ctx) | |
| 466 fz_drop_page(ctx, page); | |
| 467 fz_catch(ctx) | |
| 468 fz_rethrow(ctx); | |
| 469 return count; | |
| 470 } | |
| 471 | |
| 472 int | |
| 473 fz_search_chapter_page_number_cb(fz_context *ctx, fz_document *doc, int chapter, int number, const char *needle, fz_search_callback_fn *cb, void *opaque) | |
| 474 { | |
| 475 fz_page *page; | |
| 476 int count = 0; | |
| 477 | |
| 478 page = fz_load_chapter_page(ctx, doc, chapter, number); | |
| 479 fz_try(ctx) | |
| 480 count = fz_search_page_cb(ctx, page, needle, cb, opaque); | |
| 481 fz_always(ctx) | |
| 482 fz_drop_page(ctx, page); | |
| 483 fz_catch(ctx) | |
| 484 fz_rethrow(ctx); | |
| 485 return count; | |
| 486 } | |
| 487 | |
| 488 fz_buffer * | |
| 489 fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page) | |
| 490 { | |
| 491 fz_stext_block *block; | |
| 492 fz_stext_line *line; | |
| 493 fz_stext_char *ch; | |
| 494 fz_buffer *buf; | |
| 495 | |
| 496 buf = fz_new_buffer(ctx, 256); | |
| 497 fz_try(ctx) | |
| 498 { | |
| 499 for (block = page->first_block; block; block = block->next) | |
| 500 { | |
| 501 if (block->type == FZ_STEXT_BLOCK_TEXT) | |
| 502 { | |
| 503 for (line = block->u.t.first_line; line; line = line->next) | |
| 504 { | |
| 505 for (ch = line->first_char; ch; ch = ch->next) | |
| 506 fz_append_rune(ctx, buf, ch->c); | |
| 507 fz_append_byte(ctx, buf, '\n'); | |
| 508 } | |
| 509 fz_append_byte(ctx, buf, '\n'); | |
| 510 } | |
| 511 } | |
| 512 } | |
| 513 fz_catch(ctx) | |
| 514 { | |
| 515 fz_drop_buffer(ctx, buf); | |
| 516 fz_rethrow(ctx); | |
| 517 } | |
| 518 | |
| 519 return buf; | |
| 520 } | |
| 521 | |
| 522 fz_buffer * | |
| 523 fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options) | |
| 524 { | |
| 525 fz_stext_page *text; | |
| 526 fz_buffer *buf = NULL; | |
| 527 | |
| 528 text = fz_new_stext_page_from_display_list(ctx, list, options); | |
| 529 fz_try(ctx) | |
| 530 buf = fz_new_buffer_from_stext_page(ctx, text); | |
| 531 fz_always(ctx) | |
| 532 fz_drop_stext_page(ctx, text); | |
| 533 fz_catch(ctx) | |
| 534 fz_rethrow(ctx); | |
| 535 return buf; | |
| 536 } | |
| 537 | |
| 538 fz_buffer * | |
| 539 fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options) | |
| 540 { | |
| 541 fz_stext_page *text; | |
| 542 fz_buffer *buf = NULL; | |
| 543 | |
| 544 text = fz_new_stext_page_from_page(ctx, page, options); | |
| 545 fz_try(ctx) | |
| 546 buf = fz_new_buffer_from_stext_page(ctx, text); | |
| 547 fz_always(ctx) | |
| 548 fz_drop_stext_page(ctx, text); | |
| 549 fz_catch(ctx) | |
| 550 fz_rethrow(ctx); | |
| 551 return buf; | |
| 552 } | |
| 553 | |
| 554 fz_buffer * | |
| 555 fz_new_buffer_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options) | |
| 556 { | |
| 557 fz_page *page; | |
| 558 fz_buffer *buf = NULL; | |
| 559 | |
| 560 page = fz_load_page(ctx, doc, number); | |
| 561 fz_try(ctx) | |
| 562 buf = fz_new_buffer_from_page(ctx, page, options); | |
| 563 fz_always(ctx) | |
| 564 fz_drop_page(ctx, page); | |
| 565 fz_catch(ctx) | |
| 566 fz_rethrow(ctx); | |
| 567 return buf; | |
| 568 } | |
| 569 | |
| 570 void | |
| 571 fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image) | |
| 572 { | |
| 573 fz_compressed_buffer *cbuf; | |
| 574 fz_buffer *buf; | |
| 575 | |
| 576 cbuf = fz_compressed_image_buffer(ctx, image); | |
| 577 | |
| 578 if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG) | |
| 579 { | |
| 580 int type = fz_colorspace_type(ctx, image->colorspace); | |
| 581 if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB) | |
| 582 { | |
| 583 fz_write_string(ctx, out, "data:image/jpeg;base64,"); | |
| 584 fz_write_base64_buffer(ctx, out, cbuf->buffer, 1); | |
| 585 return; | |
| 586 } | |
| 587 } | |
| 588 if (cbuf && cbuf->params.type == FZ_IMAGE_PNG) | |
| 589 { | |
| 590 fz_write_string(ctx, out, "data:image/png;base64,"); | |
| 591 fz_write_base64_buffer(ctx, out, cbuf->buffer, 1); | |
| 592 return; | |
| 593 } | |
| 594 | |
| 595 buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params); | |
| 596 fz_try(ctx) | |
| 597 { | |
| 598 fz_write_string(ctx, out, "data:image/png;base64,"); | |
| 599 fz_write_base64_buffer(ctx, out, buf, 1); | |
| 600 } | |
| 601 fz_always(ctx) | |
| 602 fz_drop_buffer(ctx, buf); | |
| 603 fz_catch(ctx) | |
| 604 fz_rethrow(ctx); | |
| 605 } | |
| 606 | |
| 607 static uint32_t read16(const uint8_t *d, size_t *pos, size_t len, int order) | |
| 608 { | |
| 609 size_t p = *pos; | |
| 610 uint32_t v; | |
| 611 | |
| 612 if (p+1 >= len) | |
| 613 { | |
| 614 *pos = len; | |
| 615 return 0; | |
| 616 } | |
| 617 | |
| 618 if (order) | |
| 619 { | |
| 620 v = d[p++]<<8; /* BE */ | |
| 621 v |= d[p++]; | |
| 622 } | |
| 623 else | |
| 624 { | |
| 625 v = d[p++]; /* LE */ | |
| 626 v |= d[p++]<<8; | |
| 627 } | |
| 628 | |
| 629 *pos = p; | |
| 630 | |
| 631 return v; | |
| 632 } | |
| 633 | |
| 634 static uint32_t read32(const uint8_t *d, size_t *pos, size_t len, int order) | |
| 635 { | |
| 636 size_t p = *pos; | |
| 637 uint32_t v; | |
| 638 | |
| 639 if (p+3 >= len) | |
| 640 { | |
| 641 *pos = len; | |
| 642 return 0; | |
| 643 } | |
| 644 | |
| 645 if (order) | |
| 646 { | |
| 647 v = d[p++]<<24; /* BE */ | |
| 648 v |= d[p++]<<16; | |
| 649 v |= d[p++]<<8; | |
| 650 v |= d[p++]; | |
| 651 } | |
| 652 else | |
| 653 { | |
| 654 v = d[p++]; | |
| 655 v |= d[p++]<<8; /* LE */ | |
| 656 v |= d[p++]<<16; | |
| 657 v |= d[p++]<<24; | |
| 658 } | |
| 659 | |
| 660 *pos = p; | |
| 661 | |
| 662 return v; | |
| 663 } | |
| 664 | |
| 665 static void write16(uint8_t *d, size_t *pos, size_t len, int order, uint32_t v) | |
| 666 { | |
| 667 size_t p = *pos; | |
| 668 | |
| 669 if (p+1 >= len) | |
| 670 { | |
| 671 *pos = len; | |
| 672 return; | |
| 673 } | |
| 674 | |
| 675 if (order) | |
| 676 { | |
| 677 d[p++] = (v>>8); | |
| 678 d[p++] = v; | |
| 679 } | |
| 680 else | |
| 681 { | |
| 682 d[p++] = v; | |
| 683 d[p++] = (v>>8); | |
| 684 } | |
| 685 | |
| 686 *pos = p; | |
| 687 } | |
| 688 | |
| 689 static void write32( uint8_t *d, size_t *pos, size_t len, int order, uint32_t v) | |
| 690 { | |
| 691 size_t p = *pos; | |
| 692 | |
| 693 if (p+3 >= len) | |
| 694 { | |
| 695 *pos = len; | |
| 696 return; | |
| 697 } | |
| 698 | |
| 699 if (order) | |
| 700 { | |
| 701 d[p++] = (v>>24); | |
| 702 d[p++] = (v>>16); | |
| 703 d[p++] = (v>>8); | |
| 704 d[p++] = v; | |
| 705 } | |
| 706 else | |
| 707 { | |
| 708 d[p++] = v; | |
| 709 d[p++] = (v>>8); | |
| 710 d[p++] = (v>>16); | |
| 711 d[p++] = (v>>24); | |
| 712 } | |
| 713 | |
| 714 *pos = p; | |
| 715 } | |
| 716 | |
| 717 fz_buffer * | |
| 718 fz_sanitize_jpeg_buffer(fz_context *ctx, fz_buffer *in) | |
| 719 { | |
| 720 fz_buffer *out = fz_clone_buffer(ctx, in); | |
| 721 size_t len = out->len; | |
| 722 size_t pos = 0; | |
| 723 uint8_t *d = out->data; | |
| 724 | |
| 725 /* We need at least 4 data bytes. */ | |
| 726 while (pos+4 < len) | |
| 727 { | |
| 728 uint8_t m; | |
| 729 /* We should be on a marker. If not, inch forwards until we are. */ | |
| 730 if (d[pos++] != 0xff) | |
| 731 continue; | |
| 732 m = d[pos++]; | |
| 733 if (m == 0xDA) | |
| 734 break; /* Start Of Scan. All our rewriting happens before this. */ | |
| 735 if (m == 0xE1) | |
| 736 { | |
| 737 uint8_t order; | |
| 738 uint32_t tmp; | |
| 739 size_t body_start; | |
| 740 /* APP1 tag. This is where the EXIF data lives. */ | |
| 741 /* Read and discard the marker length. We're not continuing after this anyway. */ | |
| 742 (void)read16(d, &pos, len, 0); | |
| 743 tmp = read32(d, &pos, len, 0); | |
| 744 if (tmp != 0x66697845) /* Exif */ | |
| 745 break; /* Not exif - nothing to rewrite. */ | |
| 746 tmp = read16(d, &pos, len, 0); | |
| 747 if (tmp != 0) /* Terminator + Pad */ | |
| 748 break; /* Not exif - nothing to rewrite. */ | |
| 749 /* Now we're at the APP1 Body. */ | |
| 750 body_start = pos; | |
| 751 tmp = read16(d, &pos, len, 0); | |
| 752 if (tmp == 0x4949) | |
| 753 order = 0; /* LE */ | |
| 754 else if (tmp == 0x4d4d) | |
| 755 order = 1; /* BE */ | |
| 756 else | |
| 757 break; /* Bad TIFF type. Bale. */ | |
| 758 tmp = read16(d, &pos, len, order); | |
| 759 if (tmp != 0x002a) /* 42 */ | |
| 760 break; /* Bad version field. Bale. */ | |
| 761 do | |
| 762 { | |
| 763 uint32_t i, n; | |
| 764 tmp = read32(d, &pos, len, order); | |
| 765 pos = body_start + tmp; | |
| 766 if (tmp == 0 || pos >= len) | |
| 767 break; | |
| 768 n = read16(d, &pos, len, order); | |
| 769 for (i = 0; i < n; i++) | |
| 770 { | |
| 771 if (read16(d, &pos, len, order) == 0x112) | |
| 772 { | |
| 773 /* Orientation tag! */ | |
| 774 write16(d, &pos, len, order, 3); /* 3 = short */ | |
| 775 write32(d, &pos, len, order, 1); /* Count = 1 */ | |
| 776 write16(d, &pos, len, order, 1); /* Value = 1 */ | |
| 777 write16(d, &pos, len, order, 0); /* padding */ | |
| 778 i = n; | |
| 779 pos = len; /* Done! */ | |
| 780 } | |
| 781 else | |
| 782 pos += 10; | |
| 783 } | |
| 784 } | |
| 785 while (pos+4 < len); | |
| 786 break; | |
| 787 } | |
| 788 else if (m >= 0xD0 && m <= 0xD7) | |
| 789 { | |
| 790 /* RSTm - no length code. But we shouldn't hit this! */ | |
| 791 } | |
| 792 else if (m == 0x01) | |
| 793 { | |
| 794 /* TEM - temporary private use in arithmetic coding - shouldn't hit this either. */ | |
| 795 } | |
| 796 else if (m == 0xD8) | |
| 797 { | |
| 798 /* SOI - start of image. */ | |
| 799 } | |
| 800 else if (m == 0x01) | |
| 801 { | |
| 802 /* EOI - end of image. */ | |
| 803 } | |
| 804 else | |
| 805 { | |
| 806 /* All other markers have a length. */ | |
| 807 size_t marker_len = d[pos]*256 + d[pos+1]; | |
| 808 pos += marker_len; /* The 2 length bytes are included in the marker_len */ | |
| 809 } | |
| 810 } | |
| 811 | |
| 812 return out; | |
| 813 } | |
| 814 | |
| 815 void | |
| 816 fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image) | |
| 817 { | |
| 818 fz_compressed_buffer *cbuf; | |
| 819 fz_buffer *buf; | |
| 820 const char *mime; | |
| 821 | |
| 822 cbuf = fz_compressed_image_buffer(ctx, image); | |
| 823 | |
| 824 if (cbuf && cbuf->params.type == FZ_IMAGE_JPEG) | |
| 825 { | |
| 826 int type = fz_colorspace_type(ctx, image->colorspace); | |
| 827 if (type == FZ_COLORSPACE_GRAY || type == FZ_COLORSPACE_RGB) | |
| 828 { | |
| 829 fz_buffer *new_buf = fz_sanitize_jpeg_buffer(ctx, cbuf->buffer); | |
| 830 fz_append_string(ctx, out, "data:image/jpeg;base64,"); | |
| 831 fz_try(ctx) | |
| 832 fz_append_base64_buffer(ctx, out, new_buf, 1); | |
| 833 fz_always(ctx) | |
| 834 fz_drop_buffer(ctx, new_buf); | |
| 835 fz_catch(ctx) | |
| 836 fz_rethrow(ctx); | |
| 837 return; | |
| 838 } | |
| 839 } | |
| 840 | |
| 841 if (cbuf && cbuf->params.type == FZ_IMAGE_PNG) | |
| 842 { | |
| 843 fz_append_string(ctx, out, "data:image/png;base64,"); | |
| 844 fz_append_base64_buffer(ctx, out, cbuf->buffer, 1); | |
| 845 return; | |
| 846 } | |
| 847 | |
| 848 if (fz_is_lossy_image(ctx, image)) | |
| 849 { | |
| 850 /* Convert lossy image formats to JPEG */ | |
| 851 buf = fz_new_buffer_from_image_as_jpeg(ctx, image, fz_default_color_params, 90, 0); | |
| 852 mime = "data:image/jpeg;base64,"; | |
| 853 } | |
| 854 else | |
| 855 { | |
| 856 buf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params); | |
| 857 mime = "data:image/png;base64,"; | |
| 858 } | |
| 859 | |
| 860 fz_try(ctx) | |
| 861 { | |
| 862 fz_append_string(ctx, out, mime); | |
| 863 fz_append_base64_buffer(ctx, out, buf, 1); | |
| 864 } | |
| 865 fz_always(ctx) | |
| 866 fz_drop_buffer(ctx, buf); | |
| 867 fz_catch(ctx) | |
| 868 fz_rethrow(ctx); | |
| 869 } | |
| 870 | |
| 871 void | |
| 872 fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap) | |
| 873 { | |
| 874 fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params); | |
| 875 fz_try(ctx) | |
| 876 { | |
| 877 fz_write_string(ctx, out, "data:image/png;base64,"); | |
| 878 fz_write_base64_buffer(ctx, out, buf, 1); | |
| 879 } | |
| 880 fz_always(ctx) | |
| 881 fz_drop_buffer(ctx, buf); | |
| 882 fz_catch(ctx) | |
| 883 fz_rethrow(ctx); | |
| 884 } | |
| 885 | |
| 886 void | |
| 887 fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap) | |
| 888 { | |
| 889 fz_buffer *buf = fz_new_buffer_from_pixmap_as_png(ctx, pixmap, fz_default_color_params); | |
| 890 fz_try(ctx) | |
| 891 { | |
| 892 fz_append_string(ctx, out, "data:image/png;base64,"); | |
| 893 fz_append_base64_buffer(ctx, out, buf, 1); | |
| 894 } | |
| 895 fz_always(ctx) | |
| 896 fz_drop_buffer(ctx, buf); | |
| 897 fz_catch(ctx) | |
| 898 fz_rethrow(ctx); | |
| 899 } | |
| 900 | |
| 901 fz_document * | |
| 902 fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts) | |
| 903 { | |
| 904 fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE }; | |
| 905 fz_document *new_doc; | |
| 906 fz_buffer *buf = NULL; | |
| 907 fz_output *out = NULL; | |
| 908 fz_stream *stm = NULL; | |
| 909 fz_stext_page *text = NULL; | |
| 910 int i; | |
| 911 | |
| 912 fz_var(buf); | |
| 913 fz_var(out); | |
| 914 fz_var(stm); | |
| 915 fz_var(text); | |
| 916 | |
| 917 if (!opts) | |
| 918 opts = &default_opts; | |
| 919 | |
| 920 fz_try(ctx) | |
| 921 { | |
| 922 buf = fz_new_buffer(ctx, 8192); | |
| 923 out = fz_new_output_with_buffer(ctx, buf); | |
| 924 fz_print_stext_header_as_xhtml(ctx, out); | |
| 925 | |
| 926 for (i = 0; i < fz_count_pages(ctx, old_doc); ++i) | |
| 927 { | |
| 928 text = fz_new_stext_page_from_page_number(ctx, old_doc, i, opts); | |
| 929 fz_print_stext_page_as_xhtml(ctx, out, text, i+1); | |
| 930 fz_drop_stext_page(ctx, text); | |
| 931 text = NULL; | |
| 932 } | |
| 933 | |
| 934 fz_print_stext_trailer_as_xhtml(ctx, out); | |
| 935 fz_close_output(ctx, out); | |
| 936 fz_terminate_buffer(ctx, buf); | |
| 937 | |
| 938 stm = fz_open_buffer(ctx, buf); | |
| 939 new_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm); | |
| 940 } | |
| 941 fz_always(ctx) | |
| 942 { | |
| 943 fz_drop_stream(ctx, stm); | |
| 944 fz_drop_buffer(ctx, buf); | |
| 945 fz_drop_output(ctx, out); | |
| 946 fz_drop_stext_page(ctx, text); | |
| 947 } | |
| 948 fz_catch(ctx) | |
| 949 fz_rethrow(ctx); | |
| 950 | |
| 951 return new_doc; | |
| 952 } | |
| 953 | |
| 954 fz_buffer * | |
| 955 fz_new_buffer_from_page_with_format(fz_context *ctx, fz_page *page, const char *format, const char *options, fz_matrix transform, fz_cookie *cookie) | |
| 956 { | |
| 957 fz_buffer *buf = NULL; | |
| 958 fz_output *out; | |
| 959 fz_document_writer *writer = NULL; | |
| 960 fz_device *dev = NULL; | |
| 961 | |
| 962 fz_var(buf); | |
| 963 fz_var(writer); | |
| 964 fz_var(dev); | |
| 965 | |
| 966 fz_try(ctx) | |
| 967 { | |
| 968 buf = fz_new_buffer(ctx, 0); | |
| 969 out = fz_new_output_with_buffer(ctx, buf); | |
| 970 writer = fz_new_document_writer_with_output(ctx, out, format, options); | |
| 971 dev = fz_begin_page(ctx, writer, fz_bound_page(ctx, page)); | |
| 972 fz_run_page(ctx, page, dev, transform, cookie); | |
| 973 fz_end_page(ctx, writer); | |
| 974 fz_close_document_writer(ctx, writer); | |
| 975 } | |
| 976 fz_always(ctx) | |
| 977 fz_drop_document_writer(ctx, writer); | |
| 978 fz_catch(ctx) | |
| 979 { | |
| 980 fz_drop_buffer(ctx, buf); | |
| 981 fz_rethrow(ctx); | |
| 982 } | |
| 983 return buf; | |
| 984 } |
