ObservableCollection doesnt virtualise data? - c#

I want to add approx 600 images to my collection to show them in a Listview that virtualizes with Itemsstackpanel. If i didnt misread with virtualization its possible to load large datasets. My problem is that the collection can only hold around 150 images and then i get a OutOfMemory Exception. Is there something more to enable virtualization or is the problem that my Collection calls its propertyChanged Event for every image added?
The error is thrown on:
await pdfPage.RenderToStreamAsync(Imagestream);
and how i add to my collection:
for (uint i = convertedPageString; i < 200 + convertedPageString; i++)
{
Image img = await LoadPage(l_document, i);
collection.Add(img);
g_rootPage.ListViewControl.ItemsSource = collection;
}
convertedPageString is just the Page im starting on when the program is opened.
EDIT:
This is my function to get the Pages.
public async Task<Image> LoadPage(PdfDocument a_document, uint page)
{
Image l_image;
BitmapImage l_bitmap;
PdfPage pdfPage;
using (IRandomAccessStream Imagestream = new MemoryStream().AsRandomAccessStream())
{
using (pdfPage = a_document.GetPage(page))
{
await pdfPage.RenderToStreamAsync(Imagestream);
l_bitmap = new BitmapImage();
await l_bitmap.SetSourceAsync(Imagestream);
l_image = new Image();
l_bitmap.DecodePixelHeight = 1200;
l_bitmap.DecodePixelWidth = 1000;
l_image.Source = l_bitmap;
l_image.Margin = new Thickness(0, 5, 0, 10);
}
}
return l_image;
}
I forgot to mention that i open the application via the commandLine with a specified page and path.

Related

How to fix Java.Lang.OutOfMemoryError in Xamarin.Forms android application?

So, i have some problems with my Xamarin.Forms app. I am getting "Java.Lang.OutOfMemoryError" when I am trying to await ViewExtensions.LayoutTo.
I have tried to increase Java Heap size up to 2G, but it did not help.
public class SplashPage : ContentPage
{
public SplashPage()
{
NavigationPage.SetHasNavigationBar(this, false);
AbsoluteLayout layout = new AbsoluteLayout();
Content = layout;
Image image1 = new Image
{
Source = ImageSource.FromFile("image1.png"),
};
layout.Children.Add(image1);
Image image2 = new Image
{
Source = ImageSource.FromFile("image2.png"),
};
layout.Children.Add(image2);
Image image3 = new Image
{
Source = ImageSource.FromFile("image3.png"),
Scale = 0.5,
};
layout.Children.Add(image3);
layout.SizeChanged += async (s, e) =>
{
AbsoluteLayout.SetLayoutBounds(image1, new Rectangle(0, 0, image1.Width, image1.Height));
AbsoluteLayout.SetLayoutBounds(image2, new Rectangle(0, ((AbsoluteLayout)s).Height, image2.Width, image2.Height));
AbsoluteLayout.SetLayoutBounds(image3, new Rectangle(-image3.Width, ((AbsoluteLayout)s).Height - image3.Height - 5, image3.Width, image3.Height));
// I have placed those animations in SizeChanged event because i needed to get actual size of layout (outside this event it would be incorrect)
await ViewExtensions.LayoutTo(image2, new Rectangle(0, ((AbsoluteLayout)s).Height - image2.Height, image2.Width, image2.Height), 2300);
// here Java.Lang.OutOfMemoryError
await ViewExtensions.LayoutTo(image3, new Rectangle(((AbsoluteLayout)s).Width, ((AbsoluteLayout)s).Height - image3.Height - 5, image3.Width, image3.Height), 3000);
await Task.WhenAll(
image2.FadeTo(0, 700), image1.FadeTo(0, 700));
Application.Current.MainPage = new NavigationPage(new LoginPage());
};
}
}
Try this way to increase your app's heap size in your AndroidManifest.xml:
<application android:largeHeap="true"></application>

WIA Duplex scanning using document feeder

Below is my c# code trying to transfer image from the duplex scanner. I'm able to acquire one image (Front Only) but i cant get the second image. I have tried changing the device property 3088 to 5 but i get a catastrophic failure. I'm working with WIA 2.0 on windows 10, 64 bit but project is using X86. I have also tried to transfer the image twice as i have read in previous questions but i get an error. I'm using duplexid600 scanner and from the windows scanner software i'm able to get a duplex image. Below is my code
CommonDialogClass commonDialogClass = new CommonDialogClass();
Device scannerDevice = commonDialogClass.ShowSelectDevice(WiaDeviceType.ScannerDeviceType, false, false);
if (scannerDevice != null)
{
Item scannnerItem = scannerDevice.Items[1];
//object value;
// AdjustScannerSettings(scannnerItem, 300, 0, 0, 1010, 620, 0, 0);
// object kuku;
// kuku = scannerDevice.Properties["Document Handling Select"].get_Value();
scannerDevice.Properties["Document Handling Select"].set_Value(1);//3088
// kuku = scannerDevice.Properties["Document Handling Select"].get_Value();
scannerDevice.Properties["Pages"].set_Value(1);//3096
// object scanResult = commonDialogClass.ShowTransfer(scannnerItem, WIA.FormatID.wiaFormatTIFF, false);
object scanResult = scannnerItem.Transfer(WIA.FormatID.wiaFormatBMP);
//object scanResult1 = scannnerItem.Transfer(WIA.FormatID.wiaFormatTIFF);
if (scanResult != null)
{
ImageFile image = (ImageFile) scanResult;
// string fileName = Path.GetTempPath() + DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss-fffffff") + ".tif";
var imageBytes = (byte[])image.FileData.get_BinaryData();
var ms = new MemoryStream(imageBytes);
var img = Image.FromStream(ms);
//int pageCount = 0;
//Image Tiff = img;
//pageCount = Tiff.GetFrameCount(FrameDimension.Page);
// Tiff.Dispose();
// SaveImageToPNGFile(image, fileName);
pictureBoxScannedImage.Image = img;
}
}
Call this one twice, it should give the 2nd image if you have 3088 set to 5 (duplex).
object scanResult = scannnerItem.Transfer(WIA.FormatID.wiaFormatBMP);
object scanResultbacksite = scannnerItem.Transfer(WIA.FormatID.wiaFormatBMP);
Beware though - on my scanner with the 2nd "start scan" command, you issue a new task, meaning your scanner could start to scan the 2nd physical page already - while assigning the backpage to your file. If you know a solution to this, tell me please!

Cache issue using pdf.js with Chrome

I'm working on a C# / ASP.NET flipbook project using pdf.js.
When I launch my application having an empty cache in Chrome, I load once my pdf file and everything is fine, but when I refresh the page without clearing it, the pdf is entirely downloaded 5 times, so the size goes from 7,5Mo to 37,5Mo.
I checked with IE 11, Edge, and FireFox, and I don't have issues with them.
I have already tried to disable the cache following these instructions, but it didn't solve my problem.
This is where I call my file :
function loadBook() {
PDFJS.disableWorker = true;
PDFJS.workerSrc = '../../Scripts/pdf.worker.js';
$(document).ready(function () {
var file = "http://localhost:51790/pdf/newspaper.pdf";
PDFJS.getDocument(file).then(function getPdf(pdf) {
var pagesNumber = pdf.numPages;
//Adding canvas to the html
for (var i = 1; i <= pagesNumber; i++) {
$('.flipbook').html($('.flipbook').html() + '<div><canvas id="page' + i + '"></canvas></div>');
}
//Adding and rendering pages
for (var i = 1; i <= pagesNumber; i++) {
renderPage(i, document.getElementById('page' + i), pdf);
}
//Creating flipbook
loadJournal();
});
})
}
And this is my function for the render :
function renderPage(numero, pageElement, pdf) {
pdf.getPage(numero).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
pageElement.width = viewport.width;
pageElement.height = viewport.height;
var renderContext = {
canvasContext: pageElement.getContext('2d'),
viewport: viewport
};
page.render(renderContext);
});
}
I'd like to understand why it react like this.

Change PdfImage type (Syncfusion PDF)

So I'm using Syncfusion Controls for UWP XAML, and I'm trying to insert JPEGs into a PDF I'm creating, but PdfImage seems to always return bitmaps. Or at least images with bitmap-like file sizes.
Is there any way to ensure the images being inserted are of JPEG size? The images I'm inputting are JPEGs to begin with.
I'd be fine with bitmaps if I wasn't making PDFs of manga (Japanese comic books), i.e. the size per manga right now ranges from 50-150MB.
It's not a working sample, but here's what I'm using right now.
public async void SaveAsPdf(Stream fs, Manga manga)
{
var m = manga;
var c = m.Content;
if (fs.Length != 0) return;
var pdf = new PdfDocument();
var pages = await GetPages(m);
pdf.PageSettings.SetMargins(0);
pdf.FileStructure.IncrementalUpdate = true;
pdf.EnableMemoryOptimization = true;
pdf.Compression = PdfCompressionLevel.Best;
for (var pi = 0; pi < c.ContentPages; pi++)
{
var section = pdf.Sections.Add();
var mr = section.PageSettings.Margins = new PdfMargins();
mr.All = 0;
var page = section.Pages.Add();
var g = page.Graphics;
page.DefaultLayerIndex = 0;
var pu = pages[pi];
var client = new HttpClient();
var im = await client.GetAsync(pu);
var pdi = PdfImage.FromStream(im.Content.ReadAsStreamAsync().Result);
g.DrawImage(pdi, new PointF(0, 0), g.ClientSize);
await pdf.SaveAsync(fs);
}
await pdf.SaveAsync(fs);
pdf.DocumentInformation.Title = c.ContentName;
pdf.DocumentInformation.Author += string.Join(", ", c.ContentArtists.Select(x => x.Attribute));
pdf.DocumentInformation.Keywords += string.Join(", ", c.ContentTags.Select(x => x.Attribute)).Replace("\"", string.Empty);
pdf.Save(fs);
pdf.Close(true);
var toast = Notifications.NotifyMangaDownloaded(m);
ToastNotificationManager.CreateToastNotifier().Show(toast);
fs.Dispose();
}
I'd ask about the memory leak but it'd probably be best if I made another post for that.
Thanks in advance.
(I posted this on the Syncfusion forums but I felt like I might get a better response here)
Well, I refactored some of the methods and the memory leak ended up being the cause. Lesson learned: using statements are your friends.
To be a little more specific, I just created a file as a destination for the PDF, then called
using (Stream s = new FileStream(/*string*/>f.Path, FileMode.OpenOrCreate))
{
await Task.Run(() => SaveAsPdf(/*StorageFile*/f, /*Manga*/m));
}
Various other things needed to be moved around, but leaving the FileStream open ended up being the problem.

How to Print Preview when using a DocumentPaginator to print?

I'm using a class I've derived from DocumentPaginator (see below) to print simple (text only) reports from a WPF application. I've got it so that everything prints correctly, But how do I get it to do a print preview before printing? I have a feeling I need to use a DocumentViewer but I can't figure out how.
Here's my Paginator Class:
public class RowPaginator : DocumentPaginator
{
private int rows;
private Size pageSize;
private int rowsPerPage;
public RowPaginator(int rows)
{
this.rows = rows;
}
public override DocumentPage GetPage(int pageNumber)
{
int currentRow = rowsPerPage * pageNumber;
int rowsToPrint = Math.Min(rowsPerPage, rows - (rowsPerPage * pageNumber - 1));
var page = new PageElementRenderer(pageNumber + 1, PageCount, currentRow, rowsToPrint)
{
Width = PageSize.Width,
Height = PageSize.Height
};
page.Measure(PageSize);
page.Arrange(new Rect(new Point(0, 0), PageSize));
return new DocumentPage(page);
}
public override bool IsPageCountValid { get { return true; } }
public override int PageCount { get { return (int)Math.Ceiling(this.rows / (double)this.rowsPerPage); } }
public override Size PageSize
{
get { return this.pageSize; }
set
{
this.pageSize = value;
this.rowsPerPage = PageElementRenderer.RowsPerPage(this.pageSize.Height);
if (rowsPerPage <= 0)
throw new InvalidOperationException("Page can't fit any rows!");
}
}
public override IDocumentPaginatorSource Source { get { return null; } }
}
The PageElementRenderer is just a simple UserControl that displays the data (at the moment just a list of rows).
Here's how I use my Row Paginator
PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
var paginator = new RowPaginator(rowsToPrint) { PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight) };
dialog.PrintDocument(paginator, "Rows Document");
}
Sorry for the code dump, but I didn't want to miss something relevant.
So I got it working after reading Pro WPF in C# 2008 (Page 726).
Basically the DocumentViewer class needs an XPS file to present a print preview of it. So I do the following:
PrintDialog dialog = new PrintDialog();
var paginator = new RowPaginator(rowsToPrint) { PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight) };
string tempFileName = System.IO.Path.GetTempFileName();
//GetTempFileName creates a file, the XpsDocument throws an exception if the file already
//exists, so delete it. Possible race condition if someone else calls GetTempFileName
File.Delete(tempFileName);
using (XpsDocument xpsDocument = new XpsDocument(tempFileName, FileAccess.ReadWrite))
{
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(paginator);
PrintPreview previewWindow = new PrintPreview
{
Owner = this,
Document = xpsDocument.GetFixedDocumentSequence()
};
previewWindow.ShowDialog();
}
I'm creating the print dialog to get the default page size. There's probably a better way to do this.
XpsDocument is in ReachFramework.dll (Namespace System.Windows.Xps.Packaging);
Here's the PrintPreview Window.
<Window x:Class="WPFPrintTest.PrintPreview"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="previewWindow"
Title="PrintPreview" Height="800" Width="800">
<Grid>
<DocumentViewer Name="viewer"
Document="{Binding ElementName=previewWindow, Path=Document}" />
</Grid>
</Window>
The code behind just has a Document property like so:
public IDocumentPaginatorSource Document
{
get { return viewer.Document; }
set { viewer.Document = value; }
}
The following code uses a MemoryStream to do a print preview.
MemoryStream stream = new MemoryStream();
Package package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite);
var uri = new Uri(#"memorystream://myXps.xps");
PackageStore.AddPackage(uri, package);
var xpsDoc = new XpsDocument(package);
xpsDoc.Uri = uri;
XpsDocument.CreateXpsDocumentWriter(xpsDoc).Write(paginator);
documentViewer.Document = xpsDoc.GetFixedDocumentSequence();
Remember to use close() and remove package from PackageStore when the print preview is closed.
WPF doesn't come with any built-in Print Preview functionality, if you want to do a print preview, you're going to have to construct it yourself. Fortunately, it's shouldn't be that difficult.
You've already got the pagination code, which creates your DocumentPage objects. These objects contain a Visual, which you can go ahead and display in your UI.
What you'll end up doing, is paginating your entire document, collecting all the DocumentPage objects, then displaying their visuals inside of a scrolling StackPanel or something similar. These are the same DocumentPage objects that you can then send to the printer.
XpsDocument doc = new XpsDocument("filename.xps", FileAccess.Read);
docViewer.Document = doc.GetFixedDocumentSequence();
doc.Close();
The WinForm code for print preview is:
PrintPreviewDialog PrintPreviewDialog = new PrintPreviewDialog();
PrintPreviewDialog.Document = PrintDocument;
PrintPreviewDialog.ShowDialog();
P.s.: The original poster has commented that this is the wrong answer for an WPF application.
I dont think there is a built in way of doing this
Here is how I got it working in NHaml
var documentViewHostDialog = new DocumentDialog();
documentViewHostDialog.LoadDocument(load);
documentViewHostDialog.ShowDialog();
Where "load" is either a FlowDocument or IDocumentPaginatorSource
and here is the DocumentDialog
http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml
http://code.google.com/p/nhaml/source/browse/trunk/src/NHaml.Xps/DocumentDialog.xaml.cs
Hope it works for your case.

Categories

Resources