Image not visible when printing - c#

I need to implement printing in my Win 8.1 app and a key requirement is to be able to generate the page after the printer has been selected and the print button has been clicked. This is driven off security requirements around the images and is not negotiable. Eventually this is the point where I'll have to download the images needed in printing.
Currently for my testing I'm using an image that is local to the project:
string testImageLocalSource = "ms-appx:///Assets/testImage.png";
In my test project I'm working in, I'm generating the print page during the PrintDocument.AddPages event handler as follows (layout/margin code removed for succinctness):
private void PrintDocument_AddPages(object sender, AddPagesEventArgs e)
{
var printPageDescription = e.PrintTaskOptions.GetPageDescription(0);
FrameworkElement printPage;
printPage = new MainPrintPage();
// get the printable content
Grid printableArea = (Grid)printPage.FindName("printableArea");
Run myRun1 = new Run();
myRun1.Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
myRun1.FontStyle = Windows.UI.Text.FontStyle.Oblique;
myRun1.Foreground = new SolidColorBrush(Windows.UI.Colors.Purple);
myRun1.FontSize = 42;
Image i = new Image();
i.Source = new BitmapImage(new Uri(testImageLocalSource, UriKind.Absolute));
i.Height = 200;
InlineUIContainer container = new InlineUIContainer();
container.Child = i;
// Create a paragraph and add the content.
Paragraph myParagraph = new Paragraph();
myParagraph.Inlines.Add(container);
myParagraph.Inlines.Add(myRun1);
// add paragraph to RichTextBlock blocks
var mainRTB = printPage.FindName("mainrtb");
((RichTextBlock)mainRTB).Blocks.Add(myParagraph);
// add page to hidden canvas
printingRoot.Children.Add(printPage);
printingRoot.InvalidateMeasure();
printingRoot.UpdateLayout();
printDocument.AddPage(printPage);
PrintDocument printDoc = (PrintDocument)sender;
printDoc.AddPagesComplete();
}
The text appears fine, and there seems to be extra space where the image should be, but the image doesn't show up.
The image shows up in the print if I use this code in an earlier event handler, such as PrintDocument.Paginate.
Has anybody tried to do something similar and found a solution or else does anybody have an explanation as to what is going on here and an idea on how to remedy it?
UPDATE
I'm attempting to move a bulk of this code to the PrintTask.Submitting event and this is showing promise. I'll update this with an example if it works.

Do you forget to set a width of the image?
i.Width = 200;

Not exactly sure what was causing this in Win 8.1, but it seems to be fixed in Windows 10.

Related

How to property remove (or keep) the background and contents when exporting PDF to PNG using Magic.NET-Q16-AnyCPU

https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf
First time trying the Magic.NET-Q16-AnyCPU and I encounter an issue that I think I just do know the correct method to use I hope someone could lead me to get this corrected. I have a pdf with some existing texts and tables, plus a redline text added by using a pdf editing software.
Attached picture #1: depends on which software I use to view the png, some software shows black background. I like to have the background can show white or show as transparent (which is preferred) for all software. With page containing the red line text, it shows the red line one correctly but the other contents.
Attached picture #2: If I use settings.UseMonochrome = true; then this is no longer an issue but the resulting image I get is not what I prefer. I may sound stupid but with settings.UseMonochrome = false; my eyes feel better, especially when there are some graphics and tables.
Can I set settings. UseMonochrome = false; and still get all the contents shown correctly? And can I ensure the PNG background is either removed or set as White? Already try the image.BackgroundColor = MagickColors.White; but this does not impact the result.
private void button1_Click(object sender, EventArgs e)
{
var settings = new MagickReadSettings();
settings.Density = new Density(100, 100);
//Do not want to use this
//settings.UseMonochrome = true;
var filename = #"C:\Users\USER1\Desktop\dummy.pdf";
using (var images = new MagickImageCollection())
{
if(System.IO.File.Exists(filename))
{
images.Read(filename, settings);
var page = 1;
foreach (var image in images)
{
image.Write("C:\\Users\\USER1\\Desktop\\dummy.PNG");
page++;
}
}
}
}

Resizing and Collapsing label in winforms

first time poster, sorry if something isn't as it should be.
I'm new to Winforms and am trying to build a simple application that will display multiple features of an item (like Size, Composition, etc.). Each Characteristic has a Name, can have a Descritpion, and some can have sub-characteristics (having also a name and sometimes a descritpion).
I want to display them one under the other, with the Name of the feature on a blue background that span the whole width of the container, with the description underneath. The name will be (or have) a button (or similar) that when clicked collapse or expand the description. This must be created at run time because I don't know how many feature an object has until the user generate it.
The issues I'm running in are that either I can't span the blue background the whole width of the container (if using a FlowLayoutPanel), or I have some issue with the Description text being not the right size (either it wraps but is too big, or it doesn't wrap and then I can't see the whole text).
Some things are fixed, mainly the number of main sections (like Size, Composition, Weather, etc.), so I can prepare the skeleton before runtime.
The closest i've been to making it work gives this. This issue here is that the height of the Panel which the description label is embded in is fixed, and if I put in in Autosize, the text don't show (probably because the label is in Fill dock style). Just as information, this is what it looks like when collapsed (this is indeed what I'm looking for)
I know some library exists with collapsible panels, but I'd rather try to make it work without external libraries. Thanks in advance for any help !
This is the code that produces the results in the screenshots :
Panel SizeDescrPanel = new Panel();
SizeDescrPanel.Dock = DockStyle.Top;
//SizeDescrPanel.AutoSize = true;
SizeDescrPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
SizeDescrPanel.BackColor = Color.Bisque;
SizePanel.Controls.Add(SizeDescrPanel);
Label SizeDescrLbl = new Label();
SizeDescrLbl.Text = Lorem;
SizeDescrLbl.AutoSize = false;
SizeDescrLbl.Dock = DockStyle.Fill;
SizeDescrLbl.BackColor = Color.BurlyWood;
SizeDescrPanel.Controls.Add(SizeDescrLbl);
/*using(Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(SizeDescrLbl.Text, SizeDescrLbl.Font, SizePanel.Width);
SizeDescrPanel.Height = (int) Math.Ceiling(size.Height);
}*/
Panel SizeNamePanel = new Panel();
SizeNamePanel.Dock = DockStyle.Top;
SizeNamePanel.BackColor = Color.Cyan;
SizeNamePanel.AutoSize = true;
SizePanel.Controls.Add(SizeNamePanel);
Button SizeNameBtn = new Button();
SizeNameBtn.Text = "<Size Name> ..." + SizeDescrLbl.Height;
SizeNameBtn.TextAlign = ContentAlignment.MiddleLeft;
SizeNameBtn.FlatStyle = FlatStyle.Flat;
SizeNameBtn.AutoSize = true;
SizeNamePanel.Controls.Add(SizeNameBtn);
SizeNameBtn.Click += delegate { HideShowPanel(SizeDescrPanel); };
It,s a test project, so later I'll put that in different methods. What isn't shown here :
I have a main panel set to Fill containing everything.
The text "SIZE" is a label set to Top
Under it is another Panel (SizePanel) that is set to Top and Autosize is at True. This is the Panel inside which I'm puttin my size name and my size description. If I had a subfeature, it would be included (ideally) inside descritpion with the same configuration (button expanding/collapsing the descritpion of the SubFeature)

Previewing FixedDocument in DocumentViewer looks ok, printing it always prints the first page

I'm creating a FixedDocument by adding FixedPages to PageContents, then adding them to the FixedDocument somehow like this
FixedDocument fd = new FixedDocument();
// add FixedPages in PageContent to fd
Printing them with a PrintDialog, like this
pdialog.PrintDocument(fd.DocumentPaginator, "Test");
results in the correct number of pages. However, every page printed - e.g. to a PDF - is the content of the first page.
I tried testing the ImageSources I add to the FixedPages, those seem correct. I also tested the final FixedDocument with a DocumentViewer like so
Window wnd = new Window();
DocumentViewer viewer = new DocumentViewer();
viewer.Document = fd;
wnd.Content = viewer;
try
{
wnd.Show();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
This strangely shows the correct output I would expect. What's even stranger is that I get an IOException after wnd.Show(); (which is why I surrounded it with a try/catch). Even with the try catch I can only view it maybe 1-2 seconds before the same IOException thrown by my MainWindow. Something like "Wrong username or password" - which doesn't make sense, since the images I'm trying to print are local ones.
Putting the DocumentViewer aside, my problem with the Print() method only printing the first page n times (n being the number of actual pages it should be) still persists, just thought that the exception in the DocumentViewer may give someone an idea of an underlying problem.
This might be a possible duplicate of FixedDocument always print first page - however he doesn't mention problems with DocumentViewer and the question remains unanswered.
Thanks in advance for any help!
I have had a similar issue, printing labels in a FixedDocument from a List of Data, that contains a List Of Image Sources (User Photo), and also dynamically creates a QRCode image from an integer for the users id.
The format for the image is created from a custom UserControl that I used to position The Text fields and images for each label. When I viewed the created document in the DocumentViewer control, it displayed perfectly. Correct photo image, correct QRCode image for each label. However, when I printed the document (or saved to PDF file or XPS File), Ever Label had only the first image in both the Photo and QRCode image positions on the label.
When I came across this post, I though that I would try saving then reloading the images as suggested, and this worked!! However the IO overhead for 30 labels per page, and many pages of labels meant that this wasn't a very useful workaround! I
Then found that simply converting the ImageSource to a ByteArray, and then back again, before adding to the FixedDocument worked also, but without the added IO overhead. Not massively elegant, but has been a real headache for me for a week now!!
Here is a snippet of code from the main body of the method that builds the labels:
var qr = GetQRCodeImage(playerId); // Gets ImageSource
var ph = LoadImage(data[dataIndex].Photo); // Gets ImageSource
var qrCode = FixDocumentCacheImageBugFix(qr); // Gets ImageSource
if (ph != null) {
var photo = FixDocumentCacheImageBugFix(ph);
label = new AveryBarcodeLabel(line1, line2, line3, qrCode, photo); // Calls constructor to instantiate new Label with new ImageSources
}
else {
label = new AveryBarcodeLabel(line1, line2, line3, qrCode); // Calls constructor to instantiate new Label with new ImageSources (where photo is null)
}
and here are the methods I used to "Fix" the Images
public static ImageSource FixDocumentCacheImageBugFix(ImageSource image) {
var bytes = ImageSourceToBytes(image);
return ByteToImage(bytes);
}
public static ImageSource ByteToImage(byte[] imageData) {
var biImg = new BitmapImage();
var ms = new MemoryStream(imageData);
biImg.BeginInit();
biImg.StreamSource = ms;
biImg.EndInit();
ImageSource imgSrc = biImg;
return imgSrc;
}
public static byte[] ImageSourceToBytes(ImageSource imageSource) {
byte[] bytes = null;
var bitmapSource = imageSource as BitmapSource;
if (bitmapSource != null) {
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var stream = new MemoryStream()) {
encoder.Save(stream);
bytes = stream.ToArray();
}
}
return bytes;
}
So, this isn't really the answer to why it happened, but I found at least the culprit: my image.
I'm loading a multipage LZW-compressed TIFF like so:
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
foreach (ImageSource frame in encoder.Frames)
{
frame.Freeze();
Images.Add(frame);
}
where Images is a collection of ImageSource. They display fine in the application, I can also save them again using a TiffBitmapEncoder, but printing them using WPF ends up with the in the question mentioned problem as well as - when using a DocumentViewer - an exception telling me about 'wrong username or password', which doesn't make sense.
The way I found out the image to be the problem was temporarily saving the individual ImageSources of the TIFF using a PngBitmapEncoder and immediately reloading the pages from the separate files with the same encoder into the same slot in my Images collection.
Since this works without any issues (no username/password exception in my DocumentViewer and my printing working correctly) I have to assume that he doesn't like something about the TIFF format.
This doesn't answer my underlying question of why it didn't work, but since this is at least a workaround that works, I'll just put that here and don't check the 'answered' mark just yet.
Maybe someone knows why my TIFF ImageSource produced those strange results?

Inline Hyperlink navigate to Page

I'm constructing text, and some pieces of the text should contain a hyperlink. However, these hyperlinks do not redirect to a webpage but should open a page in the UWP app (the currently running UWP app, not a new instance of it or a different app).
A HyperlinkButton can only open URL's that lead to an external browser, it can't open a page inside the app.
Using an InlineUIContainer doesn't work, I get
Exception thrown: 'System.ArgumentException' in mscorlib.ni.dll
Additional information: Value does not fall within the expected range.
With this code
List<Inline> ic = new List<Inline>();
InlineUIContainer container = new InlineUIContainer();
TextBlock tbClickable = new TextBlock();
tbClickable.Foreground = new SolidColorBrush(Colors.Red);
tbClickable.Text = label?.name;
tbClickable.Tag = label?.id;
tbClickable.Tapped += TbArtist_Tapped;
container.Child = tbClickable;
ic.Add(container);
When I use
foreach (var item in ic)
{
dTb.Inlines.Add(item);
}
Where tbCurrent is the TextBlock.
Any other ways to get a clickable link as an Inline element?
Best case scenario I can attach a Tapped/Click event handler.
But opening the page via a URI method or so is also good.
I changed to a RichTextBlock and using Blocks I could add a clickable TextBlock.
This works in UWP.
List<Block> ic = new List<Block>();
Paragraph para = new Paragraph();
InlineUIContainer iuic = new InlineUIContainer();
TextBlock hpb = new TextBlock();
hpb.Text = "link text";
hpb.Tag = "some tag to pass on to the click handler";
hpb.Tapped += ClickHandler;
hpb.TextDecorations = TextDecorations.Underline;
hpb.Foreground = new SolidColorBrush((Windows.UI.Color)page.Resources["SystemAccentColor"]);
iuic.Child = hpb;
para.Inlines.Add(iuic);
ic.Add(para);
There is no reason you could not use a HyperlinkButton for this. Quick example:
<HyperlinkButton Click="HyperlinkButton_Click" Content="Click me" />
And the Click handler:
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(MainPage));
}

Change button background

After several attempts to change the background of a button, and getting errors of casting and things like that I finnaly got to this point:
Uri dir = new Uri("red_flag.png",UriKind.RelativeOrAbsolute);
ImageSource source = new System.Windows.Media.Imaging.BitmapImage(dir);
ImageBrush bru = new ImageBrush();
bru.ImageSource=source;
bru.Opacity = 100;
This code does not generate errors, but I can't see the changes when I call:
button1.background = bru;
It just makes anything! :(
found the answer myelf after reading Mick's answer, I share with you what I did:
Uri dir = new Uri("red_flag.png", UriKind.Relative);
ImageSource source = new System.Windows.Media.Imaging.BitmapImage(dir);
Image image = new Image();
image.Source = source;
StackPanel stack = new StackPanel();
stack.Children.Add(image);
myButton.Content = stack;
Thanks for your help
Update 1:
For best results set the padding property of your button to 0 (in each of the cases) so the image can resize automatically to fill all the button, please note this could hide your actual content, in my case this was what I wanted.
If this code is part of the click event handler for the same button you will have this problem.
Peter Torr explains why here and offers a solution.
Why can't I change the Background of my Button on a Click event?

Categories