Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/scripts/mupdfwrap_gui.cs @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | b50eed0cc0ef |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/scripts/mupdfwrap_gui.cs Mon Sep 15 11:44:09 2025 +0200 @@ -0,0 +1,277 @@ +// Basic PDF viewer using MuPDF C# bindings. +// + +public class MuPDFGui : System.Windows.Forms.Form +{ + // We use static pixmap to ensure it isn't garbage-collected. + mupdf.FzPixmap pixmap; + + private System.Windows.Forms.MainMenu menu; + private System.Windows.Forms.MenuItem menu_item_file; + + /* Zooming works by incrementing self.zoom by +/- 1 then using + magnification = 2**(self.zoom/self.zoom_multiple). */ + private int zoom_multiple = 4; + private double zoom = 0; + private int page_number = 0; + + mupdf.FzDocument document; + mupdf.FzPage page; + System.Drawing.Bitmap bitmap; + System.Windows.Forms.PictureBox picture_box; + + // Need STAThread here otherwise OpenFileDialog hangs. + [System.STAThread] + public static void Main() + { + System.Windows.Forms.Application.Run(new MuPDFGui()); + } + + public MuPDFGui() + { + + menu_item_file = new System.Windows.Forms.MenuItem("File", + new System.Windows.Forms.MenuItem[] + { + new System.Windows.Forms.MenuItem("&Open...", new System.EventHandler(this.open)), + new System.Windows.Forms.MenuItem("&Show html", new System.EventHandler(this.show_html)), + new System.Windows.Forms.MenuItem("&Quit", new System.EventHandler(this.quit)) + } + ); + menu = new System.Windows.Forms.MainMenu(new System.Windows.Forms.MenuItem [] {menu_item_file}); + this.Menu = menu; + + Resize += handle_resize; + KeyDown += handle_key_down; + + this.picture_box = new System.Windows.Forms.PictureBox(); + this.picture_box.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; + this.AutoScroll = true; + + Controls.Add(picture_box); + + this.open_file("zlib.3.pdf"); + } + + public void open(System.Object sender, System.EventArgs e) + { + var dialog = new System.Windows.Forms.OpenFileDialog(); + var result = dialog.ShowDialog(); + if (result == System.Windows.Forms.DialogResult.OK) + { + this.open_file(dialog.FileName); + } + } + + void open_file(string path) + { + try + { + this.document = new mupdf.FzDocument(path); + } + catch (System.Exception e) + { + System.Console.WriteLine("Failed to open: " + path + " because: " + e); + return; + } + this.goto_page(0, 0); + } + + public void show_html(System.Object sender, System.EventArgs e) + { + System.Console.WriteLine("ShowHtml() called"); + var buffer = this.page.fz_new_buffer_from_page_with_format( + "docx", + "html", + new mupdf.FzMatrix(1, 0, 0, 1, 0, 0), + new mupdf.FzCookie() + ); + System.Console.WriteLine("buffer=" + buffer); + var html_bytes = buffer.fz_buffer_extract(); + var html_string = System.Text.Encoding.UTF8.GetString(html_bytes, 0, html_bytes.Length); + var web_browser = new System.Windows.Forms.WebBrowser(); + web_browser.DocumentText = html_string; + web_browser.Show(); + } + + public void quit(System.Object sender, System.EventArgs e) + { + System.Console.WriteLine("Quit() called"); + System.Windows.Forms.Application.Exit(); + } + + // Shows page. If width and/or height are zero we use .Width and/or .Height. + // + // To preserve current page and/or zoom, use .page_number and/or .zoom. + // + public void goto_page(int page_number, double zoom) + { + if (page_number < 0 || page_number >= document.fz_count_pages()) + { + return; + } + + this.zoom = zoom; + this.page_number = page_number; + this.page = document.fz_load_page(page_number); + + var z = System.Math.Pow(2, this.zoom / this.zoom_multiple); + + /* For now we always use 'fit width' view semantics. */ + var page_rect = this.page.fz_bound_page(); + var vscroll_width = System.Windows.Forms.SystemInformation.VerticalScrollBarWidth; + z *= (this.ClientSize.Width - vscroll_width) / (page_rect.x1 - page_rect.x0); + + if (System.Type.GetType("Mono.Runtime") != null) + { + /* Use pixmap data without copying. This does not work on + Windows. + + It looks like it's important to use MuPDF Fixed_RGB with + alpha=1, and C#'s Format32bppRgb. Other combinations, + e.g. (Fixed_RGB with alpha=0) and Format24bppRgb, result in a + blank display. */ + var stopwatch = new System.Diagnostics.Stopwatch(); + stopwatch.Reset(); + stopwatch.Start(); + this.pixmap = this.page.fz_new_pixmap_from_page_contents( + new mupdf.FzMatrix((float) z, 0, 0, (float) z, 0, 0), + new mupdf.FzColorspace(mupdf.FzColorspace.Fixed.Fixed_RGB), + 1 /*alpha*/ + ); + stopwatch.Stop(); + var t_pixmap = stopwatch.Elapsed; + + stopwatch.Reset(); + stopwatch.Start(); + this.bitmap = new System.Drawing.Bitmap( + this.pixmap.fz_pixmap_width(), + this.pixmap.fz_pixmap_height(), + this.pixmap.fz_pixmap_stride(), + System.Drawing.Imaging.PixelFormat.Format32bppRgb, + (System.IntPtr) this.pixmap.fz_pixmap_samples_int() + ); + stopwatch.Stop(); + var t_bitmap = stopwatch.Elapsed; + + stopwatch.Reset(); + stopwatch.Start(); + // This is slow for large pixmaps/bitmaps. + //check(pixmap, bitmap, 4); + stopwatch.Stop(); + var t_check = stopwatch.Elapsed; + + /*System.Console.WriteLine("" + + " t_pixmap=" + t_pixmap + + " t_bitmap=" + t_bitmap + + " t_check=" + t_check + );*/ + } + else + { + /* Copy pixmap's pixels into bitmap. This works on both Linux + (Mono) and Windows. + + Unlike above, it seems that we need to use MuPDF Fixed_RGB with + alpha=0, and C#'s Format32bppRgb. Other combinations give a + blank display (possibly with alpha=0 for each pixel). */ + this.pixmap = this.page.fz_new_pixmap_from_page_contents( + new mupdf.FzMatrix((float) z, 0, 0, (float) z, 0, 0), + new mupdf.FzColorspace(mupdf.FzColorspace.Fixed.Fixed_RGB), + 0 /*alpha*/ + ); + + this.bitmap = new System.Drawing.Bitmap( + this.pixmap.fz_pixmap_width(), + this.pixmap.fz_pixmap_height(), + System.Drawing.Imaging.PixelFormat.Format32bppRgb + ); + long samples = pixmap.fz_pixmap_samples_int(); + int stride = pixmap.fz_pixmap_stride(); + for (int x=0; x<bitmap.Width; x+=1) + { + for (int y=0; y<bitmap.Height; y+=1) + { + unsafe + { + byte* sample = (byte*) samples + stride * y + 3 * x; + var color = System.Drawing.Color.FromArgb(sample[0], sample[1], sample[2]); + this.bitmap.SetPixel( x, y, color); + } + } + } + //check(pixmap, bitmap, 3); + } + this.picture_box.Image = this.bitmap; + } + + private void handle_key_down(object sender, System.Windows.Forms.KeyEventArgs e) + { + //System.Console.WriteLine("HandleKeyDown: " + e.KeyCode); + if (e.Shift && e.KeyCode == System.Windows.Forms.Keys.PageUp) + { + goto_page(this.page_number - 1, this.zoom); + } + else if (e.Shift && e.KeyCode == System.Windows.Forms.Keys.PageDown) + { + goto_page(this.page_number + 1, this.zoom); + } + else if (e.KeyCode == System.Windows.Forms.Keys.D0) + { + goto_page(this.page_number, 0); + } + else if (e.KeyCode == System.Windows.Forms.Keys.Add + || e.KeyCode == System.Windows.Forms.Keys.Oemplus + ) + { + goto_page(this.page_number, this.zoom + 1); + } + else if (e.KeyCode == System.Windows.Forms.Keys.Subtract + || e.KeyCode == System.Windows.Forms.Keys.OemMinus) + { + goto_page(this.page_number, this.zoom - 1); + } + } + + private void handle_resize(object sender, System.EventArgs e) + { + goto_page(page_number, zoom); + } + + // Throws exception if pixmap and bitmap differ. + void check(mupdf.FzPixmap pixmap, System.Drawing.Bitmap bitmap, int pixmap_bytes_per_pixel) + { + long samples = pixmap.fz_pixmap_samples_int(); + if (pixmap.fz_pixmap_width() != bitmap.Width || pixmap.fz_pixmap_height() != bitmap.Height) + { + throw new System.Exception("Inconsistent sizes:" + + " pixmap=(" + pixmap.fz_pixmap_width() + " " + pixmap.fz_pixmap_height() + + " bitmap=(" + bitmap.Width + " " + bitmap.Height + ); + } + int stride = pixmap.fz_pixmap_stride(); + for (int x=0; x<bitmap.Width; x+=1) + { + for (int y=0; y<bitmap.Height; y+=1) + { + unsafe + { + byte* sample = (byte*) samples + stride * y + pixmap_bytes_per_pixel * x; + System.Drawing.Color color = bitmap.GetPixel( x, y); + if (color.R != sample[0] || color.G != sample[1] || color.B != sample[2]) + { + string pixmap_pixel_text = ""; + for (int i=0; i<pixmap_bytes_per_pixel; ++i) + { + if (i > 0) pixmap_pixel_text += " "; + pixmap_pixel_text += sample[i]; + } + throw new System.Exception("Pixels differ: (" + x + " " + y + "):" + + " pixmap: (" + pixmap_pixel_text + ")" + + " bitmap: " + color); + } + } + } + } + } +}
