Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/scripts/mupdfwrap_gui.cs @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Basic PDF viewer using MuPDF C# bindings. | |
| 2 // | |
| 3 | |
| 4 public class MuPDFGui : System.Windows.Forms.Form | |
| 5 { | |
| 6 // We use static pixmap to ensure it isn't garbage-collected. | |
| 7 mupdf.FzPixmap pixmap; | |
| 8 | |
| 9 private System.Windows.Forms.MainMenu menu; | |
| 10 private System.Windows.Forms.MenuItem menu_item_file; | |
| 11 | |
| 12 /* Zooming works by incrementing self.zoom by +/- 1 then using | |
| 13 magnification = 2**(self.zoom/self.zoom_multiple). */ | |
| 14 private int zoom_multiple = 4; | |
| 15 private double zoom = 0; | |
| 16 private int page_number = 0; | |
| 17 | |
| 18 mupdf.FzDocument document; | |
| 19 mupdf.FzPage page; | |
| 20 System.Drawing.Bitmap bitmap; | |
| 21 System.Windows.Forms.PictureBox picture_box; | |
| 22 | |
| 23 // Need STAThread here otherwise OpenFileDialog hangs. | |
| 24 [System.STAThread] | |
| 25 public static void Main() | |
| 26 { | |
| 27 System.Windows.Forms.Application.Run(new MuPDFGui()); | |
| 28 } | |
| 29 | |
| 30 public MuPDFGui() | |
| 31 { | |
| 32 | |
| 33 menu_item_file = new System.Windows.Forms.MenuItem("File", | |
| 34 new System.Windows.Forms.MenuItem[] | |
| 35 { | |
| 36 new System.Windows.Forms.MenuItem("&Open...", new System.EventHandler(this.open)), | |
| 37 new System.Windows.Forms.MenuItem("&Show html", new System.EventHandler(this.show_html)), | |
| 38 new System.Windows.Forms.MenuItem("&Quit", new System.EventHandler(this.quit)) | |
| 39 } | |
| 40 ); | |
| 41 menu = new System.Windows.Forms.MainMenu(new System.Windows.Forms.MenuItem [] {menu_item_file}); | |
| 42 this.Menu = menu; | |
| 43 | |
| 44 Resize += handle_resize; | |
| 45 KeyDown += handle_key_down; | |
| 46 | |
| 47 this.picture_box = new System.Windows.Forms.PictureBox(); | |
| 48 this.picture_box.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; | |
| 49 this.AutoScroll = true; | |
| 50 | |
| 51 Controls.Add(picture_box); | |
| 52 | |
| 53 this.open_file("zlib.3.pdf"); | |
| 54 } | |
| 55 | |
| 56 public void open(System.Object sender, System.EventArgs e) | |
| 57 { | |
| 58 var dialog = new System.Windows.Forms.OpenFileDialog(); | |
| 59 var result = dialog.ShowDialog(); | |
| 60 if (result == System.Windows.Forms.DialogResult.OK) | |
| 61 { | |
| 62 this.open_file(dialog.FileName); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 void open_file(string path) | |
| 67 { | |
| 68 try | |
| 69 { | |
| 70 this.document = new mupdf.FzDocument(path); | |
| 71 } | |
| 72 catch (System.Exception e) | |
| 73 { | |
| 74 System.Console.WriteLine("Failed to open: " + path + " because: " + e); | |
| 75 return; | |
| 76 } | |
| 77 this.goto_page(0, 0); | |
| 78 } | |
| 79 | |
| 80 public void show_html(System.Object sender, System.EventArgs e) | |
| 81 { | |
| 82 System.Console.WriteLine("ShowHtml() called"); | |
| 83 var buffer = this.page.fz_new_buffer_from_page_with_format( | |
| 84 "docx", | |
| 85 "html", | |
| 86 new mupdf.FzMatrix(1, 0, 0, 1, 0, 0), | |
| 87 new mupdf.FzCookie() | |
| 88 ); | |
| 89 System.Console.WriteLine("buffer=" + buffer); | |
| 90 var html_bytes = buffer.fz_buffer_extract(); | |
| 91 var html_string = System.Text.Encoding.UTF8.GetString(html_bytes, 0, html_bytes.Length); | |
| 92 var web_browser = new System.Windows.Forms.WebBrowser(); | |
| 93 web_browser.DocumentText = html_string; | |
| 94 web_browser.Show(); | |
| 95 } | |
| 96 | |
| 97 public void quit(System.Object sender, System.EventArgs e) | |
| 98 { | |
| 99 System.Console.WriteLine("Quit() called"); | |
| 100 System.Windows.Forms.Application.Exit(); | |
| 101 } | |
| 102 | |
| 103 // Shows page. If width and/or height are zero we use .Width and/or .Height. | |
| 104 // | |
| 105 // To preserve current page and/or zoom, use .page_number and/or .zoom. | |
| 106 // | |
| 107 public void goto_page(int page_number, double zoom) | |
| 108 { | |
| 109 if (page_number < 0 || page_number >= document.fz_count_pages()) | |
| 110 { | |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 this.zoom = zoom; | |
| 115 this.page_number = page_number; | |
| 116 this.page = document.fz_load_page(page_number); | |
| 117 | |
| 118 var z = System.Math.Pow(2, this.zoom / this.zoom_multiple); | |
| 119 | |
| 120 /* For now we always use 'fit width' view semantics. */ | |
| 121 var page_rect = this.page.fz_bound_page(); | |
| 122 var vscroll_width = System.Windows.Forms.SystemInformation.VerticalScrollBarWidth; | |
| 123 z *= (this.ClientSize.Width - vscroll_width) / (page_rect.x1 - page_rect.x0); | |
| 124 | |
| 125 if (System.Type.GetType("Mono.Runtime") != null) | |
| 126 { | |
| 127 /* Use pixmap data without copying. This does not work on | |
| 128 Windows. | |
| 129 | |
| 130 It looks like it's important to use MuPDF Fixed_RGB with | |
| 131 alpha=1, and C#'s Format32bppRgb. Other combinations, | |
| 132 e.g. (Fixed_RGB with alpha=0) and Format24bppRgb, result in a | |
| 133 blank display. */ | |
| 134 var stopwatch = new System.Diagnostics.Stopwatch(); | |
| 135 stopwatch.Reset(); | |
| 136 stopwatch.Start(); | |
| 137 this.pixmap = this.page.fz_new_pixmap_from_page_contents( | |
| 138 new mupdf.FzMatrix((float) z, 0, 0, (float) z, 0, 0), | |
| 139 new mupdf.FzColorspace(mupdf.FzColorspace.Fixed.Fixed_RGB), | |
| 140 1 /*alpha*/ | |
| 141 ); | |
| 142 stopwatch.Stop(); | |
| 143 var t_pixmap = stopwatch.Elapsed; | |
| 144 | |
| 145 stopwatch.Reset(); | |
| 146 stopwatch.Start(); | |
| 147 this.bitmap = new System.Drawing.Bitmap( | |
| 148 this.pixmap.fz_pixmap_width(), | |
| 149 this.pixmap.fz_pixmap_height(), | |
| 150 this.pixmap.fz_pixmap_stride(), | |
| 151 System.Drawing.Imaging.PixelFormat.Format32bppRgb, | |
| 152 (System.IntPtr) this.pixmap.fz_pixmap_samples_int() | |
| 153 ); | |
| 154 stopwatch.Stop(); | |
| 155 var t_bitmap = stopwatch.Elapsed; | |
| 156 | |
| 157 stopwatch.Reset(); | |
| 158 stopwatch.Start(); | |
| 159 // This is slow for large pixmaps/bitmaps. | |
| 160 //check(pixmap, bitmap, 4); | |
| 161 stopwatch.Stop(); | |
| 162 var t_check = stopwatch.Elapsed; | |
| 163 | |
| 164 /*System.Console.WriteLine("" | |
| 165 + " t_pixmap=" + t_pixmap | |
| 166 + " t_bitmap=" + t_bitmap | |
| 167 + " t_check=" + t_check | |
| 168 );*/ | |
| 169 } | |
| 170 else | |
| 171 { | |
| 172 /* Copy pixmap's pixels into bitmap. This works on both Linux | |
| 173 (Mono) and Windows. | |
| 174 | |
| 175 Unlike above, it seems that we need to use MuPDF Fixed_RGB with | |
| 176 alpha=0, and C#'s Format32bppRgb. Other combinations give a | |
| 177 blank display (possibly with alpha=0 for each pixel). */ | |
| 178 this.pixmap = this.page.fz_new_pixmap_from_page_contents( | |
| 179 new mupdf.FzMatrix((float) z, 0, 0, (float) z, 0, 0), | |
| 180 new mupdf.FzColorspace(mupdf.FzColorspace.Fixed.Fixed_RGB), | |
| 181 0 /*alpha*/ | |
| 182 ); | |
| 183 | |
| 184 this.bitmap = new System.Drawing.Bitmap( | |
| 185 this.pixmap.fz_pixmap_width(), | |
| 186 this.pixmap.fz_pixmap_height(), | |
| 187 System.Drawing.Imaging.PixelFormat.Format32bppRgb | |
| 188 ); | |
| 189 long samples = pixmap.fz_pixmap_samples_int(); | |
| 190 int stride = pixmap.fz_pixmap_stride(); | |
| 191 for (int x=0; x<bitmap.Width; x+=1) | |
| 192 { | |
| 193 for (int y=0; y<bitmap.Height; y+=1) | |
| 194 { | |
| 195 unsafe | |
| 196 { | |
| 197 byte* sample = (byte*) samples + stride * y + 3 * x; | |
| 198 var color = System.Drawing.Color.FromArgb(sample[0], sample[1], sample[2]); | |
| 199 this.bitmap.SetPixel( x, y, color); | |
| 200 } | |
| 201 } | |
| 202 } | |
| 203 //check(pixmap, bitmap, 3); | |
| 204 } | |
| 205 this.picture_box.Image = this.bitmap; | |
| 206 } | |
| 207 | |
| 208 private void handle_key_down(object sender, System.Windows.Forms.KeyEventArgs e) | |
| 209 { | |
| 210 //System.Console.WriteLine("HandleKeyDown: " + e.KeyCode); | |
| 211 if (e.Shift && e.KeyCode == System.Windows.Forms.Keys.PageUp) | |
| 212 { | |
| 213 goto_page(this.page_number - 1, this.zoom); | |
| 214 } | |
| 215 else if (e.Shift && e.KeyCode == System.Windows.Forms.Keys.PageDown) | |
| 216 { | |
| 217 goto_page(this.page_number + 1, this.zoom); | |
| 218 } | |
| 219 else if (e.KeyCode == System.Windows.Forms.Keys.D0) | |
| 220 { | |
| 221 goto_page(this.page_number, 0); | |
| 222 } | |
| 223 else if (e.KeyCode == System.Windows.Forms.Keys.Add | |
| 224 || e.KeyCode == System.Windows.Forms.Keys.Oemplus | |
| 225 ) | |
| 226 { | |
| 227 goto_page(this.page_number, this.zoom + 1); | |
| 228 } | |
| 229 else if (e.KeyCode == System.Windows.Forms.Keys.Subtract | |
| 230 || e.KeyCode == System.Windows.Forms.Keys.OemMinus) | |
| 231 { | |
| 232 goto_page(this.page_number, this.zoom - 1); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 private void handle_resize(object sender, System.EventArgs e) | |
| 237 { | |
| 238 goto_page(page_number, zoom); | |
| 239 } | |
| 240 | |
| 241 // Throws exception if pixmap and bitmap differ. | |
| 242 void check(mupdf.FzPixmap pixmap, System.Drawing.Bitmap bitmap, int pixmap_bytes_per_pixel) | |
| 243 { | |
| 244 long samples = pixmap.fz_pixmap_samples_int(); | |
| 245 if (pixmap.fz_pixmap_width() != bitmap.Width || pixmap.fz_pixmap_height() != bitmap.Height) | |
| 246 { | |
| 247 throw new System.Exception("Inconsistent sizes:" | |
| 248 + " pixmap=(" + pixmap.fz_pixmap_width() + " " + pixmap.fz_pixmap_height() | |
| 249 + " bitmap=(" + bitmap.Width + " " + bitmap.Height | |
| 250 ); | |
| 251 } | |
| 252 int stride = pixmap.fz_pixmap_stride(); | |
| 253 for (int x=0; x<bitmap.Width; x+=1) | |
| 254 { | |
| 255 for (int y=0; y<bitmap.Height; y+=1) | |
| 256 { | |
| 257 unsafe | |
| 258 { | |
| 259 byte* sample = (byte*) samples + stride * y + pixmap_bytes_per_pixel * x; | |
| 260 System.Drawing.Color color = bitmap.GetPixel( x, y); | |
| 261 if (color.R != sample[0] || color.G != sample[1] || color.B != sample[2]) | |
| 262 { | |
| 263 string pixmap_pixel_text = ""; | |
| 264 for (int i=0; i<pixmap_bytes_per_pixel; ++i) | |
| 265 { | |
| 266 if (i > 0) pixmap_pixel_text += " "; | |
| 267 pixmap_pixel_text += sample[i]; | |
| 268 } | |
| 269 throw new System.Exception("Pixels differ: (" + x + " " + y + "):" | |
| 270 + " pixmap: (" + pixmap_pixel_text + ")" | |
| 271 + " bitmap: " + color); | |
| 272 } | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 } | |
| 277 } |
