Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/docs/examples/storytest.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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/docs/examples/storytest.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,557 @@ +#include "mupdf/fitz.h" +#include "mupdf/pdf.h" + +#include <string.h> +#include <memory.h> + +const char snark[] = + "<!DOCTYPE html>" + "<style>" + "#a { margin: 30px; }" + "#b { margin: 20px; }" + "#c { margin: 5px; }" + "#a { border: 1px solid red; }" + "#b { border: 1px solid green; }" + "#c { border: 1px solid blue; }" + "</style>" + "<body>" + "<div id=\"a\">" + "A" + "</div>" + "<div id=\"b\">" + "<div id=\"c\">" + "C" + "</div>" + "</div>" + "<div style=\"text-align:center;\"><IMG width=\"300\" src=\"docs/examples/SnarkFront.svg\"></div>" + "<H1>The hunting of the Snark</H1>" + "<div style=\"text-align:center\"><IMG width=\"30\" src=\"docs/examples/huntingofthesnark.png\"></div>" + "<p>\"Just the place for a Snark!\" the Bellman cried,<br>" + "As he landed his crew with care;<br>" + "Supporting each man on the top of the tide<br>" + "By a finger entwined in his hair.</p>" + + "<P>Just the place for a Snark! I have said it twice:<br>" + "That alone should encourage the crew.<br>" + "Just the place for a Snark! I have said it thrice:<br>" + "What I tell you three times is true.</p>" + + "<p>The crew was complete: it included a Boots-<br>" + "A maker of Bonnets and Hoods-<br>" + "A Barrister, brought to arrange their disputes-<br>" + "And a Broker, to value their goods.</p>" + + "<p>A Billiard-marker, whose skill was immense,<br>" + "Might perhaps have won more than his share-<br>" + "But a Banker, engaged at enormous expense,<br>" + "Had the whole of their cash in his care.</p>" + + "<p>There was also a Beaver, that paced on the deck,<br>" + "Or would sit making lace in the bow:<br>" + "And had often (the Bellman said) saved them from wreck,<br>" + "Though none of the sailors knew how.</p>" + + "<p>There was one who was famed for the number of things<br>" + "He forgot when he entered the ship:<br>" + "His umbrella, his watch, all his jewels and rings,<br>" + "And the clothes he had bought for the trip.</p>" + "<div id=\"a\">" + "<p>He had forty-two boxes, all carefully packed,<br>" + "With his name painted clearly on each:<br>" + "But, since he omitted to mention the fact,<br>" + "They were all left behind on the beach.</p>" + "</div>" + + "<p>The loss of his clothes hardly mattered, because<br>" + "He had seven coats on when he came,<br>" + "With three pair of boots-but the worst of it was,<br>" + "He had wholly forgotten his name.</p>" + + "<p>He would answer to \"Hi!\" or to any loud cry,<br>" + "Such as \"Fry me!\" or \"Fritter my wig!\"<br>" + "To \"What-you-may-call-um!\" or \"What-was-his-name!\"<br>" + "But especially \"Thing-um-a-jig!\"</p>" + + "<p>While, for those who preferred a more forcible word,<br>" + "He had different names from these:<br>" + "His intimate friends called him \"Candle-ends,\"<br>" + "And his enemies \"Toasted-cheese.\"</p>" + + "<p>\"His form is ungainly-his intellect small-\"<br>" + "(So the Bellman would often remark)<br>" + "\"But his courage is perfect! And that, after all,<br>" + "Is the thing that one needs with a Snark.\"</p>" + + "<p>He would joke with hyenas, returning their stare<br>" + "With an impudent wag of the head:<br>" + "And he once went a walk, paw-in-paw, with a bear,<br>" + "\"Just to keep up its spirits,\" he said.</p>" + + "<p>He came as a Baker: but owned, when too late-<br>" + "And it drove the poor Bellman half-mad-<br>" + "He could only bake Bride-cake-for which, I may state,<br>" + "No materials were to be had.</p>" + + "<p>The last of the crew needs especial remark,<br>" + "Though he looked an incredible dunce:<br>" + "He had just one idea-but, that one being \"Snark,\"<br>" + "The good Bellman engaged him at once.</p>" + + "<p>He came as a Butcher: but gravely declared,<br>" + "When the ship had been sailing a week,<br>" + "He could only kill Beavers. The Bellman looked scared,<br>" + "And was almost too frightened to speak:</p>" + + "<p>But at length he explained, in a tremulous tone,<br>" + "There was only one Beaver on board;<br>" + "And that was a tame one he had of his own,<br>" + "Whose death would be deeply deplored.</p>" + + "<div id=\"b\">" + "<p>The Beaver, who happened to hear the remark,<br>" + "Protested, with tears in its eyes,<br>" + "That not even the rapture of hunting the Snark<br>" + "Could atone for that dismal surprise!</p>" + "</div>" + + "<p style=\"-mupdf-leading:7pt;\">It strongly advised that the Butcher should be<br>" + "Conveyed in a separate ship:<br>" + "But the Bellman declared that would never agree<br>" + "With the plans he had made for the trip:</p>" + + "<p style=\"-mupdf-leading:11pt;\">Navigation was always a difficult art,<br>" + "Though with only one ship and one bell:<br>" + "And he feared he must really decline, for his part,<br>" + "Undertaking another as well.</p>" + + "<p style=\"-mupdf-leading:15pt;\">The Beaver's best course was, no doubt, to procure<br>" + "A second-hand dagger-proof coat-<br>" + "So the Baker advised it-and next, to insure<br>" + "Its life in some Office of note:</p>" + + "<p style=\"-mupdf-leading:20pt;\">This the Banker suggested, and offered for hire<br>" + "(On moderate terms), or for sale,<br>" + "Two excellent Policies, one Against Fire,<br>" + "And one Against Damage From Hail.</p>" + + "<p style=\"-mupdf-leading:30pt;\">Yet still, ever after that sorrowful day,<br>" + "Whenever the Butcher was by,<br>" + "The Beaver kept looking the opposite way,<br>" + "And appeared unaccountably shy.</p>" +; + +#define MAX_CAST_MEMBERS 32 + +typedef struct { + const char *title; + const char *director; + const char *year; + const char *cast[MAX_CAST_MEMBERS]; +} film_t; + +static const film_t films[] = +{ + { + "Pulp Fiction", + "Quentin Tarantino", + "1994", + { + "John Travolta", + "Samuel L Jackson", + "Uma Thurman", + "Bruce Willis", + "Ving Rhames", + "Harvey Keitel", + "Tim Roth", + "Bridget Fonda" + } + }, + + { + "The Usual Suspects", + "Bryan Singer", + "1995", + { + "Kevin Spacey", + "Gabriel Byrne", + "Chazz Palminteri", + "Benicio Del Toro", + "Kevin Pollak", + "Pete Postlethwaite", + "Steven Baldwin" + } + + }, + + { + "Fight Club", + "David Fincher", + "1999", + { + "Brad Pitt", + "Edward Norton", + "Helena Bonham Carter" + } + } +}; + +const char *festival_template = + "<html><head><title>Why do we have a title? Why not?</title></head>" + "<body><h1 style=\"text-align:center\">Hook Norton Film Festival</h1>" + "<ol>" + "<li id=\"filmtemplate\">" + "<b id=\"filmtitle\"></b>" + "<dl>" + "<dt>Director<dd id=\"director\">" + "<dt>Release Year<dd id=\"filmyear\">" + "<dt>Cast<dd id=\"cast\">" + "</dl>" + "</li>" + "<ul>" + "</body></html"; + + +static int toc_rectfn(fz_context *ctx, void *ref, int num, fz_rect filled, fz_rect *rect, fz_matrix *ctm, fz_rect *mediabox) +{ + if (num == 0) + { + rect->x0 = 100; + rect->y0 = 200; + rect->x1 = 175; + rect->y1 = 300; + } + else + { + rect->x0 = 10; + rect->y0 = 50; + rect->x1 = 290; + rect->y1 = 350; + } + mediabox->x0 = 0; + mediabox->y0 = 0; + mediabox->x1 = 300; + mediabox->y1 = 400; + return 1; +} + +static void toc_contentfn(fz_context *ctx, void *ref, const fz_write_story_positions *positions, fz_buffer *buffer) +{ + int i; + fz_append_string(ctx, buffer, + "<!DOCTYPE html>\n" + "<style>\n" + "#a { margin: 30px; }\n" + "#b { margin: 20px; }\n" + "#c { margin: 5px; }\n" + "#a { border: 1px solid red; }\n" + "#b { border: 1px solid green; }\n" + "#c { border: 1px solid blue; }\n" + "</style>\n" + "<body>\n" + "<h2>Contents</h2>\n" + "<ol>\n" + ); + for (i=0; i<positions->num; ++i) + { + fz_write_story_position *position = &positions->positions[i]; + + fz_append_printf(ctx, buffer, + " <li>page=%i depth=%i heading=%i id='%s' rect=(%f %f %f %f) text='<b>%s</b>' open_close=%i\n", + position->page_num, + position->element.depth, + position->element.heading, + (position->element.id) ? position->element.id : "", + position->element.rect.x0, + position->element.rect.y0, + position->element.rect.x1, + position->element.rect.y1, + (position->element.text) ? position->element.text : "", + position->element.open_close + ); + } + fz_append_string(ctx, buffer, "</ol>\n"); + fz_append_string(ctx, buffer, + "<h1>Section the first</h1>\n" + "<p>Blah.\n" + "<h1>Section the second</h1>\n" + "<p>Blah blah.\n" + "<h2>Subsection</h2>\n" + "<p>Blah blah blah.\n" + "<p>Blah blah blah.\n" + "<p>Blah blah blah.\n" + "<h1>Section the third</h1>\n" + "<p>Blah blah.\n" + "</body>\n" + ); + { + const char *data = fz_string_from_buffer(ctx, buffer); + printf( "======== Html content: ========\n"); + printf( "%s", data); + printf( "========\n"); + } +} + +static void toc_pagefn(fz_context *ctx, void *ref, int page_num, fz_rect mediabox, fz_device *dev, int after) +{ + fz_path *path = fz_new_path(ctx); + fz_matrix ctm = fz_identity; + printf("toc_pagefn(): ref=%p page_num=%i dev=%p after=%i\n", ref, page_num, dev, after); + if (after) + { + float rgb[3] = { 0.75, 0.25, 0.125}; + fz_moveto(ctx, path, 50, 50); + fz_lineto(ctx, path, 100, 200); + fz_lineto(ctx, path, 50, 200); + fz_closepath(ctx, path); + fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgb, 0.9f /*alpha*/, fz_default_color_params); + fz_drop_path(ctx, path); + } + else + { + float rgb[3] = { 0.125, 0.25, 0.75}; + fz_moveto(ctx, path, 50, 50); + fz_lineto(ctx, path, 50, 200); + fz_lineto(ctx, path, 100, 50); + fz_closepath(ctx, path); + fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgb, 0.9f /*alpha*/, fz_default_color_params); + fz_drop_path(ctx, path); + } +} + +static void test_write_stabilized_story(fz_context *ctx) +{ + fz_document_writer *writer = fz_new_pdf_writer(ctx, "out_toc.pdf", ""); + fz_write_stabilized_story( + ctx, + writer, + "" /*user_css*/, + 11 /*em*/, + toc_contentfn, + NULL /*contentfn_ref*/, + toc_rectfn, + NULL /*rectfn_ref*/, + toc_pagefn /*pagefn*/, + NULL /*pagefn_ref*/, + NULL /* archive */ + ); + fz_close_document_writer(ctx, writer); + fz_drop_document_writer(ctx, writer); +} + +int main(int argc, const char *argv[]) +{ + fz_context *ctx; + fz_document_writer *writer = NULL; + fz_story *story = NULL; + fz_buffer *buf = NULL; + fz_device *dev = NULL; + fz_archive *archive = NULL; + fz_rect mediabox = { 0, 0, 512, 640 }; + float margin = 10; + int more; + + ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT); + if (ctx == NULL) + { + fprintf(stderr, "Failed to create context"); + return 1; + } + + fz_var(writer); + fz_var(story); + fz_var(buf); + fz_var(dev); + fz_var(archive); + + /* First one made with precooked content. */ + fz_try(ctx) + { + writer = fz_new_pdf_writer(ctx, "out.pdf", ""); + + buf = fz_new_buffer_from_copied_data(ctx, (unsigned char *)snark, strlen(snark)+1); + + archive = fz_open_directory(ctx, "."); + + story = fz_new_story(ctx, buf, "", 11, archive); + + do + { + fz_rect where; + fz_rect filled; + + where.x0 = mediabox.x0 + margin; + where.y0 = mediabox.y0 + margin; + where.x1 = mediabox.x1 - margin; + where.y1 = mediabox.y1 - margin; + + dev = fz_begin_page(ctx, writer, mediabox); + + more = fz_place_story(ctx, story, where, &filled); + + fz_draw_story(ctx, story, dev, fz_identity); + + fz_end_page(ctx, writer); + } + while (more); + + fz_close_document_writer(ctx, writer); + } + fz_always(ctx) + { + fz_drop_story(ctx, story); + fz_drop_buffer(ctx, buf); + fz_drop_document_writer(ctx, writer); + fz_drop_archive(ctx, archive); + } + fz_catch(ctx) + { + fz_report_error(ctx); + } + + /* Now one made with programmatic content. */ + writer = NULL; + buf = NULL; + story = NULL; + dev = NULL; + + fz_try(ctx) + { + fz_xml *dom, *body, *tmp; + + writer = fz_new_pdf_writer(ctx, "out2.pdf", ""); + + story = fz_new_story(ctx, NULL, "", 11, NULL); + + dom = fz_story_document(ctx, story); + + body = fz_dom_body(ctx, dom); + + fz_dom_append_child(ctx, body, fz_dom_create_text_node(ctx, dom, "This is some text.")); + tmp = fz_dom_create_element(ctx, dom, "b"); + fz_dom_append_child(ctx, body, tmp); + fz_dom_append_child(ctx, tmp, fz_dom_create_text_node(ctx, dom, "This is some bold text.")); + fz_dom_append_child(ctx, body, fz_dom_create_text_node(ctx, dom, "This is some normal text.")); + + do + { + fz_rect where; + fz_rect filled; + + where.x0 = mediabox.x0 + margin; + where.y0 = mediabox.y0 + margin; + where.x1 = mediabox.x1 - margin; + where.y1 = mediabox.y1 - margin; + + dev = fz_begin_page(ctx, writer, mediabox); + + more = fz_place_story(ctx, story, where, &filled); + + fz_draw_story(ctx, story, dev, fz_identity); + + fz_end_page(ctx, writer); + } + while (more); + + fz_close_document_writer(ctx, writer); + } + fz_always(ctx) + { + fz_drop_story(ctx, story); + fz_drop_buffer(ctx, buf); + fz_drop_document_writer(ctx, writer); + } + fz_catch(ctx) + { + fz_report_error(ctx); + } + + /* Now a combination of the two. */ + writer = NULL; + buf = NULL; + story = NULL; + dev = NULL; + + fz_try(ctx) + { + fz_xml *dom, *body, *tmp, *templat; + int i, j; + + writer = fz_new_pdf_writer(ctx, "out3.pdf", ""); + + buf = fz_new_buffer_from_copied_data(ctx, (unsigned char *)festival_template, strlen(festival_template)+1); + story = fz_new_story(ctx, buf, "", 11, NULL); + + dom = fz_story_document(ctx, story); + + body = fz_dom_body(ctx, dom); + + templat = fz_dom_find(ctx, body, NULL, "id", "filmtemplate"); + + for (i = 0; i < nelem(films); i++) + { + fz_xml *film = fz_dom_clone(ctx, templat); + + /* Now fill in some of the template. */ + tmp = fz_dom_find(ctx, film, NULL, "id", "filmtitle"); + fz_dom_append_child(ctx, tmp, fz_dom_create_text_node(ctx, dom, films[i].title)); + + tmp = fz_dom_find(ctx, film, NULL, "id", "director"); + fz_dom_append_child(ctx, tmp, fz_dom_create_text_node(ctx, dom, films[i].director)); + + tmp = fz_dom_find(ctx, film, NULL, "id", "filmyear"); + fz_dom_append_child(ctx, tmp, fz_dom_create_text_node(ctx, dom, films[i].year)); + + tmp = fz_dom_find(ctx, film, NULL, "id", "cast"); + for (j = 0; j < MAX_CAST_MEMBERS; j++) + { + if (films[i].cast[j] == NULL) + break; + fz_dom_append_child(ctx, tmp, fz_dom_create_text_node(ctx, dom, films[i].cast[j])); + fz_dom_append_child(ctx, tmp, fz_dom_create_element(ctx, dom, "br")); + } + + fz_dom_append_child(ctx, fz_dom_parent(ctx, templat), film); + } + + /* Remove the template. */ + fz_dom_remove(ctx, templat); + + do + { + fz_rect where; + fz_rect filled; + + where.x0 = mediabox.x0 + margin; + where.y0 = mediabox.y0 + margin; + where.x1 = mediabox.x1 - margin; + where.y1 = mediabox.y1 - margin; + + dev = fz_begin_page(ctx, writer, mediabox); + + more = fz_place_story(ctx, story, where, &filled); + + fz_draw_story(ctx, story, dev, fz_identity); + + fz_end_page(ctx, writer); + } + while (more); + + fz_close_document_writer(ctx, writer); + } + fz_always(ctx) + { + fz_drop_story(ctx, story); + fz_drop_buffer(ctx, buf); + fz_drop_document_writer(ctx, writer); + } + fz_catch(ctx) + { + fz_report_error(ctx); + } + + test_write_stabilized_story(ctx); + + fz_drop_context(ctx); + + return 0; +}
