diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2013-06-19 15:29:44 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2013-06-20 16:45:35 +0200 |
commit | 0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch) | |
tree | 3d65d820d9fdba2d0d394d99c36290c851b78ca0 /doc | |
parent | 1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff) | |
download | mupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz |
Rearrange source files.
Diffstat (limited to 'doc')
-rw-r--r-- | doc/example.c | 100 | ||||
-rw-r--r-- | doc/multi-threaded.c | 266 | ||||
-rw-r--r-- | doc/naming.txt | 30 | ||||
-rw-r--r-- | doc/overview.txt | 268 | ||||
-rw-r--r-- | doc/refcount.txt | 17 | ||||
-rw-r--r-- | doc/thirdparty.txt | 38 |
6 files changed, 0 insertions, 719 deletions
diff --git a/doc/example.c b/doc/example.c deleted file mode 100644 index 1a21c200..00000000 --- a/doc/example.c +++ /dev/null @@ -1,100 +0,0 @@ -// 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/doc/multi-threaded.c b/doc/multi-threaded.c deleted file mode 100644 index 3141e3c4..00000000 --- a/doc/multi-threaded.c +++ /dev/null @@ -1,266 +0,0 @@ -// 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/doc/naming.txt b/doc/naming.txt deleted file mode 100644 index 6c641c33..00000000 --- a/doc/naming.txt +++ /dev/null @@ -1,30 +0,0 @@ -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/doc/overview.txt b/doc/overview.txt deleted file mode 100644 index 2d4e25d7..00000000 --- a/doc/overview.txt +++ /dev/null @@ -1,268 +0,0 @@ -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/doc/refcount.txt b/doc/refcount.txt deleted file mode 100644 index e575142a..00000000 --- a/doc/refcount.txt +++ /dev/null @@ -1,17 +0,0 @@ -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/doc/thirdparty.txt b/doc/thirdparty.txt deleted file mode 100644 index 2233b634..00000000 --- a/doc/thirdparty.txt +++ /dev/null @@ -1,38 +0,0 @@ - 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. - - |