|
| 1 | +fitz: look through a display-list image that is one raster (#6330) |
| 2 | + |
| 3 | +An SVG around a single <image> (a fixed-layout EPUB page) becomes a |
| 4 | +display-list image, so Save Image and copy got a re-rasterized bitmap |
| 5 | +at the layout size. fz_unwrap_display_list_image returns that raster |
| 6 | +and the matrix from its unit square to the display-list image's, so the |
| 7 | +app can save the original bytes at full resolution. |
| 8 | + |
| 9 | +diff --git a/include/mupdf/fitz/display-list.h b/include/mupdf/fitz/display-list.h |
| 10 | +index 957efe4c2..c8e92e656 100644 |
| 11 | +--- a/include/mupdf/fitz/display-list.h |
| 12 | ++++ b/include/mupdf/fitz/display-list.h |
| 13 | +@@ -130,6 +130,12 @@ fz_rect fz_bound_display_list(fz_context *ctx, fz_display_list *list); |
| 14 | + */ |
| 15 | + fz_image *fz_new_image_from_display_list(fz_context *ctx, float w, float h, fz_display_list *list); |
| 16 | + |
| 17 | ++/** |
| 18 | ++ SumatraPDF: the single raster a display-list image draws, or NULL. |
| 19 | ++ ctm maps the raster's unit square to the display-list image's. |
| 20 | ++*/ |
| 21 | ++fz_image *fz_unwrap_display_list_image(fz_context *ctx, fz_image *image, fz_matrix *ctm); |
| 22 | ++ |
| 23 | + /** |
| 24 | + Check for a display list being empty |
| 25 | + |
| 26 | +diff --git a/source/fitz/image.c b/source/fitz/image.c |
| 27 | +index a66a7d49d..6a16d5175 100644 |
| 28 | +--- a/source/fitz/image.c |
| 29 | ++++ b/source/fitz/image.c |
| 30 | +@@ -1876,3 +1876,104 @@ fz_image *fz_new_image_from_display_list(fz_context *ctx, float w, float h, fz_d |
| 31 | + |
| 32 | + return &image->super; |
| 33 | + } |
| 34 | ++ |
| 35 | ++/* SumatraPDF: a display-list image (an SVG) that is one raster and nothing |
| 36 | ++ * else. Save Image then keeps the raster's bytes and resolution (#6330). */ |
| 37 | ++typedef struct |
| 38 | ++{ |
| 39 | ++ fz_device super; |
| 40 | ++ fz_image *image; |
| 41 | ++ fz_matrix ctm; |
| 42 | ++ int images; |
| 43 | ++ int other; |
| 44 | ++} unwrap_device; |
| 45 | ++ |
| 46 | ++static void |
| 47 | ++unwrap_fill_image(fz_context *ctx, fz_device *dev_, fz_image *img, fz_matrix ctm, float alpha, fz_color_params color_params) |
| 48 | ++{ |
| 49 | ++ unwrap_device *dev = (unwrap_device *)dev_; |
| 50 | ++ if (dev->images++ > 0 || alpha != 1) |
| 51 | ++ { |
| 52 | ++ dev->other = 1; |
| 53 | ++ return; |
| 54 | ++ } |
| 55 | ++ dev->image = fz_keep_image(ctx, img); |
| 56 | ++ dev->ctm = ctm; |
| 57 | ++} |
| 58 | ++ |
| 59 | ++static void |
| 60 | ++unwrap_other(unwrap_device *dev) |
| 61 | ++{ |
| 62 | ++ dev->other = 1; |
| 63 | ++} |
| 64 | ++ |
| 65 | ++static void unwrap_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *cs, const float *color, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 66 | ++static void unwrap_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *ss, fz_matrix ctm, fz_colorspace *cs, const float *color, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 67 | ++static void unwrap_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor) { unwrap_other((unwrap_device *)dev); } |
| 68 | ++static void unwrap_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *ss, fz_matrix ctm, fz_rect scissor) { unwrap_other((unwrap_device *)dev); } |
| 69 | ++static void unwrap_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_colorspace *cs, const float *color, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 70 | ++static void unwrap_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *ss, fz_matrix ctm, fz_colorspace *cs, const float *color, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 71 | ++static void unwrap_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor) { unwrap_other((unwrap_device *)dev); } |
| 72 | ++static void unwrap_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *ss, fz_matrix ctm, fz_rect scissor) { unwrap_other((unwrap_device *)dev); } |
| 73 | ++static void unwrap_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shd, fz_matrix ctm, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 74 | ++static void unwrap_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, fz_matrix ctm, fz_colorspace *cs, const float *color, float alpha, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 75 | ++static void unwrap_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, fz_matrix ctm, fz_rect scissor) { unwrap_other((unwrap_device *)dev); } |
| 76 | ++static void unwrap_begin_mask(fz_context *ctx, fz_device *dev, fz_rect area, int luminosity, fz_colorspace *cs, const float *bc, fz_color_params cp) { unwrap_other((unwrap_device *)dev); } |
| 77 | ++static void unwrap_begin_group(fz_context *ctx, fz_device *dev, fz_rect area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha) { unwrap_other((unwrap_device *)dev); } |
| 78 | ++static int unwrap_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id, int doc_id) { unwrap_other((unwrap_device *)dev); return 0; } |
| 79 | ++ |
| 80 | ++static void |
| 81 | ++unwrap_drop_device(fz_context *ctx, fz_device *dev_) |
| 82 | ++{ |
| 83 | ++ unwrap_device *dev = (unwrap_device *)dev_; |
| 84 | ++ fz_drop_image(ctx, dev->image); |
| 85 | ++} |
| 86 | ++ |
| 87 | ++fz_image * |
| 88 | ++fz_unwrap_display_list_image(fz_context *ctx, fz_image *image_, fz_matrix *ctm) |
| 89 | ++{ |
| 90 | ++ fz_display_list_image *image = (fz_display_list_image *)image_; |
| 91 | ++ unwrap_device *dev = NULL; |
| 92 | ++ fz_image *found = NULL; |
| 93 | ++ |
| 94 | ++ if (!image_ || image_->get_pixmap != display_list_image_get_pixmap) |
| 95 | ++ return NULL; |
| 96 | ++ |
| 97 | ++ fz_var(dev); |
| 98 | ++ fz_try(ctx) |
| 99 | ++ { |
| 100 | ++ dev = fz_new_derived_device(ctx, unwrap_device); |
| 101 | ++ dev->super.drop_device = unwrap_drop_device; |
| 102 | ++ dev->super.fill_path = unwrap_fill_path; |
| 103 | ++ dev->super.stroke_path = unwrap_stroke_path; |
| 104 | ++ dev->super.clip_path = unwrap_clip_path; |
| 105 | ++ dev->super.clip_stroke_path = unwrap_clip_stroke_path; |
| 106 | ++ dev->super.fill_text = unwrap_fill_text; |
| 107 | ++ dev->super.stroke_text = unwrap_stroke_text; |
| 108 | ++ dev->super.clip_text = unwrap_clip_text; |
| 109 | ++ dev->super.clip_stroke_text = unwrap_clip_stroke_text; |
| 110 | ++ dev->super.fill_shade = unwrap_fill_shade; |
| 111 | ++ dev->super.fill_image = unwrap_fill_image; |
| 112 | ++ dev->super.fill_image_mask = unwrap_fill_image_mask; |
| 113 | ++ dev->super.clip_image_mask = unwrap_clip_image_mask; |
| 114 | ++ dev->super.begin_mask = unwrap_begin_mask; |
| 115 | ++ dev->super.begin_group = unwrap_begin_group; |
| 116 | ++ dev->super.begin_tile = unwrap_begin_tile; |
| 117 | ++ fz_run_display_list(ctx, image->list, &dev->super, fz_identity, fz_infinite_rect, NULL); |
| 118 | ++ fz_close_device(ctx, &dev->super); |
| 119 | ++ if (dev->image && !dev->other) |
| 120 | ++ { |
| 121 | ++ /* raster unit square -> list coordinates -> this image's unit square */ |
| 122 | ++ *ctm = fz_concat(dev->ctm, image->transform); |
| 123 | ++ found = fz_keep_image(ctx, dev->image); |
| 124 | ++ } |
| 125 | ++ } |
| 126 | ++ fz_always(ctx) |
| 127 | ++ fz_drop_device(ctx, &dev->super); |
| 128 | ++ fz_catch(ctx) |
| 129 | ++ { |
| 130 | ++ fz_drop_image(ctx, found); |
| 131 | ++ fz_rethrow(ctx); |
| 132 | ++ } |
| 133 | ++ return found; |
| 134 | ++} |
0 commit comments