From f4defeee497d21a211f83e7a8d2d6c2dcadca607 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 17 Feb 2017 15:09:20 +0100 Subject: Add no-reuse-images option to SVG device. Also add explicit viewBox and width/height to image symbol and use elements, to work around a strange clipping/image scaling issue with firefox. --- include/mupdf/fitz/output-svg.h | 4 +- source/fitz/output-svg.c | 8 +++- source/fitz/svg-device.c | 96 ++++++++++++++++++++++------------------- source/tools/mudraw.c | 2 +- 4 files changed, 62 insertions(+), 48 deletions(-) diff --git a/include/mupdf/fitz/output-svg.h b/include/mupdf/fitz/output-svg.h index ebabc42a..16e2102b 100644 --- a/include/mupdf/fitz/output-svg.h +++ b/include/mupdf/fitz/output-svg.h @@ -22,7 +22,9 @@ enum { text_format: How to emit text. One of the following values: FZ_SVG_TEXT_AS_TEXT: As elements with possible layout errors and mismatching fonts. FZ_SVG_TEXT_AS_PATH: As elements with exact visual appearance. + + reuse_images: Share image resources using definitions. */ -fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format); +fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format, int reuse_images); #endif diff --git a/source/fitz/output-svg.c b/source/fitz/output-svg.c index 40260fae..f8711031 100644 --- a/source/fitz/output-svg.c +++ b/source/fitz/output-svg.c @@ -9,12 +9,14 @@ struct fz_svg_writer_s int count; fz_output *out; int text_format; + int reuse_images; }; const char *fz_svg_write_options_usage = "SVG output options:\n" "\ttext=text: Emit text as elements (inaccurate fonts).\n" "\ttext=path: Emit text as elements (accurate fonts).\n" + "\tno-reuse-images: Do not reuse images using definitions.\n" "\n" ; @@ -31,7 +33,7 @@ svg_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabo fz_format_output_path(ctx, path, sizeof path, wri->path, wri->count); wri->out = fz_new_output_with_path(ctx, path, 0); - return fz_new_svg_device(ctx, wri->out, w, h, wri->text_format); + return fz_new_svg_device(ctx, wri->out, w, h, wri->text_format, wri->reuse_images); } static void @@ -65,6 +67,7 @@ fz_new_svg_writer(fz_context *ctx, const char *path, const char *args) wri->super.drop_writer = svg_drop_writer; wri->text_format = FZ_SVG_TEXT_AS_PATH; + wri->reuse_images = 1; fz_try(ctx) { @@ -75,6 +78,9 @@ fz_new_svg_writer(fz_context *ctx, const char *path, const char *args) else if (fz_option_eq(val, "path")) wri->text_format = FZ_SVG_TEXT_AS_PATH; } + if (fz_has_option(ctx, args, "no-reuse-images", &val)) + if (fz_option_eq(val, "yes")) + wri->reuse_images = 0; wri->path = fz_strdup(ctx, path ? path : "out-%04d.svg"); } fz_catch(ctx) diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c index 09b3d82d..89c3b4b6 100644 --- a/source/fitz/svg-device.c +++ b/source/fitz/svg-device.c @@ -42,6 +42,7 @@ struct svg_device_s fz_device super; int text_as_text; + int reuse_images; fz_output *out; fz_output *out_store; @@ -806,26 +807,28 @@ send_data_base64(fz_context *ctx, fz_output *out, fz_buffer *buffer) /* We spot repeated images, and send them just once using * symbols. Unfortunately, for pathological files, such * as the example in Bug695988, this can cause viewers to - * have conniptions. We therefore have a define that can - * be made to avoid this (SVG_SEND_REPEATED_IMAGES). */ + * have conniptions. We therefore have an option that is + * made to avoid this (reuse-images=no). */ static void svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img) { fz_output *out = sdev->out; fz_compressed_buffer *buffer; -#ifndef SVG_SEND_REPEATED_IMAGES int i; int id; - for (i = sdev->num_images-1; i >= 0; i--) - { - if (img == sdev->images[i].image) - break; - } - if (i >= 0) - id = sdev->images[i].id; - else + if (sdev->reuse_images) { + for (i = sdev->num_images-1; i >= 0; i--) + if (img == sdev->images[i].image) + break; + if (i >= 0) + { + fz_printf(ctx, out, "\n", + sdev->images[i].id, img->w, img->h); + return; + } + /* We need to send this image for the first time */ if (sdev->num_images == sdev->max_images) { @@ -838,48 +841,50 @@ svg_send_image(fz_context *ctx, svg_device *sdev, fz_image *img) id = sdev->id++; out = start_def(ctx, sdev); - fz_printf(ctx, out, "\n", id); -#endif - fz_printf(ctx, out, "w, img->h); - switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) + fz_printf(ctx, out, "\n", id, img->w, img->h); + } + + fz_printf(ctx, out, "w, img->h); + switch (buffer == NULL ? FZ_IMAGE_JPX : buffer->params.type) + { + case FZ_IMAGE_PNG: + fz_printf(ctx, out, "image/png;base64,"); + send_data_base64(ctx, out, buffer->buffer); + break; + case FZ_IMAGE_JPEG: + /* SVG cannot cope with CMYK images */ + if (img->colorspace != fz_device_cmyk(ctx)) { - case FZ_IMAGE_PNG: - fz_printf(ctx, out, "image/png;base64,"); + fz_printf(ctx, out, "image/jpeg;base64,"); send_data_base64(ctx, out, buffer->buffer); break; - case FZ_IMAGE_JPEG: - /* SVG cannot cope with CMYK images */ - if (img->colorspace != fz_device_cmyk(ctx)) - { - fz_printf(ctx, out, "image/jpeg;base64,"); - send_data_base64(ctx, out, buffer->buffer); - break; - } - /*@fallthough@*/ - default: - { - fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, img); - fz_printf(ctx, out, "image/png;base64,"); - send_data_base64(ctx, out, buf); - fz_drop_buffer(ctx, buf); - break; - } } - fz_printf(ctx, out, "\"/>\n"); -#ifndef SVG_SEND_REPEATED_IMAGES + /*@fallthough@*/ + default: + { + fz_buffer *buf = fz_new_buffer_from_image_as_png(ctx, img); + fz_printf(ctx, out, "image/png;base64,"); + send_data_base64(ctx, out, buf); + fz_drop_buffer(ctx, buf); + break; + } + } + fz_printf(ctx, out, "\"/>\n"); + if (sdev->reuse_images) + { fz_printf(ctx, out, "\n"); out = end_def(ctx, sdev); sdev->images[sdev->num_images].id = id; sdev->images[sdev->num_images].image = fz_keep_image(ctx, img); sdev->num_images++; - } - fz_printf(ctx, out, "\n", id); -#endif + fz_printf(ctx, out, "\n", + id, img->w, img->h); + } } static void @@ -931,7 +936,7 @@ svg_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_ma buf = fz_new_buffer_from_pixmap_as_png(ctx, pix); if (alpha != 1.0f) fz_printf(ctx, out, "\n", alpha); - fz_printf(ctx, out, "x, pix->y, pix->w, pix->h); + fz_printf(ctx, out, "x, pix->y, pix->w, pix->h); send_data_base64(ctx, out, buf); fz_printf(ctx, out, "\"/>\n"); if (alpha != 1.0f) @@ -1198,7 +1203,7 @@ svg_dev_drop_device(fz_context *ctx, fz_device *dev) fz_free(ctx, sdev->images); } -fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format) +fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format, int reuse_images) { svg_device *dev = fz_new_device(ctx, sizeof *dev); @@ -1237,13 +1242,14 @@ fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, dev->out_store = out; dev->id = 0; dev->text_as_text = (text_format == FZ_SVG_TEXT_AS_TEXT); + dev->reuse_images = reuse_images; fz_printf(ctx, out, "\n"); fz_printf(ctx, out, "\n"); fz_printf(ctx, out, "\n", - page_width*2.54/72, page_height*2.54/72, page_width, page_height); + "width=\"%gpt\" height=\"%gpt\" viewBox=\"0 0 %g %g\">\n", + page_width, page_height, page_width, page_height); return (fz_device*)dev; } diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c index ff915f6c..3b9911c5 100644 --- a/source/tools/mudraw.c +++ b/source/tools/mudraw.c @@ -594,7 +594,7 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in fz_try(ctx) { - dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0, FZ_SVG_TEXT_AS_PATH); + dev = fz_new_svg_device(ctx, out, tbounds.x1-tbounds.x0, tbounds.y1-tbounds.y0, FZ_SVG_TEXT_AS_PATH, 1); if (lowmemory) fz_enable_device_hints(ctx, dev, FZ_NO_CACHE); if (list) -- cgit v1.2.3