diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/example.c | 100 | ||||
-rw-r--r-- | docs/man/mudraw.1 | 89 | ||||
-rw-r--r-- | docs/man/mupdf.1 | 92 | ||||
-rw-r--r-- | docs/man/mutool.1 | 77 | ||||
-rw-r--r-- | docs/multi-threaded.c | 266 | ||||
-rw-r--r-- | docs/naming.txt | 30 | ||||
-rw-r--r-- | docs/overview.txt | 268 | ||||
-rw-r--r-- | docs/refcount.txt | 17 | ||||
-rw-r--r-- | docs/thirdparty.txt | 38 |
9 files changed, 977 insertions, 0 deletions
diff --git a/docs/example.c b/docs/example.c new file mode 100644 index 00000000..1a21c200 --- /dev/null +++ b/docs/example.c @@ -0,0 +1,100 @@ +// Rendering a page of a PDF document to a PNG image in less than 100 lines. + +// Compile a debug build of mupdf, then compile and run this example: +// +// gcc -g -o build/debug/example -Iinclude doc/example.c build/debug/lib*.a -lm +// +// build/debug/example /path/to/document.pdf 1 200 25 + +// Include the MuPDF header file. +#include <mupdf/fitz.h> + +void +render(char *filename, int pagenumber, int zoom, int rotation) +{ + // Create a context to hold the exception stack and various caches. + + fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); + + // Open the PDF, XPS or CBZ document. + + fz_document *doc = fz_open_document(ctx, filename); + + // Retrieve the number of pages (not used in this example). + + int pagecount = fz_count_pages(doc); + + // Load the page we want. Page numbering starts from zero. + + fz_page *page = fz_load_page(doc, pagenumber - 1); + + // Calculate a transform to use when rendering. This transform + // contains the scale and rotation. Convert zoom percentage to a + // scaling factor. Without scaling the resolution is 72 dpi. + + fz_matrix transform; + fz_rotate(&transform, rotation); + fz_pre_scale(&transform, zoom / 100.0f, zoom / 100.0f); + + // Take the page bounds and transform them by the same matrix that + // we will use to render the page. + + fz_rect bounds; + fz_bound_page(doc, page, &bounds); + fz_transform_rect(&bounds, &transform); + + // Create a blank pixmap to hold the result of rendering. The + // pixmap bounds used here are the same as the transformed page + // bounds, so it will contain the entire page. The page coordinate + // space has the origin at the top left corner and the x axis + // extends to the right and the y axis extends down. + + fz_irect bbox; + fz_round_rect(&bbox, &bounds); + fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); + fz_clear_pixmap_with_value(ctx, pix, 0xff); + + // A page consists of a series of objects (text, line art, images, + // gradients). These objects are passed to a device when the + // interpreter runs the page. There are several devices, used for + // different purposes: + // + // draw device -- renders objects to a target pixmap. + // + // text device -- extracts the text in reading order with styling + // information. This text can be used to provide text search. + // + // list device -- records the graphic objects in a list that can + // be played back through another device. This is useful if you + // need to run the same page through multiple devices, without + // the overhead of parsing the page each time. + + // Create a draw device with the pixmap as its target. + // Run the page with the transform. + + fz_device *dev = fz_new_draw_device(ctx, pix); + fz_run_page(doc, page, dev, &transform, NULL); + fz_free_device(dev); + + // Save the pixmap to a file. + + fz_write_png(ctx, pix, "out.png", 0); + + // Clean up. + + fz_drop_pixmap(ctx, pix); + fz_free_page(doc, page); + fz_close_document(doc); + fz_free_context(ctx); +} + +int main(int argc, char **argv) +{ + char *filename = argv[1]; + int pagenumber = argc > 2 ? atoi(argv[2]) : 1; + int zoom = argc > 3 ? atoi(argv[3]) : 100; + int rotation = argc > 4 ? atoi(argv[4]) : 0; + + render(filename, pagenumber, zoom, rotation); + return 0; +} diff --git a/docs/man/mudraw.1 b/docs/man/mudraw.1 new file mode 100644 index 00000000..eec79f7b --- /dev/null +++ b/docs/man/mudraw.1 @@ -0,0 +1,89 @@ +.TH MUDRAW 1 "March 28, 2012" +.\" Please adjust this date whenever revising the manpage. +.SH NAME +mudraw \- render PDF/XPS/CBZ documents +.SH SYNOPSIS +.B mudraw +.RI [ options ] +.RI input.{pdf,xps,cbz} +.RI [ pages] +.SH DESCRIPTION +.B mudraw +will render a document of a supported document format to image files. +The supported document formats are: pdf, xps and cbz. +The supported image formats are: pgm, ppm, pam and png. +Select the pages to be rendered by specifying a comma +separated list of ranges and individual page numbers (for example: 1,5,10-15). +In no pages are specified all the pages will be rendered. +.SH OPTIONS +.TP +.B \-o output +The image format is deduced from the output file name. +Embed %d in the name to indicate the page number (for example: "page%d.png"). +.TP +.B \-p password +Use the specified password if the file is encrypted. +.TP +.B \-r resolution +Render the page at the specified resolution. +The default resolution is 72 dpi. +.TP +.B \-w width +Render the page at the specified width (or, if the -r flag is used, +render with a maximum width). +.TP +.B \-h height +Render the page at the specified height (or, if the -r flag is used, +render with a maximum height). +.TP +.B \-f +'Fit' exactly; ignore the aspect ratio when matching specified width/heights. +.TP +.B \-R angle +Rotate clockwise by given number of degrees. +.TP +.B \-a +Save the alpha channel. +The default behavior is to render each page with a white background. +With this option, the page background is transparent. +Only supported for pam and png output formats. +.TP +.B \-g +Render in grayscale. +The default is to render a full color RGB image. +If the output format is pgm or ppm this option is ignored. +.TP +.B \-m +Show timing information. +Take the time it takes for each page to render and print +a summary at the end. +.TP +.B \-5 +Print an MD5 checksum of the rendered image data for each page. +.TP +.B \-t +Print the text contents of each page in UTF-8 encoding. +Give the option twice to print detailed information +about the location of each character in XML format. +.TP +.B \-x +Print the display list used to render each page. +.TP +.B \-A +Disable the use of accelerated functions. +.TP +.B \-G gamma +Gamma correct the output image. +Some typical values are 0.7 or 1.4 to thin or darken text rendering. +.TP +.B \-I +Invert the output image colors. +.TP +.B pages +Comma separated list of ranges to render. +.SH SEE ALSO +.BR mupdf (1), +.BR mupdfclean (1). +.BR mupdfshow (1). +.SH AUTHOR +MuPDF is Copyright 2006-2013 Artifex Software, Inc. diff --git a/docs/man/mupdf.1 b/docs/man/mupdf.1 new file mode 100644 index 00000000..a4a268a5 --- /dev/null +++ b/docs/man/mupdf.1 @@ -0,0 +1,92 @@ +.TH MUPDF 1 "June 12, 2012" +.\" Please adjust this date whenever revising the manpage. +.SH NAME +mupdf \- MuPDF is a lightweight PDF viewer written in portable C +.SH SYNOPSIS +.B mupdf +.RI [ options ] " PDFfile" +.SH DESCRIPTION +This manual page briefly describes the +.B mupdf +command. +.PP +.SH OPTIONS +A description of each of the supported options is included below. +.TP +.B \-p password +Uses the given password to open an encrypted PDF file. +The password is tried both as user and owner password. +.TP +.B \-r resolution +Changes the initial zoom level, specified as the resolution in dpi. +The default value is 72. +.SH MOUSE AND KEY BINDINGS +In addition to the key bindings described below, the mouse can also be +used. Clicking the left mouse button follows links within the PDF while +dragging with the left mouse button pans the page. Dragging with the right +mouse button selects an area and copies the enclosed text to the clipboard +buffer. Using the scroll-wheel while pressing Control zooms in/out, if +Shift is pressed on the other hand then the page is panned. +.TP +.B L, R +Rotate page left (clockwise) or right (counter-clockwise). +.TP +.B h, j, k, l +Scroll page left, down, up, or right. +.TP +.B \+, \- +Zoom in or out. +.TP +.B W, H +Zoom so page exactly fits width or height of window. +.TP +.B w +Shrinkwrap window to fit the page. +.TP +.B r +Reload file. +.TP +.B . pgdn right space +Go to the next page +.TP +.B , pgup left b backspace +Go to the previous page +.TP +.B <, > +Skip back/forth 10 pages at a time. +.TP +.B m +Mark page for snap back. +.TP +.B t +Pop back to the latest mark. +.TP +.B [0-9]m +Save the current page number in the numbered register. +.TP +.B [0-9]t +Go to the page saved in the numbered register. +.TP +.B 123g +Go to page 123. +.TP +.B / +Search for text. +.TP +.B n, N +Find the next/previous search result. +.TP +.B c +Toggle between color and grayscale rendering. +.TP +.B i +Toggle between normal and inverted color rendering. +.P +Sending a \fBSIGHUP\fR signal to the mupdf process will also cause the viewed +file to be reloaded automatically, for use in e.g. build scripts. +.SH SEE ALSO +.BR mupdfclean (1), +.BR mupdfdraw (1), +.BR mupdfshow (1). +.SH AUTHOR +MuPDF is Copyright 2006-2013 Artifex Software, Inc. diff --git a/docs/man/mutool.1 b/docs/man/mutool.1 new file mode 100644 index 00000000..d1c7079b --- /dev/null +++ b/docs/man/mutool.1 @@ -0,0 +1,77 @@ +.TH "MUTOOL" "1" "Oct 02, 2012" +.\" Please adjust this date whenever revising the manpage. +.\" no hyphenation +.nh +.\" adjust left +.ad l +.SH NAME +mutool \- all purpose tool for dealing with PDF files +.SH SYNOPSIS +mutool <sub-command> [options] +.SH DESCRIPTION +mutool is a tool based on MuPDF for dealing with PDF files in various manners. +There are several sub commands available, as described below. +.SH CLEAN +mutool clean [options] input.pdf [output.pdf] [pages] +.PP +The clean command pretty prints and rewrites the syntax of a PDF file. +It can be used to repair broken files, expand compressed streams, filter +out a range of pages, etc. +.PP +If no output file is specified, it will write the cleaned PDF to "out.pdf" +in the current directory. +.TP +.B \-p password +Use the specified password if the file is encrypted. +.TP +.B \-g +Garbage collect objects that have no references from other objects. +Give the option twice to renumber all objects and compact the cross reference table. +Give it three times to merge and reuse duplicate objects. +.TP +.B \-d +Decompress streams. This will make the output file larger, but provides +easy access for reading and editing the contents with a text editor. +.TP +.B pages +Comma separated list of page ranges to include. +.SH EXTRACT +TODO +.SH INFO +TODO +.SH POSTER +TODO +.SH SHOW +mutool show [options] file.pdf [object numbers ...] +.PP +The show command will print the specified objects and streams to stdout. +Streams are decoded and non-printable characters are represented +with a period by default. +.TP +.B \-b +Print streams as binary data and omit the object header. +.TP +.B \-e +Print streams in their original encoded (or compressed) form. +.TP +.B \-p password +Use the specified password if the file is encrypted. +.PP +Specify objects by number, or use one of the following special names: +.TP +.B 'xref' or 'x' +Print the cross reference table. +.TP +.B 'trailer' or 't' +Print the trailer dictionary. +.TP +.B 'pages' or 'p' +List the object numbers for every page. +.TP +.B 'grep' or 'g' +Print all the objects in the file in a compact one-line format suitable for piping to grep. +.SH SEE ALSO +.BR mupdf (1), +.BR mudraw (1). +.SH AUTHOR +MuPDF is Copyright 2006-2013 Artifex Software, Inc. diff --git a/docs/multi-threaded.c b/docs/multi-threaded.c new file mode 100644 index 00000000..3141e3c4 --- /dev/null +++ b/docs/multi-threaded.c @@ -0,0 +1,266 @@ +// Multi-threaded rendering of all pages in a document to PNG images. + +// First look at doc/example.c and make sure you understand it. +// Then read the multi-threading section in doc/overview.txt, +// before coming back here to see an example of multi-threading. + +// This example will create one main thread for reading pages from the +// document, and one thread per page for rendering. After rendering +// the main thread will wait for each rendering thread to complete before +// writing that thread's rendered image to a PNG image. There is +// nothing in MuPDF requiring a rendering thread to only render a +// single page, this is just a design decision taken for this example. + +// Compile a debug build of mupdf, then compile and run this example: +// +// gcc -g -o build/debug/example-mt -Iinclude doc/multi-threading.c \ +// build/debug/lib*.a -lpthread -lm +// +// build/debug/example-mt /path/to/document.pdf +// +// Caution! As all pages are rendered simultaneously, please choose a +// file with just a few pages to avoid stressing your machine too +// much. Also you may run in to a limitation on the number of threads +// depending on your environment. + +// Include the MuPDF header file, and pthread's header file. +#include <mupdf/fitz.h> +#include <pthread.h> + +// A convenience function for dying abruptly on pthread errors. + +void +fail(char *msg) +{ + fprintf(stderr, "%s", msg); + abort(); +} + +// The data structure passed between the requesting main thread and +// each rendering thread. + +struct 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. + fz_context *ctx; + + // Page number sent from main to rendering thread for printing + int pagenumber; + + // The display list as obtained by the main thread and sent + // from main to rendering thread. This contains the drawing + // commands (text, images, etc.) for the page that should be + // rendered. + fz_display_list *list; + + // The area of the page to render as obtained by the main + // thread and sent from main to rendering thread. + fz_rect bbox; + + // This is the result, a pixmap containing the rendered page. + // It is passed first from main thread to the rendering + // thread, then its samples are changed by the rendering + // thread, and then back from the rendering thread to the main + // thread. + fz_pixmap *pix; +}; + +// 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) +{ + 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; + + 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. + + fprintf(stderr, "thread at page %d rendering!\n", pagenumber); + fz_device *dev = fz_new_draw_device(ctx, pix); + fz_run_display_list(list, dev, &fz_identity, &bbox, NULL); + fz_free_device(dev); + + // This threads context is freed. + + fz_free_context(ctx); + + fprintf(stderr, "thread at page %d done!\n", pagenumber); + + return data; +} + +// These are the two locking functions required by MuPDF when +// operating in a multi-threaded environment. They each take a user +// argument that can be used to transfer some state, in this case a +// pointer to the array of mutexes. + +void lock_mutex(void *user, int lock) +{ + pthread_mutex_t *mutex = (pthread_mutex_t *) user; + + if (pthread_mutex_lock(&mutex[lock]) != 0) + fail("pthread_mutex_lock()"); +} + +void unlock_mutex(void *user, int lock) +{ + pthread_mutex_t *mutex = (pthread_mutex_t *) user; + + if (pthread_mutex_unlock(&mutex[lock]) != 0) + fail("pthread_mutex_unlock()"); +} + +int main(int argc, char **argv) +{ + char *filename = argv[1]; + pthread_t *thread = NULL; + fz_locks_context locks; + pthread_mutex_t mutex[FZ_LOCK_MAX]; + 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) + fail("pthread_mutex_init()"); + } + + // Initialize the locking structure with function pointers to + // the locking functions and to the user data. In this case + // 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 + // locking structure. This context will be used to parse all + // the pages from the document. + + fz_context *ctx = fz_new_context(NULL, &locks, FZ_STORE_UNLIMITED); + + // Open the PDF, XPS or CBZ document. + + fz_document *doc = fz_open_document(ctx, filename); + + // Retrieve the number of pages, which translates to the + // number of threads used for rendering pages. + + int threads = fz_count_pages(doc); + fprintf(stderr, "spawning %d threads, one per page...\n", threads); + + thread = malloc(threads * sizeof (pthread_t)); + + for (i = 0; i < threads; i++) + { + // Load the relevant page for each thread. + + fz_page *page = fz_load_page(doc, i); + + // Compute the bounding box for each page. + + fz_rect bbox; + fz_irect rbox; + fz_bound_page(doc, page, &bbox); + + // Create a display list that will hold the drawing + // commands for the page. + + fz_display_list *list = fz_new_display_list(ctx); + + // Run the loaded page through a display list device + // to populate the page's display list. + + fz_device *dev = fz_new_list_device(ctx, list); + fz_run_page(doc, page, dev, &fz_identity, NULL); + fz_free_device(dev); + + // The page is no longer needed, all drawing commands + // are now in the display list. + + fz_free_page(doc, page); + + // Create a white pixmap using the correct dimensions. + + fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), fz_round_rect(&rbox, &bbox)); + fz_clear_pixmap_with_value(ctx, pix, 0xff); + + // Populate the data structure to be sent to the + // rendering thread for this page. + + struct data *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()"); + } + + // 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--) + { + char filename[42]; + struct data *data; + + 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_write_png(ctx, data->pix, filename, 0); + + // Free the thread's pixmap and display list since + // they were allocated by the main thread above. + + fz_drop_pixmap(ctx, data->pix); + fz_free_display_list(ctx, data->list); + + // Free the data structured passed back and forth + // between the main thread and rendering thread. + + free(data); + } + + fprintf(stderr, "finally!\n"); + fflush(NULL); + + free(thread); + + // Finally the document is closed and the main thread's + // context is freed. + + fz_close_document(doc); + fz_free_context(ctx); + + return 0; +} diff --git a/docs/naming.txt b/docs/naming.txt new file mode 100644 index 00000000..6c641c33 --- /dev/null +++ b/docs/naming.txt @@ -0,0 +1,30 @@ +Functions should be named according to one of the following schemes: + + verb_noun + verb_noun_with_noun + + noun_attribute + get_noun_attribute -- when the 'noun_attribute' name conflicts with a type + set_noun_attribute + +Prefixes are mandatory for exported functions, macros, enums, globals and types. + + fz for common code + pdf, xps, etc., for interpreter specific code + +Prefixes are optional (but encouraged) for private functions and types. + +Avoid using 'get' as this is a meaningless and redundant filler word. + +These words are reserved for reference counting schemes: + + new, find, load, open, keep -- return objects that you are responsible for freeing. + + drop, free, close -- relinquish ownership of the object passed in. + +When searching for an object or value, the name used depends on whether +returning the value is passing ownership: + + lookup -- return a value or borrowed pointer + + find -- return an object that the caller is responsible for freeing diff --git a/docs/overview.txt b/docs/overview.txt new file mode 100644 index 00000000..2d4e25d7 --- /dev/null +++ b/docs/overview.txt @@ -0,0 +1,268 @@ +Contents +======== + +* Basic MuPDF usage example +* Common function arguments +* Error Handling +* Multi-threading + +Basic MuPDF usage example +========================= + +For an example of how to use MuPDF in the most basic way, see +doc/example.c. To limit the complexity and give an easier introduction +this code has no error handling at all, but any serious piece of code +using MuPDF should use the error handling strategies described below. + +Common function arguments +========================= + +Many functions in MuPDFs interface take a context argument. + +A context contains global state used by MuPDF inside functions when +parsing or rendering pages of the document. It contains for example: + + an exception stack (see error handling below), + + a memory allocator (allowing for custom allocators) + + a resource store (for caching of images, fonts, etc.) + + a set of locks and (un-)locking functions (for multi-threading) + +Other functions in MuPDF's interface take arguments such as document, +stream and device which contain state for each type of object. Those +arguments each have a reference to a context and therefore act as +proxies for a context. + +Without the set of locks and accompanying functions the context and +its proxies may only be used in a single-threaded application. + +Error handling +============== + +MuPDF uses a set of exception handling macros to simplify error return +and cleanup. Conceptually, they work a lot like C++'s try/catch +system, but do not require any special compiler support. + +The basic formulation is as follows: + + fz_try(ctx) + { + // Try to perform a task. Never 'return', 'goto' or + // 'longjmp' out of here. 'break' may be used to + // safely exit (just) the try block scope. + } + fz_always(ctx) + { + // Any code here is always executed, regardless of + // whether an exception was thrown within the try or + // not. Never 'return', 'goto' or longjmp out from + // here. 'break' may be used to safely exit (just) the + // always block scope. + } + fz_catch(ctx) + { + // This code is called (after any always block) only + // if something within the fz_try block (including any + // functions it called) threw an exception. The code + // here is expected to handle the exception (maybe + // record/report the error, cleanup any stray state + // etc) and can then either exit the block, or pass on + // the exception to a higher level (enclosing) fz_try + // block (using fz_throw, or fz_rethrow). + } + +The fz_always block is optional, and can safely be omitted. + +The macro based nature of this system has 3 main limitations: + +1) Never return from within try (or 'goto' or longjmp out of it). + This upsets the internal housekeeping of the macros and will + cause problems later on. The code will detect such things + happening, but by then it is too late to give a helpful error + report as to where the original infraction occurred. + +2) The fz_try(ctx) { ... } fz_always(ctx) { ... } fz_catch(ctx) { ... } + is not one atomic C statement. That is to say, if you do: + + if (condition) + fz_try(ctx) { ... } + fz_catch(ctx) { ... } + + then you will not get what you want. Use the following instead: + + if (condition) { + fz_try(ctx) { ... } + fz_catch(ctx) { ... } + } + +3) The macros are implemented using setjmp and longjmp, and so + the standard C restrictions on the use of those functions + apply to fz_try/fz_catch too. In particular, any "truly local" + variable that is set between the start of fz_try and something + in fz_try throwing an exception may become undefined as part + of the process of throwing that exception. + + As a way of mitigating this problem, we provide an fz_var() + macro that tells the compiler to ensure that that variable is + not unset by the act of throwing the exception. + +A model piece of code using these macros then might be: + + house build_house(plans *p) + { + material m = NULL; + walls w = NULL; + roof r = NULL; + house h = NULL; + tiles t = make_tiles(); + + fz_var(w); + fz_var(r); + fz_var(h); + + fz_try(ctx) + { + fz_try(ctx) + { + m = make_bricks(); + } + fz_catch(ctx) + { + // No bricks available, make do with straw? + m = make_straw(); + } + w = make_walls(m, p); + r = make_roof(m, t); + // Note, NOT: return combine(w,r); + h = combine(w, r); + } + fz_always(ctx) + { + drop_walls(w); + drop_roof(r); + drop_material(m); + drop_tiles(t); + } + fz_catch(ctx) + { + fz_throw(ctx, "build_house failed"); + } + return h; + } + +Things to note about this: + +a) If make_tiles throws an exception, this will immediately be + handled by some higher level exception handler. If it + succeeds, t will be set before fz_try starts, so there is no + need to fz_var(t); + +b) We try first off to make some bricks as our building material. + If this fails, we fall back to straw. If this fails, we'll end + up in the fz_catch, and the process will fail neatly. + +c) We assume in this code that combine takes new reference to + both the walls and the roof it uses, and therefore that w and + r need to be cleaned up in all cases. + +d) We assume the standard C convention that it is safe to destroy + NULL things. + +Multi-threading +=============== + +First off, study the basic usage example in doc/example.c and make +sure you understand how it works as the data structures manipulated +there will be refered to in this section too. + +MuPDF can usefully be built into a multi-threaded application without +the library needing to know anything threading at all. If the library +opens a document in one thread, and then sits there as a 'server' +requesting pages and rendering them for other threads that need them, +then the library is only ever being called from this one thread. + +Other threads can still be used to handle UI requests etc, but as far +as MuPDF is concerned it is only being used in a single threaded way. +In this instance, there are no threading issues with MuPDF at all, +and it can safely be used without any locking, as described in the +previous sections. + +This section will attempt to explain how to use MuPDF in the more +complex case; where we genuinely want to call the MuPDF library +concurrently from multiple threads within a single application. + +MuPDF can be invoked with a user supplied set of locking functions. +It uses these to take mutexes around operations that would conflict +if performed concurrently in multiple threads. By leaving the +exact implementation of locks to the caller MuPDF remains threading +library agnostic. + +The following simple rules should be followed to ensure that +multi-threaded operations run smoothly: + +1) "No simultaneous calls to MuPDF in different threads are + allowed to use the same context." + + Most of the time it is simplest to just use a different + context for every thread; just create a new context at the + same time as you create the thread. + +2) "The document is bound to the context with which it is created." + + All subsequent accesses to the document implicitly use the same + context; this means that only 1 thread can ever be accessing + the document at once. This does not mean that the document can + only ever be used from one thread, though in many cases this + is the simplest structure overall. + +3) "Any device is bound to the context with which it is created." + + All subsequent uses of a device implicitly use the context with + which it was created; this means that if a device is used with + a document, it should be created with the same context as that + document was. This does not mean that the device can only ever + be used from one thread, though in many cases this is the + simplest structure overall. + +So, how does a multi-threaded example differ from a non-multithreaded +one? + +Firstly, when we create the first context, we call fz_new_context +as before, but the second argument should be a pointer to a set +of locking functions. + +The calling code should provide FZ_LOCK_MAX mutexes, which will be +locked/unlocked by MuPDF calling the lock/unlock function pointers +in the supplied structure with the user pointer from the structure +and the lock number, i (0 <= i < FZ_LOCK_MAX). These mutexes can +safely be recursive or non-recursive as MuPDF only calls in a non- +recursive style. + +To make subsequent contexts, the user should NOT call fz_new_context +again (as this will fail to share important resources such as the +store and glyphcache), but should rather call fz_clone_context. +Each of these cloned contexts can be freed by fz_free_context as +usual. + +To open a document, call fz_open_document as usual, passing a context +and a filename; this context is bound to the document. All future +calls to access the document will use this context internally. + +Only one thread at a time can therefore perform operations such as +fetching a page, or rendering that page to a display list. Once a +display list has been obtained however, it can be rendered from any +other thread (or even from several threads simultaneously, giving +banded rendering). + +This means that an implementer has 2 basic choices when constructing +an application to use MuPDF in multi-threaded mode. Either he can +construct it so that a single nominated thread opens the document +and then acts as a 'server' creating display lists for other threads +to render, or he can add his own mutex around calls to mupdf that +use the document. The former is likely to be far more efficient in +the long run. + +For an example of how to do multi-threading see doc/multi-threaded.c +which has a main thread and one rendering thread per page. diff --git a/docs/refcount.txt b/docs/refcount.txt new file mode 100644 index 00000000..e575142a --- /dev/null +++ b/docs/refcount.txt @@ -0,0 +1,17 @@ +Reference counting uses special words in functions to make it easy to remember +and follow the rules. + +Words that take ownership: new, find, load, open, keep. + +Words that release ownership: drop, free, close. + +If an object is returned by a function with one of the special words that take +ownership, you are responsible for freeing it by calling "drop" or "free", or +"close" before you return. You may pass ownership of an owned object by return +it only if you name the function using one of the special words. + +Any objects returned by functions that do not have any of these special words, +are borrowed and have a limited life time. Do not hold on to them past the +duration of the current function, or stow them away inside structs. If you need +to keep the object for longer than that, you have to either "keep" it or make +your own copy. diff --git a/docs/thirdparty.txt b/docs/thirdparty.txt new file mode 100644 index 00000000..2233b634 --- /dev/null +++ b/docs/thirdparty.txt @@ -0,0 +1,38 @@ + Third Party Libraries Used by MuPDF + =================================== + + +Library Version Function License URL + + + +freetype 2.4.11 Font scaling Freetype http://www.freetype.org/ + and rendering License + + + +jpeg 9.0 JPEG decoding "Free", with + acknowledgement http://www.ijg.org/ + + + +openjpeg 2.0.0 JPEG 2000 BSD-style http://www.openjpeg.org/ + (with patches) decoding + + +zlib 1.2.7 (De)Flate zlib License http://www.zlib.net/ + compression + + + +(Optional) +v8 3.9 JavaScript BSD http://code.google.com/p/v8/ + interpreter + + + + + +NOTE: jbig2dec is included in "thirdparty" but is copyright Artifex Software Inc. + + |