File: mupdfwrap_gui.cs

package info (click to toggle)
mupdf 1.25.1%2Bds1-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 21,620 kB
  • sloc: ansic: 270,929; python: 20,709; java: 6,916; javascript: 1,865; makefile: 1,130; xml: 550; sh: 430; cpp: 325; cs: 313; awk: 10; sed: 7; lisp: 3
file content (277 lines) | stat: -rw-r--r-- 10,427 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
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 + " becase: " + 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);
                    }
                }
            }
        }
    }
}