I'm generating a PDF file based on some HTML, using the pechkin dll.
This is all working nicely except the I need to it add a page break at certain places and I don't know how.
I thought that using a css page-break-before, but that doesn't seem to work.
An example of the HTML I'm using is:
<table style="border-top: 0px solid black; border-bottom: 2px solid black; height: 30px; width: 800px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="width: 200px;"><strong>Recommendation</strong></td>
<td style="width: 600px;">[6060:Builder Recommendation]</td>
</tr>
</tbody>
</table>
<table style="page-break-before: always;border-top: 0px solid black; border-bottom: 2px solid black; background-color: #99ccff; height: 30px; width: 800px;" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td><strong>Summary of Actions</strong></td>
</tr>
</tbody>
</table>
The code I'm using to generate the PDF is as below:
Dim buf As Byte() = Pechkin.Factory.Create(New GlobalConfig().SetMargins(New Margins(20, 20, 20, 20))
.SetDocumentTitle("").SetCopyCount(1).SetImageQuality(100)
.SetLosslessCompression(True)
.SetMaxImageDpi(300)
.SetOutlineGeneration(True)
.SetOutputDpi(1200)
.SetPaperOrientation(True)
.SetPaperSize(PaperKind.A4)
.SetImageQuality(100)
.SetPaperOrientation(False))
.Convert(New ObjectConfig()
.SetPrintBackground(True)
.SetAllowLocalContent(True), strHTML)
Return buf
Any ideas?
Add a div before your table.
<div style='page-break-after:always'></div>
Related
I want to compose a mail with a table with some basic style. Here is my code:
MailMessage mail = new MailMessage();
mail.From = new MailAddress("abc#domain.com");
mail.To.Add("myname#domain.com");
mail.Body = string.Format(#"<html>
<body>
<style>
table, th, td {
border: 1px solid black;
line-height: 24px;
font-size:14px;
font-family:verdana;
text-align: center;
}
</style>
<p style=""""font-family:verdana""""> Status :</p>
<table style=""""width=50%""""><tr>
<th >No. of Students</th>
<th >No. of Pass</th>
<th >No. of Failures </th>
<tr/><tr style=""""height=120%"""">
<td>{0} </td>
<td style=""""color:green"""">{1} </td>
<td style=""""color:red"""">{2} </td>
</tr></table>
<p style=""""font-family:verdana""""> Please refer to the
Log files for more details.</p>
</body>
</html>",student.Total, student.Pass,student.Fail);
mail.Subject = "Report";
};
mail.IsBodyHtml = true;
This gives me an Exception saying 'Input string is not in correct format'. If I remove the style, paragraph, and keep only , it works but no borders are present in table. How can I style my mail?
I changed the body like this, but the style is not reflected.
mail.Body = string.Format(#"
<p style=""font-family:verdana""> Status :</p>
<table style=""border: 1px solid black"", ""text-align: center""><tr>
<th style=""border: 1px solid black"">No. of new records added</th>
<th style=""border: 1px solid black"">No. of records transferred </th>
<th style=""border: 1px solid black"">No. of records not transferred </th>
<tr/><tr style=""height=120%"">
<td style=""border: 1px solid black"" ""text-align: center"">CompanyName.Value </td>
<td style=""border: 1px solid black"" ""text-align: center"" ""color:green"">1000 </td>
<td style=""border: 1px solid black"" ""text-align: center"" ""color:red"">82 </td>
</tr></table>
<p style=""font-family:verdana""> Please refer to the Log files for more details.</p>
");
Your syntax is wrong while adding style for <table> and <p>. Do it in the following way, for example:
<table style="width: 50%">
Similarly change the syntax wherever you have used style.
I am using SelectPdf, and when configuring my converter to convert the string to a pdf, my pdf keeps ending up generating some margin on the top of the page.
My converter:
private Stream ConvertToPdf(string data)
{
HtmlToPdf converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.A4;
converter.Options.AutoFitWidth = HtmlToPdfPageFitMode.NoAdjustment;
converter.Options.DisplayFooter = true;
converter.Options.DisplayHeader = true;
converter.Options.MarginTop = 0;
converter.Options.MarginBottom = 0;
converter.Options.DisplayHeader = false;
converter.Options.DisplayFooter = false;
converter.Options.CssMediaType = HtmlToPdfCssMediaType.Screen;
converter.Options.EmbedFonts = true;
PdfDocument doc = converter.ConvertHtmlString(data);
// create memory stream to save PDF
MemoryStream pdfStream = new MemoryStream();
// save pdf document into a MemoryStream
doc.Save(pdfStream);
pdfStream.Seek(0, SeekOrigin.Begin);
return pdfStream;
}
In my template, I have no apparent margin in the top of the page, so I am, so far, unable to figure out where it is coming from.
My template:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
html, body {
font-family: Arial, Helvetica, sans-serif;
margin:0;
padding:0;
}
.red-color {
color: red;
margin-left: 10px;
}
p.red-color {
margin-top: 0;
font-weight:800;
}
p.red-color:first-of-type {
margin-bottom: 0;
}
h1.red-color {
margin-bottom: 10px;
margin-top:0;
}
h2.red-color {
margin-bottom: 20px;
}
#wrapper {
position: relative;
width:750px;
height:1050px;
}
.image-wrapper {
width: 96%;
height: 350px;
margin-left: 2%;
position: relative;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
#info-banner {
position: absolute;
bottom: 0;
background-color: red;
width: 96%;
margin-left: 2%;
height: 125px;
}
#info-banner #banner-left {
float:left;
width:40%;
}
#info-banner #banner-right {
float:left;
width:60%;
}
#info-banner #banner-left a {
display: block;
text-align: center;
margin-top: 20px;
color: white;
text-decoration: none;
}
#info-banner #banner-left a img{
width:50px;
}
#info-banner #banner-right p:first-of-type {
margin-top:20px;
}
#info-banner #banner-right p {
margin: 0;
color: white;
padding-bottom: 5px;
font-size: 14px;
}
.amount {
text-align:left;
padding-left:5px;
}
.name {
}
.price {
}
table th {
text-align: left;
}
td {
padding: 10px 0;
}
table {
width: 96%;
margin-left:2%;
border-collapse: collapse;
}
.top-border {
border-top: 2px solid black;
}
.heavy-font {
font-weight: 800;
}
.less-spacing td{
padding:5px 0;
}
</style>
</head>
<body>
<div id="wrapper" style="page-break-after: always">
<h1 class="red-color">Name</h1>
<div class="image-wrapper" style="background-image: url('##EventImage##');"></div>
<h2 class="red-color">##Title##</h2>
<p class="red-color">your ticket:</p>
<p class="red-color">Print it.</p>
<table>
<tr>
<th>Amount</th>
<th>name</th>
<th>Price</th>
</tr>
<tr class="top-border">
<td class="amount">##Amount##</td>
<td class="name">
##Title##<br />
Adresse: ##Address## <br />
Dato: ##Date##<br />
Tidspunkt: ##Time##
</td>
<td class="price">##Price## USD</td>
</tr>
<tr class="top-border ">
<td class="amount"></td>
<td class="name">In Total</td>
<td class="price">##ProductTotalPrice## USD</td>
</tr>
<tr class="less-spacing">
<td class="amount"></td>
<td class="name">Total ex. tax:</td>
<td class="price">##ProductTotalExTax## USD</td>
</tr>
<tr class="less-spacing">
<td class="amount"></td>
<td class="name">shipping: </td>
<td class="price">##ShippingPrice## USD</td>
</tr>
<tr class="less-spacing">
<td class="amount"></td>
<td class="name">Subtotal ex. tax</td>
<td class="price">##PriceNoTax## USD</td>
</tr>
<tr class="less-spacing">
<td class="amount"></td>
<td class="name">tax</td>
<td class="price">##Tax## USD</td>
</tr>
<tr class="top-border">
<td class="amount"></td>
<td class="heavy-font name">Total:</td>
<td class="heavy-font price">##FinalPrice## USD</td>
</tr>
</table>
<div id="info-banner">
<div id="banner-left">
<img src="facebook-icon.png" /><br />Find us on facebook
</div>
<div id="banner-right">
<p>Name</p>
<p>Address</p>
<p>Second Address</p>
<p>Phone: 0000000000 Email: info#test.com</p>
</div>
</div>
</div>
</body>
</html>
When I generate this, I have no issues making it a pdf, but on each page it appears with a top margin, or some sort of a header.
Setting these values appears to have solved my issue.
converter.Options.WebPageHeight = 1050;
converter.Options.WebPageWidth = 750;
and i had duplicated values in these, which said true.
converter.Options.DisplayHeader = false;
converter.Options.DisplayFooter = false;
I sent an html via outlook.
In the html, I aligned a word to the right, but in the received e-mail, the word is mixed - the first letter has become the last letter.
This only occurs when the first letter is a number.
I sent the following html:
<div dir="rtl" style="margin: 20px auto; width: 650px; text-align: center; font-family: Tahoma;">
<table dir="rtl" style="width: 650px; margin: 0 auto; text-align: right; font-family: Tahoma; font-size: 0; font-weight: normal; color: #000;" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="background-color: #d0f2f6; padding: 15px 20px; margin: 0; color: #135861; font-size: 13px; font-weight: 400;">
שלום
<br /><br />
המספר הוא:<br />
<b dir="rtl" style="font-family:consolas">1fD9xG8j</b>
<br /><br />
</td>
</tr>
</tbody>
</table>
</div>
But I got the following mail:
Why does outlook change the word '1fD9xG8j' to 'fD9xG8j1' ?
This is the code in c# which sent the mail:
var smtp = new SmtpClient(SmtpServer);
var message = new MailMessage();
message.Subject = subject.Trim();
message.Body = body.Trim();
message.IsBodyHtml = true;
message.BodyEncoding = Encoding.UTF8;
smtp.Send(message);
Remove dir="rtl" from Table tag and try.
I saw, that many times, Outlook text editor adds code to the source code. This happens because Outlook is generating the email source code using mostly VML (Vector Markup Language) which causes changes in the code. There are add-ins to import a clean HTML source code, to an Outlook email, in order to get it displayed correctly.
I tried to get around the problem with the following code:
<div dir="ltr" style="font-family:consolas;font-weight:bold;text-align:right">1fD9xG8j</div>
I changed dir="ltr", and added style text-align:right,
and it works!
Page is something like this
Now on resize it is changing to something like this:
But I need last two rows to use the complete space e.g. Result should start from the below of Email, kind of Centre approach.
Table Html is
<table class="responsive">
<thead>
<tr>
<th class="grid-header"><div class="grid-header-title">Employe Id</div></th><th class="grid-header"><div class="grid-filter" data-filterdata="[]" data-name="Name" data-type="System.String" data-widgetdata="null"><span class="grid-filter-btn" title="Filter this column"></span></div><div class="grid-header-title">Name</div></th><th class="grid-header"><div class="grid-header-title">Email</div></th><th class="grid-header" style="width:80px;"><div class="grid-header-title"><span></span></div></th><th class="grid-header" style="width:80px;"><div class="grid-header-title"><span></span></div></th> </tr>
</thead>
<tbody>
<tr class="grid-row ">
<td class="grid-cell" data-name="Id">1</td><td class="grid-cell" data-name="Name">XyZ</td><td class="grid-cell" data-name="Email">XyZ#gmail.com</td><td class="grid-cell" data-name=""><a href='#'>Result </a><a href='#'>Output </a><a href='#'>Error</a></td><td class="grid-cell" data-name=""><img alt='img1' src='' ></img><img alt='img2' src='' ></img><img alt='img3' src='' ></img></td> </tr>
<tr class="grid-row ">
<td class="grid-cell" data-name="Id">2</td><td class="grid-cell" data-name="Name">XyZ2</td><td class="grid-cell" data-name="Email">XyZ#gmail.com</td><td class="grid-cell" data-name=""><a href='#'>Result </a><a href='#'>Output </a><a href='#'>Error</a></td><td class="grid-cell" data-name=""><img alt='img1' src='' ></img><img alt='img2' src='' ></img><img alt='img3' src='' ></img></td> </tr>
<tr class="grid-row ">
<td class="grid-cell" data-name="Id">3</td><td class="grid-cell" data-name="Name">Romonov</td><td class="grid-cell" data-name="Email">XyZ#gmail.com</td><td class="grid-cell" data-name=""><a href='#'>Result </a><a href='#'>Output </a><a href='#'>Error</a></td><td class="grid-cell" data-name=""><img alt='img1' src='' ></img><img alt='img2' src='' ></img><img alt='img3' src='' ></img></td> </tr>
</tbody>
</table>
jQuery is :
;(function ( $ ) {
$.fn.ngResponsiveTables = function(options) {
var defaults = {
smallPaddingCharNo: 5,
mediumPaddingCharNo: 10,
largePaddingCharNo: 15
},
$selElement = this,
ngResponsiveTables = {
opt: '',
dataContent: '',
globalWidth: 0,
init: function(){
this.opt = $.extend( defaults, options );
ngResponsiveTables.targetTable();
},
targetTable: function(){
var that = this;
$selElement.find('tr').each(function(){
$(this).find('td').each(function(i, v){
that.checkForTableHead( $(this), i );
$(this).addClass('tdno' + i);
});
});
},
checkForTableHead: function(element, index){
if( $selElement.find('th').length ){
this.dataContent = $selElement.find('th')[index].textContent;
}else{
this.dataContent = $selElement.find('tr:first td')[index].textContent;
}
// This padding is for large texts inside header of table
// Use small, medium and large paddingMax values from defaults to set-up offsets for each class
if( this.opt.smallPaddingCharNo > $.trim(this.dataContent).length ){
element.addClass('small-padding');
}else if( this.opt.mediumPaddingCharNo > $.trim(this.dataContent).length ){
element.addClass('medium-padding');
}else{
element.addClass('large-padding');
}
element.attr('data-content', this.dataContent);
}
};
$(function(){
ngResponsiveTables.init();
});
return this;
};
}( jQuery ));
css is :
#media (max-width: 480px) {
/* CSS Responsive table */
table.responsive,
table.responsive thead,
table.responsive tbody,
table.responsive th,
table.responsive td,
table.responsive tr {
display: block;
}
table.responsive thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
table.responsive tr {
border: 1px solid #ccc;
margin-bottom: 10px;
}
table.responsive td {
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 50%;
}
table.responsive td:before {
position: absolute;
top: 6px;
left: 6px;
width: 40%;
padding-right: 10px;
text-align: left;
word-wrap: break-word;
color: skyblue;
font-weight:bold;
}
table.responsive tr:first-child {
position: absolute;
top: -9999px;
left: -9999px;
}
table.responsive td:before {
content: attr(data-content);
height: 50px;
}
table.responsive td.small-padding {
padding-top: 5px;
padding-bottom: 5px;
}
table.responsive td.medium-padding {
padding-top: 15px;
padding-bottom: 15px;
}
table.responsive td.large-padding {
padding-top: 25px;
padding-bottom: 25px;
}
}
I have used ngResponsiveCss.
Can you please guide what should I edit in this.
I am using docraptor (https://docraptor.com/samples) for creating the PDF but I am not able to add Image as Header and Footer into generated PDF.
I have below Html and I am using AJAX to call the API and passing below HTML as content to crate a pad but its not adding Image in Footer and header . Its adding it as like content.
var data = $('#container-abc').html();
<!DOCTYPE html>
<head>
<style type="text/css">
/* setup the page */
##page {
size: US-Letter;
margin: 0 0 35mm 0;
background: #ffffff;
}
/* setup the footer */
##page {
##bottom {
content: flow(footer);
}
}
footer {
flow: static(footer);
}
body {
border-top: 10px solid #3877B1;
font-family: "myriad-pro-1", "myriad-pro-2", sans-serif;
}
#container {
margin: 0 auto;
}
header, #main {
margin: 15mm;
}
header {
margin-top: 5mm;
border-bottom: 1px solid #7E7E7E;
padding-bottom: 5mm;
}
.seller, .status{
float: left;
}
.buyer {
float: right;
}
.seller {
width: 50%;
}
.buyer {
max-width: 30%;
}
.brand {
font-weight: bold;
font-size: 30px;
color: #333;
padding: 10px 0 2px;
overflow: auto;
}
.brand span, .brand img {
float: left;
}
.brand span {
display: block;
margin: 8px 0 0 5px;
}
.seller address {
clear: both;
display: block;
padding-left: 65px;
ont-size: 10pt;
line-height: 12pt;
color: #262626;
}
.seller address span {
display: block;
}
.status.paid {
margin: 25pt 0 0 15pt;
letter-spacing: -1pt;
font-weight: bold;
color: #78E400;
font-size: 30pt;
border: 5px solid #78E400;
padding: 1pt 5pt;
transform: rotate(-15deg);
-ms-transform: rotate(-15deg); /* IE 9 */
-webkit-transform:rotate(-15deg); /* Safari and Chrome */
}
.buyer {
font-size: 9pt;
line-height: 12pt;
margin-top: 30pt;
color: #262626;
}
.buyer h2 {
font-weight: bold;
font-size: 11pt;
}
.buyer span { display: block; }
/* main */
table {
width: 100%;
}
th {
font-size: 8pt;
color: #919191;
line-height: 14pt;
text-align: left;
padding-left: 10pt;
border-bottom: 1px solid #D6D6D6;
}
th:last-child, td:last-child {
width: 20%;
}
th:last-child {
padding-left: 10mm;
}
td {
padding: 10pt;
border-bottom: 1px solid #D6D6D6;
}
td h4 {
font-weight: bold;
font-size: 12pt;
}
td .description {
font-size: 9pt;
line-height: 14pt;
}
td.price {
vertical-align: middle;
font-size: 12pt;
font-weight: bold;
text-align: right;
}
tr:nth-child(odd) td{
background: #F1F1F1;
}
#notes {
font-size: 9pt;
color: #7E7E7E;
line-height: 14pt;
font-style: italic;
margin-top: 4mm;
padding: 3mm;
float: left;
}
#totals{
padding: 3mm;
float: right;
text-align: right;
font-size: 12pt;
color: #7E7E7E;
line-height: 16pt;
}
/* footer */
footer {
text-align: center;
}
footer p {
background: #F3F3F3;
color: #888;
text-align: center;
font-size: 8pt;
line-height: 12pt;
padding: 7mm 0;
margin-top: 2mm;
}
.clearfix{ clear: both; }
</style>
</head>
<body>
<div id="container-abc">
<header>
<div class="seller">
<h1 class="brand">
<img src="http://docraptor.com/assets/docraptor-logo.svg" width="60" height="43" /> <span>DocRaptor</span>
</h1>
<address>
2885 Sanford Ave SW #13508, Grandville, MI 49418-1342
<span class="email">support#docraptor.com</span>
</address>
</div>
<div class="status paid">PAID</div>
<div class="buyer">
<h2>Billed To</h2>
Super Best Client
<span class="email">superbestclient#example.com</span>
<span class="date">January 20, 2014</span>
</div>
<div class="clearfix"></div>
</header>
<div id="main">
<table>
<thead>
<tr>
<th class="title">Summary</th>
<th class="price">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<h4>Max Plan</h4>
<p class="description">March 21, 2014 - April 21, 2014</p>
</td>
<td class="price"><span class="price">$149.00 USD</span></td>
</tr>
<tr>
<td>
<h4>Document Overage</h4>
<p class="description">0 docs $.39</p>
</td>
<td class="price"><span class="price">$0.00 USD</span></td>
</tr>
</tbody>
</table>
<p id="notes">
This charge will appear on your credit card statement as "DOCRAPTOR.COM".
</p>
<div id="totals">
<p>Total: <span class="price">$149.00 USD</span></p>
<p>Due: <span class="price">$0.00 USD</span></p>
</div>
<table>
<thead>
<tr>
<th class="title">Summary</th>
<th class="price">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<h4>Max Plan</h4>
<p class="description">March 21, 2014 - April 21, 2014</p>
</td>
<td class="price"><span class="price">$149.00 USD</span></td>
</tr>
<tr>
<td>
<h4>Document Overage</h4>
<p class="description">0 docs $.39</p>
</td>
<td class="price"><span class="price">$0.00 USD</span></td>
</tr>
</tbody>
</table>
<p id="notes">
This charge will appear on your credit card statement as "DOCRAPTOR.COM".
</p>
<div id="totals">
<p>Total: <span class="price">$149.00 USD</span></p>
<p>Due: <span class="price">$0.00 USD</span></p>
</div>
<table>
<thead>
<tr>
<th class="title">Summary</th>
<th class="price">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<h4>Max Plan</h4>
<p class="description">March 21, 2014 - April 21, 2014</p>
</td>
<td class="price"><span class="price">$149.00 USD</span></td>
</tr>
<tr>
<td>
<h4>Document Overage</h4>
<p class="description">0 docs $.39</p>
</td>
<td class="price"><span class="price">$0.00 USD</span></td>
</tr>
</tbody>
</table>
<p id="notes">
This charge will appear on your credit card statement as "DOCRAPTOR.COM".
</p>
<div id="totals">
<p>Total: <span class="price">$149.00 USD</span></p>
<p>Due: <span class="price">$0.00 USD</span></p>
</div>
</div>
<footer>
<img alt="Expected Behavior Logo" height="34" src="https://docraptor.com/assets/expected-behavior-logo.svg" width="150" />
<p>DocRaptor is made and supported by Expected Behavior, LLC<br>1-866-991-3746 | 2885 Sanford Ave SW #13508, Grandville, MI 49418-1342 | support#docraptor.com</p>
</footer>
</div>
</body>
</html>
At least part of the problem is the use of ## as opposed to the singular # when you are handling page and page bottom styles. I changed those to singular and got back a more sane looking PDF from DocRaptor.
Here is a minimal example that has images in the header and footer, on every page.
<html>
<head>
<style type="text/css">
#page {
#top { content: flow(header) };
#bottom { content: flow(footer) };
}
header { flow: static(header); }
footer { flow: static(footer); }
hr { page-break-after: always; }
</style>
</head>
<body>
<header>
<img src="http://i.imgur.com/MtMwkBX.png" />
</header>
<footer>
<img src="http://i.imgur.com/ZZw85mx.png" />
</footer>
<p>This is the first page.</p>
<hr />
<p>This is the second page.</p>
<hr />
<p>This is the third page.</p>
</body>
</html>