I'm writing a Windows 8 Store App using WinJS. My app needs to generate PDFs with text and graphs. I was under the impression that PDFtron could convert HTML to PDF, but that does not seem to be the case for an App Store application. Is this true?
The front end uses WinJS/HTML and Telerik Radcharts to render graphs in SVG. I then pipe the DOM down to disk as an HTML file. It shows the graph and numbers nicely. I want to convert the HTML to a PDF to preserve the styling as well as the content.
The WinRT version does not come with the HTML2PDF assembly or the .Convert() method. Is it somewhere else? I've searched the docs, samples, and the web.
PDFTron's PDFNet SDK on WinRT does not support HTML to PDF conversion (as at version 6.2).
Here is the response I received from PDFTron support on this question:
While the PDFNet SDK on WinRT cannot itself convert from HTML
to PDF, the PDFNet SDK on Windows desktop can do so. You can find
sample code for for HTML to PDF conversion at
http://www.pdftron.com/pdfnet/samplecode.html#HTML2PDF.
Some of our clients send HTML to a server of theirs, where
PDFNet can convert the HTML to PDF. Note that on Windows
desktop there are many conversion options, including converting Office
to PDF and converting any printable document format to PDF.
EVO has implemented the following solution to convert HTML to PDF in WinRT and Windows Store Applications. You can find a compelte code sample in that page.
The copy of the code sample is:
private async void buttonConvertUrlToPdf_Click(object sender, RoutedEventArgs e)
{
// If another conversion is in progress then ignore current request
bool ignoreRequest = false;
lock(pendingConversionSync)
{
if (pendingConversion)
ignoreRequest = true;
else
{
msgUrlToPdfInProgress.Visibility = Windows.UI.Xaml.Visibility.Visible;
pendingConversion = true;
}
}
if (ignoreRequest)
return;
try
{
String serverIP = textBoxServerIP.Text;
uint port = uint.Parse(textBoxServerPort.Text);
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter(serverIP, port);
// set service password if necessary
if (textBoxServicePassword.Text.Length > 0)
htmlToPdfConverter.ServicePassword = textBoxServicePassword.Text;
// set HTML viewer width
htmlToPdfConverter.HtmlViewerWidth = int.Parse(textBoxHtmlViewerWidth.Text);
// set HTML viewer height if necessary
if (textBoxHtmlViewerHeight.Text.Length > 0)
htmlToPdfConverter.HtmlViewerHeight = int.Parse(textBoxHtmlViewerHeight.Text);
// set navigation timeout
htmlToPdfConverter.NavigationTimeout = int.Parse(textBoxHtmlViewerWidth.Text);
// set conversion delay if necessary
if (textBoxConversionDelay.Text.Length > 0)
htmlToPdfConverter.ConversionDelay = int.Parse(textBoxConversionDelay.Text);
// set PDF page size
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = SelectedPdfPageSize();
// set PDF page orientation
htmlToPdfConverter.PdfDocumentOptions.PdfPageOrientation = SelectedPdfPageOrientation();
// set margins
htmlToPdfConverter.PdfDocumentOptions.LeftMargin = int.Parse(textBoxLeftMargin.Text);
htmlToPdfConverter.PdfDocumentOptions.RightMargin = int.Parse(textBoxRightMargin.Text);
htmlToPdfConverter.PdfDocumentOptions.TopMargin = int.Parse(textBoxTopMargin.Text);
htmlToPdfConverter.PdfDocumentOptions.BottomMargin = int.Parse(textBoxBottomMargin.Text);
// add header
if (checkBoxAddHeader.IsChecked != null && (bool)checkBoxAddHeader.IsChecked)
{
htmlToPdfConverter.PdfDocumentOptions.ShowHeader = true;
DrawHeader(htmlToPdfConverter, true);
}
// add footer
if (checkBoxAddFooter.IsChecked != null && (bool)checkBoxAddFooter.IsChecked)
{
htmlToPdfConverter.PdfDocumentOptions.ShowFooter = true;
DrawFooter(htmlToPdfConverter, true, true);
}
string urlToConvert = textBoxUrl.Text;
string errorMessage = null;
// Convert the HTML page from give URL to PDF in a buffer
byte[] pdfBytes = await Task.Run<byte[]>(() =>
{
byte[] resultBytes = null;
try
{
resultBytes = htmlToPdfConverter.ConvertUrl(urlToConvert);
}
catch (Exception ex)
{
errorMessage = String.Format("Conversion failed. {0}", ex.Message);
return null;
}
return resultBytes;
});
if (pdfBytes == null)
{
MessageDialog errorMessageDialog = new MessageDialog(errorMessage, "Conversion failed");
await errorMessageDialog.ShowAsync();
return;
}
// Save the PDF in a file
Windows.Storage.StorageFolder installedLocation = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile outStorageFile = installedLocation.CreateFileAsync("EvoHtmlToPdf.pdf", CreationCollisionOption.ReplaceExisting).AsTask().Result;
FileIO.WriteBytesAsync(outStorageFile, pdfBytes).AsTask().Wait();
// Open the file in a PDF viewer
await Windows.System.Launcher.LaunchFileAsync(outStorageFile);
}
finally
{
lock (pendingConversionSync)
{
msgUrlToPdfInProgress.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
pendingConversion = false;
}
}
}
Related
I've got an app that, since 5 years now, that displays an offline map by reading from a folder embed in it ("assets").
Since Android 11, it's impossible to read from ApplicationStorage (Error #3001: File or directory access denied), so I'm trying to copy the folder from applicationStorage to "Documents".
What I did :
source = File.applicationDirectory.resolvePath("assets/maps");
destination = File.documentsDirectory.resolvePath("Documents/www");
source.addEventListener(Event.COMPLETE, onMapCopyComplete);
source.copyToAsync(destination, false);
function onMapCopyComplete(e: Event): void {
source.removeEventListener(Event.COMPLETE, onMapCopyComplete);
log("onMapCopyComplete()");
}
I've got a return onMapCopyComplete() but when I'm looking in InternalStorage/Documents of my phone I've got the folders but all are empty... None of the files were copy..
PrintScreen computer vs phone
To read the files, here's what I'm doing :
function startMapsView()
{
var indexFile:File = File.applicationStorageDirectory.resolvePath("www/index.html");
if (!indexFile.exists)
{
log("startMapsView() Index file not found, Please check www/index.html");
return;
}
// Create StageWebView
stageWebView = new StageWebView(isMobile); // Set to TRUE for System's NativeWebView, FALSE is for AIR's WebView
stageWebView.stage = stage;
stageWebView.viewPort = new Rectangle(0, iOSStatusBarHeight + headerBarHeight, deviceStageSize.width, deviceStageSize.height - (iOSStatusBarHeight + headerBarHeight + footerBarHeight));
stageWebView.addEventListener(flash.events.Event.COMPLETE, onStageWebViewLoaded);
stageWebView.addEventListener(flash.events.ErrorEvent.ERROR, onStageWebViewError);
stageWebView.addEventListener(LocationChangeEvent.LOCATION_CHANGING, onStageWebViewLocationChanging);
// Load Map URL
stageWebView.loadURL(mapsURL);
}
And mapsURL is define by :
function setMapsURL(doNotEnableButtons: Boolean = false): void {
var indexFile: File = File.documentsDirectory.resolvePath("Documents/www/index.html");
trace("indexFile url is = "+indexFile.url);
if (!indexFile.exists) {
log("setMapsURL() Index file not found, Please check www/index.html");
return;
}
var assetsDir: File;
if (!useOnlineMaps) {
assetsDir = new File(destination.resolvePath("index.html").nativePath);
} else {
assetsDir = new File(destination.resolvePath("onlineMaps.html").nativePath);
mySavedData.data.onlineMapChoosen = false;
}
mapsURL = assetsDir.url;
log("setMapsURL() " + mapsURL);
if (!doNotEnableButtons) enableMapButtons();
}
I have a question about opening Multiple Revit Model in background to perform some batch automation task. These models were downloaded from BIM360 Design collaboration and placed into a folder.
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiapp = commandData.Application;
Document rvtDoc = null;
string[] files = Directory.GetFiles(#"C:\Models", "*.rvt");
foreach (string file in files)
{
ModelPath modelPath = ModelPathUtils.ConvertUserVisiblePathToModelPath(Path.GetFileName(file));
if (modelPath != null)
{
OpenOptions openOptions = new OpenOptions();
WorksetConfiguration openConfiguration = new WorksetConfiguration(WorksetConfigurationOption.OpenAllWorksets);
openOptions.SetOpenWorksetsConfiguration(openConfiguration);
openOptions.DetachFromCentralOption = DetachFromCentralOption.ClearTransmittedSaveAsNewCentral;
openOptions.Audit = false;
var currentDoc = uiapp.OpenAndActivateDocument(modelPath, openOptions, false);
}
}
return Result.Succeeded;
}
I couldn't skip the Login screen as shown in below images.
Any suggestion will be highly appreciated.
Do you really want to open and activate the document by?
var currentDoc = uiapp.OpenAndActivateDocument(modelPath, openOptions, false);
How about using the following way:
var currentDoc = uiapp.Application.OpenDocumentFile(modelPath, openOptions);
I'm exporting SVFs from a model using the design automation API. With some models, the orientation in the Viewer of the viewable does not match the orientation in Inventor.
How do I correct this so that all models come out with their Viewer orientation matching the input Inventor model?
The following code is where the SVF is exported. A blog post on this functionality would be helpful.
private string SaveForgeViewable(Inventor.Document doc) {
string viewableOutputDir = null;
using(new HeartBeat()) {
//LogTrace($"** Saving SVF");
try {
TranslatorAddIn oAddin = null;
foreach(ApplicationAddIn item in inventorApplication.ApplicationAddIns) {
if (item.ClassIdString == "{C200B99B-B7DD-4114-A5E9-6557AB5ED8EC}") {
//Trace.TraceInformation("SVF Translator addin is available");
oAddin = (TranslatorAddIn) item;
break;
}
else {}
}
if (oAddin != null) {
//Trace.TraceInformation("SVF Translator addin is available");
TranslationContext oContext = inventorApplication.TransientObjects.CreateTranslationContext();
// Setting context type
oContext.Type = IOMechanismEnum.kFileBrowseIOMechanism;
NameValueMap oOptions = inventorApplication.TransientObjects.CreateNameValueMap();
// Create data medium;
DataMedium oData = inventorApplication.TransientObjects.CreateDataMedium();
Trace.TraceInformation("SVF save");
var workingDir = Path.GetDirectoryName(doc.FullFileName);
var sessionDir = Path.Combine(workingDir, "SvfOutput");
// Make sure we delete any old contents that may be in the output directory first,
// this is for local debugging. In DA4I the working directory is always clean
if (Directory.Exists(sessionDir)) {
Directory.Delete(sessionDir, true);
}
oData.FileName = Path.Combine(sessionDir, "result.collaboration");
var outputDir = Path.Combine(sessionDir, "output");
var bubbleFileOriginal = Path.Combine(outputDir, "bubble.json");
var bubbleFileNew = Path.Combine(sessionDir, "bubble.json");
// Setup SVF options
if (oAddin.get_HasSaveCopyAsOptions(doc, oContext, oOptions)) {
oOptions.set_Value("GeometryType", 1);
oOptions.set_Value("EnableExpressTranslation", true);
oOptions.set_Value("SVFFileOutputDir", sessionDir);
oOptions.set_Value("ExportFileProperties", false);
oOptions.set_Value("ObfuscateLabels", true);
}
oAddin.SaveCopyAs(doc, oContext, oOptions, oData);
LogTrace($ "** Saved SVF as {oData.FileName}");
File.Move(bubbleFileOriginal, bubbleFileNew);
viewableOutputDir = sessionDir;
}
}
catch(Exception e) {
LogError($ "********Export to format SVF failed: {e.Message}");
return null;
}
}
return viewableOutputDir;
}
we have met this issue too, this is our setup of SVF output which respects the ground of your design:
oOptions.set_Value("EnableExpressTranslation", false);
oOptions.set_Value("ExportFileProperties", true);
oOptions.set_Value("ObfuscateLabels", false);
For full code you can see our new sample app repository https://github.com/Developer-Autodesk/forge-configurator-inventor/blob/master/AppBundles/CreateSVFPlugin/CreateSvfAutomation.cs#L96
I am trying to experiment with downloading files on a regular basis with background tasks for windows store applications, and am having trouble.
I followed the sample at https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977055.aspx, and even downloaded/ran it and everything worked perfectly (including being able to step into the timer background task).
So with that I created my own background task in a brand new Windows namespace
Win8BackgroundTest
{
public class TestBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
var uri = new Uri("http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_480p_h264.mov");
var folder = ApplicationData.Current.LocalFolder;
var downloadFile = await folder.CreateFileAsync(uri.Segments.Last(), CreationCollisionOption.GenerateUniqueName);
var dataFile = await folder.CreateFileAsync("downloadData", CreationCollisionOption.GenerateUniqueName);
var downloader = new BackgroundDownloader();
var operation = downloader.CreateDownload(uri, downloadFile);
await FileIO.WriteTextAsync(dataFile, "Success at " + DateTime.Now);
deferral.Complete();
}
public static async void RegisterTask()
{
const string taskName = "TestBackgroundTask";
try
{
var status = await BackgroundExecutionManager.RequestAccessAsync();
if (status == BackgroundAccessStatus.Denied)
{
return;
}
}
catch
{
// already accepted
}
var tasks = BackgroundTaskRegistration.AllTasks
.Where(x => x.Value.Name == taskName)
.ToArray();
if (tasks.Any())
{
return;
}
var builder = new BackgroundTaskBuilder
{
Name = taskName,
TaskEntryPoint = "Win8BackgroundTest.TestBackgroundTask",
};
builder.SetTrigger(new TimeTrigger(60, false));
var registeredTask = builder.Register();
}
}
}
I set up the application's manifest with a Background Tasks declaration, checking the Timer properties checkbox, and set the EntryPoint to Win8BackgroundTest.TestBackgroundTask.
I then added the following at the end of my App.xaml.cs's OnLaunched() method:
TestBackgroundTask.RegisterTask();
Stepping through seems to have task registration work successfully with no exceptions. I then go back to visual studio, added a breakpoint to the first line in my task's Run() method, I then go to the debug locations toolbar, click the down arrow and select TestBackgroundTask. A few seconds later visual studio exits (as does my app).
Does anyone see what I am doing wrong that is causing background tasks to fail?
So after much frustration and a lot of trial and error the issue was a combination of both of the comments.
So first of all, it appears like you cannot have a background task in the same project as the rest of your windows store application. It must be in it's own windows runtime component project.
Finally, there are times where it just doesn't work and for whatever reason deleting the bin and obj folders fix it.
I have problem with initialization camera on Windows Universal Apps. This code works and never throw any exception, but i have wrapped it into dialog control. Problem is sometimes (1/10 dialog openings) i don't see preview from camera. Have you any idea how to fix that or at least check if preview is displayed?
private async Task InitCameraAsync()
{
var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
var backCam = devices.FirstOrDefault(q => q.EnclosureLocation != null && q.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
var mediaCapture = new MediaCapture();
if (backCam != null)
{
await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings()
{
VideoDeviceId = backCam.Id,
AudioDeviceId = String.Empty,
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
});
}
else
{
await mediaCapture.InitializeAsync();
}
CameraControl.Source = mediaCapture;
SetImageEncodingProperties(); // get encoding properties to save images
await SetPreviewResolutionAsync();
await CameraControl.Source.StartPreviewAsync();
}
}
Are you sure that you are calling the function from the UI thread to access the camera for the API to run reliably?
https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.core.coredispatcher.runasync.aspx