// Throws exception if pixmap and bitmap differ. void check(mupdf.Pixmap pixmap, System.Drawing.Bitmap bitmap, int pixmap_bytes_per_pixel) { long samples = pixmap.pixmap_samples_int(); if (pixmap.pixmap_width() != bitmap.Width || pixmap.pixmap_height() != bitmap.Height) { throw new System.Exception("Inconsistent sizes:" + " pixmap=(" + pixmap.pixmap_width() + " " + pixmap.pixmap_height() + " bitmap=(" + bitmap.Width + " " + bitmap.Height ); } int stride = pixmap.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); } } } } }
// 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.count_pages()) { return; } this.zoom = zoom; this.page_number = page_number; this.page = document.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.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.new_pixmap_from_page_contents( new mupdf.Matrix((float)z, 0, 0, (float)z, 0, 0), new mupdf.Colorspace(mupdf.Colorspace.Fixed.Fixed_RGB), 1 /*alpha*/ ); stopwatch.Stop(); var t_pixmap = stopwatch.Elapsed; stopwatch.Reset(); stopwatch.Start(); this.bitmap = new System.Drawing.Bitmap( this.pixmap.pixmap_width(), this.pixmap.pixmap_height(), this.pixmap.pixmap_stride(), System.Drawing.Imaging.PixelFormat.Format32bppRgb, (System.IntPtr) this.pixmap.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.new_pixmap_from_page_contents( new mupdf.Matrix((float)z, 0, 0, (float)z, 0, 0), new mupdf.Colorspace(mupdf.Colorspace.Fixed.Fixed_RGB), 0 /*alpha*/ ); this.bitmap = new System.Drawing.Bitmap( this.pixmap.pixmap_width(), this.pixmap.pixmap_height(), System.Drawing.Imaging.PixelFormat.Format32bppRgb ); long samples = pixmap.pixmap_samples_int(); int stride = pixmap.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; }