Skip to content

Commit

Permalink
- fix UI-vs-BackgroundThreads crashes in annotation report
Browse files Browse the repository at this point in the history
- code review & fix: properly `.Dispose()` any Bitmap or Image. `.Freeze()` the ones we pass on to WPF (UI)
  • Loading branch information
GerHobbelt committed Sep 11, 2021
1 parent d24c78e commit 5703f3f
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 247 deletions.
2 changes: 1 addition & 1 deletion Qiqqa/AnnotationsReportBuilding/AnnotationWorkGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static List<AnnotationWork> GenerateAnnotationWorks(WebLibraryDetail web_
// is the answer to everything and thus also to 'reasonable measure for one page/screen full' ;-P ) we simply DO NOT PASS
// the set on to the query generator-annex-processor call GetLibraryItemsAsCache() but let that one follow its *default*
// behaviour *instead*, which is to dump the entire table in our lap and good riddance.
// for more than 42 documents in the set and medium to huge libraries, this is expected to be 'near enough to optimal'. :-)
// For more than 42 documents in the set and medium to huge libraries, this is expected to be 'near enough to optimal'. :-)
// When you beg to differ, you may. Benchmarks, please! (I know you'll be able to improve on this, surely, but you get my drift:
// is it worth it yet? Or are there other areas with bigger fish to fry? ;-)
//
Expand Down
90 changes: 55 additions & 35 deletions Qiqqa/AnnotationsReportBuilding/AsyncAnnotationReportBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,9 @@ internal static void BuildReport(WebLibraryDetail web_library_detail, List<PDFDo
if ((!annotation_report_options.ObeySuppressedImages || !pdf_annotation.AnnotationReportSuppressImage) && !annotation_report_options.SuppressAllImages)
{
Image image = new Image();
MouseWheelDisabler.DisableMouseWheelForControl(image);
MouseWheelDisabler.DisableMouseWheelForControl(image);
image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageWaiting);
image.Source.Freeze();
BlockUIContainer image_container = new BlockUIContainer(image);
Figure floater = new Figure(image_container);
floater.HorizontalAnchor = FigureHorizontalAnchor.PageCenter;
Expand Down Expand Up @@ -558,22 +559,12 @@ private static void BackgroundRenderImages_BACKGROUND(FlowDocument flow_document
{
try
{
// Clear the waiting for processing text
WPFDoEvents.InvokeInUIThread(() =>
{
annotation_work.processing_error.Text = "";
});


if (pdf_document.DocumentExists)
{
// Fill in the paragraph text
if (null != annotation_work.annotation_paragraph)
{
WPFDoEvents.InvokeInUIThread(() =>
{
BuildAnnotationWork_FillAnnotationText(pdf_document, pdf_annotation, annotation_work);
});
BuildAnnotationWork_FillAnnotationText(pdf_document, pdf_annotation, annotation_work);
}

if (null != annotation_work.report_floater)
Expand All @@ -600,6 +591,7 @@ private static void BackgroundRenderImages_BACKGROUND(FlowDocument flow_document
WPFDoEvents.InvokeInUIThread(() =>
{
annotation_work.report_image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageError);
ASSERT.Test(annotation_work.report_image.Source.IsFrozen);
annotation_work.processing_error.Text = "There was a problem while rendering this annotation.";
});
}
Expand Down Expand Up @@ -650,9 +642,16 @@ private static void BackgroundRenderImages_BACKGROUND(FlowDocument flow_document

private static void BuildAnnotationWork_FillAnnotationText(PDFDocument pdf_document, PDFAnnotation pdf_annotation, AnnotationWorkGenerator.AnnotationWork annotation_work)
{
WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

int current_color = -1;
Run current_run = new Run();
annotation_work.annotation_paragraph.Inlines.Add(current_run);
Run current_run = null;
WPFDoEvents.InvokeInUIThread(() =>
{
current_run = new Run();
annotation_work.annotation_paragraph.Inlines.Add(current_run);
});
ASSERT.Test(current_run != null);

try
{
Expand Down Expand Up @@ -680,18 +679,21 @@ private static void BuildAnnotationWork_FillAnnotationText(PDFDocument pdf_docum
// If the colour has change
if (new_color != current_color)
{
// Emit the existing span
current_run.Text = current_sb.ToString();

// Create the new span
current_color = new_color;
current_run = new Run();
current_sb = new StringBuilder();
annotation_work.annotation_paragraph.Inlines.Add(current_run);
if (-1 != new_color)
WPFDoEvents.InvokeInUIThread(() =>
{
current_run.Background = new SolidColorBrush(StandardHighlightColours.GetColor(new_color));
}
// Emit the existing span
current_run.Text = current_sb.ToString();
// Create the new span
current_color = new_color;
current_run = new Run();
current_sb = new StringBuilder();
annotation_work.annotation_paragraph.Inlines.Add(current_run);
if (-1 != new_color)
{
current_run.Background = new SolidColorBrush(StandardHighlightColours.GetColor(new_color));
}
});
}

// Tidy up dashes on line-ends
Expand All @@ -709,24 +711,42 @@ private static void BuildAnnotationWork_FillAnnotationText(PDFDocument pdf_docum
}
}

// Emit the final span
current_run.Text = current_sb.ToString();
WPFDoEvents.InvokeInUIThread(() =>
{
// Clear the waiting for processing text
annotation_work.processing_error.Text = "";
// Emit the final span
current_run.Text = current_sb.ToString();
});
}
else
{
Run run = new Run();
run.Background = Brushes.Orange;
run.Text = String.Format("OCR is not complete for page {0}", pdf_annotation.Page);
annotation_work.annotation_paragraph.Inlines.Add(run);
WPFDoEvents.InvokeInUIThread(() =>
{
// Clear the waiting for processing text
annotation_work.processing_error.Text = "";
Run run = new Run();
run.Background = Brushes.Orange;
run.Text = String.Format("OCR is not complete for page {0}", pdf_annotation.Page);
annotation_work.annotation_paragraph.Inlines.Add(run);
});
}
}
catch (Exception ex)
{
Logging.Error(ex, "There was a problem while trying to add annotation text for document {0}", pdf_document.Fingerprint);
Run run = new Run();
run.Background = Brushes.Red;
run.Text = String.Format("Processing error: {0}", ex.Message);
annotation_work.annotation_paragraph.Inlines.Add(run);
WPFDoEvents.InvokeInUIThread(() =>
{
// Clear the waiting for processing text
annotation_work.processing_error.Text = "";
Run run = new Run();
run.Background = Brushes.Red;
run.Text = String.Format("Processing error: {0}", ex.Message);
annotation_work.annotation_paragraph.Inlines.Add(run);
});
}
}

Expand Down
13 changes: 9 additions & 4 deletions Qiqqa/Common/MainWindowServiceDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,16 @@ public void GenerateAnnotationReport(WebLibraryDetail web_library_detail, List<P

private void OnShowTagOptionsComplete(WebLibraryDetail web_library_detail, List<PDFDocument> pdf_documents, AnnotationReportOptions annotation_report_options)
{
AsyncAnnotationReportBuilder.BuildReport(web_library_detail, pdf_documents, annotation_report_options, delegate (AsyncAnnotationReportBuilder.AnnotationReport annotation_report)
SafeThreadPool.QueueSafeExecUserWorkItem(() =>
{
ReportViewerControl report_view_control = new ReportViewerControl(annotation_report);
string title = String.Format("Annotation report at {0}", DateTime.UtcNow.ToShortTimeString());
OpenNewWindow(title, Icons.GetAppIcon(Icons.ModulePDFAnnotationReport), true, true, report_view_control);
AsyncAnnotationReportBuilder.BuildReport(web_library_detail, pdf_documents, annotation_report_options, delegate (AsyncAnnotationReportBuilder.AnnotationReport annotation_report)
{
WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();
ReportViewerControl report_view_control = new ReportViewerControl(annotation_report);
string title = String.Format("Annotation report at {0}", DateTime.UtcNow.ToShortTimeString());
OpenNewWindow(title, Icons.GetAppIcon(Icons.ModulePDFAnnotationReport), true, true, report_view_control);
});
});
}

Expand Down
2 changes: 2 additions & 0 deletions Qiqqa/DocumentLibrary/LibraryFilter/LibraryFilterHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static Inline GetClearImageInline(string header, MouseButtonEventHandler
uicont.BaselineAlignment = BaselineAlignment.Center;
uicont.Background = Brushes.Transparent;
Image image = GetClearImage(header, on_click);
image.Source.Freeze();
uicont.Child = image;
return uicont;
}
Expand All @@ -36,6 +37,7 @@ public static Image GetClearImage(string header, MouseButtonEventHandler on_clic
image.ToolTip = header;
image.Cursor = Cursors.Hand;
image.Source = Icons.GetAppIcon(Icons.Clear);
image.Source.Freeze();
image.MouseDown += on_click;
return image;
}
Expand Down
Loading

0 comments on commit 5703f3f

Please sign in to comment.