From 7e24e989fbc54d16a8ca3171f1795b158c888aca Mon Sep 17 00:00:00 2001 From: Michael Vrhel Date: Wed, 19 Mar 2014 14:38:37 -0700 Subject: Addition of code and UI elements for performing text search --- platform/winrt/gsview/MainWindow.xaml | 133 ++++++++++--- platform/winrt/gsview/MainWindow.xaml.cs | 267 ++++++++++++++++++++++++-- platform/winrt/gsview/RectList.cs | 31 ++- platform/winrt/gsview/mudocument.cs | 50 ++++- platform/winrt/libmupdf_winRT.vcxproj.filters | 3 + platform/winrt/mupdfnet/mupdfnet.cpp | 32 +++ platform/winrt/mupdfnet/mupdfnet.h | 5 +- 7 files changed, 473 insertions(+), 48 deletions(-) (limited to 'platform/winrt') diff --git a/platform/winrt/gsview/MainWindow.xaml b/platform/winrt/gsview/MainWindow.xaml index 45459d02..959e4eb0 100644 --- a/platform/winrt/gsview/MainWindow.xaml +++ b/platform/winrt/gsview/MainWindow.xaml @@ -5,12 +5,59 @@ - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -309,6 +356,66 @@ + + + + + + + + + Search: + + + + + + + + + + + + + + Zoom: + + + + @@ -335,7 +442,7 @@ Cancel - + @@ -418,24 +525,6 @@ - - - - - - - - Zoom: - - - - rectangles; + public int num_rects; + } + public partial class MainWindow : Window { mudocument mu_doc; @@ -166,7 +175,7 @@ namespace gsview int m_contents_size; int m_content_item; List m_linkset; - List m_text_list; + List m_text_list = null; private int m_rectlist_page; private List m_content_list; private bool m_file_open; @@ -177,8 +186,8 @@ namespace gsview private bool m_links_on; private int m_search_rect_count; private bool m_page_update; - String m_textcolor; - String m_linkcolor; + String m_textcolor = "#402572AC"; + String m_linkcolor = "#40AC7225"; RenderingStatus_t m_ren_status; private bool m_insearch; private bool m_search_active; @@ -195,12 +204,14 @@ namespace gsview Password m_password = null; bool m_zoomhandled; BackgroundWorker m_thumbworker = null; + BackgroundWorker m_textsearch = null; String m_document_type; Info m_infowindow; OutputIntent m_outputintents; Selection m_selection; private Point startPoint; private Rectangle rect; + String m_prevsearch = null; public MainWindow() { @@ -215,7 +226,6 @@ namespace gsview m_docPages = new Pages(); m_thumbnails = new List(); m_page_link_list = new List>(); - m_text_list = new List(); m_linkset = new List(); m_ghostscript = new ghostsharp(); m_ghostscript.gsUpdateMain += new ghostsharp.gsCallBackMain(gsProgress); @@ -276,7 +286,10 @@ namespace gsview if (m_page_link_list != null && m_page_link_list.Count > 0) m_page_link_list.Clear(); if (m_text_list != null && m_text_list.Count > 0) + { m_text_list.Clear(); + m_text_list = null; + } if (m_linkset != null && m_linkset.Count > 0) m_linkset.Clear(); @@ -807,6 +820,8 @@ namespace gsview status_t code = (status_t)ren_task.Result; if (code == status_t.S_ISOK) { + if (m_docPages[k].TextBox != null) + ScaleTextBox(k); UpdatePage(k, bitmap, ras_size, Page_Content_t.FULL_RESOLUTION, m_doczoom); m_docPages[k].PageRefresh(); if (k == curr_page && scrollto) @@ -877,11 +892,6 @@ namespace gsview } - private void Search(object sender, RoutedEventArgs e) - { - - } - private void ZoomOut(object sender, RoutedEventArgs e) { m_doczoom = m_doczoom - Constants.ZOOM_STEP; @@ -900,11 +910,6 @@ namespace gsview RenderRange(m_currpage, false); } - private void CancelSearchClick(object sender, RoutedEventArgs e) - { - - } - private void gsIO(object gsObject, String mess, int len) { m_gsoutput.Update(mess, len); @@ -1621,7 +1626,6 @@ namespace gsview return; } } - m_selection.Close(); break; case SelectStatus_t.ZOOMIN: @@ -1655,5 +1659,238 @@ namespace gsview { m_outputintents.Show(); } + + /* Search related code */ + private void Search(object sender, RoutedEventArgs e) + { + if (!m_init_done || (m_textsearch != null && m_textsearch.IsBusy)) + return; + + m_textsearch = null; /* Start out fresh */ + if (xaml_SearchControl.Visibility == System.Windows.Visibility.Collapsed) + xaml_SearchControl.Visibility = System.Windows.Visibility.Visible; + else + { + xaml_SearchControl.Visibility = System.Windows.Visibility.Collapsed; + ClearTextSearch(); + } + } + + private void OnSearchBackClick(object sender, RoutedEventArgs e) + { + String textToFind = xaml_SearchText.Text; + TextSearchSetUp(-1, textToFind); + } + + private void OnSearchForwardClick(object sender, RoutedEventArgs e) + { + String textToFind = xaml_SearchText.Text; + TextSearchSetUp(1, textToFind); + } + + /* The thread that is actually doing the search work */ + void SearchWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + List genericlist = e.Argument as List; + int direction = (int) genericlist[0]; + String needle = (String) genericlist[1]; + /* To make sure we get the next page or current page during search */ + int in_search = (int)genericlist[2]; + m_searchpage = m_currpage + direction * in_search; + searchResults_t results = new searchResults_t(); + + /* Break if we find something, get to the end (or start of doc) + * or if we have a cancel occur */ + while (true) + { + int box_count = mu_doc.TextSearchPage(m_searchpage, needle); + int percent; + + if (direction == 1) + percent = (int)(100.0 * ((double)m_searchpage + 1) / (double)m_num_pages); + else + percent = 100 - (int)(100.0 * ((double)m_searchpage) / (double)m_num_pages); + + if (box_count > 0) + { + /* This page has something lets go ahead and extract and + * signal to the UI thread and end this thread */ + results.done = false; + results.num_rects = box_count; + results.page_found = m_searchpage; + results.rectangles = new List(); + + for (int kk = 0; kk < box_count; kk++ ) + { + Point top_left; + Size size; + mu_doc.GetTextSearchItem(kk, out top_left, out size); + var rect = new Rect(top_left, size); + results.rectangles.Add(rect); + } + worker.ReportProgress(percent, results); + break; + } + else + { + /* This page has nothing. Lets go ahead and just update + * the progress bar */ + worker.ReportProgress(percent, null); + if (percent >= 100) + { + results.done = true; + results.needle = needle; + break; + } + m_searchpage = m_searchpage + direction; + } + if (worker.CancellationPending == true) + { + e.Cancel = true; + break; + } + } + e.Result = results; + } + + private void SearchProgressChanged(object sender, ProgressChangedEventArgs e) + { + if (e.UserState == null) + { + /* Nothing found */ + xaml_SearchProgress.Value = e.ProgressPercentage; + } + else + { + m_text_list = new List(); + /* found something go to page and show results */ + searchResults_t results = (searchResults_t)e.UserState; + xaml_SearchProgress.Value = e.ProgressPercentage; + m_currpage = results.page_found; + /* Add in the rectangles */ + for (int kk = 0; kk < results.num_rects; kk++) + { + var rect_item = new RectList(); + rect_item.Scale = m_doczoom; + rect_item.Color = m_textcolor; + rect_item.Height = results.rectangles[kk].Height * m_doczoom; + rect_item.Width = results.rectangles[kk].Width * m_doczoom; + rect_item.X = results.rectangles[kk].X * m_doczoom; + rect_item.Y = results.rectangles[kk].Y * m_doczoom; + rect_item.Index = kk.ToString(); + m_text_list.Add(rect_item); + } + m_docPages[results.page_found].TextBox = m_text_list; + m_docPages[results.page_found].PageRefresh(); + xaml_PageList.ScrollIntoView(m_docPages[results.page_found]); + } + } + + private void SearchCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (e.Cancelled == true) + { + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + } + else + { + searchResults_t results = (searchResults_t) e.Result; + if (results.done == true) + { + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + ShowMessage(NotifyType_t.MESS_STATUS, "End of document search for \"" + results.needle + "\""); + } + } + } + + private void CancelSearchClick(object sender, RoutedEventArgs e) + { + if (m_textsearch != null && m_textsearch.IsBusy) + m_textsearch.CancelAsync(); + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + ClearTextSearch(); + } + + private void ClearTextSearch() + { + for (int kk = 0; kk < m_num_pages; kk++) + { + var temp = m_docPages[kk].TextBox; + if (temp != null) + { + m_docPages[kk].TextBox = null; + m_docPages[kk].PageRefresh(); + } + } + } + + private void ScaleTextBox(int pagenum) + { + var temp = m_docPages[pagenum].TextBox; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = m_doczoom / temp[kk].Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = m_doczoom; + temp[kk].PageRefresh(); + } + m_docPages[pagenum].TextBox = temp; + } + + private void TextSearchSetUp(int direction, String needle) + { + /* Create background task for performing text search. */ + try + { + int in_text_search = 0; + + if (m_textsearch != null && m_textsearch.IsBusy) + return; + + if (m_textsearch != null) + { + in_text_search = 1; + m_textsearch = null; + } + + if (m_prevsearch != null && needle != m_prevsearch) + { + in_text_search = 0; + ClearTextSearch(); + } + + if (m_textsearch == null) + { + m_prevsearch = needle; + m_textsearch = new BackgroundWorker(); + m_textsearch.WorkerReportsProgress = true; + m_textsearch.WorkerSupportsCancellation = true; + var arguments = new List(); + arguments.Add(direction); + arguments.Add(needle); + arguments.Add(in_text_search); + m_textsearch.DoWork += new DoWorkEventHandler(SearchWork); + m_textsearch.RunWorkerCompleted += new RunWorkerCompletedEventHandler(SearchCompleted); + m_textsearch.ProgressChanged += new ProgressChangedEventHandler(SearchProgressChanged); + xaml_SearchGrid.Visibility = System.Windows.Visibility.Visible; + m_textsearch.RunWorkerAsync(arguments); + } + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during text search\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } } } \ No newline at end of file diff --git a/platform/winrt/gsview/RectList.cs b/platform/winrt/gsview/RectList.cs index 3c761876..0cdba66d 100644 --- a/platform/winrt/gsview/RectList.cs +++ b/platform/winrt/gsview/RectList.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.ComponentModel; namespace gsview { - public class RectList + public class RectList : INotifyPropertyChanged { public String Index { @@ -20,25 +21,31 @@ namespace gsview set; } - public int Height + public double Height { get; set; } - public int Width + public double Width { get; set; } - public int X + public double X { get; set; } - public int Y + public double Y + { + get; + set; + } + + public double Scale { get; set; @@ -61,5 +68,19 @@ namespace gsview get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + + public void PageRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("X")); + PropertyChanged(this, new PropertyChangedEventArgs("Height")); + PropertyChanged(this, new PropertyChangedEventArgs("Width")); + PropertyChanged(this, new PropertyChangedEventArgs("Y")); + } + + } } } diff --git a/platform/winrt/gsview/mudocument.cs b/platform/winrt/gsview/mudocument.cs index 0c1f0a6e..35b4d8b9 100644 --- a/platform/winrt/gsview/mudocument.cs +++ b/platform/winrt/gsview/mudocument.cs @@ -93,15 +93,25 @@ namespace gsview int page_width, int page_height, Byte[] bmp_data, int bmp_width, int bmp_height, double scale, bool flipy); + [DllImport("mupdfnet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mTextSearchPage(IntPtr ctx, int page_num, + string needle); + + [DllImport("mupdfnet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern bool mGetTextSearchItem(int k, ref double top_x, + ref double top_y, ref double height, ref double width); + + [DllImport("mupdfnet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void mReleaseTextSearch(); + /* [DllImport("mugs.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern void GetLinks(IntPtr ctx); - [DllImport("mugs.dll", CharSet = CharSet.Auto, - CallingConvention = CallingConvention.StdCall)] - public static extern void GetTextSearch(IntPtr ctx); - [DllImport("mugs.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern void GetHTML(IntPtr ctx); @@ -109,7 +119,6 @@ namespace gsview ~muctx(void); unsigned int GetLinks(int page_num, sh_vector_link links_vec); - int GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec); std::string GetHTML(int page_num); */ @@ -234,5 +243,36 @@ namespace gsview { mReleaseContents(); } + + public int TextSearchPage(int page_num, String needle) + { + int num_found; + lock (m_lock) + { + num_found = mTextSearchPage(mu_object, page_num, needle); + } + return num_found; + } + + public bool GetTextSearchItem(int k, out Point top_left, out Size size_rect) + { + double top_x = 0, top_y = 0 , height = 0, width = 0; + bool found = mGetTextSearchItem(k, ref top_x, ref top_y, ref height, ref width); + + top_left = new Point(); + size_rect = new Size(); + + top_left.X = top_x; + top_left.Y = top_y; + size_rect.Width = width; + size_rect.Height = height; + + return found; + } + + public void ReleaseTextSearch() + { + mReleaseTextSearch(); + } } } diff --git a/platform/winrt/libmupdf_winRT.vcxproj.filters b/platform/winrt/libmupdf_winRT.vcxproj.filters index b89a6288..8ed107bb 100644 --- a/platform/winrt/libmupdf_winRT.vcxproj.filters +++ b/platform/winrt/libmupdf_winRT.vcxproj.filters @@ -31,6 +31,9 @@ {d7d9ecf3-3abb-4238-a833-0c0f8ed08976} + + {631e9425-7a6a-4529-95c8-06ea5b145899} + diff --git a/platform/winrt/mupdfnet/mupdfnet.cpp b/platform/winrt/mupdfnet/mupdfnet.cpp index e5b32e93..621762a2 100644 --- a/platform/winrt/mupdfnet/mupdfnet.cpp +++ b/platform/winrt/mupdfnet/mupdfnet.cpp @@ -16,6 +16,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser } std::shared_ptr> gContents; +std::shared_ptr> gTextResults; char* String_to_char(PCWSTR text) { @@ -146,6 +147,37 @@ SYMBOL_DECLSPEC char* __stdcall mGetContentsItem(int k, int *len, int *page) return retstr; } +SYMBOL_DECLSPEC int __stdcall mTextSearchPage(void *ctx, int page_num, PCWSTR needle) +{ + muctx *mu_ctx = static_cast(ctx); + + sh_vector_text text_smart_ptr_vec(new std::vector()); + gTextResults = text_smart_ptr_vec; + + return mu_ctx->GetTextSearch(page_num, String_to_char(needle), gTextResults); +} + +SYMBOL_DECLSPEC bool __stdcall mGetTextSearchItem(int k, double *top_x, double + *top_y, double *height, double *width) +{ + char* retstr = NULL; + + if (k < 0 || k > gTextResults->size()) + return false; + sh_text muctx_search = gTextResults->at(k); + *top_x = muctx_search->upper_left.X; + *top_y = muctx_search->upper_left.Y; + *width = muctx_search->lower_right.X - muctx_search->upper_left.X; + *height = muctx_search->lower_right.Y - muctx_search->upper_left.Y; + return true; +} + +SYMBOL_DECLSPEC void __stdcall mReleaseTextSearch() +{ + if (gTextResults != nullptr) + gTextResults.reset(); +} + SYMBOL_DECLSPEC void* __stdcall mCreateDisplayList(void *ctx, int page_num, int *page_width, int *page_height) { diff --git a/platform/winrt/mupdfnet/mupdfnet.h b/platform/winrt/mupdfnet/mupdfnet.h index ac869b98..d16a50f8 100644 --- a/platform/winrt/mupdfnet/mupdfnet.h +++ b/platform/winrt/mupdfnet/mupdfnet.h @@ -32,7 +32,10 @@ EXTERN_C SYMBOL_DECLSPEC int __stdcall mRenderPage(void *ctx, int page_num, EXTERN_C SYMBOL_DECLSPEC int __stdcall mGetContents(void *ctx); EXTERN_C SYMBOL_DECLSPEC char* __stdcall mGetContentsItem(int k, int *len, int *page); EXTERN_C SYMBOL_DECLSPEC void __stdcall mReleaseContents(); - +EXTERN_C SYMBOL_DECLSPEC int __stdcall mTextSearchPage(void *ctx, int page_num, PCWSTR needle); +EXTERN_C SYMBOL_DECLSPEC bool __stdcall mGetTextSearchItem(int k, double *top_x, double + *top_y, double *height, double *width); +EXTERN_C SYMBOL_DECLSPEC void __stdcall mReleaseTextSearch(); EXTERN_C SYMBOL_DECLSPEC void* __stdcall mCreateDisplayList(void *ctx, int page_num, int *page_width, int *page_height); EXTERN_C SYMBOL_DECLSPEC int __stdcall mRenderPageMT(void *ctx, void *dlist, -- cgit v1.2.3