diff options
-rw-r--r-- | docs/example.c | 231 |
1 files changed, 122 insertions, 109 deletions
diff --git a/docs/example.c b/docs/example.c index 257e17f9..3099ecb1 100644 --- a/docs/example.c +++ b/docs/example.c @@ -1,120 +1,133 @@ -// 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 docs/example.c \ -// build/debug/libmupdf.a \ -// build/debug/libfreetype.a build/debug/libjbig2dec.a \ -// build/debug/libjpeg.a build/debug/libopenjpeg.a \ -// build/debug/libmujs.a \ -// build/debug/libz.a -lm -// -// (If this fails with errors about missing BIO_ and X509_ references -// try again with "-lcrypto" added to the end of that command). -// -// build/debug/example /path/to/document.pdf 1 200 25 - -// Include the MuPDF header file. +/* + How to use MuPDF to render a single page and print the result as a PPM to stdout. + + Build the mupdf library using make, then either run 'make examples' or + compile the example manually: + + gcc -Iinclude -o example.exe docs/example.c build/debug/libmupdf.a \ + build/debug/libfreetype.a \ + build/debug/libjbig2dec.a \ + build/debug/libjpeg.a \ + build/debug/libmujs.a \ + build/debug/libopenjpeg.a \ + build/debug/libz.a \ + -lcrypto \ + -lm + + ./example.exe document.pdf 100 0 1 +*/ + #include <mupdf/fitz.h> -void -render(char *filename, int pagenumber, int zoom, int rotation) +int main(int argc, char **argv) { + char *input; + float zoom, rotate; + int page_number, page_count; fz_context *ctx; fz_document *doc; - int pagecount; - fz_page *page; - fz_matrix transform; - fz_rect bounds; - fz_irect bbox; fz_pixmap *pix; - fz_device *dev; - - // Create a context to hold the exception stack and various caches. - + fz_matrix ctm; + int x, y; + + if (argc < 3) + { + fprintf(stderr, "usage: example input-file page-number [ zoom [ rotate ] ]\n"); + fprintf(stderr, "\tinput-file: path of PDF, XPS, CBZ or EPUB document to open\n"); + fprintf(stderr, "\tPage numbering starts from one.\n"); + fprintf(stderr, "\tZoom level is in percent (100 percent is 72 dpi).\n"); + fprintf(stderr, "\tRotation is in degrees clockwise.\n"); + return EXIT_FAILURE; + } + + input = argv[1]; + page_number = atoi(argv[2]) - 1; + zoom = argc > 3 ? atof(argv[3]) : 100; + rotate = argc > 4 ? atof(argv[4]) : 0; + + /* Create a context to hold the exception stack and various caches. */ ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); - - // Register the 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 (not used in this example). - - pagecount = fz_count_pages(ctx, doc); - - // Load the page we want. Page numbering starts from zero. - - page = fz_load_page(ctx, 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_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_bound_page(ctx, 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_round_rect(&bbox, &bounds); - 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. - - dev = fz_new_draw_device(ctx, pix); - fz_run_page(ctx, page, dev, &transform, NULL); - fz_drop_device(ctx, dev); - - // Save the pixmap to a file. - - fz_write_png(ctx, pix, "out.png", 0); - - // Clean up. - + if (!ctx) + { + fprintf(stderr, "cannot create mupdf context\n"); + return EXIT_FAILURE; + } + + /* Register the default file types to handle. */ + fz_try(ctx) + fz_register_document_handlers(ctx); + fz_catch(ctx) + { + fprintf(stderr, "cannot register document handlers: %s\n", fz_caught_message(ctx)); + fz_drop_context(ctx); + return EXIT_FAILURE; + } + + /* Open the document. */ + fz_try(ctx) + doc = fz_open_document(ctx, input); + fz_catch(ctx) + { + fprintf(stderr, "cannot open document: %s\n", fz_caught_message(ctx)); + fz_drop_context(ctx); + return EXIT_FAILURE; + } + + /* Count the number of pages. */ + fz_try(ctx) + page_count = fz_count_pages(ctx, doc); + fz_catch(ctx) + { + fprintf(stderr, "cannot count number of pages: %s\n", fz_caught_message(ctx)); + fz_drop_document(ctx, doc); + fz_drop_context(ctx); + return EXIT_FAILURE; + } + + if (page_number < 0 || page_number >= page_count) + { + fprintf(stderr, "page number out of range: %d (page count %d)\n", page_number + 1, page_count); + fz_drop_document(ctx, doc); + fz_drop_context(ctx); + return EXIT_FAILURE; + } + + /* Compute a transformation matrix for the zoom and rotation desired. */ + /* The default resolution without scaling is 72 dpi. */ + fz_scale(&ctm, zoom / 100, zoom / 100); + fz_pre_rotate(&ctm, rotate); + + /* Render page to an RGB pixmap. */ + fz_try(ctx) + pix = fz_new_pixmap_from_page_number(ctx, doc, page_number, &ctm, fz_device_rgb(ctx)); + fz_catch(ctx) + { + fprintf(stderr, "cannot render page: %s\n", fz_caught_message(ctx)); + fz_drop_document(ctx, doc); + fz_drop_context(ctx); + return EXIT_FAILURE; + } + + /* Print image data in ascii PPM format. */ + printf("P3\n"); + printf("%d %d\n", pix->w, pix->h); + printf("255\n"); + for (y = 0; y < pix->h; ++y) + { + unsigned char *p = &pix->samples[y * pix->w * pix->n]; + for (x = 0; x < pix->w; ++x) + { + if (x > 0) + printf(" "); + printf("%3d %3d %3d", p[0], p[1], p[2]); + p += 4; + } + printf("\n"); + } + + /* Clean up. */ fz_drop_pixmap(ctx, pix); - fz_drop_page(ctx, page); fz_drop_document(ctx, doc); fz_drop_context(ctx); -} - -int main(int argc, char **argv) -{ - char *filename = argc >= 2 ? 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; + return EXIT_SUCCESS; } |