Skip to content

Commit

Permalink
update mupdf
Browse files Browse the repository at this point in the history
  • Loading branch information
kjk committed Feb 17, 2023
1 parent 9aa748b commit dfa2314
Show file tree
Hide file tree
Showing 21 changed files with 910 additions and 229 deletions.
282 changes: 152 additions & 130 deletions mupdf/docs/examples/multi-threaded.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ depending on your environment.
// A convenience function for dying abruptly on pthread errors.

void
fail(char *msg)
fail(const char *msg)
{
fprintf(stderr, "%s\n", msg);
abort();
Expand All @@ -49,7 +49,7 @@ fail(char *msg)
// The data structure passed between the requesting main thread and
// each rendering thread.

struct data {
struct thread_data {
// A pointer to the original context in the main thread sent
// from main to rendering thread. It will be used to create
// each rendering thread's context clone.
Expand All @@ -74,41 +74,55 @@ struct data {
// thread, and then back from the rendering thread to the main
// thread.
fz_pixmap *pix;

// This is a note of whether a given thread failed or not.
int failed;
};

// This is the function run by each rendering function. It takes
// pointer to an instance of the data structure described above and
// renders the display list into the pixmap before exiting.

void *
renderer(void *data)
renderer(void *data_)
{
int pagenumber = ((struct data *) data)->pagenumber;
fz_context *ctx = ((struct data *) data)->ctx;
fz_display_list *list = ((struct data *) data)->list;
fz_rect bbox = ((struct data *) data)->bbox;
fz_pixmap *pix = ((struct data *) data)->pix;
fz_device *dev;
struct thread_data *data = (struct thread_data *)data_;
int pagenumber = data->pagenumber;
fz_context *ctx = data->ctx;
fz_display_list *list = data->list;
fz_rect bbox = data->bbox;
fz_device *dev = NULL;

fprintf(stderr, "thread at page %d loading!\n", pagenumber);

// The context pointer is pointing to the main thread's
// context, so here we create a new context based on it for
// use in this thread.

ctx = fz_clone_context(ctx);

// Next we run the display list through the draw device which
// will render the request area of the page to the pixmap.

fz_var(dev);

fprintf(stderr, "thread at page %d rendering!\n", pagenumber);
dev = fz_new_draw_device(ctx, fz_identity, pix);
fz_run_display_list(ctx, list, dev, fz_identity, bbox, NULL);
fz_close_device(ctx, dev);
fz_drop_device(ctx, dev);
fz_try(ctx)
{
// Create a white pixmap using the correct dimensions.
data->pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), fz_round_rect(bbox), NULL, 0);
fz_clear_pixmap_with_value(ctx, data->pix, 0xff);

// This threads context is freed.
// Do the actual rendering.
dev = fz_new_draw_device(ctx, fz_identity, data->pix);
fz_run_display_list(ctx, list, dev, fz_identity, bbox, NULL);
fz_close_device(ctx, dev);
}
fz_always(ctx)
fz_drop_device(ctx, dev);
fz_catch(ctx)
data->failed = 1;

// Free this thread's context.
fz_drop_context(ctx);

fprintf(stderr, "thread at page %d done!\n", pagenumber);
Expand Down Expand Up @@ -144,12 +158,11 @@ int main(int argc, char **argv)
fz_locks_context locks;
pthread_mutex_t mutex[FZ_LOCK_MAX];
fz_context *ctx;
fz_document *doc;
fz_document *doc = NULL;
int threads;
int i;

// Initialize FZ_LOCK_MAX number of non-recursive mutexes.

for (i = 0; i < FZ_LOCK_MAX; i++)
{
if (pthread_mutex_init(&mutex[i], NULL) != 0)
Expand All @@ -161,136 +174,145 @@ int main(int argc, char **argv)
// the user data is a pointer to the array of mutexes so the
// locking functions can find the relevant lock to change when
// they are called. This way we avoid global variables.

locks.user = mutex;
locks.lock = lock_mutex;
locks.unlock = unlock_mutex;

// This is the main threads context function, so supply the
// This is the main thread's context function, so supply the
// locking structure. This context will be used to parse all
// the pages from the document.

ctx = fz_new_context(NULL, &locks, FZ_STORE_UNLIMITED);

// Register default file types.

fz_register_document_handlers(ctx);

// Open the PDF, XPS or CBZ document. Note, this binds doc to ctx.
// You must only ever use doc with ctx - never a clone of it!
fz_var(thread);
fz_var(doc);

doc = fz_open_document(ctx, filename);

// Retrieve the number of pages, which translates to the
// number of threads used for rendering pages.

threads = fz_count_pages(ctx, doc);
fprintf(stderr, "spawning %d threads, one per page...\n", threads);

thread = malloc(threads * sizeof (pthread_t));

for (i = 0; i < threads; i++)
fz_try(ctx)
{
fz_page *page;
fz_rect bbox;
fz_display_list *list;
fz_device *dev;
fz_pixmap *pix;
struct data *data;

// Load the relevant page for each thread. Note, that this
// cannot be done on the worker threads, as each use of doc
// uses ctx, and only one thread can be using ctx at a time.

page = fz_load_page(ctx, doc, i);

// Compute the bounding box for each page.

bbox = fz_bound_page(ctx, page);

// Create a display list that will hold the drawing
// commands for the page. Once we have the display list
// this can safely be used on any other thread as it is
// not bound to a given context.

list = fz_new_display_list(ctx, bbox);

// Run the loaded page through a display list device
// to populate the page's display list.

dev = fz_new_list_device(ctx, list);
fz_run_page(ctx, page, dev, fz_identity, NULL);
fz_close_device(ctx, dev);
fz_drop_device(ctx, dev);

// The page is no longer needed, all drawing commands
// are now in the display list.

fz_drop_page(ctx, page);

// Create a white pixmap using the correct dimensions.

pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), fz_round_rect(bbox), NULL, 0);
fz_clear_pixmap_with_value(ctx, pix, 0xff);

// Populate the data structure to be sent to the
// rendering thread for this page.

data = malloc(sizeof (struct data));

data->pagenumber = i + 1;
data->ctx = ctx;
data->list = list;
data->bbox = bbox;
data->pix = pix;

// Create the thread and pass it the data structure.

if (pthread_create(&thread[i], NULL, renderer, data) != 0)
fail("pthread_create()");
// Register default file types.
fz_register_document_handlers(ctx);

// Open the PDF, XPS or CBZ document.
doc = fz_open_document(ctx, filename);

// Retrieve the number of pages, which translates to the
// number of threads used for rendering pages.
threads = fz_count_pages(ctx, doc);
fprintf(stderr, "spawning %d threads, one per page...\n", threads);

thread = malloc(threads * sizeof (*thread));

for (i = 0; i < threads; i++)
{
fz_page *page;
fz_rect bbox;
fz_display_list *list;
fz_device *dev = NULL;
fz_pixmap *pix;
struct thread_data *data;

fz_var(dev);

fz_try(ctx)
{
// Load the relevant page for each thread. Note, that this
// cannot be done on the worker threads, as only one thread
// at a time can ever be accessing the document.
page = fz_load_page(ctx, doc, i);

// Compute the bounding box for each page.
bbox = fz_bound_page(ctx, page);

// Create a display list that will hold the drawing
// commands for the page. Once we have the display list
// this can safely be used on any other thread.
list = fz_new_display_list(ctx, bbox);

// Create a display list device to populate the page's display list.
dev = fz_new_list_device(ctx, list);

// Run the page to that device.
fz_run_page(ctx, page, dev, fz_identity, NULL);

// Close the device neatly, so everything is flushed to the list.
fz_close_device(ctx, dev);
}
fz_always(ctx)
{
// Throw away the device.
fz_drop_device(ctx, dev);

// The page is no longer needed, all drawing commands
// are now in the display list.
fz_drop_page(ctx, page);
}
fz_catch(ctx)
fz_rethrow(ctx);

// Populate the data structure to be sent to the
// rendering thread for this page.
data = malloc(sizeof (*data));

data->pagenumber = i + 1;
data->ctx = ctx;
data->list = list;
data->bbox = bbox;
data->pix = NULL;
data->failed = 0;

// Create the thread and pass it the data structure.
if (pthread_create(&thread[i], NULL, renderer, data) != 0)
fail("pthread_create()");
}

// Now each thread is rendering pages, so wait for each thread
// to complete its rendering.
fprintf(stderr, "joining %d threads...\n", threads);
for (i = 0; i < threads; i++)
{
char filename[42];
struct thread_data *data;

if (pthread_join(thread[i], (void **) &data) != 0)
fail("pthread_join");

if (data->failed)
{
fprintf(stderr, "\tRendering for page %d failed\n", i + 1);
}
else
{
sprintf(filename, "out%04d.png", i);
fprintf(stderr, "\tSaving %s...\n", filename);

// Write the rendered image to a PNG file
fz_save_pixmap_as_png(ctx, data->pix, filename);
}

// Free the thread's pixmap and display list.
fz_drop_pixmap(ctx, data->pix);
fz_drop_display_list(ctx, data->list);

// Free the data structure passed back and forth
// between the main thread and rendering thread.
free(data);
}
}

// Now each thread is rendering pages, so wait for each thread
// to complete its rendering.

fprintf(stderr, "joining %d threads...\n", threads);
for (i = threads - 1; i >= 0; i--)
fz_always(ctx)
{
char filename[42];
struct data *data;
// Free the thread structure
free(thread);

if (pthread_join(thread[i], (void **) &data) != 0)
fail("pthread_join");

sprintf(filename, "out%04d.png", i);
fprintf(stderr, "\tSaving %s...\n", filename);

// Write the rendered image to a PNG file

fz_save_pixmap_as_png(ctx, data->pix, filename);

// Free the thread's pixmap and display list since
// they were allocated by the main thread above.

fz_drop_pixmap(ctx, data->pix);
fz_drop_display_list(ctx, data->list);

// Free the data structured passed back and forth
// between the main thread and rendering thread.

free(data);
// Drop the document
fz_drop_document(ctx, doc);
}
fz_catch(ctx)
fail(fz_caught_message(ctx));

// Finally the main thread's context is freed.
fz_drop_context(ctx);

fprintf(stderr, "finally!\n");
fflush(NULL);

free(thread);

// Finally the document is closed and the main thread's
// context is freed.

fz_drop_document(ctx, doc);
fz_drop_context(ctx);

return 0;
}
8 changes: 8 additions & 0 deletions mupdf/docs/manual-mutool-run.html
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ <h2>
<dd>Create a new link within the rectangle on the page, linking to the destination URI string.
<dt>Page#deleteLink(link)
<dd>Delete the link from the page.
<dt>Page#getLabel()
<dd>Returns the page number as a string using the numbering scheme of the document.
<dt>Page#isPDF()
<dd>Returns true if the page is from a PDF document.
</dl>
Expand Down Expand Up @@ -716,6 +718,12 @@ <h2>
<dd>Returns true if the document was an XFA form without AcroForm fields.
<dt>PDFDocument#wasRepaired()
<dd>Returns true if the document was repaired when opened.
<dt>PDFDocument#setPageLabels(index, label)
<dd>Sets the page label numbering for the page and all pages following it, until the next page with an attached label.
The label must be an array or object with three values: style, prefix, and start.
Style can be one of the following strings: "", "D", "R", "r", "A", or "a".
Start is the ordinal with which to start numbering.
If the label is null, any attached label is removed instead.
</dl>

<h3>
Expand Down
Loading

0 comments on commit dfa2314

Please sign in to comment.