How can I get and wait for external process to complete? - c#

I have rewritten a paginator to display header and footer for my documents. Everything seems to work until I save it as xps Document :
public void SaveAsXps(string fileName, FlowDocument document, string DocumentTitle, string DocumentFooter)
{
document.PageHeight = 1122.5 - 30;
document.PageWidth = 793.7 - 30;
using (Package container = Package.Open(fileName + ".xps", FileMode.Create))
{
using (XpsDocument xpsDoc = new XpsDocument(container, CompressionOption.Maximum))
{
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDoc), false);
DocumentPaginator paginator = ((IDocumentPaginatorSource)document).DocumentPaginator;
paginator = new VisualPaginator(paginator, new Size(793.7, 1122.5), new Size(30, 30), DocumentTitle, DocumentFooter);
rsm.SaveAsXaml(paginator);
}
}
}
I give you the paginator :
public class VisualPaginator : DocumentPaginator
{
string m_DocumentTitle;
string m_DocumentFooter;
private Size pageSize;
private Size margin;
private readonly DocumentPaginator paginator;
private Typeface typeface;
public override Size PageSize
{
get { return pageSize; }
set { pageSize = value; }
}
public override bool IsPageCountValid
{
get
{
return paginator.IsPageCountValid;
}
}
public override int PageCount
{
get
{
return paginator.PageCount;
}
}
public override IDocumentPaginatorSource Source
{
get
{
return paginator.Source;
}
}
public VisualPaginator(DocumentPaginator paginator, Size pageSize, Size margin, string DocumentTitle, string DocumentFooter)
{
PageSize = pageSize;
this.margin = margin;
this.paginator = paginator;
m_DocumentTitle = DocumentTitle;
m_DocumentFooter = DocumentFooter;
this.paginator.PageSize = new Size(PageSize.Width - margin.Width * 2,
PageSize.Height - margin.Height * 2);
}
public void DrawFunction(DrawingVisual content, string drawContent, Point point)
{
try
{
using (DrawingContext ctx = content.RenderOpen())
{
if (typeface == null)
{
typeface = new Typeface("Times New Roman");
}
FormattedText text = new FormattedText(drawContent, CultureInfo.CurrentCulture,
FlowDirection.LeftToRight, typeface, 14, Brushes.Black,
VisualTreeHelper.GetDpi(content).PixelsPerDip);
Thread.Sleep(300);
ctx.DrawText(text, point);
}
}
catch (Exception)
{
throw;
}
}
public override DocumentPage GetPage(int pageNumber)
{
DocumentPage page = paginator.GetPage(pageNumber);
// Create a wrapper visual for transformation and add extras
ContainerVisual newpage = new ContainerVisual();
//Title
DrawingVisual pagetitle = new DrawingVisual();
DrawFunction(pagetitle, m_DocumentTitle, new Point(paginator.PageSize.Width / 2 - 100, -96 / 4));
//Page Number
DrawingVisual pagenumber = new DrawingVisual();
DrawFunction(pagenumber, "Page " + (pageNumber + 1), new Point(paginator.PageSize.Width - 200, paginator.PageSize.Height - 100));
//Footer
DrawingVisual pagefooter = new DrawingVisual();
DrawFunction(pagefooter, m_DocumentFooter, new Point(paginator.PageSize.Width / 2 - 100, paginator.PageSize.Height - 100));
DrawingVisual background = new DrawingVisual();
using (DrawingContext ctx = background.RenderOpen())
{
ctx.DrawRectangle(new SolidColorBrush(Color.FromRgb(240, 240, 240)), null, page.ContentBox);
}
newpage.Children.Add(background); // Scale down page and center
ContainerVisual smallerPage = new ContainerVisual();
smallerPage.Children.Add(page.Visual);
//smallerPage.Transform = new MatrixTransform(0.95, 0, 0, 0.95,
// 0.025 * page.ContentBox.Width, 0.025 * page.ContentBox.Height);
newpage.Children.Add(smallerPage);
newpage.Children.Add(pagetitle);
newpage.Children.Add(pagenumber);
newpage.Children.Add(pagefooter);
newpage.Transform = new TranslateTransform(margin.Width, margin.Height);
return new DocumentPage(newpage, PageSize, page.BleedBox, page.ContentBox);
}
}
The code execution leads to a break point due to external process unless I use a Thread.Sleep(300) instruction. I think the program has to wait for some external process to complete but I have no Idea what processes are involve here and what I can do to wait for them to fix the problem without using a Thread.Sleep() which is a very bad practice.
Any help or clues would be gladly appreciate.

Related

Add a page number in the footer of a PDF file using iText7 and ASP.NET C#

I can create a pdf file using iText7 and C# ASP.NET
This pdf file contains 9 pages total.
I have tried to add in my code the total number of pages and a dotted line
But I have two problems
the number of pages (1 of 9, 2 of 9, 3 of 9...) are showing only in the pages number 8 and number 9 in the PDF file
the dotted line don't showing in page number one...
Any help would greatly appreciate... Thank you.
My code below
private void mtpdfnew()
{
DataTable dt = new DataTable();
filename = #"C:\inetpub\wwwroot\public\pdf\" +
DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";
PdfWriter writer = new PdfWriter(filename);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
using (MySqlConnection myConnectionString =
new MySqlConnection(ConfigurationManager.ConnectionStrings["cn"].ConnectionString))
{
using (MySqlCommand cmd =
new MySqlCommand("SP", myConnectionString))
{
cmd.Connection.Open();
cmd.CommandType = CommandType.StoredProcedure;
using (MySqlDataAdapter da =
new MySqlDataAdapter(cmd))
{
da.Fill(dt);
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
contents = new Paragraph(dt.Rows[i]["contents"].ToString())
.SetTextAlignment(TextAlignment.JUSTIFIED)
.SetFontSize(12);
if (dt.Rows[i]["contents"].ToString().StartsWith("Set") && i != 0)
{
document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
document.Add(new LineSeparator(new DottedLine(1, 2)).SetMarginTop(4));
}
List<IElement> lst = HtmlConverter.ConvertToElements(dt.Rows[i]["contents"].ToString()).ToList();
for (int j = 0; j < lst.Count; j++)
{
IBlockElement element = (IBlockElement)lst[j];
if (dt.Rows[i]["contents"].ToString().StartsWith("Set"))
{
contents.SetFontSize(12)
.SetBold()
.SetFontColor(ColorConstants.BLUE);
}
else if (dt.Rows[i]["contents"].ToString().StartsWith("- "))
{
contents.SetFontSize(10)
.SetBold()
.SetFontColor(ColorConstants.BLACK);
}
else
{
contents.SetTextAlignment(TextAlignment.JUSTIFIED_ALL)
.SetFontSize(10)
.SetFontColor(ColorConstants.BLACK);
}
element.SetProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, -1f));
document.Add(element);
}
}
Footer footerHandler = new Footer();
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
footerHandler.WriteTotal(pdf);
dest = filename.ToString();
document.Close();
}
Response.Clear();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + dest);
Response.TransmitFile(dest);
Response.End();
}
}
}
}
private class TableFooterEventHandler : IEventHandler
{
private Table table;
public TableFooterEventHandler(Table table)
{
this.table = table;
}
public void HandleEvent(Event currentEvent)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
PdfDocument pdfDoc = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
int pageNumber = pdfDoc.GetPageNumber(page);
Rectangle pageSize = page.GetPageSize();
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
new Canvas(canvas, new Rectangle(36, 20, page.GetPageSize().GetWidth() - 72, 50))
.Add(table)
.Close();
}
}
protected class Footer : IEventHandler
{
protected PdfFormXObject placeholder;
protected float side = 20;
protected float x = 300;
protected float y = 25;
protected float space = 4.5f;
protected float descent = 3;
public Footer()
{
placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
}
public virtual void HandleEvent(Event #event)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent)#event;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
int pageNumber = pdf.GetPageNumber(page);
Rectangle pageSize = page.GetPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(page);
Canvas canvas = new Canvas(pdfCanvas, pageSize);
canvas.SetFontSize(10);
Paragraph p = new Paragraph()
.Add("Page ")
.Add(pageNumber.ToString())
.Add(" of");
canvas.ShowTextAligned(p, x, y, TextAlignment.RIGHT);
canvas.Close();
pdfCanvas.AddXObjectAt(placeholder, x + space, y - descent);
pdfCanvas.Release();
}
public void WriteTotal(PdfDocument pdfDoc)
{
Canvas canvas = new Canvas(placeholder, pdfDoc);
canvas.SetFontSize(10);
canvas.ShowTextAligned(pdfDoc.GetNumberOfPages().ToString(),
0, descent, TextAlignment.LEFT);
canvas.Close();
}
}
private class TableHeaderEventHandler : IEventHandler
{
private Table table;
private float tableHeight;
private Document doc;
public TableHeaderEventHandler(Document doc)
{
this.doc = doc;
InitTable();
TableRenderer renderer = (TableRenderer)table.CreateRendererSubTree();
renderer.SetParent(new DocumentRenderer(doc));
LayoutResult result = renderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4)));
tableHeight = result.GetOccupiedArea().GetBBox().GetHeight();
}
public void HandleEvent(Event currentEvent)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
PdfDocument pdfDoc = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
int pageNum = docEvent.GetDocument().GetPageNumber(page);
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
PageSize pageSize = pdfDoc.GetDefaultPageSize();
float coordX = pageSize.GetX() + doc.GetLeftMargin();
float coordY = pageSize.GetTop() - doc.GetTopMargin();
float width = pageSize.GetWidth() - doc.GetRightMargin() - doc.GetLeftMargin();
float height = GetTableHeight();
Rectangle rect = new Rectangle(coordX, coordY, width, height);
new Canvas(canvas, rect)
.Add(table)
.Close();
}
public float GetTableHeight()
{
return tableHeight;
}
private void InitTable()
{
}
}
You add the footer drawing event handler to the document just before closing the document:
Footer footerHandler = new Footer();
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
footerHandler.WriteTotal(pdf);
dest = filename.ToString();
document.Close();
At that time nearly all pages already are finished and the END_PAGE events for them have been triggered and processed, so your footer handler won't receive them. Only the last and probably the previous page still are to be finished, so your footer handler will be called for them.
So, to have your footer handler receive the END_PAGE events for all pages, create and register it early, right after creating the pdf document:
PdfWriter writer = new PdfWriter(filename);
PdfDocument pdf = new PdfDocument(writer);
Footer footerHandler = new Footer();
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
Document document = new Document(pdf);
Writing the total, of course, still must be done at the end:
footerHandler.WriteTotal(pdf);
dest = filename.ToString();
document.Close();

How to preview document with DocumentViewer with multi-pages per sheet in WPF

How can I preview a document with DocumentViewer with multi-pages per sheet (Like 2, 4, 6, 8, etc. pages per sheet) in WPF. In the default, DocumentViewer can only preview document with one page per sheet. But I want to preview document with multi-pages per sheet like this:
I just use the DocumentViewer control in WPF, I want to view document with multi-pages per sheet, but DocumentViewer doesn't have a property or method to do that. So I think I can change the DocumentViewer.Document property, like change the document, put multi-pages into one page, etc. But I don't know how to do that.
Thanks in advance.
I wrote a class to put a few FixedPage into one FixedPage, it works perfectly.
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Markup;
using System.Windows.Controls;
using System.Windows.Documents;
namespace PreviewHelper
{
internal enum DocumentOrientation
{
Portrait,
Landscape
}
internal class MultiPagesPerSheetHelper
{
private readonly int _pagesPerSheet;
private readonly Size _innerPageSize;
private readonly FixedDocument _document;
private readonly DocumentOrientation _documentOrientation;
private readonly List<int> _allowedPagesPerSheetCount = new List<int> { 1, 2, 4, 6, 9, 16 };
private readonly List<Size> _allowedPagesPerSheetArrange = new List<Size> { new Size(1, 1), new Size(1, 2), new Size(2, 2), new Size(2, 3), new Size(3, 3), new Size(4, 4) };
public MultiPagesPerSheetHelper()
{
_document = null;
_pagesPerSheet = 0;
_innerPageSize = new Size();
_documentOrientation = DocumentOrientation.Portrait;
}
public MultiPagesPerSheetHelper(int pagesPerSheet, FixedDocument document)
{
_document = document;
_pagesPerSheet = pagesPerSheet;
_innerPageSize = new Size();
_documentOrientation = DocumentOrientation.Portrait;
}
public MultiPagesPerSheetHelper(int pagesPerSheet, FixedDocument document, Size innerPageSize)
{
_document = document;
_pagesPerSheet = pagesPerSheet;
_innerPageSize = innerPageSize;
_documentOrientation = DocumentOrientation.Portrait;
}
public MultiPagesPerSheetHelper(int pagesPerSheet, FixedDocument document, Size innerPageSize, DocumentOrientation documentOrientation)
{
_document = document;
_pagesPerSheet = pagesPerSheet;
_innerPageSize = innerPageSize;
_documentOrientation = documentOrientation;
}
public FixedDocument GetMultiPagesPerSheetDocument()
{
if (_document == null && _document.Pages.Count == 0 && _pagesPerSheet == 0)
{
return new FixedDocument();
}
if (_allowedPagesPerSheetCount.Contains(_pagesPerSheet) == false)
{
return new FixedDocument();
}
FixedDocument doc = new FixedDocument();
doc.DocumentPaginator.PageSize = _document.DocumentPaginator.PageSize;
int currentPageCount = 0;
int pagesPerSheetIndex = _allowedPagesPerSheetCount.IndexOf(_pagesPerSheet);
int arrangeRows;
int arrangeColumns;
if (_documentOrientation == DocumentOrientation.Portrait)
{
arrangeRows = (int)_allowedPagesPerSheetArrange[pagesPerSheetIndex].Height;
arrangeColumns = (int)_allowedPagesPerSheetArrange[pagesPerSheetIndex].Width;
}
else
{
arrangeRows = (int)_allowedPagesPerSheetArrange[pagesPerSheetIndex].Width;
arrangeColumns = (int)_allowedPagesPerSheetArrange[pagesPerSheetIndex].Height;
}
double innerPageHeight = doc.DocumentPaginator.PageSize.Height / arrangeRows;
double innerPageWidth = doc.DocumentPaginator.PageSize.Width / arrangeColumns;
while (currentPageCount < _document.Pages.Count)
{
FixedPage outerPage = new FixedPage
{
Width = doc.DocumentPaginator.PageSize.Width,
Height = doc.DocumentPaginator.PageSize.Height
};
Grid outergrid = new Grid()
{
Width = outerPage.Width,
Height = outerPage.Height,
};
for (int i = 0; i < arrangeRows; i++)
{
outergrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
}
for (int i = 0; i < arrangeColumns; i++)
{
outergrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
}
for (int i = 0; i < arrangeRows; i++)
{
for (int j = 0; j < arrangeColumns && currentPageCount < _document.Pages.Count; j++)
{
Grid innerGrid = new Grid()
{
Width = innerPageWidth,
Height = innerPageHeight,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center
};
innerGrid.SetValue(Grid.RowProperty, i);
innerGrid.SetValue(Grid.ColumnProperty, j);
string xaml = XamlWriter.Save(_document.Pages[currentPageCount].Child);
FixedPage innerPage = XamlReader.Parse(xaml) as FixedPage;
if (_innerPageSize.Width == 0 || _innerPageSize.Height == 0 || _innerPageSize.Width == double.NaN || _innerPageSize.Height == double.NaN)
{
innerPage.Width = outerPage.Width;
innerPage.Height = outerPage.Width;
}
else
{
innerPage.Width = _innerPageSize.Width;
innerPage.Height = _innerPageSize.Height;
}
innerPage.VerticalAlignment = VerticalAlignment.Center;
innerPage.HorizontalAlignment = HorizontalAlignment.Center;
double widthRatio;
double heightRatio;
widthRatio = innerPageWidth / innerPage.Width;
heightRatio = innerPageHeight / innerPage.Height;
if (innerPage.Height * widthRatio <= innerPageHeight)
{
innerPage.Width *= widthRatio;
innerPage.Height *= widthRatio;
innerPage.RenderTransform = new ScaleTransform(widthRatio, widthRatio);
}
else
{
innerPage.Width *= heightRatio;
innerPage.Height *= heightRatio;
innerPage.RenderTransform = new ScaleTransform(heightRatio, heightRatio);
}
innerGrid.Children.Add(innerPage);
outergrid.Children.Add(innerGrid);
currentPageCount++;
}
}
outerPage.Children.Add(outergrid);
doc.Pages.Add(new PageContent { Child = outerPage });
}
return doc;
}
}
}
And you can use it like this:
PreviewHelper.MultiPagesPerSheetHelper multiPagesPerSheetHelper = new PreviewHelper.MultiPagesPerSheetHelper(PAGES_PER_SHEET_COUNT, ORGINAL_DOCUMENT, ORGINAL_DOCUMENT_SIZE, DOCUMENT_ORIENTATION);
FixedDocument newDocument = multiPagesPerSheetHelper.GetMultiPagesPerSheetDocument();
It will work like this:

SharpDX 3 loading .DDS to apply onto a 3d model (C#)

I'm attempting to create a model viewer for a game to try and learn SharpDX but the game uses .DDS files and the viewer can only read .BMPs. I've looked far and wide on the webs and the only things I can find are load them but don't seem to work for SharpDX (I don't know im a noob :D)
using SharpDX.Direct3D11;
using SharpDX.WIC;
namespace ModelViewer.Programming.GraphicClasses
{
public class TextureClass
{
public ShaderResourceView TextureResource { get; private set; }
public bool Init(Device device, string fileName)
{
try
{
using (var texture = LoadFromFile(device, new ImagingFactory(), fileName))
{
ShaderResourceViewDescription srvDesc = new ShaderResourceViewDescription()
{
Format = texture.Description.Format,
Dimension = SharpDX.Direct3D.ShaderResourceViewDimension.Texture2D,
};
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = -1;
TextureResource = new ShaderResourceView(device, texture, srvDesc);
device.ImmediateContext.GenerateMips(TextureResource);
}
return true;
}
catch
{
return false;
}
}
public void Shutdown()
{
TextureResource?.Dispose();
TextureResource = null;
}
public Texture2D LoadFromFile(Device device, ImagingFactory factory, string fileName)
{
using (var bs = LoadBitmap(factory, fileName))
return CreateTextureFromBitmap(device, bs);
}
public BitmapSource LoadBitmap(ImagingFactory factory, string filename)
{
var bitmapDecoder = new BitmapDecoder(factory, filename, DecodeOptions.CacheOnDemand);
var result = new FormatConverter(factory);
result.Initialize(bitmapDecoder.GetFrame(0), SharpDX.WIC.PixelFormat.Format32bppPRGBA, BitmapDitherType.None, null, 0.0, BitmapPaletteType.Custom);
return result;
}
public Texture2D CreateTextureFromBitmap(Device device, BitmapSource bitmapSource)
{
int stride = bitmapSource.Size.Width * 4;
using (var buffer = new SharpDX.DataStream(bitmapSource.Size.Height * stride, true, true))
{
bitmapSource.CopyPixels(stride, buffer);
return new Texture2D(device, new Texture2DDescription()
{
Width = bitmapSource.Size.Width,
Height = bitmapSource.Size.Height,
ArraySize = 1,
BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
Usage = ResourceUsage.Default,
CpuAccessFlags = CpuAccessFlags.None,
Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm,
MipLevels = 1,
OptionFlags = ResourceOptionFlags.GenerateMipMaps,
SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
},
new SharpDX.DataRectangle(buffer.DataPointer, stride));
}
}
}
}
I have a feeling this will need to be completely redone to utilize the DDS format. Is it easier to simply read one and then convert it to a bitmap?

Printing a local file on Android via Xamarin.Forms

I need to use the print dialog via Forms. I have found an solution on iOS but the android implementation is giving me problems.
As far as i can see it is not possible to call the Android print manager and parse a file to it.
It can only be a Android.Views.View, is that true?
To do that would be my ideal solution.
I have tried to convert my content (A webview showing a local pdf) to this android view but this seems also not really to work but i am out off my depths here.
in the code below i try to convert a forms.webview to an android.view and then parse it to the print manager.
This produce the print dialog but with a black white page.
var size = new Rectangle(webview.X, webview.Y, webview.Width, webview.Height);
var vRenderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(webview);
var viewGroup = vRenderer.ViewGroup;
vRenderer.Tracker.UpdateLayout();
var layoutParams = new Android.Views.ViewGroup.LayoutParams((int)size.Width, (int)size.Height);
viewGroup.LayoutParameters = layoutParams;
webview.Layout(size);
viewGroup.Layout(0, 0, (int)webview.WidthRequest, (int)webview.HeightRequest);
var printMgr = (Android.Print.PrintManager)Forms.Context.GetSystemService(Android.Content.Context.PrintService);
var docAdt = new Droid.GenericPrintAdapter(Forms.Context, viewGroup);
printMgr.Print("test", docAdt, null);
The next is the "GenericPrintAdapter"
public class GenericPrintAdapter : PrintDocumentAdapter
{
View view;
Context context;
PrintedPdfDocument document;
float scale;
public GenericPrintAdapter(Context context, View view)
{
this.view = view;
this.context = context;
}
public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
{
document = new PrintedPdfDocument(context, newAttributes);
CalculateScale(newAttributes);
var printInfo = new PrintDocumentInfo
.Builder("MyPrint.pdf")
.SetContentType(PrintContentType.Document)
.SetPageCount(1)
.Build();
callback.OnLayoutFinished(printInfo, true);
}
void CalculateScale(PrintAttributes newAttributes)
{
int dpi = Math.Max(newAttributes.GetResolution().HorizontalDpi, newAttributes.GetResolution().VerticalDpi);
int leftMargin = (int)(dpi * (float)newAttributes.MinMargins.LeftMils / 1000);
int rightMargin = (int)(dpi * (float)newAttributes.MinMargins.RightMils / 1000);
int topMargin = (int)(dpi * (float)newAttributes.MinMargins.TopMils / 1000);
int bottomMargin = (int)(dpi * (float)newAttributes.MinMargins.BottomMils / 1000);
int w = (int)(dpi * (float)newAttributes.GetMediaSize().WidthMils / 1000) - leftMargin - rightMargin;
int h = (int)(dpi * (float)newAttributes.GetMediaSize().HeightMils / 1000) - topMargin - bottomMargin;
scale = Math.Min((float)document.PageContentRect.Width() / w, (float)document.PageContentRect.Height() / h);
}
public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback)
{
PrintedPdfDocument.Page page = document.StartPage(0);
page.Canvas.Scale(scale, scale);
view.Draw(page.Canvas);
document.FinishPage(page);
WritePrintedPdfDoc(destination);
document.Close();
document.Dispose();
callback.OnWriteFinished(pages);
}
void WritePrintedPdfDoc(ParcelFileDescriptor destination)
{
var javaStream = new Java.IO.FileOutputStream(destination.FileDescriptor);
var osi = new OutputStreamInvoker(javaStream);
using (var mem = new MemoryStream())
{
document.WriteTo(mem);
var bytes = mem.ToArray();
osi.Write(bytes, 0, bytes.Length);
}
}
}
I have now a "working" solution.
This gets the current Android.Webkir.WebView and create the printAdapter from that.
Thanks to #SushiHangover for pointing me in the right direction.
Its a bit of a hack but works for my needs.
If anyone else ever needs this i have included both the Android and iOS code.
#if __ANDROID__
var vRenderer = Xamarin.Forms.Platform.Android.Platform.GetRenderer(webview);
var viewGroup = vRenderer.ViewGroup;
for (int i = 0; i < viewGroup.ChildCount; i++)
{
if (viewGroup.GetChildAt(i).GetType().Name == "WebView")
{
var AndroidWebView = viewGroup.GetChildAt(i) as Android.Webkit.WebView;
var tmp = AndroidWebView.CreatePrintDocumentAdapter("print");
var printMgr = (Android.Print.PrintManager)Forms.Context.GetSystemService(Android.Content.Context.PrintService);
printMgr.Print("print", tmp, null);
break;
}
}
#elif __IOS__
var printInfo = UIKit.UIPrintInfo.PrintInfo;
printInfo.Duplex = UIKit.UIPrintInfoDuplex.LongEdge;
printInfo.OutputType = UIKit.UIPrintInfoOutputType.General;
printInfo.JobName = "AppPrint";
var printer = UIKit.UIPrintInteractionController.SharedPrintController;
printer.PrintInfo = printInfo;
printer.PrintingItem = Foundation.NSData.FromFile(pdfPath);
printer.ShowsPageRange = true;
printer.Present(true, (handler, completed, err) =>
{
if (!completed && err != null)
{
System.Diagnostics.Debug.WriteLine("Printer Error");
}
});
#endif

How to save WebViewBrush as image? (UWP / Universal)

Summary: I have a collection FrameworkElements (basically web view brushes drawn on rectanlges), and I'd like to save each of these as a PNG file in my UWP app.
More details: I followed the example at https://stackoverflow.com/a/17222629/2884981 to split the content of a WebView into separate "pages".
I've put the main bits of code at the bottom.
At the bottom of GetWebPages() I have return pages;
At this point I have a list of all the "pages".
What I'd like to do, is then convert each of those pages into an image (so by the end of it I'd have a collection of PNG files, for instance).
Does anyone know how I can do this? Thanks in advance.
public async Task<WebViewBrush> GetWebViewBrush(WebView webView)
{
// resize width to content
double originalWidth = webView.Width;
var widthString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });
int contentWidth;
if (!int.TryParse(widthString, out contentWidth))
{
throw new Exception(string.Format("failure/width:{0}", widthString));
}
webView.Width = contentWidth;
// resize height to content
double originalHeight = webView.Height;
var heightString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
int contentHeight;
if (!int.TryParse(heightString, out contentHeight))
{
throw new Exception(string.Format("failure/height:{0}", heightString));
}
webView.Height = contentHeight;
// create brush
var originalVisibilty = webView.Visibility;
webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
WebViewBrush brush = new WebViewBrush
{
SourceName = webView.Name,
Stretch = Stretch.Uniform
};
brush.Redraw();
// reset, return
webView.Width = originalWidth;
webView.Height = originalHeight;
webView.Visibility = originalVisibilty;
return brush;
}
And:
public async Task<IEnumerable<FrameworkElement>> GetWebPages(WebView webView, Windows.Foundation.Size page)
{
// ask the content its width
var widthString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollWidth.toString()" });
int contentWidth;
if (!int.TryParse(widthString, out contentWidth))
{
throw new Exception(string.Format("failure/width:{0}", widthString));
}
webView.Width = contentWidth;
// ask the content its height
var heightString = await webView.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
int contentHeight;
if (!int.TryParse(heightString, out contentHeight))
{
throw new Exception(string.Format("failure/height:{0}", heightString));
}
webView.Height = contentHeight;
// how many pages will there be?
double scale = page.Width / contentWidth;
double scaledHeight = (contentHeight * scale);
double pageCount = (double) scaledHeight / page.Height;
pageCount = pageCount + ((pageCount > (int) pageCount) ? 1 : 0);
// create the pages
var pages = new List<Windows.UI.Xaml.Shapes.Rectangle>();
for (int i = 0; i < (int)pageCount; i++)
{
var translateY = -page.Height * i;
var rectanglePage = new Windows.UI.Xaml.Shapes.Rectangle
{
Height = page.Height,
Width = page.Width,
Margin = new Thickness(5),
Tag = new TranslateTransform { Y = translateY },
};
rectanglePage.Loaded += (async (s, e) =>
{
var subRectangle = s as Windows.UI.Xaml.Shapes.Rectangle;
var subBrush = await GetWebViewBrush(webView);
subBrush.Stretch = Stretch.UniformToFill;
subBrush.AlignmentY = AlignmentY.Top;
subBrush.Transform = subRectangle.Tag as TranslateTransform;
subRectangle.Fill = subBrush;
});
pages.Add(rectanglePage);
}
return pages;
}
I'd like to save each of these as a PNG file in my UWP app.
You can get all the rectangles and show them in the ItemsControl in the NavigationCompleted event of WebView like this:
private async void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
MyWebViewRectangle.Fill = await GetWebViewBrush(webView);
MyPrintPages.ItemsSource = await GetWebPages(webView, new Windows.Foundation.Size(842, 595));
}
Then in a button click event you can save all the items as .png images like this:
private async void Savetoimage_Clicked(object sender, RoutedEventArgs e)
{
var piclib = Windows.Storage.KnownFolders.PicturesLibrary;
foreach (var item in MyPrintPages.Items)
{
var rect = item as Rectangle;
RenderTargetBitmap renderbmp = new RenderTargetBitmap();
await renderbmp.RenderAsync(rect);
var pixels = await renderbmp.GetPixelsAsync();
var file = await piclib.CreateFileAsync("webview.png", Windows.Storage.CreationCollisionOption.GenerateUniqueName);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)rect.Width, (uint)rect.Height,
0, 0, bytes);
await encoder.FlushAsync();
}
}
}

Categories