How can I print a visual as grayscale without actually showing the PrintDialog, e.g.
PrintDialog dialog = new Dialog();
dialog.PrintQueue = new PrintQueue(new PrintServer(), printerNameAsString);
dialog.PrintTicket.InputBin = InputBin.AutoSelect;
// Further settings, e.g. PageMediaSize and scaling the visual.
dialog.PrintVisual(myVisual, "myDescription");
Can I somehow get the PrinterDialog to print the visual in grayscale? Or is there a completely other way to achieve a grayscale printout of my visual?
Edit: myVisual (the Visual I want to print) is a Grid, so it inherits from UIElement.
Edit 2: If possible I would prefer not to use any external libraries (because of company policies).
In the PrintDialog the OutputColor can be set:
myPrintDialog.PrintTicket.OutputColor = OutputColor.Grayscale;
Also, the PrintCapabilities make it possible to actually check which OutputColors are possible:
PrintCapabilities capabilities = myPrintDialog.PrintQueue.GetPrintCapabilities(myPrintDialog.PrintTicket);
ReadOnlyCollection<OutputColor> possibleColors = capabilities.OutputColorCapability;
On the hardware available to me this works fine.
You can try using the standard lib in Microsoft.Expression.Effects assembly. The effect here is MonochromeEffect. Just apply this effect before printing your visual:
myVisual.Effect = new MonochromeEffect();//make grayscale
dialog.PrintVisual(myVisual, "myDescription");
myVisual.Effect = null; //turn it off
You have to import the library I mentioned above and add this using instruction:
using Microsoft.Expression.Media.Effects;
I ran into a similar problem where DrawString would always print solid black--even though the Brushes specified a lighter shade. I finally discovered that by placing an image onto the graphics object, it would print lighter shades that were in the image. It feels like a hack, but it works! (The printdialog solution might have worked too--I don't know since I'm printing automatically from a service where there is no printdialog.)
Related
I'm a MAC user so I can't use Windows Forms. I'm trying to figure out Gtk# myself but there is little to no tutorials and documentation to be found on the internet. I want to create a bitmap, draw something in it and display it. So far, I came with this and that displays a window:
Application.Init();
Window Win = new Window("Ray Tracing #2");
Win.Resize(480, 480);
Win.ShowAll();
Application.Run();
However, I would like to manipulate with the window, so let's say: add a bitmap for a start.
I know that to create a bitmap I must write:
System.Drawing.Image IMG = new Bitmap(640, 640);
but what then?
All right, let's try to fix all the problems at once:
You can find a Gtk# tutorial in ZetCode.
If you are going to mess with graphics, then you need to know about Cairo#.
I have a Github repository for my students with a simple demo using both Gtk# and Cairo.
I have another Github repository with a CSV-based spreadsheet application.
My advise is not to rely on the visual designer present in MonoDevelop/XamarinStudio, but to understand how the toolkit works and use it directly. Nowadays graphic toolkits are easy to use enough, and this way you are not tied to any editor/environment.
About your specific question, Bitmap pertains to the WinForms's universe (in fact, it is within the Drawing namespace), you should use a Gtk.Image. Let's create a scrolled panel (though it is called a "window"), and use it to show the bitmap.
var swScroll = new Gtk.ScrolledWindow();
var picBox = new Gtk.Image( "/path/to/image.jpg" );
var vbox = new VBox( false, 5 );
swScroll.AddWithViewport( picBox );
vbox.PackStart( swScroll, true, true, 5 );
this.Add( vbox );
this.ShowAll();
You can build an empty image with a specific size or whatever. Explore the constructors available for Gtk.Image.
Hope this helps!
I'm using CEFSharp (the C# wrapper for CEF) to print a web page to PDF, like this:
browser.PrintToPdfAsync(#"C:\out.pdf", new PdfPrintSettings
{
BackgroundsEnabled = true,
HeaderFooterEnabled = false,
Landscape = false,
MarginType = CefPdfPrintMarginType.Custom,
MarginBottom = 0,
MarginTop = 0,
MarginLeft = 0,
MarginRight = 0,
PageWidth = 210000,
PageHeight = 297000
});
However, the problem is that the resulting PDF is very blurry when compared to manually printing the same page in the "real" Chrome application.
I've made a comparison screenshot to show the difference:
(open it at full resolution to notice the difference)
Basically, as you can see, CEF seems to be compressing images and other non-vector graphics much more than the native Chrome printing function.
Ideally, I'd like to disable compression completely, or at least it bring it closer to native Chrome levels. Can it be done?
Also related: is there was a way to print at higher resolution? The PdfPrintSettings class only accepts width and height measurements in microns, but I don't see any way to set the rendering definition (DPIs)... is it possible?
I guess images are blurry because PDF gets printed as a preview:
https://bitbucket.org/chromiumembedded/cef/src/6006f77bd9e030e9b456e180798c7c13d19cae08/libcef/browser/printing/print_view_manager.cc?at=master&fileviewer=file-view-default#print_view_manager.cc-110
It was my pull-request which added PDF printing to CEF. Printing as a preview seemed good enough for me. It allowed to write less code and implement less components involved in PDF printing.
It's also possible that some other settings make images blurry. For example:
https://bitbucket.org/chromiumembedded/cef/annotate/6006f77bd9e030e9b456e180798c7c13d19cae08/libcef/browser/printing/print_view_manager.cc?at=master&fileviewer=file-view-default#print_view_manager.cc-50
It needs some debugging. In order to do that you most likely would need to build CEF from source:
https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding
DPI can not be set because Chromium itself does not have such setting in its PDF print dialog. Although you can try to set different DPI options here:
https://bitbucket.org/chromiumembedded/cef/src/6006f77bd9e030e9b456e180798c7c13d19cae08/libcef/browser/printing/print_view_manager.cc?at=master&fileviewer=file-view-default#print_view_manager.cc-53 But it's possible that those settings are just ignored by Chromium.
We're using migradoc api to create an rtf document.. intermittently when we add an image it;s being resized and coming out absolutely tiny.
Code sample as follows:
MigraDoc.DocumentObjectModel.Shapes.Image image = section.AddImage(imagePath);
image.WrapFormat.Style = MigraDoc.DocumentObjectModel.Shapes.WrapStyle.Through;
If I set LockAspectRatio to true and set a width it does stop is from rendering very small but ideally would like to be able to set a MaxWidth.
Has anyone experiences similar issue?
You have a choice of either changing the image itself by storing a different DPI value in it.
The .Net command to do so with a Bitmap bmp is:
bmp.SetResolution(newHRes , newVRes);
This should not involve reencoding, but I'm not sure.
However you also can simply set the desired DPI value in the Migradoc Image by using its Image.Resolution Property, which
Gets or sets a user defined resolution for the image in dots per inch.
I am not familiar with it at all but I found this code that might help you :
image.RelativeVertical = RelativeVertical.Page;
image.RelativeHorizontal = RelativeHorizontal.Page;
I'm trying to add printing support to a C# WPF application I'm writing and I'm tearing my hair out over this. I'm trying to print a single image from a window in a WPF application. The image is a shipping label and the printer is a thermal printer loaded with 4"x6" shipping label stock. The code to print is as follows:
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
Image tmpImage = new Image();
tmpImage.Stretch = Stretch.Uniform;
tmpImage.Width = pd.PrintableAreaWidth;
tmpImage.Source = this.img_label.Source;
tmpImage.Measure(new Size(pd.PrintableAreaWidth, pd.PrintableAreaHeight));
tmpImage.Arrange(new Rect(new Point(0, 0), tmpImage.DesiredSize));
pd.PrintVisual(tmpImage, "Shipping Label");
}
This code works in that it will display the print dialog, I can choose my printer, configure it to use the correct label stock, and print the label. However, as other posts have indicated, it does not save the settings I have selected. So, if I choose to print the same image again without closing the application in between, it reverts to the default printer and, even when I choose the correct printer, defaults that printer to the default settings, which includes using the wrong size label stock. So every time I print I have to select the printer and configure it to use the correct stock. This is simply not acceptable in real world use.
After much searching online I have found numerous posts about this but all of them talk about saving the PrintDialog.PrinterSettings object and then using that to initialize the next PrintDialog instance. However, in WPF, there is no PrinterSettings member of the PrintDialog class. That is a Win Forms object. Why the Win Forms and WPF PrintDialog objects are different is beyond me, but that's likely a question that won't get answered. The real question is what I do now. I can, if necessary, re-invent the entire wheel and have my own printer selector and printer configuration pages and print the image using a PrintDocument object and bypass the PrintDialog entirely. I'd rather not do this unless it is entirely necessary. Displaying the PrintDialog is nice, it's what people are used to, and it already has all the ability to configure the printer built right in. But how can I initialize the PrintDialog in WPF to select the proper printer and use the proper printer settings? If only I were using Windows Forms this would be built in. What's the WPF equivalent?
The secondary question is, if there is no WPF equivalent, what is the recommended way to handle this? I don't really need to give the user the ability to configure the printer within my application. All I want it to do is remember the previous settings they chose the next time they go to print, just like every single other PC application that has ever been written. How can this be so hard?
Any help anyone can provide would be greatly appreciated. In the mean time I'm going down the path of re-inventing the proverbial wheel. I hope to get an easier answer soon.
Thanks!
WPF has PrintTicket and PrintQueue classes (and PrintDialog has corresponding properties, which can be initialized with your saved settings).
For the simplicity, you can consider the first one as the paper settings, and the second one - as the printer settings (selected printer).
I am trying to take a screenshot of an application and I would like to make the parts of the rectangle that are not part of the applications region be transparent. So for instance on a standard windows application I would like to make the rounded corners transparent.
I wrote a quick test application which works on on XP (or vista/windows 7 with aero turned off):
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// Just find a window to test with
IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
GetWindowRgn(hwnd, hrgn);
// fill a rectangle which would be where I would probably
// write some mask color
g.FillRectangle(Brushes.Red, r);
// fill the region over the top, all I am trying to do here
// is show the contrast between the applications region and
// the rectangle that the region would be placed in
Region region = Region.FromHrgn(hrgn);
region.Translate(info.rcWindow.Left, info.rcWindow.Top);
g.FillRegion(Brushes.Blue, region);
}
When I run this test app on XP (or Vista/Windows 7 with Aero off), I get something like this, which is great because I can eek an xor mask out of this that can be used later with BitBlt.
removed dead Imageshack link - Screenshot
Here is the problem, on Vista or Windows 7 with Aero enabled, there isn't necessarily a region on the window, in fact in most cases there isn't. Can anybody help me figure out some way to build a mask like this on these platforms?
Here are some of the approaches I have already tried...
1. Using the PrintWindow function: This doesn't work because it gives back a screenshot taken of the window with Aero off and this window is a different shape from the window returned with Aero on
2 Using the Desktop Window Manager API to get a full size thumbnail: This didn't work because it draws directly to the screen and from what I can tell you can't get a screenshot directly out of this api. Yeah, I could open a window with a pink background, show the thumbnail, take a screenshot then hide this temporary window but thats a horrible user experience and a complete hack I would rather not have my name on.
3. Using Graphics.CopyFromScreen or some other pinvoke variant of this: This doesn't work because I can't assume that the window I need information from is at the top of the z-order on the screen.
Right now, the best solution I can think of is to special case Aero on Windows 7 and Vista to manually rub out the corners by hard coding some graphics paths I paint out but this solution would suck since any application that performs custom skinning will break this.
Can you think of another or better solution?
If you are here, thanks for taking time to read this post, I appreciate any help or direction that you can offer!
If you are looking for a finished application, there is 7capture, which captures also the translucency, so images can be saved to PNG format for later compositing.
EDIT:
The original question and comments indicate you are looking to produce a region on Windows Vista/7 that you can then use to mask out parts the captured image, as is done with Windows XP and non-Aero UIs. Using a region is not going to give you the result you are looking for, since the window outline is not computed as a region, but as an image with variable transparency - RGBA. The Alpha channel in that image is your mask, but it's not an on-off mask like a region, but a gradual mask with a range of values from pixels being fully included to being fully masked out.
Although it uses undocumented APIs, the code at http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/ will capture to a RGBA buffer which you can then use to render or save the image with the shadow and other translucency effects intact.
In DwmCapture.cs Change
BackBufferFormat = Format.X8R8G8B8
to
BackBufferFormat = Format.A8R8G8B8
(X8->A8)
And you should then be able to access both the usual RGB data plus transparency from the captured buffer. This can then be saved as a PNG or other format with alpha-channel for composing.
Removed idea that is terrible but would have been awesome back in the '90s
You say that using the DWM API only allows you to capture directly to the screen... could you create a window offscreen (say, X = -100000px, Y = -100000px) but visible (maybe even hidden?) and draw the screenshot to it? Since when using the DWM each window has a backing texture, I'm thinking it might still get drawn fine even though the target isn't directly onscreen.
Also, if you want to go the DirectX route and access the actual DX texture backing the window, I found a few leads that might help (especially the first link):
http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/
http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
http://web.archive.org/web/20080625183653/http://www.aeroxp.org/board/index.php?showtopic=6286
http://www.youtube.com/watch?v=hRTgFTMnT_U
Using Graphics.CopyFromScreen or some other pinvoke variant of this:
This doesn't work because I can't
assume that the window I need
information from is at the top of the
z-order on the screen.
If you know which window you need the information from, can you bring it to the front, call Graphics.CopyFromScreen, and then reset its z-index? I know from experience that Aero does odd things when items are in the background in order to make their glass interface work correctly (partial rendering etc). This may not be great UX; however, it would be a special case and used only when Aero is turned on.
You can take a look at the source code of AeroShot, as described on the main page, it can capture rounded edges and with the Aero Glass transparency effect and save it to a PNG file. It's written in C#.