iText7 for .NET - error while merging files - c#-4.0

I've created simple method that allows me to merge multiple PDF files.
Below is my code:
private void Merge(List<string> src, string dest)
{
Stopwatch sw = new Stopwatch();
sw.Start();
PdfDocument pdfDocument1 = new PdfDocument(new PdfReader(src[0]), new PdfWriter(dest));
for (int i = 1,max=src.Count; i < max; i++)
{
PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(src[i]));
var pagesCount = pdfDocument2.GetNumberOfPages();
pdfDocument2.CopyPagesTo(1, pagesCount, pdfDocument1);
pdfDocument2.Close();
}
pdfDocument1.Close();
sw.Stop();
Debug.WriteLine(sw.Elapsed);
}
I've based my code on example from iText book: http://developers.itextpdf.com/examples/merging-pdf-documents/clone-merging-documents-bookmarks
For test purpose I've attached that method to button and I'm caling it like this:
private void button1_Click(object sender, EventArgs e)
{
try
{
string dest = #"E:\final.pdf";
var files = Directory.GetFiles(#"E:\PDFS", "*.pdf").Take(100).ToList();
Merge(files,dest);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
From time to time (after n'th click on that button) I get exception saying:
Cant cast from 'iText.Kernel.Pdf.PdfNumber' to
'iText.Kernel.Pdf.PdfStream'.
Also first time I click my application takes about 100MB of memory, next time I click it increase to 150MB, next click and I get 230MB of memory used, so it look like it isn't releasing memory.
Is there a better way to merge multiple PDF's into one using iTextSharp 7?
As per request I'm adding StackTrace:
w iText.Kernel.Pdf.PdfPage.GetContentStream(Int32 index)
w iText.Kernel.Pdf.PdfPage.Flush(Boolean flushXObjects)
w iText.Kernel.Pdf.PdfPage.Flush()
w iText.Kernel.Pdf.PdfDocument.Close()
w iTextSharp7_Merge.Form1.Merge(List`1 src, String dest)
w c:\Users\Misiu\Documents\Visual Studio 2013\Projects\iTextSharp7_Merge\Form1.cs:wiersz 75
And here are exception details:
EDIT:
I've changed button click function so now it loads 100 file names from directory and calls Merge method 10 times with same list:
private void button1_Click(object sender, EventArgs e)
{
try
{
string dest = #"E:\final.pdf";
var files = Directory.GetFiles(#"E:\PDFS", "*.pdf").OrderBy(x => x).Skip(0).Take(100).ToList();
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 10; i++)
{
Debug.WriteLine(i);
Merge(files, dest1);
}
sw.Stop();
Debug.WriteLine(sw.Elapsed);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
This way I've excluded random sort of Directory.GetFiles.
Here is sample output that comes from Visual Studio:
'iTextSharp7_Merge.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'
1
'iTextSharp7_Merge.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\Misiu\documents\visual studio 2013\Projects\iTextSharp7_Merge\bin\Debug\itext.kernel.dll'
'iTextSharp7_Merge.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Users\Misiu\documents\visual studio 2013\Projects\iTextSharp7_Merge\bin\Debug\itext.io.dll'
A first chance exception of type 'System.NullReferenceException' occurred in itext.kernel.dll
2
3
The thread '<No Name>' (0x2dd0) has exited with code 0 (0x0).
4
5
A first chance exception of type 'System.InvalidCastException' occurred in itext.kernel.dll

Related

UI thread slow to respond to Progress updaters on async Task method using VS2022 & Net6.0

I’ve run into a performance obstacle and I’m uncertain of the cause, all of this is running under VS2022 & Net6.0. As this is my 1st time using this combination of a modal windows form, and progress bar, with the work running on a background thread and two Progress objects updating the UI, the progress bar, and a text label, I don’t know where to attack the problem. Prior to placing the workload on a background thread, everything was snappy, searching a thousand files with about 600 lines of text in each, in about a minute. Naturally, the windows form was frozen during this, which is why the workload was placed on a background thread.
After doing so, the workload will be 25-50% complete before the UI starts displaying the values from the Progress objects, and overall, the entire process now takes 10x as long to complete. Progress objects aren’t skipping over any values sent to them, the UI thread just seems slow in getting the information. Likewise, if I try to drag the modal form to a new spot on the desktop it’s unresponsive for 20—30 seconds before it finally moves. One more thing, I can step through the code on the background thread and see it calling the Progress updaters, but the UI thread is just very slow in responding to them.
I could use some suggestions on how to uncover the problem or if clearly evident, point out where the likely problem could be. Here are the essential controls and methods used.
public class SearchProgressForm : Form
{
private System.Windows.Forms.Button btnSearch = new Button();
private System.Windows.Forms.TextBox txtTextSearch = new TextBox();
private System.Windows.Forms.Label lblSearchFile = new Label();
private System.Windows.Forms.ProgressBar SearchProgressBar = new ProgressBar();
public event LogSearchEventHandler SearchSucceededEvent;
protected void OnSearchSucceeded(LogSearchEventArguments p_eventArguments)
{
LogSearchEventHandler handler = SearchSucceededEvent;
if (handler != null)
{
handler(this, p_eventArguments);
}
}
private void InitializeComponent()
{
this.btnSearch.Name = "btnSearch";
this.btnSearch.Text = "Search";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
this.lblSearchFile.Text = "Searching File: ";
this.txtTextSearch.Text = "search string";
}
public SearchProgressForm() { }
private void btnSearch_Click(object sender, EventArgs e)
{
this.SearchByText(this.txtTextSearch.Text);
}
private void SearchByText(string p_searchParameter)
{
// Setup a progress report for thr ProgressBar
var _progressBarUpdate = new Progress<int>(value =>
{
this.SearchProgressBar.Value = value;
this.SearchProgressBar.Refresh();
});
var _progressFileNameUpdate = new Progress<string>(value =>
{
this.lblSearchFile.Text = "Searching File For : " + value;
this.lblSearchFile.Refresh();
});
// Start search on a backgroud thread and report progress as it occurs
Task.Run(async () => await this.SearchByStringAsync(p_searchParameter, _progressBarUpdate, _progressFileNameUpdate));
}
private async Task SearchByStringAsync(string p_searchParameter, IProgress<int> p_progressBar, IProgress<string> p_progressFileName)
{
await Task.Delay(1);
TextFileReader textFileReader = new TextFileReader();
LogSearchEventArguments logSearchEventArguments = null;
long _sessionloopCount = 0;
long _totalTextLinesCount = this.GetTotalSearchCount(p_searchParameter, SearchType.TextString);
// Get file names from SQL table
var _logFiles = DataOperations.LogFileSortableList(null);
foreach (var log in _logFiles)
{
// Format a file name to be read from the file system
string _fileName = log.Directory + "\\" + log.FileName;
p_progressFileName.Report(log.FileName);
// If we've raised an event for this file, then stop iterating over remaning text
if (logSearchEventArguments != null)
{
logSearchEventArguments = null;
break;
}
// Read in file contents from file system
List<string> _fileContents = textFileReader.ReadAndReturnStringList(_fileName);
long _fileTotalRecordCount = _fileContents.Count;
long _fileRecordCount = 0;
foreach (var _line in _fileContents)
{
if (_line.ToUpper().Contains(p_searchParameter.ToUpper()))
{
// Raise an event so search parameter and file name can be captured in another form
logSearchEventArguments =
new LogSearchEventArguments
(
"TextSearch", p_searchParameter, SearchType.TextString, true, log,
new DateTime(
Convert.ToInt32("20" + log.FileName.Substring(14, 2)),
Convert.ToInt32(log.FileName.Substring(16, 2)),
Convert.ToInt32(log.FileName.Substring(18, 2)))
);
// We found a match, so no further searching is needed in this log file,
// and it's been flagged in the DB, so raise the event to save search parameter and file name
// then break out of this loop to get the next file to search in.
this.OnSearchSucceeded(logSearchEventArguments);
break;
}
// These calcs are based on actual searches performed
_fileRecordCount++;
_sessionloopCount++;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
// Because we exit a search as soon as the 1st match is made, need to resynch all counts
// and update the progress bar accordingly
if (_fileRecordCount < _fileTotalRecordCount)
{
long _countDifference = _fileTotalRecordCount - _fileRecordCount;
// Add count difference to sessionLoopCount and update progress bar
_sessionloopCount += _countDifference;
p_progressBar.Report(Convert.ToInt32((_sessionloopCount * 100) / _totalTextLinesCount));
}
}
//Search is complete set Progress to 100% and report before exiting
p_progressBar.Report(100);
// Close the modal SearchForm and exit
this.Close();
}
}
I solved this problem but I'm still not certain of what caused it. I eliminated the method "private void SearchByText(string p_searchParameter)" and moved the code there into the btnSearch_Click event handler so I could call my background worker "SearchByStringAsync" directly from the button click event handler.
I also updated the EFCore NuGet Packages, which were version Net6.0 to version 6.0.4, because of single line of code in my Async background method, "var _logFiles = DataOperations.LogFileSortableList(null)".
That call returned a Sortable BindingList, using BindingList <T>. Between the NuGet updates and a minor change on a custom comparer method in my BindingList <T> class, the windows modal form now updates the ProgressBar and Label text as expected, and the form now responds immediately to user interaction.

Multiple Backgroundworker threads in a single Backgroundworker thread

I have an issue here with multi-threading. Tried using both backgroundworker and threads.
Objective: Select an item from a combo-box and click a button to trigger multiple backup file restores into the MSSQL Server. The intention is to popup as many popups as there are Backup files to restore. The main window starts a backgroundworker, showing the overall progress, while the child threads result in non-modal child popups representing each restoration process with progress. This works fine if run serially (without threads/backgroundworker). My intention is to run a bunch of parallel popups, so that the restoration is much more quick.
Problem Statement: My intention is to run a bunch of parallel popups, so that the restoration is much more quick instead of running serially. While trying to debug, its a chaotic break-point show that the Visual Studio shows up (perhaps to represent multiple threads in parallel). But the ultimate goal is not being achieved. Can anybody help me in this regard?
- Code Extracts
Here is the code extract, which I've done and this works in a serial fashion. But as soon as I put the code for multi-threading, nothing works. Only the popups appear, but no processing happens.
This is the button click event, which starts the whole process
private void btnSnapshot_Click(object sender, EventArgs e)
{
this.SetPanelEnabledProperty(false); // Disable All Controls on the main window
// Select the text against which the DATABASE Backup Files are to be picked
// Start the main background worker process, which in turn will trigger few other child threads
BGWrk.RunWorkerAsync(2000);
BGWrk.DoWork += new DoWorkEventHandler(BGWrk_DoWork);
BGWrk.ProgressChanged += new ProgressChangedEventHandler(BGWrk_ProgressChanged);
BGWrk.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(BGWrk_RunWorkerCompleted);
BackgroundWorker helperBW = sender as BackgroundWorker;
BGWrk.WorkerReportsProgress = true;
BGWrk.WorkerSupportsCancellation = true;
}
private void BGWrk_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker helperBW = sender as BackgroundWorker;
int arg = (int)e.Argument;
//Call the method that invokes the popup window instances in a loop, for each file found for the SnapShotName selected in the combobox
ParallelRestoreSnapshot();
if (helperBW.CancellationPending)
{
e.Cancel = true;
}
}
// This method will create backgroundworker instances and in turn the Do_Work events of those backgroundworkers will call the popup against each backup file.
private bool ParallelRestoreSnapshot()
{
FileOperations FIO = new FileOperations();
if (SelectedSnapShot != null && SelectedSnapShot != "None")
{
string[] sBakFiles;
sBakFiles = FIO.GetListOfBackupFiles(sEntireBackupFilePath);
try
{
progressPopupsList = new List<FrmProgressPopup>();
for (int aIndex = 0; aIndex < sBakFiles.Length; aIndex++)
{
BackgroundWorker bgPopups = new BackgroundWorker();
BAKFileName = sBakFiles[aIndex];
bgPopups.RunWorkerAsync(2000);
bgPopups.DoWork += new DoWorkEventHandler(bgPopups_DoWork);
bgPopups.ProgressChanged += new ProgressChangedEventHandler(bgPopups_ProgressChanged);
bgPopups.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(bgPopups_RunWorkerCompleted);
bgPopups.WorkerReportsProgress = true;
bgPopups.WorkerSupportsCancellation = true;
}
retVal = true;
}
catch (Exception exc)
{
MessageBox.Show("Error while Restoring: " + exc.Message, "Exception encountered", MessageBoxButtons.OK, MessageBoxIcon.Error);
//goto NextDB;
return false;
}
}
FIO = null;
return retVal;
}
// This DoWork event calls a method GeneratePopupInstances which makes copies of a window, which is shown as non-modal
private void bgPopups_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker helperBW = sender as BackgroundWorker;
int arg = (int)e.Argument;
//BackgroundProcessLogicMethod(helperBW, arg);
GeneratePopupInstances();
if (helperBW.CancellationPending)
{
e.Cancel = true;
}
}

JavaFX: Platform.runLater(task) not recognized for task = new FutureTask<>(new Runnable() {....}?

Over the last two weeks I have studied 10 different ways to avoid problems with sleep(). The concept of running a block of code on the UI Thread that cannot be interrupted seems the most practical. So I have proceeded to create a FutureTask<Void> object that contains the code not to be interrupted before completed. The code in for loops, pixelArray[r][c].setFill(color) sets the new colors for Circle Objects in a Grid Array that's 32x64. This has always failed to display the colors when just sleep(5000) is invoked between the pixel art files, FileChooser selects and assigns to List<File> selectedFiles. Unfortunately the following code will not compile because runLater in the linePlatform.runLater(diplayFileTask); can't be resolved in the following code:
public class PlayPlaylist{
public static List<File> selectedFiles;
public static void play() throws ExecutionException {
FileChooser fileChooser = new FileChooser();
fileChooser.setInitialDirectory(new File("C:\\ProgramData\\L1 Art Files\\"));
fileChooser.setTitle("Play One or More Pixel Art Files");
List<File> selectedFiles = fileChooser.showOpenMultipleDialog(null);
for (File selectedFile : selectedFiles) {
try {
displayFile(selectedFile.getPath());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
public static void displayFile( String pathName) throws IOException, InterruptedException, ExecutionException {
FutureTask<Void> displayFileTask = new FutureTask<>(new Runnable() {
#Override
public void run() {
path = Paths.get(pathName);
try {
pixelByteArray = Files.readAllBytes(path);
} catch (IOException e) {
e.printStackTrace();
}
int cnt = 0;
for (int r = 0; r < row; r++) {
for (int c = 0; c < col; c++) {
//int i = r * col + c;
//System.out.println("\nr = " + r + " c = " + c);
String hexRGB = String.format("#%02X%02X%02X",
pixelByteArray[cnt++], //red
pixelByteArray[cnt++], //green
pixelByteArray[cnt++]); //blue
Color color = Color.valueOf(hexRGB);
//System.out.println("\ncolor is " + color);
pixelArray[r][c].setFill(color);
}
}
String fileName = path.getFileName().toString();
window.setTitle(MessageFormat.format("Pixel Array {0} x {1} File: {2}", Integer.toString(row), Integer.toString(col), fileName));
}
}, null); // displayFile
Platform.runLater(displayFileTask);
displayFileTask.get();
sleep(5000);
}
I've followed the example(s) closely in Stack Overflow and fail to see the problem(s).
I have more details on past attempts posted on Stack Overflow at: Wait() & Sleep() Not Working As Thought.
I also have the two UI windows posted on the web at: Virtual Art. I think the pixel art shown in the Pixel Array window clarifies the goal of creating a user-defined slide show.
Can anyone correct my errors? Do you think my sleep(5000) is in the best location?
Answering James_D's questions. This is my best solution to your answer at my first post, Wait() & Sleep() Not Working As Thought. I was actually following your logic and code posted at, java thread immediately update UI.
I save and display pixel art files that are 32x64. You can see an example posted on the Virtual Art website. I thought it would be straight forward to create a slide show under Playlist, click Play. I would use the same class and OpenFile(pathname) method in a for loop to display each file selected and placed in the ArrayList<> but pause by putting Thread.sleep(5000) in the loop.
As you pointed out, this doesn't work, as I best understand, because the Thread.sleep(5000) interrupts the UI Thread causing a "skip" over of just the display code of all the files looped through. But last pixel art file will appear after 5 secs.
I thought your answer in the post referenced above applied: You create a block of code using FutureTask<Void> and Platform.runLater<task> that can't be interrupted until completed. I thought the FutureTask<Void> runs on the UI Thread and would finish displaying the pixel art file before Thread.sleep(5000) could interrupt.
At 68 and retired, I'm new to JavaFX and trying to develop this RGB LED product that can be programmed with a basic pixel editor. Learning JavaFX is a real challenge for me, thanks for your time and patience.

How to work with multiple rss files in j2me(java)

i am developing Rss Feed Reader App in j2me(java) for 2 xml files,but my for loop is
having a problem,xml file is giving null,when i run my application ,control is not going to this method in my loop getXMLFeed(url1); ,instead of that it is completing for loop.can any one help?is my looping is correct?once check my source Code?i am having problem with for loop
check my source code:
urls = new String[2];//Array Declaration
urls[0] = "http://www.teluguone.com/news/tonefeeds/topnews/topnews-20.rss";
urls[1] = "http://www.teluguone.com/news/tonefeeds/topstory/topstory-25.rss";
for (int i = 0; i < urls.length; i++) //iterration
{
myThread = new ParseThread(this);
myThread.getXMLFeed(url1);
myDysplay.setCurrent(mform);
}
public void getXMLFeed(final String url) {
Thread t = new Thread() {
public void run() {
myConnection = (HttpConnection) Connector.open(url);//HttpConnection
InputStream stream = myConnection.openInputStream();
ParseXMLFeed(stream);
}
Maybe you just forgot to paste the line, but it seems that you are no calling t.start() inside getXMLFeed method.

update pathgraphic only

I use the following code to draw line as following
private void Form1_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
path = new GraphicsPath(new Point[]{ new Point(10, 10),
new Point(100, 100) } ,
new byte[] {(byte)PathPointType.Start,
(byte)PathPointType.Line });
e.Graphics.DrawPath(Pens.Red, path);
}
I need when click a button to change the path and redraw it only so I use
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < path.PointCount; i++)
{
path.PathPoints[i].X += 100;
path.PathPoints[i].Y += 100;
}
Invalidate();
//path.
}
the problem no effect happened, and I don't want to refresh the container I draw on it
First, it will not give you any effect since you always create a new path in OnPaint. As a result you have the same picture. In order to change it you need at least move your path creation to the constructor or another initialization method
Second, PathPoint is an array of PointF, PointF is a structure, therefore it is immutable and you will not get a new point in array by doing so - PathPoints[i].X += 10

Resources