I'm trying to print a PDF file from my Windows 8 app to connected printer. I'm coding with WinJS, and know that I have to create a print task to initiate printing from a Windows 8 app. So, after reviewing the documentation, I have this code:
onPrintTaskRequested: function (e) {
var self = Application.navigator.pageControl,
printTask = e.request.createPrintTask("Print Test Doc", function (args) {
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
// Register the handler for print task completion event
printTask.oncompleted = self.onPrintTaskCompleted;
});
}
According to the documentation, the MSApp.getHhtmlPrintDocumentSource method accepts a specific set of data types. As stated in the documentation:
This can be the root document, the document in an IFrame, a document
fragment, or a SVG document. Be aware that htmlDoc must be a document,
not an element.
Apparently I cannot simply set the argument for getHtmlPrintDocumentSource to a .PDF or .PNG binary. So, I'm curious: does the WinJS library offer a method for printing so that I can implement the printing of a PDF file to a connected printer? Can anybody offer some tips to implement?
After trial and error, I was finally able implement the printing of a Base64 stream representing a PDF binary from a Windows 8 application.
I'm coding the app in HTML / CSS / WinJS. Essentially here is a brief explanation of how it was accomplished:
Create a new <canvas> element within the default.html file. Place it right after the open tag of the element. Like this:
<body role="application" class="app">
<canvas id="pdf-render-output"></canvas>
.
.
.
</body>
Then inside the default.css file, setup a few rules as well as a print media query. Like this:
body > canvas {
display: none;
}
.
. /* all your app's default css styles */
.
#media print {
body > * {
display:none;
max-width: 100%;
}
html {
max-width: 100%;
border-top-color: none;
border-top: 0;
}
body > canvas {
display: block;
border: none;
max-width: 100%;
width: 100%;
height: 100%;
position: relative;
}
}
Of note is the order in which the rules are declared in CSS. It's important to place the print media query after declaring default CSS rules.
After this is setup, javascript handles the rest. The basic idea is to render the PDF.js output to the "hidden" canvas in the DOM. When the document object gets sent to print, the CSS print media declaration is queried so that all elements under <body> are hidden except for the canvas element. Here is the javascript to print only the first page in the PDF:
//Define a container for the Base64 data we'll use with PDF.js
var pdfPrintData = {};
//Function to render PDF to canvas and begin printing contract with Windows 8 OS
printPrescription: function () {
var self = Application.navigator.pageControl,
printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
self.getPDF().done(function () {
var pdfStream = pdfPrintData.base64,
pdfFile = convertDataURIToBinary(pdfStream);
PDFJS.disableWorker = true;
PDFJS.getDocument(pdfFile).then(function (pdf) {
var numPages = pdf.numPages,
renderCanvas = $('#pdf-render-output')[0];
//setup canvas
renderCanvas.height = pdf.getPage(1).data.getViewport(1).height;
renderCanvas.width = pdf.getPage(1).data.getViewport(1).width;
//Setup a render context for pdf.js to out a pdf file to the canvas.
var renderContext = {
canvasContext: renderCanvas.getContext('2d'),
viewport: pdf.getPage(1).data.getViewport(1)
};
//Bring up Windows 8 OS print after PDF is rendered to render context.
pdf.getPage(1).data.render(renderContext).then(function () {
printManager.onprinttaskrequested = self.onPrintTaskRequested;
Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
});
})
});
},
onPrintTaskRequested: function (e) {
var self = Application.navigator.pageControl,
printTask = e.request.createPrintTask("Print Prescription", function (args) {
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
printTask.oncompleted = self.onPrintTaskCompleted;
});
},
onPrintTaskCompleted: function (e) {
if (e.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed) {
console.log("[ERX] : Failed to print!");
}
}
The self.getPDF method is just a function that retrieves the Base64 data stream, and that streams gets set on the .base64 property of the global pdfPrintData object. For some reason, I was not able to render the pdf using pdf.js to a dynamically create canvas in a dynamically created document. I had to render the output of the pdf.js render method to a canvas already present in the DOM.
As far as I know, MSApp.getHtmlPrintDocumentSource(document) is meant to be used with HTML document objects, and nothing else.
If you can assume Windows 8.1, you can try to assemble a new HTML document from your PDF file by exporting each page into a raster image using PdfPage.RenderToStreamAsync. There is a sample project in MSDN for a PDF viewer that uses this new API where you can learn how to use this method.
If you cannot assume Windows 8.1 and you need to support plain Windows 8 or Windows RT (ARM), you might need to use a third party library to create the raster images or to do the printing all together.
Amyuni PDF Creator for WinRT for example can do the printing for you. Disclaimer: I currently work for the company that develops the library
Related
Has anyone tried to implement tags using the ABCPDF Gecko engine? I have it working fine on the MSHTML engine (Internet Explorer) as soon as I use Gecko, which is rendering my HTML better, it can't find the tags specified in the HTML.
I'm using style="abcpdf-tag-visible: true;" to specify a tag which works using the default engine.
The following code produces a blank document.
[Test]
public void Tags_With_Gecko()
{
Doc theDoc = new Doc();
theDoc.Rect.Inset(100, 100);
theDoc.Rect.Top = 700;
theDoc.HtmlOptions.Engine = EngineType.Gecko;
// Tag elements with style 'abcpdf-tag-visible: true'
theDoc.HtmlOptions.ForGecko.AddTags = true;
int id = theDoc.AddImageHtml("<FONT id=\"p1\" style=\"abcpdf-tag-visible: true; font-size: 72pt\">Gallia est omnis divisa in partes tres.</FONT>");
// Frame location of the tagged element
XRect[] tagRects = theDoc.HtmlOptions.ForGecko.GetTagRects(id);
foreach (XRect theRect in tagRects)
{
theDoc.Rect.String = theRect.ToString();
theDoc.FrameRect();
}
// Output tag ID
string[] tagIds = theDoc.HtmlOptions.ForGecko.GetTagIDs(id);
theDoc.Rect.String = theDoc.MediaBox.String;
theDoc.Rect.Inset(20, 20);
theDoc.FontSize = 64;
theDoc.Color.String = "255 0 0";
theDoc.AddText("Tag ID \"" + tagIds[0] + "\":");
// Save the document
const string testFilename = #"C:\pdf\HtmlOptionsGetTagRects.pdf";
if (File.Exists(testFilename))
File.Delete(testFilename);
theDoc.Save(testFilename);
theDoc.Clear();
Process.Start(testFilename);
}
Almost identical code for the default engine produces it correctly.
I've been talking to WebSuperGoo support. Found out the documentation isn't consistent/complete.
http://www.websupergoo.com/helppdfnet/source/5-abcpdf/xhtmloptions/2-properties/addtags.htm
In Gecko, your tag has to have a visible impact on the page for it to be picked up. In my case, I had a tag that displayed a non-breaking space, and thus it wasn't found.
From their example, changing the style to the following got it to be findable:
style="abcpdf-tag-visible: true; border: 1px solid transparent"
Note the Border settings is what makes this work apparently.
Again, this fixes their demo and thus should fix Dillorscroft's example.
I have to futz a bit more to fix my problem, as I am trying to allocate blank spaces on the page (for a table of contents) so they can be updated after the html is rendered and I know where the first content page will start.
I am able to find img tag using iwebdriver.findElement() query. Image contains captcha.
I also get the src attribute which contains the url of image but it is not working when i open it it gives me 404 error.
This is the img tag i am looking for and i need its valid image path.
{img src="https://EU1.client.hip.live.com/GetHIPData?hid=EU1.d3f00459fcb444fc8efb402f3c2dc237&fid=bbc4f6c344e7434c9b712c2d80f7268c&id=274850&type=visual&hdid=0&rnd=1798e82f1c7d4d51922f1a58c03c4d74" style="display: inline; width: 218px; height: 48px;" id="wlspispHIPBimg05f4e37f6e1bc431d8c335e2d169a0f440"}
// Assuming webdriver is set and running
IWebdriver _driver=new firefoxdriver(capabilities);
_driver.Navigate().GoToUrl("http://www.bing.com/toolbox/submit-site-url");
IWebElement img_tag = _driver.FindElement(By.CssSelector("img[style='display: inline; width: 218px; height: 48px;']"));
// Now i have the entire img tag required which contains a image.
string source_path=img_tag.GetAttribute("src");
// Now i have src url of image. but it does not show the image when i go to this source path. This is the relative path of the image i think.
I've opened the page you'r visiting. As you're trying to get captcha image. You won't be able to get image from captcha image source.
You have to get screenshot of page and crop the captcha image.
Don't use css selector with width and height. Some pages are responsive, it will put you in trouble. Use XPath instead.
public Image GetCaptchaImage()
{
Image imgCap = null;
try
{
var arrScreen = driver.GetScreenshot().AsByteArray;
using (var msScreen = new MemoryStream(arrScreen))
{
var bmpScreen = new Bitmap(msScreen);
var cap = driver.FindElement(By.XPath("//div[#id='ispHIPHIP']//img"));
var rcCrop = new Rectangle(cap.Location, cap.Size);
imgCap = bmpScreen.Clone(rcCrop, bmpScreen.PixelFormat);
}
}
catch
{
}
return imgCap;
}
I have created table with data using "custom html app".
I want now print this page but when I try to do it, it cuts few last columns.
I have tried to set style of body to "width:1000px" and then it prints ok but then it doesn't shows on whole screen and I have table of size 1000px
We usually end up having slightly different css for printing than runtime.
Try this:
#media print {
body {
width: 1000px;
}
}
I am building a windows store app that has a default css and a default font size in that css. I am allowing the user to customize the font size from settings screen and that preference gets stored in local settings. How do I update my app to reflect the new font size? Are there any current patterns? This is a Html5/js app. Can I simply reload the css value from the change event?
When your app launches, read the font size from local settings and then set the document's font size with JavaScript:
document.body.style.fontSize = fontSizeFromSettings;
When the app is running and the user changes the font size, also call the above line. You could do this right after your code which saves the font size to local settings.
Naturally, you can also change the font size of individual elements using document.getElementById("myId").style.fontSize.
I read this as the OP having a class selector already defined, like
.myclass
{
font-size: 36px;
}
and wanting to modify all elements with the .myclass selector to be a new value, say 72px. If that's the intent, then you can dynamically modify the CSS.
Here's a simple (and fragile, not-suitable-for-production) function that looks for a specific style selector in a known CSS file and modifies it on the fly. You could probably generalize this, take a look at Changing External Stylesheets and How to change CSS Stylesheets with JavaScript for more details.
function updateFontSize(newFontSize) {
for (var i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].href.indexOf("default.css") >= 0) {
var mySheet = document.styleSheets[i];
for (var r in mySheet.cssRules) {
if (mySheet.cssRules[r].selectorText == ".myclass") {
var myRule = mySheet.cssRules[r];
myRule.style.fontSize = newFontSize;
return;
}
}
}
}
};
Then somewhere you call it like (without hardcoding the value, of course):
updateFontSize("128px");
I made a vertical carousel which consists of images that when clicked should be visible fullscreen. But the problem is i'm not able to figure out how to make sure the fullscreen images are preloaded or something and works like the thumbnail images(getting preloaded).
I'm not sure what approach to follow for preloading the fullscreen images using css background and how to make sure the images fadeIn or just some transition when i click on the thumbnail in the carousel.
Please have a look at the following link where my code is uploaded.
http://www.lluvia.me/slideshow/carousel.html
If its convenient,feel free to check the script by checking the source.
Help would be appreciated. Thanks!
Found this post and figured it might help you, Preloading images with jQuery
Try and post some of the code in your body for future reference. :)
Quick and easy:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}
// Usage:
preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);
Or, if you want a jQuery plugin:
$.fn.preload = function() {
this.each(function(){
$('<img/>')[0].src = this;
});
}
// Usage:
$(['img1.jpg','img2.jpg','img3.jpg']).preload();
Alternatively, if you want to stick purely with CSS check out this page: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/ You can just have the background image be positioned off screen then come on screen when needed.
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }
#preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; }
#preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }