font family is not working in PDF - pdf

I'm converting HTML to PDF as below:
public const string PdfDocumentHeaderHtml = #"<!DOCTYPE html>
<html lang='en' xmlns='http://www.w3.org/1999/xhtml'>
<head>
<meta charset='utf-16' />
<title></title>
</head>
<body>
<table>
<tr>
<td colspan='3'>
<span Style='font-family:Arial;font-size:10pt;font-weight:bold;'>{0}</span>
<br/>
<br/>
<span class='pageHeaderText'>{1}</span>
</td>
<td colspan='1'>
<span><img src='' width='150' height='90' alt='NOS'/></span>
</td>
</tr>
</table>
</body>
</html>";
And save to PDF using the below code:
public override void OnCreatePDF(PdfWriter writer, Document document)
{
iTextSharp.text.FontFactory.Register(#"C:\Windows\Fonts\arial.ttf", "Arial");
base.OnCreatePDF(writer, document);
if (writer == null)
throw new ArgumentNullException("writer");
if (document == null)
throw new ArgumentNullException("document");
var headerHtml = string.Format(Constants.NosPdfDocumentHeaderHtml, Urn, Title);
var providers = new Dictionary<string, Object> { { HTMLWorker.IMG_BASEURL, string.Format(Constants.HeaderImageLocation, SiteUrlForHeaderImage) } };
List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(headerHtml), null, providers);
foreach (IElement htmlElement in htmlarraylist)
{
document.Add(htmlElement);
document.Add(new LineSeparator((float)0.90, 100, new BaseColor(0, 112, 192, 0), 0, 0));
}
}
I want to set Font-Family:Arial for the PDF but the problem is, when I see the PDF-File properties, it says Helvetica is used.
I think I need to download Adobe Font Metric file (arial.afm file) and set this font family (instead of arial.ttf) for use with pdf. But I don't know how to do it.
Could you please advice?
Thanks,

In the comment section, you are asking for an alternative to add a table structure to a document.
That's easy with PdfPTable. For instance, if I want to create a table with 3 columns, I do:
PdfPTable table = new PdfPTable(3);
I want to span 100% of the available width between the margins of the page, so I do:
table.WidthPercentage = 100;
I want the first column to be twice as wide as column two and three, so I do:
table.SetWidths(new int[]{2, 1, 1});
Now I add cells:
PdfPCell cell;
cell = new PdfPCell(new Phrase("Table 1"));
cell.Colspan = 3;
table.AddCell(cell);
cell = new PdfPCell(new Phrase("Cell with rowspan 2"));
cell.Rowspan = 2;
table.AddCell(cell);
table.AddCell("row 1; cell 1");
table.AddCell("row 1; cell 2");
table.AddCell("row 2; cell 1");
table.AddCell("row 2; cell 2");
Finally, I add the table to the Document:
document.Add(table);
And that's it.

Related

Selenium and JavaScript: Accessing multiple elements with the same ID

I've got a page (Angular8) with multiple button/input elements having the same ID.
The ID's are, in the order the appear on the page:
1: for="lastOppDokument-0-VERGE-LEGITIMASJON"
2: for="lastOppDokument-1-VERGE-VERGEMAL"
...
3: for="lastOppDokument-0-VERGE-LEGITIMASJON"
4: for="lastOppDokument-1-VERGE-VERGEMAL"
The elements on lines 1,3 and 2,4 have the same ID.
I'm trying to access the elements using XPath and index like this:
driver.findElement(By.xpath("(//input[#for='lastOppDokument-0-VERGE-LEGITIMASJON'])[1]
driver.findElement(By.xpath("(//input[#for='lastOppDokument-0-VERGE-LEGITIMASJON'])[2]
If I check the size:
int x = driver.findElements(By.xpath("(//input[#for='lastOppDokument-0-VERGE-LEGITIMASJON'])")).size();
it says "2", which is correct.
However, when I try to click those two buttons, the first one (LINE 1) is clicked, but then the next button on the page (LINE 2) i clicked istead of the one on LINE 3.
There's obviously something wrong with my XPath expression, but what? Also, the page is an Angular page, and in the markup code "for" is used to automatically index the ID. But selenium finds the elements (albeit not all the correct ones) using ID. But maybe I need to use something else to identify the correct elements?
UPDATE:
To troubleshoot, I'm skipping the use of a loop and just trying to access the two elements manually:
WebElement buttonToClick = driver.findElement(By.xpath("(//input[#id='lastOppDokument-0-VERGE-LEGITIMASJON'])[1]"));
filUtils.uploadFile(buttonToClick, legitimasjonfil);
WebElement buttonToClick2 = driver.findElement(By.xpath("(//input[#for='lastOppDokument-0-VERGE-LEGITIMASJON'])[2]"));
filUtils.uploadFile(buttonToClick2, legitimasjonfil);
The uploadFile (and related) methods:
public void uploadFile(WebElement id, String filename) {
id.sendKeys(getAbsolutePathToTestFile(TESTFILER_PATH + "/" + filename));
}
private String getAbsolutePathToTestFile(String path) {
return copyFileToTargetTempPath(path, path);
}
private String copyFileToTargetTempPath(String originPath, String destinationPath) {
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(originPath);
File destination = new File(TARGET_TEMP_PATH + destinationPath);
try {
assert resourceAsStream != null;
org.apache.commons.io.FileUtils.copyInputStreamToFile(resourceAsStream, destination);
} catch (IOException e) {
throw new RuntimeException(e);
}
return destination.getAbsolutePath();
}
UPDATE 2:
<td>
<span class="hb-felt knappesamling-gruppe hb-avstandIngen ng-star-inserted">
<input class="hb-lastOppFil-input hb-bare-skjermleser" type="file" id="lastOppDokument-0-VERGE-LEGITIMASJON"
accept=".pdf,.bmp,.gif,.jpeg,.jpg,.png,.tiff">
<label class="hb-knapp hb-knapp--standard hb-spinner-tekst" for="lastOppDokument-0-VERGE-LEGITIMASJON"> Velg fil </label><!---->
</span>
</td>
<td>
<span class="hb-felt knappesamling-gruppe hb-avstandIngen ng-star-inserted">
<input class="hb-lastOppFil-input hb-bare-skjermleser" type="file" id="lastOppDokument-1-VERGE-VERGEMAL"
accept=".pdf,.bmp,.gif,.jpeg,.jpg,.png,.tiff"><label class="hb-knapp hb-knapp--standard hb-spinner-tekst" for="lastOppDokument-1-VERGE-VERGEMAL"> Velg fil </label><!----></span>
<label class="hb-knapp hb-knapp--standard hb-spinner-tekst" for="lastOppDokument-1-VERGE-VERGEMAL"> Velg fil </label>
</span>

Expert Pdf - add footer on all pages except on the first page

I am using Expert PDF to generate PDF from HTML.
I have to generate footer on all pages except on the first page.
I tried with:
PdfConverter pdfConverter = new PdfConverter();
AddFooter(pdfConverter);
private void AddFooter(PdfConverter pdfConverter)
{
string thisPageURL = HttpContext.Current.Request.Url.AbsoluteUri;
string headerAndFooterHtmlUrl = thisPageURL.Substring(0, thisPageURL.LastIndexOf('/')) + "/HeaderAndFooterHtml.htm";
//enable footer
pdfConverter.PdfDocumentOptions.ShowFooter = true;
// set the footer height in points
pdfConverter.PdfFooterOptions.FooterHeight = 60;
//write the page number
pdfConverter.PdfFooterOptions.TextArea = new TextArea(0, 30, "This is page &p; of &P; ",
new System.Drawing.Font(new System.Drawing.FontFamily("Times New Roman"), 10, System.Drawing.GraphicsUnit.Point));
pdfConverter.PdfFooterOptions.TextArea.EmbedTextFont = true;
pdfConverter.PdfFooterOptions.TextArea.TextAlign = HorizontalTextAlign.Right;
// set the footer HTML area
pdfConverter.PdfFooterOptions.HtmlToPdfArea = new HtmlToPdfArea(0, 0, -1, pdfConverter.PdfFooterOptions.FooterHeight,
headerAndFooterHtmlUrl, 1024, -1);
pdfConverter.PdfFooterOptions.HtmlToPdfArea.FitHeight = true;
}
but this code generate footer on all pages.
Can someone give me idea or solution for this problem?
Thanks in advance!
Add below line in your code:
pdfConverter.PdfFooterOptions.ShowOnFirstPage = false;

html to pdf convert, cyrillic characters not displayed properly

I have a problem with pdf fonts. I have used a method for generating pdf from html which worked fine on my local machine which is windows OS, but now on linux Cyrillic text is displayed with question marks. I checked for fonts there but it turned out that there were required fonts. Now I switched to another method which is shown below.
Document document = new Document(PageSize.A4);
String myFontsDir = "C:\\";
String filePath = AppProperties.downloadLocation + "Order_" + orderID + ".pdf";
try {
OutputStream file = new FileOutputStream(new File(filePath));
PdfWriter writer = PdfWriter.getInstance(document, file);
int iResult = FontFactory.registerDirectory(myFontsDir);
if (iResult == 0) {
System.out.println("TestPDF(): Could not register font directory " + myFontsDir);
} else {
System.out.println("TestPDF(): Registered font directory " + myFontsDir);
}
document.open();
String htmlContent = "<html><head>"
+ "<meta http-equiv=\"content-type\" content=\"application/xhtml+xml; charset=UTF-8\"/>"
+ "</head>"
+ "<body>"
+ "<h4 style=\"font-family: arialuni, arial; font-size:16px; font-weight: normal; \" >"
+ "Здраво Kristijan!"
+ "</h4></body></html>";
InputStream inf = new ByteArrayInputStream(htmlContent.getBytes("UTF-8"));
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(myFontsDir);
FontFactory.setFontImp(fontImp);
XMLWorkerHelper.getInstance().parseXHtml(writer, document, inf, null, null, fontImp);
document.close();
System.out.println("Done.");
} catch (Exception e) {
e.printStackTrace();
}
with this peace of code I am able to generate proper pdf from latin text, but cyrillic is displayed with weird characters. This happens on Windows, I haven't yet test it on Linux. Any advice for encoding or font?
Thanks in advance
First this: it is very hard to believe that your font directory is C:\\. You are assuming that you have a file with path C:\\arialuni.ttf whereas I assume that the path to MS Arial Unicode is C:\\windows\fonts\arialuni.ttf.
Secondly: I don't think arialuni is the correct name. I'm pretty sure it's arial unicode ms. You can check this by running this code:
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("c:/windows/fonts/arialuni.ttf");
for (String s : fontProvider.getRegisteredFamilies()) {
System.out.println(s);
}
The output should be:
courier
arial unicode ms
zapfdingbats
symbol
helvetica
times
times-roman
These are the values you can use; arialuni isn't one of them.
Also: aren't you defining the character set in the wrong place?
I have slightly adapted your source code in the sense that I stored the HTML in an HTML file cyrillic.html:
<html>
<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
</head>
<body>
<h4 style="font-family: Arial Unicode MS, FreeSans; font-size:16px; font-weight: normal; " >Здраво Kristijan!</h4>
</body>
</html>
Note that I replaced arialuni with Arial Unicode MS and that I used FreeSans as an alternative font. In my code, I used FreeSans.ttf instead of arialttf.
See ParseHtml11:
public static final String DEST = "results/xmlworker/cyrillic.pdf";
public static final String HTML = "resources/xml/cyrillic.html";
public static final String FONT = "resources/fonts/FreeSans.ttf";
public void createPdf(String file) throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
// step 3
document.open();
// step 4
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontImp.register(FONT);
FontFactory.setFontImp(fontImp);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new FileInputStream(HTML), null, Charset.forName("UTF-8"), fontImp);
// step 5
document.close();
}
As you can see, I use the Charset when parsing the HTML. The result looks like this:
If you insist on using Arial Unicode, just replace this line:
public static final String FONT = "resources/fonts/FreeSans.ttf";
With this one:
public static final String FONT = "c:/windows/fonts/arialuni.ttf";
I have tested this on a Windows machine and it works too:

Update html from csv

I have a quite long html menu list (circa 30 menu positions) where I am trying to dynamically populate with labels according to a .csv file. I’d like to change the each menu label i.e. “the Slots”. Each time the page is loaded, I’ll need to look up position1, and return the right label and Title tag in the page I'm pointing to. There are many fixed positions, but when the .csv file is updated, the menu label needs to change accordingly. To add fuel to my fire, I need to hide a menu if the position in the first column of the .csv cannot be found. This absolute amateur would appreciate any insight you might have.
CSV file saved into directory
position1,Slot1
position2,Slot2
position3,Slot3
position4,Slot4
HTML
<a href='link'>
<span class='hidden-minibar'>Slot 1 </span>
</a>
</li>
<a href='gohere'>
<span class='hidden-minibar'>Slot 2 </span>
</a>
</li>
<a href='link'>
<span class='hidden-minibar'>Slot 3 </span>
</a>
</li>
<a href='link'>
<span class='hidden-minibar'>Slot 4 </span>
</a>
</li>
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function(filedata) {
var list = filedata.target.result;
csvParser(list);
};
reader.readAsText(this.selectedfile.target.files.item(0));
}
var csvParser = function(list) {
var quoteRegexp = new RegExp("^\"(.*)\"$");
var data = [];
var lines = list.split(new RegExp("\r?[\r\n]"));
for (var iCtr = 0; iCtr < lines.length; iCtr += 1) {
var fields = lines[iCtr].split(",");
for (var jCtr = 0; jCtr < fields.length; jCtr += 1) {
fields[jCtr] = fields[jCtr].replace(quoteRegexp, "$1");
}
data.push(fields);
}
return data;
}
use FileReader object and read csv file on client site
use csvParser function to parse row csv data
create dynamic html and appropriate logic on csvParser function result data.
Basic csv read Example
http://jsfiddle.net/techrevolt/W8fME/

Is there a working sample of the Google custom search rest API?

I need to create a screen which automates Google search.
I know JavaScript and I'm trying to get GSE works.
I have a search engine and an API key.
The problem is Google's documentation is cyclic i.e. pages point to each other.
There is no working sample from where I can start my research.
Please help if you know of a working sample.
The documents I have read are:
cselement-devguide
introduction
I know this is an old question, but here is what I did to make the API results formatted like the Google Site Search used to give since they are ending the paid accounts and will have ads now. The API way has an option to pay still for over 100 searches per day, so going with that but had to format the results still, and used the existing one to build the css to do similar styling also.
Search form going to this page is just a simple:
<form action="search-results.htm" id="cse-search-box">
<div>
<input class="" name="q" type="text">
<input class="" type="submit">
</div>
</form>
and then the search results page:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>JSON/Atom Custom Search API Example</title>
<!--<link href="default.css" rel="stylesheet" type="text/css">-->
<link href="google.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="gsc-result-info" id="resInfo-0"></div>
<hr/>
<div id="googleContent"></div>
<script>
//Handler for response from google.
function hndlr(response) {
if (response.items == null) {
//Sometimes there is a strange thing with the results where it says there are 34 results/4 pages, but when you click through to 3 then there is only 30, so page 4 is invalid now.
//So if we get to the invalid one, send them back a page.
window.location.replace("searchresults.htm?start=" + (start - 10) + "&q=" + query);
return;
}
//Search results load time
document.getElementById("resInfo-0").innerHTML = "About " + response.searchInformation.formattedTotalResults + " results (" + response.searchInformation.formattedSearchTime + " seconds)";
//Clear the div first, CMS is inserting a space for some reason.
document.getElementById("googleContent").innerHTML = "";
//Loop through each item in search results
for (var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var content = "";
content += "<div class='gs-webResult gs-result'>" +
"<table class='gsc-table-result'><tbody><tr>";
//Thumbnail image
if (item.pagemap.cse_thumbnail != null)
content += "<td class='gsc-table-cell-thumbnail gsc-thumbnail'><div class='gs-image-box gs-web-image-box gs-web-image-box-portrait'><a class='gs-image' href='" + item.link + "'>" +
"<img class='gs-image' class = 'gs-image-box gs-web-image-box gs-web-image-box-portrait' src='" + item.pagemap.cse_thumbnail[0].src + "'></a></td>";
//Link
content += "<td><a class='gs-title' href='" + item.link + "'>" + item.htmlTitle + "</a><br/>";
//File format for PDF, etc.
if (item.fileFormat != null)
content += "<div class='gs-fileFormat'><span class='gs-fileFormat'>File Format: </span><span class='gs-fileFormatType'>" + item.fileFormat + "</span></div>";
//description text and URL text.
content += item.htmlSnippet.replace('<br>','') + "<br/><div class='gs-bidi-start-align gs-visibleUrl gs-visibleUrl-long' dir='ltr' style='word-break:break-all;'>" + item.htmlFormattedUrl +"</div>" +
"<br/></td></tr></tbody></table></div>";
document.getElementById("googleContent").innerHTML += content;
}
//Page Controls
var totalPages = Math.ceil(response.searchInformation.totalResults / 10);
console.log(totalPages);
var currentPage = Math.floor(start / 10 + 1);
console.log(currentPage);
var pageControls = "<div class='gsc-results'><div class='gsc-cursor-box gs-bidi-start-align' dir='ltr'><div class='gsc-cursor'>";
//Page change controls, 10 max.
for (var x = 1; x <= totalPages && x<=10; x++) {
pageControls += "<div class='gsc-cursor-page";
if (x === currentPage)
pageControls += " gsc-cursor-current-page";
var pageLinkStart = x * 10 - 9;
pageControls+="'><a href='search-results.htm?start="+pageLinkStart+"&q="+query+"'>"+x+"</a></div>";
}
pageControls += "</div></div></div>";
document.getElementById("googleContent").innerHTML += pageControls;
}
//Get search text from query string.
var query = document.URL.substr(document.URL.indexOf("q=") + 2);
var start = document.URL.substr(document.URL.indexOf("start=") + 6, 2);
if (start === "1&" || document.URL.indexOf("start=") === -1)
start = 1;
//Load the script src dynamically to load script with query to call.
// DOM: Create the script element
var jsElm = document.createElement("script");
// set the type attribute
jsElm.type = "application/javascript";
// make the script element load file
jsElm.src = "https://www.googleapis.com/customsearch/v1?key=yourApikeyhere&cx=yoursearchengineidhere&start="+start+"&q=" +query +"&callback=hndlr";
// finally insert the element to the body element in order to load the script
document.body.appendChild(jsElm);
</script>
</body>
</html>