/// <summary> /// Generates all PDF pages as JPEG files for a given pdf source and a destination folder. /// </summary> /// <param name="source">The PDF source</param> /// <param name="destination">The destination folder</param> /// <param name="width">Used to get a smaller or bigger JPEG file, depending on the specified value</param> /// <param name="password">The password for the pdf file (if required)</param> public static void GeneratePagesAtWidth(IPdfSource source, string destination, int width, string password = null) { if (!Directory.Exists(destination)) { throw new DirectoryNotFoundException("The directory \"" + destination + "\" does not exist !"); } using (var stream = new PdfFileStream(source)) { ValidatePassword(stream.Document, password); int pageCount = CountPages(source); var currentDpi = DpiHelper.GetCurrentDpi(); for (int i = 0; i < pageCount; i++) { GC.Collect(); GC.WaitForPendingFinalizers(); IntPtr p = NativeMethods.LoadPage(stream.Document, i); // loads the page var bmp = RenderPageAtWidth(stream.Context, stream.Document, p, width, currentDpi.HorizontalDpi, currentDpi.VerticalDpi); NativeMethods.FreePage(stream.Document, p); // releases the resources consumed by the page bmp.Save(Path.Combine(destination, i + generateOutputExtension), generateOutputFormat); } } GC.Collect(); GC.WaitForPendingFinalizers(); }
private void DragMoveCurrentWindow(object sender, MouseButtonEventArgs e) { if (WindowState == WindowState.Maximized) { var dpi = DpiHelper.GetCurrentDpi(); // MouseDevice.GetPosition() returns device-dependent coordinate, however WPF is not like that var point = PointToScreen(e.MouseDevice.GetPosition(this)); Left = point.X / (dpi.HorizontalDpi / DpiHelper.DEFAULT_DPI) - RestoreBounds.Width * 0.5; Top = point.Y / (dpi.VerticalDpi / DpiHelper.DEFAULT_DPI); WindowState = WindowState.Normal; } DragMove(); }
/// <summary> /// Extracts a PDF page as a Bitmap for a given pdf source and a page number. /// </summary> /// <param name="source">The PDF source</param> /// <param name="pageNumber">Page number, starting at 0</param> /// <param name="zoomFactor">Used to get a smaller or bigger Bitmap, depending on the specified value</param> /// <param name="password">The password for the pdf file (if required)</param> public static BitmapSource ExtractPageAtScale(IPdfSource source, int pageNumber, float zoomFactor = 1.0f, string password = null) { if (pageNumber < 0 || pageNumber >= CountPages(source)) { throw new ArgumentOutOfRangeException("pageNumber", "The page \"" + pageNumber + "\" does not exist !"); } using (var stream = new PdfFileStream(source)) { ValidatePassword(stream.Document, password); IntPtr p = NativeMethods.LoadPage(stream.Document, pageNumber); // loads the page var currentDpi = DpiHelper.GetCurrentDpi(); var bmp = RenderPageAtScale(stream.Context, stream.Document, p, zoomFactor, currentDpi.HorizontalDpi, currentDpi.VerticalDpi); NativeMethods.FreePage(stream.Document, p); // releases the resources consumed by the page return(bmp.ToBitmapSource()); } }
static Bitmap RenderPage(IntPtr context, IntPtr document, IntPtr page, float zoomFactor) { Rectangle pageBound = NativeMethods.BoundPage(document, page); Matrix ctm = new Matrix(); IntPtr pix = IntPtr.Zero; IntPtr dev = IntPtr.Zero; var currentDpi = DpiHelper.GetCurrentDpi(); var zoomX = zoomFactor * (currentDpi.HorizontalDpi / DpiHelper.DEFAULT_DPI); var zoomY = zoomFactor * (currentDpi.VerticalDpi / DpiHelper.DEFAULT_DPI); // gets the size of the page and multiplies it with zoom factors int width = (int)(pageBound.Width * zoomX); int height = (int)(pageBound.Height * zoomY); // sets the matrix as a scaling matrix (zoomX,0,0,zoomY,0,0) ctm.A = zoomX; ctm.D = zoomY; // creates a pixmap the same size as the width and height of the page pix = NativeMethods.NewPixmap(context, NativeMethods.FindDeviceColorSpace(context, "DeviceRGB"), width, height); // sets white color as the background color of the pixmap NativeMethods.ClearPixmap(context, pix, 0xFF); // creates a drawing device dev = NativeMethods.NewDrawDevice(context, pix); // draws the page on the device created from the pixmap NativeMethods.RunPage(document, page, dev, ctm, IntPtr.Zero); NativeMethods.FreeDevice(dev); // frees the resources consumed by the device dev = IntPtr.Zero; // creates a colorful bitmap of the same size of the pixmap Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); var imageData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat); unsafe { // converts the pixmap data to Bitmap data byte *ptrSrc = (byte *)NativeMethods.GetSamples(context, pix); // gets the rendered data from the pixmap byte *ptrDest = (byte *)imageData.Scan0; for (int y = 0; y < height; y++) { byte *pl = ptrDest; byte *sl = ptrSrc; for (int x = 0; x < width; x++) { //Swap these here instead of in MuPDF because most pdf images will be rgb or cmyk. //Since we are going through the pixels one by one anyway swap here to save a conversion from rgb to bgr. pl[2] = sl[0]; //b-r pl[1] = sl[1]; //g-g pl[0] = sl[2]; //r-b //sl[3] is the alpha channel, we will skip it here pl += 3; sl += 4; } ptrDest += imageData.Stride; ptrSrc += width * 4; } } bmp.UnlockBits(imageData); NativeMethods.DropPixmap(context, pix); bmp.SetResolution(currentDpi.HorizontalDpi, currentDpi.VerticalDpi); return(bmp); }
private static Bitmap RenderPage(IntPtr context, IntPtr page, float zoomFactor) { Rectangle pageBound = NativeMethods.BoundPage(context, page); Matrix ctm = new Matrix(); IntPtr pix = IntPtr.Zero; IntPtr dev = IntPtr.Zero; var currentDpi = DpiHelper.GetCurrentDpi(); var zoomX = zoomFactor * (currentDpi.HorizontalDpi / DpiHelper.DEFAULT_DPI); var zoomY = zoomFactor * (currentDpi.VerticalDpi / DpiHelper.DEFAULT_DPI); // gets the size of the page and multiplies it with zoom factors int width = (int)(pageBound.Width * zoomX); int height = (int)(pageBound.Height * zoomY); // sets the matrix as a scaling matrix (zoomX,0,0,zoomY,0,0) ctm.A = zoomX; ctm.D = zoomY; // creates a pixmap the same size as the width and height of the page #if UNSAFE pix = NativeMethods.NewPixmap(context, NativeMethods.FindDeviceColorSpace(context, ColorSpace.Rgb), width, height, IntPtr.Zero, 0); #else // use BGR color space to save byte conversions pix = NativeMethods.NewPixmap(context, NativeMethods.FindDeviceColorSpace(context, ColorSpace.Bgr), width, height, IntPtr.Zero, 0); #endif // sets white color as the background color of the pixmap NativeMethods.ClearPixmap(context, pix, 0xFF); // creates a drawing device var im = Matrix.Identity; dev = NativeMethods.NewDrawDevice(context, im, pix); // draws the page on the device created from the pixmap NativeMethods.RunPage(context, page, dev, ctm, IntPtr.Zero); NativeMethods.CloseDevice(context, dev); NativeMethods.DropDevice(context, dev); // frees the resources consumed by the device dev = IntPtr.Zero; // creates a colorful bitmap of the same size of the pixmap Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); var imageData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bmp.PixelFormat); #if UNSAFE // note: unsafe conversion from pixmap to bitmap // without the overhead of P/Invokes, the following code can run faster than the safe-conversion code below unsafe { // converts the pixmap data to Bitmap data byte *ptrSrc = (byte *)NativeMethods.GetSamples(context, pix); // gets the rendered data from the pixmap byte *ptrDest = (byte *)imageData.Scan0; for (int y = 0; y < height; y++) { byte *pl = ptrDest; byte *sl = ptrSrc; for (int x = 0; x < width; x++) { //Swap these here instead of in MuPDF because most pdf images will be rgb or cmyk. //Since we are going through the pixels one by one anyway swap here to save a conversion from rgb to bgr. pl[2] = sl[0]; //b-r pl[1] = sl[1]; //g-g pl[0] = sl[2]; //r-b pl += 3; sl += 3; } ptrDest += imageData.Stride; ptrSrc += width * 3; } } #else // note: Safe-conversion from pixmap to bitmap var source = NativeMethods.GetSamples(context, pix); var target = imageData.Scan0; for (int y = 0; y < height; y++) { // copy memory line by line NativeMethods.RtlMoveMemory(target, source, width * 3); target = (IntPtr)(target.ToInt64() + imageData.Stride); source = (IntPtr)(source.ToInt64() + width * 3); } #endif bmp.UnlockBits(imageData); NativeMethods.DropPixmap(context, pix); bmp.SetResolution(currentDpi.HorizontalDpi, currentDpi.VerticalDpi); return(bmp); }