diff options
-rw-r--r-- | include/mupdf/fitz/device.h | 31 | ||||
-rw-r--r-- | source/fitz/draw-device.c | 122 | ||||
-rw-r--r-- | source/fitz/output-cbz.c | 34 | ||||
-rw-r--r-- | source/tools/muconvert.c | 5 |
4 files changed, 165 insertions, 27 deletions
diff --git a/include/mupdf/fitz/device.h b/include/mupdf/fitz/device.h index 3a3dd416..02f20ef6 100644 --- a/include/mupdf/fitz/device.h +++ b/include/mupdf/fitz/device.h @@ -357,4 +357,35 @@ fz_device *fz_new_draw_device_with_bbox(fz_context *ctx, fz_pixmap *dest, const fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_pixmap *dest); +/* + struct fz_draw_options: Options for creating a pixmap and draw device. +*/ +typedef struct fz_draw_options_s fz_draw_options; + +struct fz_draw_options_s +{ + int rotate; + int resolution; + int width; + int height; + fz_colorspace *colorspace; + int alpha; +}; + +extern const char *fz_draw_options_usage; + +/* + fz_parse_draw_options: Parse draw device options from a comma separated key-value string. +*/ +fz_draw_options *fz_parse_draw_options(fz_context *ctx, fz_draw_options *options, const char *string); + +/* + fz_new_draw_device_with_options: Create a new pixmap and draw device, using the specified options. + + mediabox: An in parameter containing the size of the page. + pixmap: An out parameter containing the newly created pixmap. + transform: An out parameter containing the transform to be used when running the page. +*/ +fz_device *fz_new_draw_device_with_options(fz_context *ctx, const fz_draw_options *opts, const fz_rect *mediabox, fz_matrix *transform, fz_pixmap **pixmap); + #endif diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c index d72b20d0..f725fd41 100644 --- a/source/fitz/draw-device.c +++ b/source/fitz/draw-device.c @@ -1,6 +1,128 @@ #include "mupdf/fitz.h" #include "draw-imp.h" +const char *fz_draw_options_usage = + "Common raster format output options:\n" + "\trotate=N: rotate rendered pages N degrees counterclockwise\n" + "\tresolution=N: resolution of rendered pages in pixels per inch\n" + "\twidth=N: render pages to fit N pixels wide (ignore resolution option)\n" + "\theight=N: render pages to fit N pixels tall (ignore resolution option)\n" + "\tcolorspace=(gray|rgb|cmyk): render using specified colorspace\n" + "\talpha: render pages with alpha channel and transparent background\n" + ; + +static int opteq(const char *a, const char *b) +{ + int n = strlen(b); + return !strncmp(a, b, n) && (a[n] == ',' || a[n] == 0); +} + +fz_draw_options * +fz_parse_draw_options(fz_context *ctx, fz_draw_options *opts, const char *args) +{ + const char *val; + + memset(opts, 0, sizeof *opts); + + opts->resolution = 96; + opts->rotate = 0; + opts->width = 0; + opts->height = 0; + opts->colorspace = fz_device_rgb(ctx); + opts->alpha = 0; + + if (fz_has_option(ctx, args, "rotate", &val)) + opts->rotate = fz_atoi(val); + if (fz_has_option(ctx, args, "resolution", &val)) + opts->resolution = fz_atoi(val); + if (fz_has_option(ctx, args, "width", &val)) + opts->width = fz_atoi(val); + if (fz_has_option(ctx, args, "height", &val)) + opts->height = fz_atoi(val); + if (fz_has_option(ctx, args, "colorspace", &val)) + { + if (opteq(val, "gray") || opteq(val, "grey")) + opts->colorspace = fz_device_gray(ctx); + else if (opteq(val, "rgb")) + opts->colorspace = fz_device_rgb(ctx); + else if (opteq(val, "cmyk")) + opts->colorspace = fz_device_cmyk(ctx); + else + fz_throw(ctx, FZ_ERROR_GENERIC, "unknown colorspace in options"); + } + if (fz_has_option(ctx, args, "alpha", &val)) + opts->alpha = opteq(val, "yes"); + + /* Sanity check values */ + if (opts->resolution <= 0) opts->resolution = 96; + if (opts->width < 0) opts->width = 0; + if (opts->height < 0) opts->height = 0; + + return opts; +} + +fz_device * +fz_new_draw_device_with_options(fz_context *ctx, const fz_draw_options *opts, const fz_rect *mediabox, + fz_matrix *transform, fz_pixmap **pixmap) +{ + float zoom = opts->resolution / 72.0f; + int w = opts->width; + int h = opts->height; + fz_rect bounds; + fz_irect ibounds; + fz_device *dev; + + fz_pre_scale(fz_rotate(transform, opts->rotate), zoom, zoom); + bounds = *mediabox; + fz_round_rect(&ibounds, fz_transform_rect(&bounds, transform)); + + /* If width or height are set, we may need to adjust the transform */ + if (w || h) + { + float scalex = 1; + float scaley = 1; + if (w != 0) + scalex = w / (bounds.x1 - bounds.x0); + if (h != 0) + scaley = h / (bounds.y1 - bounds.y0); + if (scalex != scaley) + { + if (w == 0) + scalex = scaley; + else if (h == 0) + scaley = scalex; + else if (scalex > scaley) + scalex = scaley; + else + scaley = scalex; + } + if (scalex != 1 || scaley != 1) + { + fz_pre_scale(transform, scalex, scaley); + bounds = *mediabox; + fz_round_rect(&ibounds, fz_transform_rect(&bounds, transform)); + } + } + + *pixmap = fz_new_pixmap_with_bbox(ctx, opts->colorspace, &ibounds, opts->alpha); + fz_try(ctx) + { + if (opts->alpha) + fz_clear_pixmap(ctx, *pixmap); + else + fz_clear_pixmap_with_value(ctx, *pixmap, 255); + + dev = fz_new_draw_device(ctx, *pixmap); + } + fz_catch(ctx) + { + fz_drop_pixmap(ctx, *pixmap); + *pixmap = NULL; + fz_rethrow(ctx); + } + return dev; +} + #define STACK_SIZE 96 /* Enable the following to attempt to support knockout and/or isolated diff --git a/source/fitz/output-cbz.c b/source/fitz/output-cbz.c index 4c6d0ca0..ebfded4c 100644 --- a/source/fitz/output-cbz.c +++ b/source/fitz/output-cbz.c @@ -8,32 +8,18 @@ struct fz_cbz_writer_s { fz_document_writer super; fz_zip_writer *zip; - float resolution; + fz_draw_options options; fz_pixmap *pixmap; int count; }; -const char *fz_cbz_write_options_usage = - "CBZ output options:\n" - "\tresolution=N: resolution of rendered pages in pixels per inch (default 96)\n" - ; +const char *fz_cbz_write_options_usage = ""; static fz_device * -cbz_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox, fz_matrix *ctm) +cbz_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox, fz_matrix *transform) { fz_cbz_writer *wri = (fz_cbz_writer*)wri_; - fz_rect bbox; - fz_irect ibbox; - - fz_scale(ctm, wri->resolution / 72, wri->resolution / 72); - bbox = *mediabox; - fz_transform_rect(&bbox, ctm); - fz_round_rect(&ibbox, &bbox); - - wri->pixmap = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &ibbox, 1); - fz_clear_pixmap_with_value(ctx, wri->pixmap, 0xFF); - - return fz_new_draw_device(ctx, wri->pixmap); + return fz_new_draw_device_with_options(ctx, &wri->options, mediabox, transform, &wri->pixmap); } static void @@ -57,6 +43,8 @@ cbz_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev) fz_drop_pixmap(ctx, wri->pixmap); wri->pixmap = NULL; + + fz_drop_device(ctx, dev); } static void @@ -74,7 +62,6 @@ cbz_close(fz_context *ctx, fz_document_writer *wri_) fz_document_writer * fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options) { - const char *val; fz_cbz_writer *wri; wri = fz_malloc_struct(ctx, fz_cbz_writer); @@ -83,18 +70,15 @@ fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options) wri->super.close = cbz_close; fz_try(ctx) + { + fz_parse_draw_options(ctx, &wri->options, options); wri->zip = fz_new_zip_writer(ctx, path); + } fz_catch(ctx) { fz_free(ctx, wri); fz_rethrow(ctx); } - if (fz_has_option(ctx, options, "resolution", &val)) - wri->resolution = fz_atof(val); - - if (wri->resolution <= 0) - wri->resolution = 96; - return (fz_document_writer*)wri; } diff --git a/source/tools/muconvert.c b/source/tools/muconvert.c index 926536fa..8d655bd3 100644 --- a/source/tools/muconvert.c +++ b/source/tools/muconvert.c @@ -43,9 +43,10 @@ static void usage(void) "\tpages\tcomma separated list of page numbers and ranges, where N is the last page\n" "\n" ); - fprintf(stderr, "%s\n", fz_cbz_write_options_usage); + fprintf(stderr, "%s", fz_draw_options_usage); + fprintf(stderr, "%s", fz_cbz_write_options_usage); #if FZ_ENABLE_PDF - fprintf(stderr, "%s\n", fz_pdf_write_options_usage); + fprintf(stderr, "%s", fz_pdf_write_options_usage); #endif exit(1); } |