|
| 1 | + |
| 2 | +/****************************************************************************** |
| 3 | + * MODULE : mupdf_picture.cpp |
| 4 | + * DESCRIPTION: Picture objects for MuPDF |
| 5 | + * COPYRIGHT : (C) 2022 Massimiliano Gubinelli, Joris van der Hoeven |
| 6 | + ******************************************************************************* |
| 7 | + * This software falls under the GNU general public license version 3 or later. |
| 8 | + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE |
| 9 | + * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>. |
| 10 | + ******************************************************************************/ |
| 11 | + |
| 12 | +#include "mupdf_picture.hpp" |
| 13 | + |
| 14 | +#include "effect.hpp" |
| 15 | +#include "file.hpp" |
| 16 | +#include "image_files.hpp" |
| 17 | +#include "tm_url.hpp" |
| 18 | + |
| 19 | +/****************************************************************************** |
| 20 | + * Abstract mupdf pictures |
| 21 | + ******************************************************************************/ |
| 22 | + |
| 23 | +mupdf_picture_rep::mupdf_picture_rep (fz_pixmap* _pix, int ox2, int oy2) |
| 24 | + : pix (_pix), im (NULL), w (fz_pixmap_width (mupdf_context (), pix)), |
| 25 | + h (fz_pixmap_height (mupdf_context (), pix)), ox (ox2), oy (oy2) { |
| 26 | + fz_keep_pixmap (mupdf_context (), pix); |
| 27 | +} |
| 28 | + |
| 29 | +mupdf_picture_rep::~mupdf_picture_rep () { |
| 30 | + fz_drop_pixmap (mupdf_context (), pix); |
| 31 | + fz_drop_image (mupdf_context (), im); |
| 32 | +} |
| 33 | + |
| 34 | +picture_kind |
| 35 | +mupdf_picture_rep::get_type () { |
| 36 | + return picture_native; |
| 37 | +} |
| 38 | +void* |
| 39 | +mupdf_picture_rep::get_handle () { |
| 40 | + return (void*) this; |
| 41 | +} |
| 42 | + |
| 43 | +int |
| 44 | +mupdf_picture_rep::get_width () { |
| 45 | + return w; |
| 46 | +} |
| 47 | +int |
| 48 | +mupdf_picture_rep::get_height () { |
| 49 | + return h; |
| 50 | +} |
| 51 | +int |
| 52 | +mupdf_picture_rep::get_origin_x () { |
| 53 | + return ox; |
| 54 | +} |
| 55 | +int |
| 56 | +mupdf_picture_rep::get_origin_y () { |
| 57 | + return oy; |
| 58 | +} |
| 59 | +void |
| 60 | +mupdf_picture_rep::set_origin (int ox2, int oy2) { |
| 61 | + ox= ox2; |
| 62 | + oy= oy2; |
| 63 | +} |
| 64 | + |
| 65 | +color |
| 66 | +mupdf_picture_rep::internal_get_pixel (int x, int y) { |
| 67 | + unsigned char* samples= fz_pixmap_samples (mupdf_context (), pix); |
| 68 | + return rgbap_to_argb (((color*) samples)[x + w * (h - 1 - y)]); |
| 69 | +} |
| 70 | + |
| 71 | +void |
| 72 | +mupdf_picture_rep::internal_set_pixel (int x, int y, color c) { |
| 73 | + unsigned char* samples= fz_pixmap_samples (mupdf_context (), pix); |
| 74 | + ((color*) samples)[x + w * (h - 1 - y)]= argb_to_rgbap (c); |
| 75 | +} |
| 76 | + |
| 77 | +picture |
| 78 | +mupdf_picture (fz_pixmap* _pix, int ox, int oy) { |
| 79 | + return (picture) tm_new<mupdf_picture_rep, fz_pixmap*, int, int> (_pix, ox, |
| 80 | + oy); |
| 81 | +} |
| 82 | + |
| 83 | +picture |
| 84 | +as_mupdf_picture (picture pic) { |
| 85 | + if (pic->get_type () == picture_native) return pic; |
| 86 | + fz_pixmap* pix= |
| 87 | + fz_new_pixmap (mupdf_context (), fz_device_rgb (mupdf_context ()), |
| 88 | + pic->get_width (), pic->get_height (), NULL, 1); |
| 89 | + picture ret= mupdf_picture (pix, pic->get_origin_x (), pic->get_origin_y ()); |
| 90 | + fz_drop_pixmap (mupdf_context (), pix); |
| 91 | + ret->copy_from (pic); // FIXME: is this inefficient??? |
| 92 | + return ret; |
| 93 | +} |
| 94 | + |
| 95 | +#ifdef MUPDF_RENDERER |
| 96 | +picture |
| 97 | +as_native_picture (picture pict) { |
| 98 | + return as_mupdf_picture (pict); |
| 99 | +} |
| 100 | + |
| 101 | +picture |
| 102 | +native_picture (int w, int h, int ox, int oy) { |
| 103 | + fz_pixmap* pix= fz_new_pixmap ( |
| 104 | + mupdf_context (), fz_device_rgb (mupdf_context ()), w, h, NULL, 1); |
| 105 | + fz_clear_pixmap (mupdf_context (), pix); |
| 106 | + picture p= mupdf_picture (pix, ox, oy); |
| 107 | + fz_drop_pixmap (mupdf_context (), pix); |
| 108 | + return p; |
| 109 | +} |
| 110 | +#endif |
| 111 | + |
| 112 | +/****************************************************************************** |
| 113 | + * Rendering on images |
| 114 | + ******************************************************************************/ |
| 115 | + |
| 116 | +class mupdf_image_renderer_rep : public mupdf_renderer_rep { |
| 117 | +public: |
| 118 | + picture pict; |
| 119 | + |
| 120 | +public: |
| 121 | + mupdf_image_renderer_rep (picture pict, double zoom); |
| 122 | + void* get_data_handle (); |
| 123 | +}; |
| 124 | + |
| 125 | +mupdf_image_renderer_rep::mupdf_image_renderer_rep (picture p, double zoom) |
| 126 | + : mupdf_renderer_rep (), pict (p) { |
| 127 | + zoomf = zoom; |
| 128 | + shrinkf= (int) tm_round (std_shrinkf / zoomf); |
| 129 | + pixel = (SI) tm_round ((std_shrinkf * PIXEL) / zoomf); |
| 130 | + thicken= (shrinkf >> 1) * PIXEL; |
| 131 | + |
| 132 | + int pw = p->get_width (); |
| 133 | + int ph = p->get_height (); |
| 134 | + int pox= p->get_origin_x (); |
| 135 | + int poy= p->get_origin_y (); |
| 136 | + |
| 137 | + ox= pox * pixel; |
| 138 | + oy= poy * pixel; |
| 139 | + /* |
| 140 | + cx1= 0; |
| 141 | + cy1= 0; |
| 142 | + cx2= pw * pixel; |
| 143 | + cy2= ph * pixel; |
| 144 | + */ |
| 145 | + cx1= 0; |
| 146 | + cy1= -ph * pixel; |
| 147 | + cx2= pw * pixel; |
| 148 | + cy2= 0; |
| 149 | + |
| 150 | + mupdf_picture_rep* handle= (mupdf_picture_rep*) pict->get_handle (); |
| 151 | + begin (handle->pix); |
| 152 | +} |
| 153 | + |
| 154 | +void* |
| 155 | +mupdf_image_renderer_rep::get_data_handle () { |
| 156 | + return (void*) this; |
| 157 | +} |
| 158 | + |
| 159 | +#ifdef MUPDF_RENDERER |
| 160 | +renderer |
| 161 | +picture_renderer (picture p, double zoomf) { |
| 162 | + return (renderer) tm_new<mupdf_image_renderer_rep> (p, zoomf); |
| 163 | +} |
| 164 | +#endif |
| 165 | + |
| 166 | +/****************************************************************************** |
| 167 | + * Loading pictures |
| 168 | + ******************************************************************************/ |
| 169 | + |
| 170 | +fz_image* |
| 171 | +mupdf_load_image (url u) { |
| 172 | + fz_image* im = NULL; |
| 173 | + string suf= suffix (u); |
| 174 | + if (suf == "svg") { |
| 175 | + // FIXME: implement! |
| 176 | +#if 0 |
| 177 | + QSvgRenderer renderer (utf8_to_qstring (concretize (u))); |
| 178 | + pm= new QImage (w, h, QImage::Format_ARGB32); |
| 179 | + pm->fill (Qt::transparent); |
| 180 | + QPainter painter (pm); |
| 181 | + renderer.render (&painter); |
| 182 | +#endif |
| 183 | + } |
| 184 | + else if ((suf == "jpg") || (suf == "png")) { |
| 185 | + // FIXME: add more supported formats |
| 186 | + c_string path (concretize (u)); |
| 187 | + im= fz_new_image_from_file (mupdf_context (), path); |
| 188 | + } |
| 189 | + else if (suf == "xpm") { |
| 190 | + // try to load higher definition png equivalent if available |
| 191 | + url png_equiv= glue (unglue (u, 4), "_x4.png"); |
| 192 | + if (exists (png_equiv)) { |
| 193 | + return mupdf_load_image (png_equiv); |
| 194 | + } |
| 195 | + png_equiv= glue (unglue (u, 4), "_x2.png"); |
| 196 | + if (exists (png_equiv)) { |
| 197 | + return mupdf_load_image (png_equiv); |
| 198 | + } |
| 199 | + png_equiv= glue (unglue (u, 4), ".png"); |
| 200 | + if (exists (png_equiv)) { |
| 201 | + return mupdf_load_image (png_equiv); |
| 202 | + } |
| 203 | + // ok, try to load the xpm finally |
| 204 | + picture xp = as_mupdf_picture (load_xpm (u)); |
| 205 | + fz_pixmap* pix= ((mupdf_picture_rep*) xp->get_handle ())->pix; |
| 206 | + im = fz_new_image_from_pixmap (mupdf_context (), pix, NULL); |
| 207 | + } |
| 208 | + return im; |
| 209 | +} |
| 210 | + |
| 211 | +fz_pixmap* |
| 212 | +mupdf_load_pixmap (url u, int w, int h, tree eff, SI pixel) { |
| 213 | + fz_image* im= mupdf_load_image (u); |
| 214 | + |
| 215 | + if (im == NULL) { |
| 216 | + // attempt to convert to png |
| 217 | + url temp= url_temp (".png"); |
| 218 | + image_to_png (u, temp, w, h); |
| 219 | + c_string path (as_string (temp)); |
| 220 | + im= fz_new_image_from_file (mupdf_context (), path); |
| 221 | + remove (temp); |
| 222 | + } |
| 223 | + |
| 224 | + // Error Handling |
| 225 | + if (im == NULL) { |
| 226 | + cout << "TeXmacs] warning: cannot render " << concretize (u) << "\n"; |
| 227 | + return NULL; |
| 228 | + } |
| 229 | + |
| 230 | + // Scaling |
| 231 | + if (im->w != w || im->h != h) { |
| 232 | + // FIXME: implement? |
| 233 | + // we opt to draw natively scalables, so here we do not support rescaling |
| 234 | + // (*pm)= pm->scaled (w, h, Qt::IgnoreAspectRatio, |
| 235 | + // Qt::SmoothTransformation); |
| 236 | + cout << "TeXmacs] warning: image rescaling not supported " << concretize (u) |
| 237 | + << "\n"; |
| 238 | + } |
| 239 | + |
| 240 | + fz_pixmap* pix= |
| 241 | + fz_get_pixmap_from_image (mupdf_context (), im, NULL, NULL, NULL, NULL); |
| 242 | + fz_drop_image (mupdf_context (), im); // we do not need it anymore |
| 243 | + |
| 244 | + // Build effect |
| 245 | + if (eff != "") { |
| 246 | + effect e = build_effect (eff); |
| 247 | + picture src= mupdf_picture (pix, 0, 0); |
| 248 | + array<picture> a; |
| 249 | + a << src; |
| 250 | + picture pic = e->apply (a, pixel); |
| 251 | + picture dest= as_mupdf_picture (pic); |
| 252 | + mupdf_picture_rep* rep = (mupdf_picture_rep*) dest->get_handle (); |
| 253 | + fz_pixmap* tpix= rep->pix; |
| 254 | + fz_drop_pixmap (mupdf_context (), pix); |
| 255 | + pix= tpix; |
| 256 | + } |
| 257 | + return pix; |
| 258 | +} |
| 259 | + |
| 260 | +#ifdef MUPDF_RENDERER |
| 261 | +picture |
| 262 | +load_picture (url u, int w, int h, tree eff, int pixel) { |
| 263 | + fz_pixmap* pix= mupdf_load_pixmap (u, w, h, eff, pixel); |
| 264 | + if (pix == NULL) return error_picture (w, h); |
| 265 | + picture p= mupdf_picture (pix, 0, 0); |
| 266 | + fz_drop_pixmap (mupdf_context (), pix); |
| 267 | + return p; |
| 268 | +} |
| 269 | + |
| 270 | +void |
| 271 | +save_picture (url dest, picture p) { |
| 272 | + if (suffix (dest) != "png") { |
| 273 | + cout << "TeXmacs] warning: cannot save " << concretize (dest) |
| 274 | + << ", format not supported\n"; |
| 275 | + return; |
| 276 | + } |
| 277 | + picture q = as_mupdf_picture (p); |
| 278 | + mupdf_picture_rep* pict= (mupdf_picture_rep*) q->get_handle (); |
| 279 | + if (exists (dest)) remove (dest); |
| 280 | + c_string path= concretize (dest); |
| 281 | + fz_output* out = fz_new_output_with_path (mupdf_context (), path, 0); |
| 282 | + fz_write_pixmap_as_png (mupdf_context (), out, pict->pix); |
| 283 | + fz_close_output (mupdf_context (), out); |
| 284 | + fz_drop_output (mupdf_context (), out); |
| 285 | +} |
| 286 | +#endif |
0 commit comments