PDFTextSearch.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. using ComPDFKit.Import;
  2. using ComPDFKit.NativeMethod;
  3. using ComPDFKit.PDFDocument;
  4. using ComPDFKit.PDFPage;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Text.RegularExpressions;
  9. using System.Threading;
  10. using System.Windows.Media;
  11. using System.Windows;
  12. namespace ComPDFKit.Tool
  13. {
  14. /// <summary>
  15. /// This class is about search result object.
  16. /// </summary>
  17. public class TextSearchItem
  18. {
  19. /// <summary>
  20. /// Page index
  21. /// </summary>
  22. public int PageIndex;
  23. /// <summary>
  24. /// The bounds of the selection on the page(PDF 72DPI)
  25. /// </summary>
  26. public Rect TextRect;
  27. /// <summary>
  28. /// The text contains in the selection
  29. /// </summary>
  30. public string TextContent;
  31. /// <summary>
  32. /// Page rotation angle
  33. /// </summary>
  34. public int PageRotate;
  35. public void CreatePaintBrush(Color color)
  36. {
  37. Application.Current.Dispatcher.Invoke(() =>
  38. {
  39. this.PaintBrush = new SolidColorBrush(color);
  40. });
  41. }
  42. public SolidColorBrush PaintBrush { get; private set; } = Brushes.Transparent;
  43. public void CreateBorderBrush(Color color)
  44. {
  45. Application.Current.Dispatcher.Invoke(() =>
  46. {
  47. this.BorderBrush = new SolidColorBrush(color);
  48. });
  49. }
  50. public SolidColorBrush BorderBrush { get; private set; } = Brushes.Transparent;
  51. public int BorderThickness;
  52. public Thickness Padding;
  53. }
  54. /// <summary>
  55. /// Result of text search
  56. /// </summary>
  57. public class TextSearchResult
  58. {
  59. /// <summary>
  60. /// Start page index
  61. /// </summary>
  62. public int StartPage;
  63. /// <summary>
  64. /// End page index
  65. /// </summary>
  66. public int EndPage;
  67. /// <summary>
  68. /// Percentage of search process
  69. /// </summary>
  70. public double Percent;
  71. /// <summary>
  72. /// Current page index
  73. /// </summary>
  74. public int CurrentPage;
  75. /// <summary>
  76. /// The number of search result
  77. /// </summary>
  78. public int TotalCount;
  79. /// <summary>
  80. /// The maximum value of search result
  81. /// </summary>
  82. public int PageMaxCount;
  83. /// <summary>
  84. /// Details of current search result
  85. /// </summary>
  86. public Dictionary<int, List<TextSearchItem>> Items = new Dictionary<int, List<TextSearchItem>>();
  87. }
  88. /// <summary>
  89. /// This class is about text search.
  90. /// </summary>
  91. public class PDFTextSearch
  92. {
  93. /// <summary>
  94. /// A notification that a find operation finished working on a page of a document.
  95. /// </summary>
  96. public event EventHandler<TextSearchResult> SearchPercentHandler;
  97. /// <summary>
  98. /// A notification that a find operation cancels.
  99. /// </summary>
  100. public event EventHandler<TextSearchResult> SearchCancelHandler;
  101. /// <summary>
  102. /// A notification that a find operation finished of a document.
  103. /// </summary>
  104. public event EventHandler<TextSearchResult> SearchCompletedHandler;
  105. /// <summary>
  106. /// Associates a CPDFDocument.
  107. /// </summary>
  108. public CPDFDocument TextSearchDocument;
  109. private CPDFDocument mSearchDocument;
  110. private bool isCancel;
  111. private string searchKeywords;
  112. private string password;
  113. private C_Search_Options searchOption;
  114. private int startPage;
  115. private int endPage;
  116. /// <summary>
  117. /// Whether to allow to search.
  118. /// </summary>
  119. public bool CanDoSearch { get; private set; } = true;
  120. /// <summary>
  121. /// Constructor function.
  122. /// </summary>
  123. public PDFTextSearch()
  124. {
  125. }
  126. private void DoWork()
  127. {
  128. endPage = endPage == -1 ? TextSearchDocument.PageCount - 1 : Math.Min(TextSearchDocument.PageCount - 1, endPage);
  129. TextSearchResult searchResult = new TextSearchResult();
  130. searchResult.StartPage = startPage;
  131. searchResult.EndPage = endPage;
  132. double searchPercent = 100;
  133. mSearchDocument = CPDFDocument.InitWithFilePath(TextSearchDocument.FilePath);
  134. if (mSearchDocument.IsLocked && !string.IsNullOrEmpty(password))
  135. {
  136. mSearchDocument.UnlockWithPassword(password);
  137. }
  138. if (mSearchDocument != null && !mSearchDocument.IsLocked)
  139. {
  140. int pageMaxCount = 0;
  141. int recordCount = 0;
  142. searchPercent = 0;
  143. for (int i = startPage; i <= endPage; i++)
  144. {
  145. CPDFTextSearcher mPDFTextSearcher = new CPDFTextSearcher();
  146. CPDFPage pageCore = mSearchDocument.PageAtIndex(i);
  147. if(pageCore == null)
  148. {
  149. continue;
  150. }
  151. CPDFTextPage textPage = pageCore.GetTextPage();
  152. int startIndex = 0;
  153. List<TextSearchItem> textSearchItems = new List<TextSearchItem>();
  154. if (mPDFTextSearcher.FindStart(textPage, searchKeywords, searchOption, startIndex))
  155. {
  156. CRect textRect = new CRect();
  157. string textContent = "";
  158. while (mPDFTextSearcher.FindNext(pageCore, textPage, ref textRect, ref textContent, ref startIndex))
  159. {
  160. if (textContent == "")
  161. {
  162. textContent = searchKeywords;
  163. }
  164. textSearchItems.Add(new TextSearchItem()
  165. {
  166. PageIndex = i,
  167. TextRect = new Rect(textRect.left, textRect.top, textRect.width(), textRect.height()),
  168. TextContent = textContent,
  169. PageRotate = pageCore.Rotation
  170. });
  171. var matchResult = Regex.Matches(textContent, searchKeywords, RegexOptions.IgnoreCase);
  172. if (matchResult != null)
  173. {
  174. recordCount += matchResult.Count;
  175. }
  176. }
  177. }
  178. mPDFTextSearcher.FindClose();
  179. if (textSearchItems.Count > 0)
  180. {
  181. searchResult.Items.Add(i, textSearchItems);
  182. }
  183. pageMaxCount = Math.Max(pageMaxCount, textSearchItems.Count);
  184. searchResult.TotalCount = recordCount;
  185. searchResult.PageMaxCount = pageMaxCount;
  186. if (SearchPercentHandler != null)
  187. {
  188. searchPercent = (int)((i + 1 - startPage) * 100 / (endPage + 1 - startPage));
  189. searchResult.Percent = searchPercent;
  190. searchResult.CurrentPage = i;
  191. SearchPercentHandler.Invoke(this, searchResult);
  192. }
  193. mSearchDocument.ReleasePages(i);
  194. if (isCancel)
  195. {
  196. break;
  197. }
  198. }
  199. searchPercent = 100;
  200. mSearchDocument.Release();
  201. }
  202. if (SearchCompletedHandler != null && !isCancel)
  203. {
  204. searchResult.Percent = searchPercent;
  205. SearchCompletedHandler.Invoke(this, searchResult);
  206. }
  207. if (SearchCancelHandler != null && isCancel)
  208. {
  209. SearchCancelHandler.Invoke(this, searchResult);
  210. }
  211. CanDoSearch = true;
  212. isCancel = false;
  213. }
  214. /// <summary>
  215. /// Cancles a search.
  216. /// </summary>
  217. public void CancleSearch()
  218. {
  219. isCancel = true;
  220. }
  221. /// <summary>
  222. /// Searches the specified string in the document.
  223. /// </summary>
  224. /// <param name="search">Search the specified string</param>
  225. /// <param name="option">Search options</param>
  226. /// <param name="pwd">Document password</param>
  227. /// <param name="startPage">Start page index</param>
  228. /// <param name="endPage">End page index</param>
  229. /// <returns>Returns true on success, false on failure</returns>
  230. public bool SearchText(string search, C_Search_Options option, string pwd = "", int startPage = 0, int endPage = -1)
  231. {
  232. if (CPDFSDKVerifier.TextSearch == false)
  233. {
  234. Trace.WriteLine("Your license does not support this feature, please upgrade your license privilege.");
  235. return false;
  236. }
  237. if (CanDoSearch)
  238. {
  239. searchKeywords = search;
  240. password = pwd;
  241. searchOption = option;
  242. this.startPage = startPage;
  243. this.endPage = endPage;
  244. isCancel = false;
  245. CanDoSearch = false;
  246. Thread taskThread = new Thread(DoWork);
  247. taskThread.Start();
  248. return true;
  249. }
  250. return false;
  251. }
  252. }
  253. }