MigraDoc: Rendering the same document twice - c#

I want to render a "Document"-object twice, but on the second generation the PDF-File shows an error:
Error on this page. Maybe this page couldn't appear correctly. Please talk to the document-creator.
Sorry, it is german...
This is my example-code:
using System;
using System.Windows.Forms;
using MigraDoc.Rendering;
using MigraDoc.DocumentObjectModel;
using PdfSharp.Pdf;
using System.Diagnostics;
namespace Temp
{
public partial class Form1 : Form
{
Document document; //using the same document- and renderer-object ..
PdfDocumentRenderer renderer; //..creates the error
public Form1()
{
InitializeComponent();
document = new Document();
renderer = new PdfDocumentRenderer(false, PdfFontEmbedding.Always);
}
private void button1_Click(object sender, EventArgs e)
{
Section section = document.AddSection();
Paragraph paragraph = section.AddParagraph();
paragraph.AddFormattedText("Hello World", TextFormat.Bold);
SaveFile(renderer);
}
private void SaveFile(PdfDocumentRenderer renderer)
{
renderer.Document = document;
renderer.RenderDocument();
string pdfFilename = string.Format("Rekla-{0:dd.MM.yyyy_hh-mm-ss}.pdf", DateTime.Now);
renderer.PdfDocument.Save(pdfFilename);
Process.Start(pdfFilename);
}
}
}
Of course i could always create a new "Document"-object:
private void button1_Click(object sender, EventArgs e)
{
Document document = new Document(); //Creating a new document-object solves the problem..
PdfDocumentRenderer renderer = new PdfDocumentRenderer(false, PdfFontEmbedding.Always);
Section section = document.AddSection();
Paragraph paragraph = section.AddParagraph();
paragraph.AddFormattedText("Hi", TextFormat.Bold);
SaveFile(renderer, document);
}
This works. But i need to change the current document while performing other button-click-events. The second code-snippet doesn't solve this task.
Does someone know how to fix the first code-snippet?

Do not re-use the Renderer. Create a new Renderer in the SaveFile method and everything should be fine.
If a new Renderer is not enough, call document.Clone() and assign that to the Renderer.

A method I have found very useful for repeatedly saving a Migradoc pdf to a file is to save the document to a MemoryStream/byte array when I render it. Then when I need to save the pdf file, I just save the byte array.
Put this part in your constructor where you want to render the document:
// First we render our document and save it to a byte array
bytes[] documentBytes;
Document doc;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
PdfDocumentRenderer pdfRender = new PdfDocumentRenderer();
pdfRender.Document = doc;
pdfRender.RenderDocument();
pdfRender.Save(ms, false);
documentBytes = ms.ToArray();
}
Put this part in your button event where you want to save to a file:
// Then we save the byte array to a file when needed
string filename;
using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
fs.Write(documentBytes, 0, documentBytes.Length);
}

Related

IronBarCode stream only

I want to create an QrCode using IronBarCode, and then save it as a Stream or Byte[].
However both methods expect the file to be saved prior to creation:
var absolute = Request.Scheme + "://" + Request.Host + url;
var qrcode = IronBarCode.QRCodeWriter.CreateQrCode(absolute);
qrcode.AddAnnotationTextAboveBarcode(device.Name);
qrcode.AddBarcodeValueTextBelowBarcode(absolute);
var f = qrcode.ToJpegStream();
var y = qrcode.ToJpegBinaryData();
ToJpegStream() and ToJpegBinaryData expects the absolute string to be an actual file path. I want to create a QrCode and save it as a Byte[] or Stream, however the error thrown is "The filename, directory name, or volume label syntax is incorrect."
AddBarcodeValueTextBelowBarcode method parameter for string is FontPath. That is why it was trying to find the font file that does not exist.
string absolute = "https://ironsoftware.com/";
string Name = "Product URL:";
//Add Annotation(text) below the generated barcode
var qrcode = QRCodeWriter.CreateQrCode(absolute);
qrcode.AddAnnotationTextBelowBarcode(Name);
qrcode.ToJpegBinaryData();
//Add Barcode value below the generated barcode
var qrcode = QRCodeWriter.CreateQrCode(absolute);
qrcode.AddBarcodeValueTextBelowBarcode();
qrcode.ToJpegBinaryData();
The below image is FontPath. FontPath is actually the directory path that actually lead to the Font file.
//This will add Barcode value into QRCode
.AddBarcodeValueTextBelowBarcode()
If you want to add absolute path to the QRCode you should use
//This will add your text to Barcode
.AddAnnotationTextBelowBarcode(absolute)
For more information on how to use the method please refer to the API reference:
https://ironsoftware.com/csharp/barcode/object-reference/api/IronBarCode.GeneratedBarcode.html#IronBarCode_GeneratedBarcode_AddBarcodeValueTextBelowBarcode
The issue mentioned isn't reproducible with the code provided. The code below is adapted from your code and the from the example. It's been tested.
Create a new Windows Forms App (.NET Framework)
Download/install NuGet package: Barcode
Add a Button to Form1 (name: btnCreateQRCode)
Add a PictureBox to Form1 (name: pictureBox1)
Add using directives:
using IronBarCode;
using System.IO;
Form1.cs:
public partial class Form1 : Form
{
private byte[] _qrCode = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private byte[] CreateBarCode(string url, string annotationText)
{
//create new instance
GeneratedBarcode qrCode = QRCodeWriter.CreateQrCode(url);
qrCode.AddAnnotationTextAboveBarcode(annotationText);
qrCode.AddBarcodeValueTextBelowBarcode(url);
byte[] qrCodeBytes = qrCode.ToJpegBinaryData();
return qrCodeBytes;
}
private void btnCreateQRCode_Click(object sender, EventArgs e)
{
_qrCode = CreateBarCode("https://www.google.com/search?q=how+to+search", "How To Search");
using (MemoryStream ms = new MemoryStream(_qrCode))
{
pictureBox1.Image = Image.FromStream(ms);
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; //fit to size
pictureBox1.Refresh();
}
}
}
Resources:
Create QR Code

Print RDLC Report without showing ReportViewer Control

I was wondering if is possible to send/print data from DataGridView directly to rdlc report without binding it to ReportViewercontrol.
There are many threads about binding dgv data to report viewer control.
I don't want to create another form with report viewer control, but use existing form with data on DataGridView and on print button to send the data to RDLC report and print it.
Is it possible?
Thanks
You can print an RDLC report programmatically by using LocalReport object and CreateStreamCallback callback function. Here is a complete Microsoft docs walkthrough which you may find useful:
Walkthrough: Printing a Local Report without Preview
To make it easier to use, I've created a Print extension method which you can easily use it this way:
this.reportViewer1.LocalReport.Print();
Here is the extension method:
using Microsoft.Reporting.WinForms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.IO;
public static class LocalReportExtensions
{
public static void Print(this LocalReport report)
{
var pageSettings = new PageSettings();
pageSettings.PaperSize = report.GetDefaultPageSettings().PaperSize;
pageSettings.Landscape = report.GetDefaultPageSettings().IsLandscape;
pageSettings.Margins = report.GetDefaultPageSettings().Margins;
Print(report, pageSettings);
}
public static void Print(this LocalReport report, PageSettings pageSettings)
{
string deviceInfo =
$#"<DeviceInfo>
<OutputFormat>EMF</OutputFormat>
<PageWidth>{pageSettings.PaperSize.Width * 100}in</PageWidth>
<PageHeight>{pageSettings.PaperSize.Height * 100}in</PageHeight>
<MarginTop>{pageSettings.Margins.Top * 100}in</MarginTop>
<MarginLeft>{pageSettings.Margins.Left * 100}in</MarginLeft>
<MarginRight>{pageSettings.Margins.Right * 100}in</MarginRight>
<MarginBottom>{pageSettings.Margins.Bottom * 100}in</MarginBottom>
</DeviceInfo>";
Warning[] warnings;
var streams = new List<Stream>();
var currentPageIndex = 0;
report.Render("Image", deviceInfo,
(name, fileNameExtension, encoding, mimeType, willSeek) =>
{
var stream = new MemoryStream();
streams.Add(stream);
return stream;
}, out warnings);
foreach (Stream stream in streams)
stream.Position = 0;
if (streams == null || streams.Count == 0)
throw new Exception("Error: no stream to print.");
var printDocument = new PrintDocument();
printDocument.DefaultPageSettings = pageSettings;
if (!printDocument.PrinterSettings.IsValid)
throw new Exception("Error: cannot find the default printer.");
else
{
printDocument.PrintPage += (sender, e) =>
{
Metafile pageImage = new Metafile(streams[currentPageIndex]);
Rectangle adjustedRect = new Rectangle(
e.PageBounds.Left - (int)e.PageSettings.HardMarginX,
e.PageBounds.Top - (int)e.PageSettings.HardMarginY,
e.PageBounds.Width,
e.PageBounds.Height);
e.Graphics.FillRectangle(Brushes.White, adjustedRect);
e.Graphics.DrawImage(pageImage, adjustedRect);
currentPageIndex++;
e.HasMorePages = (currentPageIndex < streams.Count);
e.Graphics.DrawRectangle(Pens.Red, adjustedRect);
};
printDocument.EndPrint += (Sender, e) =>
{
if (streams != null)
{
foreach (Stream stream in streams)
stream.Close();
streams = null;
}
};
printDocument.Print();
}
}
}
Print with showing Print dialog
Just in case someone wants to print with showing Print dialog, you can put a ReportViewer on form and set the Visible property of the control to false then pass data to the report and when the RenderingComplete event fired, call PrintDialog:
ReportViewer.PrintDialog Method

Why am I getting file access denied trying to make a StreamWriter instance?

string pathDir = Path.GetDirectoryName(Application.LocalUserAppDataPath) + "\\settings";
string settingsFile = "settings.txt";
StreamWriter w;
public Form1()
{
InitializeComponent();
if (!Directory.Exists(Path.Combine(pathDir, settingsFile)))
Directory.CreateDirectory(Path.Combine(pathDir, settingsFile));
settingsFile = Path.Combine(pathDir, settingsFile);
w = new StreamWriter(settingsFile, true);
The exception is on the line:
w = new StreamWriter(settingsFile, true);
Access to the path 'C:\Users\bout0_000\AppData\Local\Grads_Scripts\Grads_Scripts\settings\settings.txt' is denied
And now i moved the instance of the StreamWriter to a textBox1_TextChanged event:
private void textBox1_TextChanged(object sender, EventArgs e)
{
w = new StreamWriter(settingsFile, true);
w.Write(textBox1.Text);
w.Close();
}
I want to write the text i type in the textBox1 in real time to the text file. Without a button click confirm or something but in real time. While i'm typing it will write it to the text file. But the way it is now i see in the text file everything i typed many times the same.
I appears you are creating a directory named [...]\Grads_Scripts\settings\settings.txt then trying to write to it as a file. Go to the directory C:\Users\bout0_000\AppData\Local\Grads_Scripts\Grads_Scripts\settings\ and see if there is a folder called settings.txt. If so, delete it and modify your code to create the parent directory only.
You should be able to change your code as follows:
string pathDir = Path.GetDirectoryName(Application.LocalUserAppDataPath) + "\\settings";
string settingsFile = "settings.txt";
StreamWriter w;
public Form1()
{
InitializeComponent();
// Create the parent directory if it doesn't exist
if (!Directory.Exists(pathDir))
Directory.CreateDirectory(pathDir);
settingsFile = Path.Combine(pathDir, settingsFile);
w = new StreamWriter(settingsFile, true);
}
Remember to wrap your StreamWriter in a using statement (or call Dispose manually) so that the file resources are released after you've finished writing.
using( w = new StreamWriter(settingsFile, true) ){
// Write to stream writer
}

Load local html file in webbrowser control in editable mode

I want to load a local html file in webbrowser control in editable mode. My code for loading in html file in webBrowser is:
private void LoadFile(string filename)
{
using (StreamReader reader = File.OpenText(filename))
{
webBrowser1.DocumentText = reader.ReadToEnd();
reader.Close();
Text = webBrowser1.DocumentTitle;
}
}
But it is not editable.
Please check this snippet.
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.Url = new Uri(#"D:\TEMP\sample.htm");

How to get this UI output in printout?

I am working on WPF application.Here i have to work on some print formats.To solve paging issue for print i am using the following code :
private void Button_Click(object sender, RoutedEventArgs e)
{
// Create a PrintDialog
PrintDialog printDlg = new PrintDialog();
// Create a FlowDocument dynamically.
FlowDocument doc = CreateFlowDocument();
doc.Name = "FlowDoc";
doc.PageHeight = printDlg.PrintableAreaHeight;
doc.PageWidth = printDlg.PrintableAreaWidth;
// Create IDocumentPaginatorSource from FlowDocument
IDocumentPaginatorSource idpSource = doc;
// Call PrintDocument method to send document to printer
printDlg.PrintDocument(idpSource.DocumentPaginator, "Hello WPF Printing.");
}
and
private FlowDocument CreateFlowDocument()
{
// Create a FlowDocument
FlowDocument doc = new FlowDocument();
int i = 0;
while (i <2)
{
// Create first Paragraph
Paragraph p1 = new Paragraph();
MyUserControl comp = new MyUserControl ();
p1.BorderBrush = new SolidColorBrush(Color.FromRgb(79, 129, 189));
p1.BorderThickness = new Thickness(3);
p1.Inlines.Add(comp);
// Add Paragraph to Section
doc.Blocks.Add(p1);
// Add Section to FlowDocument
//doc.Blocks.Add(sec);
i++;
}
return doc;
}
this code works fine for me.
Problem :
I just have problem with UI which i am getting using this code.
This is the print which i am getting now on paper :
and this is the print which i require on paper:
Please provide some idea and code so that i can clear this problem.
Thanks in advance.

Categories