├── .gitignore
├── App.config
├── LICENSE
├── NativeMethods.Pdfium.cs
├── NativeMethods.cs
├── PdfBookmarkCollection.cs
├── PdfDocument.cs
├── PdfError.cs
├── PdfException.cs
├── PdfInformation.cs
├── PdfLibrary.cs
├── PdfMatches.cs
├── PdfPage.cs
├── PdfPageLink.cs
├── PdfPageLinks.cs
├── PdfPoint.cs
├── PdfRectangle.cs
├── PdfRenderFlags.cs
├── PdfRotation.cs
├── PdfTextSpan.cs
├── PdfiumLight.csproj
├── PdfiumLight.nuspec
├── PdfiumLight.sln
├── README.md
├── StreamExtensions.cs
├── StreamManager.cs
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/csharp
3 |
4 | ### Csharp ###
5 | ## Ignore Visual Studio temporary files, build results, and
6 | ## files generated by popular Visual Studio add-ons.
7 | ##
8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # .NET Core
50 | project.lock.json
51 | project.fragment.lock.json
52 | artifacts/
53 | **/Properties/launchSettings.json
54 |
55 | *_i.c
56 | *_p.c
57 | *_i.h
58 | *.ilk
59 | *.meta
60 | *.obj
61 | *.pch
62 | *.pdb
63 | *.pgc
64 | *.pgd
65 | *.rsp
66 | *.sbr
67 | *.tlb
68 | *.tli
69 | *.tlh
70 | *.tmp
71 | *.tmp_proj
72 | *.log
73 | *.vspscc
74 | *.vssscc
75 | .builds
76 | *.pidb
77 | *.svclog
78 | *.scc
79 |
80 | # Chutzpah Test files
81 | _Chutzpah*
82 |
83 | # Visual C++ cache files
84 | ipch/
85 | *.aps
86 | *.ncb
87 | *.opendb
88 | *.opensdf
89 | *.sdf
90 | *.cachefile
91 | *.VC.db
92 | *.VC.VC.opendb
93 |
94 | # Visual Studio profiler
95 | *.psess
96 | *.vsp
97 | *.vspx
98 | *.sap
99 |
100 | # TFS 2012 Local Workspace
101 | $tf/
102 |
103 | # Guidance Automation Toolkit
104 | *.gpState
105 |
106 | # ReSharper is a .NET coding add-in
107 | _ReSharper*/
108 | *.[Rr]e[Ss]harper
109 | *.DotSettings.user
110 |
111 | # JustCode is a .NET coding add-in
112 | .JustCode
113 |
114 | # TeamCity is a build add-in
115 | _TeamCity*
116 |
117 | # DotCover is a Code Coverage Tool
118 | *.dotCover
119 |
120 | # Visual Studio code coverage results
121 | *.coverage
122 | *.coveragexml
123 |
124 | # NCrunch
125 | _NCrunch_*
126 | .*crunch*.local.xml
127 | nCrunchTemp_*
128 |
129 | # MightyMoose
130 | *.mm.*
131 | AutoTest.Net/
132 |
133 | # Web workbench (sass)
134 | .sass-cache/
135 |
136 | # Installshield output folder
137 | [Ee]xpress/
138 |
139 | # DocProject is a documentation generator add-in
140 | DocProject/buildhelp/
141 | DocProject/Help/*.HxT
142 | DocProject/Help/*.HxC
143 | DocProject/Help/*.hhc
144 | DocProject/Help/*.hhk
145 | DocProject/Help/*.hhp
146 | DocProject/Help/Html2
147 | DocProject/Help/html
148 |
149 | # Click-Once directory
150 | publish/
151 |
152 | # Publish Web Output
153 | *.[Pp]ublish.xml
154 | *.azurePubxml
155 | # TODO: Uncomment the next line to ignore your web deploy settings.
156 | # By default, sensitive information, such as encrypted password
157 | # should be stored in the .pubxml.user file.
158 | #*.pubxml
159 | *.pubxml.user
160 | *.publishproj
161 |
162 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
163 | # checkin your Azure Web App publish settings, but sensitive information contained
164 | # in these scripts will be unencrypted
165 | PublishScripts/
166 |
167 | # NuGet Packages
168 | *.nupkg
169 | # The packages folder can be ignored because of Package Restore
170 | **/packages/*
171 | # except build/, which is used as an MSBuild target.
172 | !**/packages/build/
173 | # Uncomment if necessary however generally it will be regenerated when needed
174 | #!**/packages/repositories.config
175 | # NuGet v3's project.json files produces more ignorable files
176 | *.nuget.props
177 | *.nuget.targets
178 |
179 | # Microsoft Azure Build Output
180 | csx/
181 | *.build.csdef
182 |
183 | # Microsoft Azure Emulator
184 | ecf/
185 | rcf/
186 |
187 | # Windows Store app package directories and files
188 | AppPackages/
189 | BundleArtifacts/
190 | Package.StoreAssociation.xml
191 | _pkginfo.txt
192 |
193 | # Visual Studio cache files
194 | # files ending in .cache can be ignored
195 | *.[Cc]ache
196 | # but keep track of directories ending in .cache
197 | !*.[Cc]ache/
198 |
199 | # Others
200 | ClientBin/
201 | ~$*
202 | *~
203 | *.dbmdl
204 | *.dbproj.schemaview
205 | *.jfm
206 | *.pfx
207 | *.publishsettings
208 | orleans.codegen.cs
209 |
210 | # Since there are multiple workflows, uncomment next line to ignore bower_components
211 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
212 | #bower_components/
213 |
214 | # RIA/Silverlight projects
215 | Generated_Code/
216 |
217 | # Backup & report files from converting an old project file
218 | # to a newer Visual Studio version. Backup files are not needed,
219 | # because we have git ;-)
220 | _UpgradeReport_Files/
221 | Backup*/
222 | UpgradeLog*.XML
223 | UpgradeLog*.htm
224 |
225 | # SQL Server files
226 | *.mdf
227 | *.ldf
228 | *.ndf
229 |
230 | # Business Intelligence projects
231 | *.rdl.data
232 | *.bim.layout
233 | *.bim_*.settings
234 |
235 | # Microsoft Fakes
236 | FakesAssemblies/
237 |
238 | # GhostDoc plugin setting file
239 | *.GhostDoc.xml
240 |
241 | # Node.js Tools for Visual Studio
242 | .ntvs_analysis.dat
243 | node_modules/
244 |
245 | # Typescript v1 declaration files
246 | typings/
247 |
248 | # Visual Studio 6 build log
249 | *.plg
250 |
251 | # Visual Studio 6 workspace options file
252 | *.opt
253 |
254 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
255 | *.vbw
256 |
257 | # Visual Studio LightSwitch build output
258 | **/*.HTMLClient/GeneratedArtifacts
259 | **/*.DesktopClient/GeneratedArtifacts
260 | **/*.DesktopClient/ModelManifest.xml
261 | **/*.Server/GeneratedArtifacts
262 | **/*.Server/ModelManifest.xml
263 | _Pvt_Extensions
264 |
265 | # Paket dependency manager
266 | .paket/paket.exe
267 | paket-files/
268 |
269 | # FAKE - F# Make
270 | .fake/
271 |
272 | # JetBrains Rider
273 | .idea/
274 | *.sln.iml
275 |
276 | # CodeRush
277 | .cr/
278 |
279 | # Python Tools for Visual Studio (PTVS)
280 | __pycache__/
281 | *.pyc
282 |
283 | # Cake - Uncomment if you are using it
284 | # tools/**
285 | # !tools/packages.config
286 |
287 | # Telerik's JustMock configuration file
288 | *.jmconfig
289 |
290 | # BizTalk build output
291 | *.btp.cs
292 | *.btm.cs
293 | *.odx.cs
294 | *.xsd.cs
295 |
296 |
297 | # End of https://www.gitignore.io/api/csharp
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/NativeMethods.Pdfium.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using System.Text;
5 |
6 | #pragma warning disable 1591
7 |
8 | namespace PdfiumLight
9 | {
10 | public partial class NativeMethods
11 | {
12 | // Interned strings are cached over AppDomains. This means that when we
13 | // lock on this string, we actually lock over AppDomain's. The Pdfium
14 | // library is not thread safe, and this way of locking
15 | // guarantees that we don't access the Pdfium library from different
16 | // threads, even when there are multiple AppDomain's in play.
17 | private static readonly string LockString = string.Intern("e362349b-001d-4cb2-bf55-a71606a3e36f");
18 |
19 | public static void FPDF_AddRef()
20 | {
21 | lock (LockString)
22 | {
23 | Imports.FPDF_AddRef();
24 | }
25 | }
26 |
27 | public static void FPDF_Release()
28 | {
29 | lock (LockString)
30 | {
31 | Imports.FPDF_Release();
32 | }
33 | }
34 |
35 | public static IntPtr FPDF_LoadMemDocument(SafeHandle data_buf, int size, string password)
36 | {
37 | lock (LockString)
38 | {
39 | return Imports.FPDF_LoadMemDocument(data_buf, size, password);
40 | }
41 | }
42 |
43 | public static IntPtr FPDF_LoadMemDocument(byte[] data_buf, int size, string password)
44 | {
45 | lock (LockString)
46 | {
47 | return Imports.FPDF_LoadMemDocument(data_buf, size, password);
48 | }
49 | }
50 |
51 | public static void FPDF_CloseDocument(IntPtr document)
52 | {
53 | lock (LockString)
54 | {
55 | Imports.FPDF_CloseDocument(document);
56 | }
57 | }
58 |
59 | public static int FPDF_GetPageCount(IntPtr document)
60 | {
61 | lock (LockString)
62 | {
63 | return Imports.FPDF_GetPageCount(document);
64 | }
65 | }
66 |
67 | public static uint FPDF_GetDocPermissions(IntPtr document)
68 | {
69 | lock (LockString)
70 | {
71 | return Imports.FPDF_GetDocPermissions(document);
72 | }
73 | }
74 |
75 | public static IntPtr FPDFDOC_InitFormFillEnvironment(IntPtr document, FPDF_FORMFILLINFO formInfo)
76 | {
77 | lock (LockString)
78 | {
79 | return Imports.FPDFDOC_InitFormFillEnvironment(document, formInfo);
80 | }
81 | }
82 |
83 | public static void FPDF_SetFormFieldHighlightColor(IntPtr hHandle, int fieldType, uint color)
84 | {
85 | lock (LockString)
86 | {
87 | Imports.FPDF_SetFormFieldHighlightColor(hHandle, fieldType, color);
88 | }
89 | }
90 |
91 | public static void FPDF_SetFormFieldHighlightAlpha(IntPtr hHandle, byte alpha)
92 | {
93 | lock (LockString)
94 | {
95 | Imports.FPDF_SetFormFieldHighlightAlpha(hHandle, alpha);
96 | }
97 | }
98 |
99 | public static void FORM_DoDocumentJSAction(IntPtr hHandle)
100 | {
101 | lock (LockString)
102 | {
103 | Imports.FORM_DoDocumentJSAction(hHandle);
104 | }
105 | }
106 |
107 | public static void FORM_DoDocumentOpenAction(IntPtr hHandle)
108 | {
109 | lock (LockString)
110 | {
111 | Imports.FORM_DoDocumentOpenAction(hHandle);
112 | }
113 | }
114 |
115 | public static void FPDFDOC_ExitFormFillEnvironment(IntPtr hHandle)
116 | {
117 | lock (LockString)
118 | {
119 | Imports.FPDFDOC_ExitFormFillEnvironment(hHandle);
120 | }
121 | }
122 |
123 | public static void FORM_DoDocumentAAction(IntPtr hHandle, FPDFDOC_AACTION aaType)
124 | {
125 | lock (LockString)
126 | {
127 | Imports.FORM_DoDocumentAAction(hHandle, aaType);
128 | }
129 | }
130 |
131 | public static IntPtr FPDF_LoadPage(IntPtr document, int page_index)
132 | {
133 | lock (LockString)
134 | {
135 | return Imports.FPDF_LoadPage(document, page_index);
136 | }
137 | }
138 |
139 |
140 | public static void FPDFPage_SetCropBox(IntPtr page_object, float left, float bottom, float right, float top)
141 | {
142 | lock (LockString)
143 | {
144 | Imports.FPDFPage_SetCropBox(page_object, left, bottom, right, top);
145 | }
146 | }
147 |
148 | // remove start
149 | public static IntPtr FPDFPageObj_NewPathObj()
150 | {
151 | lock (LockString)
152 | {
153 | return Imports.FPDFPageObj_NewPathObj();
154 | }
155 | }
156 |
157 | public static IntPtr FPDFPathObj_GetPath(IntPtr path_object)
158 | {
159 | lock (LockString)
160 | {
161 | return Imports.FPDFPathObj_GetPath(path_object);
162 | }
163 | }
164 |
165 |
166 | public static void FPDFPathObj_InsertPoint(IntPtr path_object, double x, double y, int flag)
167 | {
168 | lock (LockString)
169 | {
170 | Imports.FPDFPathObj_InsertPoint(path_object, x, y, flag);
171 | }
172 | }
173 |
174 | public static void FPDFPageObj_AddClip(IntPtr page_object, IntPtr path_object, int type)
175 | {
176 | lock (LockString)
177 | {
178 | Imports.FPDFPageObj_AddClip(page_object, path_object, type);
179 | }
180 | }
181 |
182 | // remove end
183 |
184 | public static IntPtr FPDFText_LoadPage(IntPtr page)
185 | {
186 | lock (LockString)
187 | {
188 | return Imports.FPDFText_LoadPage(page);
189 | }
190 | }
191 |
192 | public static void FORM_OnAfterLoadPage(IntPtr page, IntPtr _form)
193 | {
194 | lock (LockString)
195 | {
196 | Imports.FORM_OnAfterLoadPage(page, _form);
197 | }
198 | }
199 |
200 | public static void FORM_DoPageAAction(IntPtr page, IntPtr _form, FPDFPAGE_AACTION fPDFPAGE_AACTION)
201 | {
202 | lock (LockString)
203 | {
204 | Imports.FORM_DoPageAAction(page, _form, fPDFPAGE_AACTION);
205 | }
206 | }
207 |
208 | public static double FPDF_GetPageWidth(IntPtr page)
209 | {
210 | lock (LockString)
211 | {
212 | return Imports.FPDF_GetPageWidth(page);
213 | }
214 | }
215 |
216 | public static double FPDF_GetPageHeight(IntPtr page)
217 | {
218 | lock (LockString)
219 | {
220 | return Imports.FPDF_GetPageHeight(page);
221 | }
222 | }
223 |
224 | public static void FORM_OnBeforeClosePage(IntPtr page, IntPtr _form)
225 | {
226 | lock (LockString)
227 | {
228 | Imports.FORM_OnBeforeClosePage(page, _form);
229 | }
230 | }
231 |
232 | public static void FPDFText_ClosePage(IntPtr text_page)
233 | {
234 | lock (LockString)
235 | {
236 | Imports.FPDFText_ClosePage(text_page);
237 | }
238 | }
239 |
240 | public static void FPDF_ClosePage(IntPtr page)
241 | {
242 | lock (LockString)
243 | {
244 | Imports.FPDF_ClosePage(page);
245 | }
246 | }
247 |
248 | public static void FPDF_RenderPage(IntPtr dc, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags)
249 | {
250 | lock (LockString)
251 | {
252 | Imports.FPDF_RenderPage(dc, page, start_x, start_y, size_x, size_y, rotate, flags);
253 | }
254 | }
255 |
256 | public static void FPDF_RenderPageBitmap(IntPtr bitmapHandle, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags)
257 | {
258 | lock (LockString)
259 | {
260 | Imports.FPDF_RenderPageBitmap(bitmapHandle, page, start_x, start_y, size_x, size_y, rotate, flags);
261 | }
262 | }
263 |
264 | public static int FPDF_GetPageSizeByIndex(IntPtr document, int page_index, out double width, out double height)
265 | {
266 | lock (LockString)
267 | {
268 | return Imports.FPDF_GetPageSizeByIndex(document, page_index, out width, out height);
269 | }
270 | }
271 |
272 | public static IntPtr FPDFBitmap_CreateEx(int width, int height, int format, IntPtr first_scan, int stride)
273 | {
274 | lock (LockString)
275 | {
276 | return Imports.FPDFBitmap_CreateEx(width, height, format, first_scan, stride);
277 | }
278 | }
279 |
280 | public static void FPDFBitmap_FillRect(IntPtr bitmapHandle, int left, int top, int width, int height, uint color)
281 | {
282 | lock (LockString)
283 | {
284 | Imports.FPDFBitmap_FillRect(bitmapHandle, left, top, width, height, color);
285 | }
286 | }
287 |
288 | public static IntPtr FPDFBitmap_Destroy(IntPtr bitmapHandle)
289 | {
290 | lock (LockString)
291 | {
292 | return Imports.FPDFBitmap_Destroy(bitmapHandle);
293 | }
294 | }
295 |
296 | public static IntPtr FPDFText_FindStart(IntPtr page, byte[] findWhat, FPDF_SEARCH_FLAGS flags, int start_index)
297 | {
298 | lock (LockString)
299 | {
300 | return Imports.FPDFText_FindStart(page, findWhat, flags, start_index);
301 | }
302 | }
303 |
304 | public static int FPDFText_GetSchResultIndex(IntPtr handle)
305 | {
306 | lock (LockString)
307 | {
308 | return Imports.FPDFText_GetSchResultIndex(handle);
309 | }
310 | }
311 |
312 | public static int FPDFText_GetSchCount(IntPtr handle)
313 | {
314 | lock (LockString)
315 | {
316 | return Imports.FPDFText_GetSchCount(handle);
317 | }
318 | }
319 |
320 | public static int FPDFText_GetText(IntPtr page, int start_index, int count, byte[] result)
321 | {
322 | lock (LockString)
323 | {
324 | return Imports.FPDFText_GetText(page, start_index, count, result);
325 | }
326 | }
327 |
328 | public static void FPDFText_GetCharBox(IntPtr page, int index, out double left, out double right, out double bottom, out double top)
329 | {
330 | lock (LockString)
331 | {
332 | Imports.FPDFText_GetCharBox(page, index, out left, out right, out bottom, out top);
333 | }
334 | }
335 |
336 | public static int FPDFText_CountChars(IntPtr page)
337 | {
338 | lock (LockString)
339 | {
340 | return Imports.FPDFText_CountChars(page);
341 | }
342 | }
343 |
344 | public static bool FPDFText_FindNext(IntPtr handle)
345 | {
346 | lock (LockString)
347 | {
348 | return Imports.FPDFText_FindNext(handle);
349 | }
350 | }
351 |
352 | public static void FPDFText_FindClose(IntPtr handle)
353 | {
354 | lock (LockString)
355 | {
356 | Imports.FPDFText_FindClose(handle);
357 | }
358 | }
359 |
360 | public static bool FPDFLink_Enumerate(IntPtr page, ref int startPos, out IntPtr linkAnnot)
361 | {
362 | lock (LockString)
363 | {
364 | return Imports.FPDFLink_Enumerate(page, ref startPos, out linkAnnot);
365 | }
366 | }
367 |
368 | public static IntPtr FPDFLink_GetDest(IntPtr document, IntPtr link)
369 | {
370 | lock (LockString)
371 | {
372 | return Imports.FPDFLink_GetDest(document, link);
373 | }
374 | }
375 |
376 | public static uint FPDFDest_GetPageIndex(IntPtr document, IntPtr dest)
377 | {
378 | lock (LockString)
379 | {
380 | return Imports.FPDFDest_GetPageIndex(document, dest);
381 | }
382 | }
383 |
384 | public static bool FPDFLink_GetAnnotRect(IntPtr linkAnnot, FS_RECTF rect)
385 | {
386 | lock (LockString)
387 | {
388 | return Imports.FPDFLink_GetAnnotRect(linkAnnot, rect);
389 | }
390 | }
391 |
392 | public static void FPDF_DeviceToPage(IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, out double page_x, out double page_y)
393 | {
394 | lock (LockString)
395 | {
396 | Imports.FPDF_DeviceToPage(page, start_x, start_y, size_x, size_y, rotate, device_x, device_y, out page_x, out page_y);
397 | }
398 | }
399 |
400 | public static void FPDF_PageToDevice(IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, out int device_x, out int device_y)
401 | {
402 | lock (LockString)
403 | {
404 | Imports.FPDF_PageToDevice(page, start_x, start_y, size_x, size_y, rotate, page_x, page_y, out device_x, out device_y);
405 | }
406 | }
407 |
408 | public static IntPtr FPDFLink_GetAction(IntPtr link)
409 | {
410 | lock (LockString)
411 | {
412 | return Imports.FPDFLink_GetAction(link);
413 | }
414 | }
415 |
416 | public static uint FPDFAction_GetURIPath(IntPtr document, IntPtr action, StringBuilder buffer, uint buflen)
417 | {
418 | lock (LockString)
419 | {
420 | return Imports.FPDFAction_GetURIPath(document, action, buffer, buflen);
421 | }
422 | }
423 |
424 | public static IntPtr FPDF_BookmarkGetFirstChild(IntPtr document, IntPtr bookmark)
425 | {
426 | lock (LockString)
427 | {
428 | return Imports.FPDFBookmark_GetFirstChild(document, bookmark);
429 | }
430 | }
431 |
432 | public static IntPtr FPDF_BookmarkGetNextSibling(IntPtr document, IntPtr bookmark)
433 | {
434 | lock (LockString)
435 | return Imports.FPDFBookmark_GetNextSibling(document, bookmark);
436 | }
437 |
438 | public static uint FPDF_BookmarkGetTitle(IntPtr bookmark, byte[] buffer, uint buflen)
439 | {
440 | lock (LockString)
441 | return Imports.FPDFBookmark_GetTitle(bookmark, buffer, buflen);
442 | }
443 |
444 | public static IntPtr FPDF_BookmarkGetAction(IntPtr bookmark)
445 | {
446 | lock (LockString)
447 | return Imports.FPDFBookmark_GetAction(bookmark);
448 | }
449 |
450 | public static IntPtr FPDF_BookmarkGetDest(IntPtr document, IntPtr bookmark)
451 | {
452 | lock (LockString)
453 | return Imports.FPDFBookmark_GetDest(document, bookmark);
454 | }
455 |
456 | public static uint FPDF_ActionGetType(IntPtr action)
457 | {
458 | lock (LockString)
459 | return Imports.FPDFAction_GetType(action);
460 | }
461 |
462 | ///
463 | /// Opens a document using a .NET Stream. Allows opening huge
464 | /// PDFs without loading them into memory first.
465 | ///
466 | /// The input Stream. Don't dispose prior to closing the pdf.
467 | /// Password, if the PDF is protected. Can be null.
468 | /// Retrieves an IntPtr to the COM object for the Stream. The caller must release this with Marshal.Release prior to Disposing the Stream.
469 | /// An IntPtr to the FPDF_DOCUMENT object.
470 | public static IntPtr FPDF_LoadCustomDocument(Stream input, string password, int id)
471 | {
472 | var getBlock = Marshal.GetFunctionPointerForDelegate(_getBlockDelegate);
473 |
474 | var access = new FPDF_FILEACCESS
475 | {
476 | m_FileLen = (uint)input.Length,
477 | m_GetBlock = getBlock,
478 | m_Param = (IntPtr)id
479 | };
480 |
481 | lock (LockString)
482 | {
483 | return Imports.FPDF_LoadCustomDocument(access, password);
484 | }
485 | }
486 |
487 | public static FPDF_ERR FPDF_GetLastError()
488 | {
489 | lock (LockString)
490 | {
491 | return (FPDF_ERR)Imports.FPDF_GetLastError();
492 | }
493 | }
494 |
495 | public static uint FPDF_GetMetaText(IntPtr document, string tag, byte[] buffer, uint buflen)
496 | {
497 | lock (LockString)
498 | {
499 | return Imports.FPDF_GetMetaText(document, tag, buffer, buflen);
500 | }
501 | }
502 |
503 | #region Save / Edit Methods
504 |
505 | public static void FPDFPage_SetRotation(IntPtr page, PdfRotation rotation)
506 | {
507 | lock (LockString)
508 | {
509 | Imports.FPDFPage_SetRotation(page, (int)rotation);
510 | }
511 | }
512 |
513 | public static bool FPDFPage_GenerateContent(IntPtr page)
514 | {
515 | lock (LockString)
516 | {
517 | return Imports.FPDFPage_GenerateContent(page);
518 | }
519 | }
520 |
521 | public static void FPDFPage_Delete(IntPtr doc, int page)
522 | {
523 | lock (LockString)
524 | {
525 | Imports.FPDFPage_Delete(doc, page);
526 | }
527 | }
528 |
529 | public static bool FPDF_SaveAsCopy(IntPtr doc, Stream output, FPDF_SAVE_FLAGS flags)
530 | {
531 | int id = StreamManager.Register(output);
532 |
533 | try
534 | {
535 | var write = new FPDF_FILEWRITE
536 | {
537 | stream = (IntPtr)id,
538 | version = 1,
539 | WriteBlock = Marshal.GetFunctionPointerForDelegate(_saveBlockDelegate)
540 | };
541 |
542 | lock (LockString)
543 | {
544 | return Imports.FPDF_SaveAsCopy(doc, write, flags);
545 | }
546 | }
547 | finally
548 | {
549 | StreamManager.Unregister(id);
550 | }
551 | }
552 |
553 | public static bool FPDF_SaveWithVersion(IntPtr doc, Stream output, FPDF_SAVE_FLAGS flags, int fileVersion)
554 | {
555 | int id = StreamManager.Register(output);
556 |
557 | try
558 | {
559 | var write = new FPDF_FILEWRITE
560 | {
561 | stream = (IntPtr)id,
562 | version = 1,
563 | WriteBlock = Marshal.GetFunctionPointerForDelegate(_saveBlockDelegate)
564 | };
565 |
566 | lock (LockString)
567 | {
568 | return Imports.FPDF_SaveWithVersion(doc, write, flags, fileVersion);
569 | }
570 | }
571 | finally
572 | {
573 | StreamManager.Unregister(id);
574 | }
575 | }
576 |
577 | public static int FPDFText_GetCharIndexAtPos(IntPtr page, double x, double y, double x_tolerance, double y_tolerance)
578 | {
579 | lock (LockString)
580 | {
581 | return Imports.FPDFText_GetCharIndexAtPos(page, x, y, x_tolerance, y_tolerance);
582 | }
583 | }
584 |
585 | public static int FPDFText_CountRects(IntPtr text_page, int start_index, int count)
586 | {
587 | lock (LockString)
588 | {
589 | return Imports.FPDFText_CountRects(text_page, start_index, count);
590 | }
591 | }
592 |
593 | public static void FPDFText_GetRect(IntPtr text_page, int rect_index, out double left, out double top, out double right, out double bottom)
594 | {
595 | lock (LockString)
596 | {
597 | Imports.FPDFText_GetRect(text_page, rect_index, out left, out top, out right, out bottom);
598 | }
599 | }
600 |
601 |
602 | // Parameters:
603 | // text_page - Handle to a text page information structure.
604 | // left - Left boundary.
605 | // top - Top boundary.
606 | // right - Right boundary.
607 | // bottom - Bottom boundary.
608 | // buffer - A unicode buffer.
609 | // buflen - Number of characters (not bytes) for the buffer, excluding an additional terminator.
610 | // Return Value:
611 | // If buffer is NULL or buflen is zero, return number of characters (not bytes) needed,
612 | // otherwise, return number of characters copied into the buffer.
613 | public static uint FPDFText_GetBoundedText(IntPtr text_page, double left, double top, double right, double bottom, byte[] buffer, uint buflen)
614 | {
615 | lock (LockString)
616 | {
617 | return Imports.FPDFText_GetBoundedText(text_page, left, top, right, bottom, buffer, buflen);
618 | }
619 | }
620 |
621 |
622 | public static void FPDF_FFLDraw(IntPtr form, IntPtr bitmap, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags)
623 | {
624 | lock (LockString)
625 | {
626 | Imports.FPDF_FFLDraw(form, bitmap, page, start_x, start_y, size_x, size_y, rotate, flags);
627 | }
628 | }
629 | #endregion
630 |
631 | #region Custom Load/Save Logic
632 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
633 | private delegate int FPDF_GetBlockDelegate(IntPtr param, uint position, IntPtr buffer, uint size);
634 |
635 | private static readonly FPDF_GetBlockDelegate _getBlockDelegate = FPDF_GetBlock;
636 |
637 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
638 | private delegate int FPDF_SaveBlockDelegate(IntPtr fileWrite, IntPtr data, uint size);
639 |
640 | private static readonly FPDF_SaveBlockDelegate _saveBlockDelegate = FPDF_SaveBlock;
641 |
642 | private static int FPDF_GetBlock(IntPtr param, uint position, IntPtr buffer, uint size)
643 | {
644 | var stream = StreamManager.Get((int)param);
645 | if (stream is null)
646 | return 0;
647 | byte[] managedBuffer = new byte[size];
648 |
649 | stream.Position = position;
650 | int read = stream.Read(managedBuffer, 0, (int)size);
651 | if (read != size)
652 | return 0;
653 |
654 | Marshal.Copy(managedBuffer, 0, buffer, (int)size);
655 | return 1;
656 | }
657 |
658 | private static int FPDF_SaveBlock(IntPtr fileWrite, IntPtr data, uint size)
659 | {
660 | var write = new FPDF_FILEWRITE();
661 | Marshal.PtrToStructure(fileWrite, write);
662 |
663 | var stream = StreamManager.Get((int)write.stream);
664 | if (stream is null)
665 | return 0;
666 |
667 | byte[] buffer = new byte[size];
668 | Marshal.Copy(data, buffer, 0, (int)size);
669 |
670 | try
671 | {
672 | stream.Write(buffer, 0, (int)size);
673 | return (int)size;
674 | }
675 | catch
676 | {
677 | return 0;
678 | }
679 | }
680 | #endregion
681 |
682 | private static class Imports
683 | {
684 | [DllImport("pdfium.dll")]
685 | public static extern void FPDF_AddRef();
686 |
687 | [DllImport("pdfium.dll")]
688 | public static extern void FPDF_Release();
689 |
690 | [DllImport("pdfium.dll", CharSet = CharSet.Ansi)]
691 | public static extern IntPtr FPDF_LoadCustomDocument([MarshalAs(UnmanagedType.LPStruct)]FPDF_FILEACCESS access, string password);
692 |
693 | [DllImport("pdfium.dll", CharSet = CharSet.Ansi)]
694 | public static extern IntPtr FPDF_LoadMemDocument(SafeHandle data_buf, int size, string password);
695 |
696 | [DllImport("pdfium.dll", CharSet = CharSet.Ansi)]
697 | public static extern IntPtr FPDF_LoadMemDocument(byte[] data_buf, int size, string password);
698 |
699 | [DllImport("pdfium.dll")]
700 | public static extern void FPDF_CloseDocument(IntPtr document);
701 |
702 | [DllImport("pdfium.dll")]
703 | public static extern int FPDF_GetPageCount(IntPtr document);
704 |
705 | [DllImport("pdfium.dll")]
706 | public static extern uint FPDF_GetDocPermissions(IntPtr document);
707 |
708 | [DllImport("pdfium.dll")]
709 | public static extern IntPtr FPDFDOC_InitFormFillEnvironment(IntPtr document, FPDF_FORMFILLINFO formInfo);
710 |
711 | [DllImport("pdfium.dll")]
712 | public static extern void FPDF_SetFormFieldHighlightColor(IntPtr hHandle, int fieldType, uint color);
713 |
714 | [DllImport("pdfium.dll")]
715 | public static extern void FPDF_SetFormFieldHighlightAlpha(IntPtr hHandle, byte alpha);
716 |
717 | [DllImport("pdfium.dll")]
718 | public static extern void FORM_DoDocumentJSAction(IntPtr hHandle);
719 |
720 | [DllImport("pdfium.dll")]
721 | public static extern void FORM_DoDocumentOpenAction(IntPtr hHandle);
722 |
723 | [DllImport("pdfium.dll")]
724 | public static extern void FPDFDOC_ExitFormFillEnvironment(IntPtr hHandle);
725 |
726 | [DllImport("pdfium.dll")]
727 | public static extern void FORM_DoDocumentAAction(IntPtr hHandle, FPDFDOC_AACTION aaType);
728 |
729 | [DllImport("pdfium.dll")]
730 | public static extern IntPtr FPDF_LoadPage(IntPtr document, int page_index);
731 |
732 | [DllImport("pdfium.dll")]
733 | public static extern IntPtr FPDFPage_SetCropBox(IntPtr page_object, float left, float bottom, float right, float top);
734 |
735 | // remove start
736 | [DllImport("pdfium.dll")]
737 | public static extern IntPtr FPDFPathObj_GetPath(IntPtr path_object);
738 |
739 | [DllImport("pdfium.dll")]
740 | public static extern IntPtr FPDFPageObj_NewPathObj();
741 |
742 |
743 | [DllImport("pdfium.dll")]
744 | public static extern void FPDFPathObj_InsertPoint(IntPtr path_object, double x, double y, int flag);
745 |
746 | [DllImport("pdfium.dll")]
747 | public static extern IntPtr FPDFPageObj_AddClip(IntPtr page_object, IntPtr path_object, int type);
748 | // remove end
749 |
750 | [DllImport("pdfium.dll")]
751 | public static extern IntPtr FPDFText_LoadPage(IntPtr page);
752 |
753 | [DllImport("pdfium.dll")]
754 | public static extern void FORM_OnAfterLoadPage(IntPtr page, IntPtr _form);
755 |
756 | [DllImport("pdfium.dll")]
757 | public static extern void FORM_DoPageAAction(IntPtr page, IntPtr _form, FPDFPAGE_AACTION fPDFPAGE_AACTION);
758 |
759 | [DllImport("pdfium.dll")]
760 | public static extern double FPDF_GetPageWidth(IntPtr page);
761 |
762 | [DllImport("pdfium.dll")]
763 | public static extern double FPDF_GetPageHeight(IntPtr page);
764 |
765 | [DllImport("pdfium.dll")]
766 | public static extern void FORM_OnBeforeClosePage(IntPtr page, IntPtr _form);
767 |
768 | [DllImport("pdfium.dll")]
769 | public static extern void FPDFText_ClosePage(IntPtr text_page);
770 |
771 | [DllImport("pdfium.dll")]
772 | public static extern int FPDFText_GetCharIndexAtPos(IntPtr text_page, double x, double y, double x_tolerance, double y_tolerance);
773 |
774 | [DllImport("pdfium.dll")]
775 | public static extern void FPDFText_GetRect(IntPtr text_page, int rect_index, out double left, out double top, out double right, out double bottom);
776 |
777 | [DllImport("pdfium.dll")]
778 | public static extern uint FPDFText_GetBoundedText(IntPtr text_page, double left, double top, double right, double bottom, byte[] buffer, uint buflen);
779 |
780 | [DllImport("pdfium.dll")]
781 | public static extern int FPDFText_CountRects(IntPtr text_page, int start_index, int count);
782 |
783 | [DllImport("pdfium.dll")]
784 | public static extern void FPDF_ClosePage(IntPtr page);
785 |
786 | [DllImport("pdfium.dll")]
787 | public static extern void FPDF_RenderPage(IntPtr dc, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags);
788 |
789 | [DllImport("pdfium.dll")]
790 | public static extern void FPDF_RenderPageBitmap(IntPtr bitmapHandle, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags);
791 |
792 | [DllImport("pdfium.dll")]
793 | public static extern int FPDF_GetPageSizeByIndex(IntPtr document, int page_index, out double width, out double height);
794 |
795 | [DllImport("pdfium.dll")]
796 | public static extern IntPtr FPDFBitmap_CreateEx(int width, int height, int format, IntPtr first_scan, int stride);
797 |
798 | [DllImport("pdfium.dll")]
799 | public static extern void FPDFBitmap_FillRect(IntPtr bitmapHandle, int left, int top, int width, int height, uint color);
800 |
801 | [DllImport("pdfium.dll")]
802 | public static extern IntPtr FPDFBitmap_Destroy(IntPtr bitmapHandle);
803 |
804 | [DllImport("pdfium.dll")]
805 | public static extern IntPtr FPDFText_FindStart(IntPtr page, byte[] findWhat, FPDF_SEARCH_FLAGS flags, int start_index);
806 |
807 | [DllImport("pdfium.dll")]
808 | public static extern int FPDFText_GetSchResultIndex(IntPtr handle);
809 |
810 | [DllImport("pdfium.dll")]
811 | public static extern int FPDFText_GetSchCount(IntPtr handle);
812 |
813 | [DllImport("pdfium.dll")]
814 | public static extern int FPDFText_GetText(IntPtr page, int start_index, int count, byte[] result);
815 |
816 | [DllImport("pdfium.dll")]
817 | public static extern void FPDFText_GetCharBox(IntPtr page, int index, out double left, out double right, out double bottom, out double top);
818 |
819 | [DllImport("pdfium.dll")]
820 | public static extern int FPDFText_CountChars(IntPtr page);
821 |
822 | [DllImport("pdfium.dll")]
823 | public static extern bool FPDFText_FindNext(IntPtr handle);
824 |
825 | [DllImport("pdfium.dll")]
826 | public static extern void FPDFText_FindClose(IntPtr handle);
827 |
828 | [DllImport("pdfium.dll")]
829 | public static extern bool FPDFLink_Enumerate(IntPtr page, ref int startPos, out IntPtr linkAnnot);
830 |
831 | [DllImport("pdfium.dll")]
832 | public static extern IntPtr FPDFLink_GetDest(IntPtr document, IntPtr link);
833 |
834 | [DllImport("pdfium.dll")]
835 | public static extern uint FPDFDest_GetPageIndex(IntPtr document, IntPtr dest);
836 |
837 | [DllImport("pdfium.dll")]
838 | public static extern bool FPDFLink_GetAnnotRect(IntPtr linkAnnot, FS_RECTF rect);
839 |
840 | [DllImport("pdfium.dll")]
841 | public static extern void FPDF_DeviceToPage(IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, int device_x, int device_y, out double page_x, out double page_y);
842 |
843 | [DllImport("pdfium.dll")]
844 | public static extern void FPDF_PageToDevice(IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, double page_x, double page_y, out int device_x, out int device_y);
845 |
846 | [DllImport("pdfium.dll")]
847 | public static extern IntPtr FPDFLink_GetAction(IntPtr link);
848 |
849 | [DllImport("pdfium.dll")]
850 | public static extern uint FPDFAction_GetURIPath(IntPtr document, IntPtr action, StringBuilder buffer, uint buflen);
851 |
852 | [DllImport("pdfium.dll")]
853 | public static extern IntPtr FPDFBookmark_GetFirstChild(IntPtr document, IntPtr bookmark);
854 |
855 | [DllImport("pdfium.dll")]
856 | public static extern IntPtr FPDFBookmark_GetNextSibling(IntPtr document, IntPtr bookmark);
857 |
858 | [DllImport("pdfium.dll")]
859 | public static extern uint FPDFBookmark_GetTitle(IntPtr bookmark, byte[] buffer, uint buflen);
860 |
861 | [DllImport("pdfium.dll")]
862 | public static extern IntPtr FPDFBookmark_GetAction(IntPtr bookmark);
863 |
864 | [DllImport("pdfium.dll")]
865 | public static extern IntPtr FPDFBookmark_GetDest(IntPtr document, IntPtr bookmark);
866 |
867 | [DllImport("pdfium.dll")]
868 | public static extern uint FPDFAction_GetType(IntPtr action);
869 |
870 | [DllImport("pdfium.dll")]
871 | public static extern uint FPDF_GetLastError();
872 |
873 | [DllImport("pdfium.dll")]
874 | public static extern uint FPDF_GetMetaText(IntPtr document, string tag, byte[] buffer, uint buflen);
875 |
876 | #region Save/Edit APIs
877 |
878 | [DllImport("pdfium.dll")]
879 | public static extern bool FPDF_ImportPages(IntPtr destDoc, IntPtr srcDoc, [MarshalAs(UnmanagedType.LPStr)]string pageRange, int index);
880 |
881 | [DllImport("pdfium.dll")]
882 | public static extern bool FPDF_SaveAsCopy(IntPtr doc,
883 | [MarshalAs(UnmanagedType.LPStruct)]FPDF_FILEWRITE writer,
884 | [MarshalAs(UnmanagedType.I4)]FPDF_SAVE_FLAGS flag);
885 |
886 | [DllImport("pdfium.dll")]
887 | public static extern bool FPDF_SaveWithVersion(IntPtr doc,
888 | [MarshalAs(UnmanagedType.LPStruct)]FPDF_FILEWRITE writer,
889 | [MarshalAs(UnmanagedType.I4)]FPDF_SAVE_FLAGS flags,
890 | int fileVersion);
891 |
892 | [DllImport("pdfium.dll")]
893 | public static extern IntPtr FPDFPage_New(IntPtr doc, int index, double width, double height);
894 |
895 | [DllImport("pdfium.dll")]
896 | public static extern void FPDFPage_Delete(IntPtr doc, int index);
897 |
898 | [DllImport("pdfium.dll")]
899 | public static extern int FPDFPage_GetRotation(IntPtr page);
900 |
901 | [DllImport("pdfium.dll")]
902 | public static extern void FPDFPage_SetRotation(IntPtr page, int rotate);
903 |
904 | [DllImport("pdfium.dll")]
905 | public static extern IntPtr FPDF_CreateNewDocument();
906 |
907 | [DllImport("pdfium.dll")]
908 | public static extern IntPtr FPDFPageObj_NewImgeObj(IntPtr document);
909 |
910 | [DllImport("pdfium.dll")]
911 | public static extern bool FPDFImageObj_SetBitmap(IntPtr pages, int count, IntPtr imageObject, IntPtr bitmap);
912 |
913 | [DllImport("pdfium.dll")]
914 | public static extern void FPDFPageObj_Transform(IntPtr page, double a, double b, double c, double d, double e, double f);
915 |
916 | [DllImport("pdfium.dll")]
917 | public static extern void FPDFPage_InsertObject(IntPtr page, IntPtr pageObject);
918 |
919 | [DllImport("pdfium.dll")]
920 | public static extern bool FPDFPage_GenerateContent(IntPtr page);
921 |
922 | [DllImport("pdfium.dll")]
923 | public static extern void FPDF_FFLDraw(IntPtr form, IntPtr bitmap, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags);
924 |
925 | #endregion
926 | }
927 |
928 | [StructLayout(LayoutKind.Sequential)]
929 | public class FPDF_FORMFILLINFO
930 | {
931 | public int version;
932 |
933 | private IntPtr Release;
934 |
935 | private IntPtr FFI_Invalidate;
936 |
937 | private IntPtr FFI_OutputSelectedRect;
938 |
939 | private IntPtr FFI_SetCursor;
940 |
941 | private IntPtr FFI_SetTimer;
942 |
943 | private IntPtr FFI_KillTimer;
944 |
945 | private IntPtr FFI_GetLocalTime;
946 |
947 | private IntPtr FFI_OnChange;
948 |
949 | private IntPtr FFI_GetPage;
950 |
951 | private IntPtr FFI_GetCurrentPage;
952 |
953 | private IntPtr FFI_GetRotation;
954 |
955 | private IntPtr FFI_ExecuteNamedAction;
956 |
957 | private IntPtr FFI_SetTextFieldFocus;
958 |
959 | private IntPtr FFI_DoURIAction;
960 |
961 | private IntPtr FFI_DoGoToAction;
962 |
963 | private IntPtr m_pJsPlatform;
964 |
965 | // XFA support i.e. version 2
966 |
967 | private IntPtr FFI_DisplayCaret;
968 |
969 | private IntPtr FFI_GetCurrentPageIndex;
970 |
971 | private IntPtr FFI_SetCurrentPage;
972 |
973 | private IntPtr FFI_GotoURL;
974 |
975 | private IntPtr FFI_GetPageViewRect;
976 |
977 | private IntPtr FFI_PageEvent;
978 |
979 | private IntPtr FFI_PopupMenu;
980 |
981 | private IntPtr FFI_OpenFile;
982 |
983 | private IntPtr FFI_EmailTo;
984 |
985 | private IntPtr FFI_UploadTo;
986 |
987 | private IntPtr FFI_GetPlatform;
988 |
989 | private IntPtr FFI_GetLanguage;
990 |
991 | private IntPtr FFI_DownloadFromURL;
992 |
993 | private IntPtr FFI_PostRequestURL;
994 |
995 | private IntPtr FFI_PutRequestURL;
996 | }
997 |
998 | public enum FPDF_UNSP
999 | {
1000 | DOC_XFAFORM = 1,
1001 | DOC_PORTABLECOLLECTION = 2,
1002 | DOC_ATTACHMENT = 3,
1003 | DOC_SECURITY = 4,
1004 | DOC_SHAREDREVIEW = 5,
1005 | DOC_SHAREDFORM_ACROBAT = 6,
1006 | DOC_SHAREDFORM_FILESYSTEM = 7,
1007 | DOC_SHAREDFORM_EMAIL = 8,
1008 | ANNOT_3DANNOT = 11,
1009 | ANNOT_MOVIE = 12,
1010 | ANNOT_SOUND = 13,
1011 | ANNOT_SCREEN_MEDIA = 14,
1012 | ANNOT_SCREEN_RICHMEDIA = 15,
1013 | ANNOT_ATTACHMENT = 16,
1014 | ANNOT_SIG = 17
1015 | }
1016 |
1017 | public enum FPDFDOC_AACTION
1018 | {
1019 | WC = 0x10,
1020 | WS = 0x11,
1021 | DS = 0x12,
1022 | WP = 0x13,
1023 | DP = 0x14
1024 | }
1025 |
1026 | public enum FPDFPAGE_AACTION
1027 | {
1028 | OPEN = 0,
1029 | CLOSE = 1
1030 | }
1031 |
1032 | [Flags]
1033 | public enum FPDF
1034 | {
1035 | ANNOT = 0x01,
1036 | LCD_TEXT = 0x02,
1037 | NO_NATIVETEXT = 0x04,
1038 | GRAYSCALE = 0x08,
1039 | DEBUG_INFO = 0x80,
1040 | NO_CATCH = 0x100,
1041 | RENDER_LIMITEDIMAGECACHE = 0x200,
1042 | RENDER_FORCEHALFTONE = 0x400,
1043 | PRINTING = 0x800,
1044 | REVERSE_BYTE_ORDER = 0x10
1045 | }
1046 |
1047 | [Flags]
1048 | public enum FPDF_SEARCH_FLAGS
1049 | {
1050 | FPDF_MATCHCASE = 1,
1051 | FPDF_MATCHWHOLEWORD = 2
1052 | }
1053 |
1054 | [StructLayout(LayoutKind.Sequential)]
1055 | public class FS_RECTF
1056 | {
1057 | public float left;
1058 | public float top;
1059 | public float right;
1060 | public float bottom;
1061 | }
1062 |
1063 | public enum FPDF_ERR : uint
1064 | {
1065 | FPDF_ERR_SUCCESS = 0, // No error.
1066 | FPDF_ERR_UNKNOWN = 1, // Unknown error.
1067 | FPDF_ERR_FILE = 2, // File not found or could not be opened.
1068 | FPDF_ERR_FORMAT = 3, // File not in PDF format or corrupted.
1069 | FPDF_ERR_PASSWORD = 4, // Password required or incorrect password.
1070 | FPDF_ERR_SECURITY = 5, // Unsupported security scheme.
1071 | FPDF_ERR_PAGE = 6 // Page not found or content error.
1072 | }
1073 |
1074 | #region Save/Edit Structs and Flags
1075 | [Flags]
1076 | public enum FPDF_SAVE_FLAGS
1077 | {
1078 | FPDF_INCREMENTAL = 1,
1079 | FPDF_NO_INCREMENTAL = 2,
1080 | FPDF_REMOVE_SECURITY = 3
1081 | }
1082 |
1083 | [StructLayout(LayoutKind.Sequential)]
1084 | public class FPDF_FILEACCESS
1085 | {
1086 | public uint m_FileLen;
1087 | public IntPtr m_GetBlock;
1088 | public IntPtr m_Param;
1089 | }
1090 |
1091 | [StructLayout(LayoutKind.Sequential)]
1092 | public class FPDF_FILEWRITE
1093 | {
1094 | public int version;
1095 | public IntPtr WriteBlock;
1096 | public IntPtr stream;
1097 | }
1098 | #endregion
1099 | }
1100 | }
1101 |
--------------------------------------------------------------------------------
/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.IO;
4 | using System.Runtime.ConstrainedExecution;
5 | using System.Runtime.InteropServices;
6 | using System.Security.Permissions;
7 | using Microsoft.Win32.SafeHandles;
8 |
9 | namespace PdfiumLight
10 | {
11 | public static partial class NativeMethods
12 | {
13 | static NativeMethods()
14 | {
15 | // Load the platform dependent Pdfium.dll if it exists.
16 |
17 | if (!TryLoadNativeLibrary(AppDomain.CurrentDomain.RelativeSearchPath))
18 | {
19 | TryLoadNativeLibrary(Path.GetDirectoryName(typeof(NativeMethods).Assembly.Location));
20 | }
21 | }
22 |
23 | private static bool TryLoadNativeLibrary(string path)
24 | {
25 | if (path is null)
26 | return false;
27 |
28 | path = Path.Combine(path, IntPtr.Size == 4 ? "x86" : "x64");
29 | path = Path.Combine(path, "Pdfium.dll");
30 |
31 | return File.Exists(path) && LoadLibrary(path) != IntPtr.Zero;
32 | }
33 |
34 | [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
35 | private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPTStr)] string lpFileName);
36 |
37 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
38 | public static extern MemoryMappedHandle CreateFileMapping(SafeHandle hFile, IntPtr lpFileMappingAttributes, FileMapProtection flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, [MarshalAs(UnmanagedType.LPTStr)] string lpName);
39 |
40 | [DllImport("kernel32.dll", SetLastError = true)]
41 | [return: MarshalAs(UnmanagedType.Bool)]
42 | public static extern bool CloseHandle(IntPtr hObject);
43 |
44 | [Flags]
45 | public enum FileMapProtection : uint
46 | {
47 | PageReadonly = 0x02,
48 | PageReadWrite = 0x04,
49 | PageWriteCopy = 0x08,
50 | PageExecuteRead = 0x20,
51 | PageExecuteReadWrite = 0x40,
52 | SectionCommit = 0x8000000,
53 | SectionImage = 0x1000000,
54 | SectionNoCache = 0x10000000,
55 | SectionReserve = 0x4000000,
56 | }
57 |
58 | [DllImport("kernel32.dll", SetLastError = true)]
59 | public static extern MappedViewHandle MapViewOfFile(SafeHandle hFileMappingObject, FileMapAccess dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
60 |
61 | [Flags]
62 | public enum FileMapAccess : uint
63 | {
64 | FileMapCopy = 0x0001,
65 | FileMapWrite = 0x0002,
66 | FileMapRead = 0x0004,
67 | FileMapAllAccess = 0x001f,
68 | FileMapExecute = 0x0020,
69 | }
70 |
71 | [DllImport("kernel32.dll", SetLastError = true)]
72 | public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
73 |
74 | [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
75 | [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
76 | public class MemoryMappedHandle : SafeHandleZeroOrMinusOneIsInvalid
77 | {
78 | public MemoryMappedHandle()
79 | : base(true)
80 | {
81 | }
82 |
83 | [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
84 | protected override bool ReleaseHandle()
85 | {
86 | return CloseHandle(handle);
87 | }
88 | }
89 |
90 | public class MappedViewHandle : SafeHandleZeroOrMinusOneIsInvalid
91 | {
92 | public MappedViewHandle()
93 | : base(true)
94 | {
95 | }
96 |
97 | protected override bool ReleaseHandle()
98 | {
99 | return UnmapViewOfFile(handle);
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/PdfBookmarkCollection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 |
3 | namespace PdfiumLight
4 | {
5 | public class PdfBookmark
6 | {
7 | public PdfBookmark()
8 | {
9 | Children = new PdfBookmarkCollection();
10 | }
11 |
12 | public string Title { get; set; }
13 |
14 | public int PageIndex { get; set; }
15 |
16 | public PdfBookmarkCollection Children { get; set; }
17 |
18 | public override string ToString() => Title;
19 | }
20 |
21 | public class PdfBookmarkCollection : Collection
22 | {
23 | }
24 | }
--------------------------------------------------------------------------------
/PdfDocument.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.IO;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Text.RegularExpressions;
8 |
9 | namespace PdfiumLight
10 | {
11 | ///
12 | /// Represents a PDF document.
13 | ///
14 | public class PdfDocument : IDisposable
15 | {
16 | private static readonly Encoding FPDFEncoding = new UnicodeEncoding(false, false, false);
17 |
18 | private IntPtr _document;
19 | private IntPtr _form;
20 | private bool _disposed;
21 | private NativeMethods.FPDF_FORMFILLINFO _formCallbacks;
22 | private GCHandle _formCallbacksHandle;
23 | private int _id;
24 | private Stream _stream;
25 |
26 | ///
27 | /// Initializes a new instance of PdfDocument
28 | ///
29 | /// The path to the PDF-file
30 | /// Password to decrypt PDF
31 | public PdfDocument(string path, string password = null)
32 | {
33 | if (path is null)
34 | throw new ArgumentNullException(nameof(path));
35 |
36 | LoadFile(File.OpenRead(path), password);
37 | }
38 |
39 | ///
40 | /// Initializes a new instance of PdfDocument a .NET Stream. Allows opening huge PDFs without loading them into memory first.
41 | ///
42 | /// The input Stream. Don't dispose prior to closing the PDF.
43 | /// Password to decrypt PDF
44 | public PdfDocument(Stream stream, string password = null)
45 | {
46 | LoadFile(stream, password);
47 | }
48 |
49 | ///
50 | /// The Bookmarks of this PDF document.
51 | ///
52 | public PdfBookmarkCollection Bookmarks { get; private set; }
53 |
54 | private void LoadFile(Stream stream, string password)
55 | {
56 | PdfLibrary.EnsureLoaded();
57 |
58 | _stream = stream ?? throw new ArgumentNullException(nameof(stream));
59 | _id = StreamManager.Register(stream);
60 |
61 | var document = NativeMethods.FPDF_LoadCustomDocument(stream, password, _id);
62 |
63 | if (document == IntPtr.Zero)
64 | {
65 | throw new PdfException((PdfError)NativeMethods.FPDF_GetLastError());
66 | }
67 |
68 | LoadDocument(document);
69 | }
70 |
71 | ///
72 | /// This method returns the dimension of the pages in this document without loading them into memory first
73 | ///
74 | /// The List of page dimensions
75 | public SizeF[] GetPageSize()
76 | {
77 | if (_disposed)
78 | {
79 | throw new ObjectDisposedException(nameof(PdfDocument));
80 | }
81 |
82 | int pageCount = NativeMethods.FPDF_GetPageCount(_document);
83 |
84 | var result = new SizeF[pageCount];
85 |
86 | for (int i = 0; i < pageCount; i++)
87 | {
88 | result[i] = GetPageSize(i);
89 | }
90 |
91 | return result;
92 | }
93 |
94 | ///
95 | /// This method returns the dimension of a page in this document without loading it into memory first
96 | ///
97 | /// The page number of the page you want to retrice the dimensions for
98 | /// Dimesions as SizeF
99 | public SizeF GetPageSize(int pageNumber)
100 | {
101 | NativeMethods.FPDF_GetPageSizeByIndex(_document, pageNumber, out double width, out double height);
102 |
103 | return new SizeF((float)width, (float)height);
104 | }
105 |
106 | public void Save(Stream stream)
107 | {
108 | NativeMethods.FPDF_SaveAsCopy(_document, stream, NativeMethods.FPDF_SAVE_FLAGS.FPDF_NO_INCREMENTAL);
109 | }
110 |
111 | protected void LoadDocument(IntPtr document)
112 | {
113 | _document = document;
114 |
115 | NativeMethods.FPDF_GetDocPermissions(_document);
116 |
117 | _formCallbacks = new NativeMethods.FPDF_FORMFILLINFO();
118 | _formCallbacksHandle = GCHandle.Alloc(_formCallbacks, GCHandleType.Pinned);
119 |
120 | // Depending on whether XFA support is built into the PDFium library, the version
121 | // needs to be 1 or 2. We don't really care, so we just try one or the other.
122 |
123 | for (int i = 1; i <= 2; i++)
124 | {
125 | _formCallbacks.version = i;
126 |
127 | _form = NativeMethods.FPDFDOC_InitFormFillEnvironment(_document, _formCallbacks);
128 | if (_form != IntPtr.Zero)
129 | {
130 | break;
131 | }
132 | }
133 |
134 | NativeMethods.FPDF_SetFormFieldHighlightColor(_form, 0, 0xFFE4DD);
135 | NativeMethods.FPDF_SetFormFieldHighlightAlpha(_form, 100);
136 |
137 | NativeMethods.FORM_DoDocumentJSAction(_form);
138 | NativeMethods.FORM_DoDocumentOpenAction(_form);
139 |
140 |
141 | Bookmarks = LoadBookmarks(NativeMethods.FPDF_BookmarkGetFirstChild(document, IntPtr.Zero));
142 | }
143 |
144 | private PdfBookmarkCollection LoadBookmarks(IntPtr bookmark)
145 | {
146 | var result = new PdfBookmarkCollection();
147 | if (bookmark == IntPtr.Zero)
148 | return result;
149 |
150 | result.Add(LoadBookmark(bookmark));
151 |
152 | while ((bookmark = NativeMethods.FPDF_BookmarkGetNextSibling(_document, bookmark)) != IntPtr.Zero)
153 | {
154 | result.Add(LoadBookmark(bookmark));
155 | }
156 |
157 | return result;
158 | }
159 |
160 | private PdfBookmark LoadBookmark(IntPtr bookmark)
161 | {
162 | var pdfbookmark = new PdfBookmark
163 | {
164 | Title = GetBookmarkTitle(bookmark),
165 | PageIndex = (int)GetBookmarkPageIndex(bookmark)
166 | };
167 |
168 | // Action = NativeMethods.FPDF_BookmarkGetAction(_bookmark);
169 | // if (Action != IntPtr.Zero)
170 | // ActionType = NativeMethods.FPDF_ActionGetType(Action);
171 |
172 | var child = NativeMethods.FPDF_BookmarkGetFirstChild(_document, bookmark);
173 |
174 | if (child != IntPtr.Zero)
175 | {
176 | pdfbookmark.Children = LoadBookmarks(child);
177 | }
178 |
179 | return pdfbookmark;
180 | }
181 |
182 | private string GetBookmarkTitle(IntPtr bookmark)
183 | {
184 | uint length = NativeMethods.FPDF_BookmarkGetTitle(bookmark, null, 0);
185 | byte[] buffer = new byte[length];
186 | NativeMethods.FPDF_BookmarkGetTitle(bookmark, buffer, length);
187 |
188 | string result = Encoding.Unicode.GetString(buffer);
189 |
190 | if (result.Length > 0 && result[result.Length - 1] == 0)
191 | {
192 | result = result.Substring(0, result.Length - 1);
193 | }
194 |
195 | return result;
196 | }
197 |
198 | private uint GetBookmarkPageIndex(IntPtr bookmark)
199 | {
200 | IntPtr dest = NativeMethods.FPDF_BookmarkGetDest(_document, bookmark);
201 |
202 | return (dest != IntPtr.Zero)
203 | ? NativeMethods.FPDFDest_GetPageIndex(_document, dest)
204 | : 0u;
205 | }
206 |
207 | ///
208 | /// This method will load and return the sepecific page
209 | ///
210 | /// The null-based index of the page
211 | /// A new PdfPage
212 | public PdfPage GetPage(int page) => new PdfPage(_document, _form, page);
213 |
214 | ///
215 | /// Returns the page count of the document. This will call a native Pdfium function.
216 | ///
217 | ///
218 | public int PageCount() => NativeMethods.FPDF_GetPageCount(_document);
219 |
220 | ///
221 | /// Dtailed meta informations from the PDF document
222 | ///
223 | /// A PdfInformation containing the metadata
224 | public PdfInformation GetInformation()
225 | {
226 | return new PdfInformation
227 | {
228 | Creator = GetMetaText("Creator"),
229 | Title = GetMetaText("Title"),
230 | Author = GetMetaText("Author"),
231 | Subject = GetMetaText("Subject"),
232 | Keywords = GetMetaText("Keywords"),
233 | Producer = GetMetaText("Producer"),
234 | CreationDate = GetMetaTextAsDate("CreationDate"),
235 | ModificationDate = GetMetaTextAsDate("ModDate")
236 | };
237 | }
238 |
239 | private string GetMetaText(string tag)
240 | {
241 | // Length includes a trailing \0.
242 |
243 | uint length = NativeMethods.FPDF_GetMetaText(_document, tag, null, 0);
244 | if (length <= 2)
245 | return string.Empty;
246 |
247 | byte[] buffer = new byte[length];
248 | NativeMethods.FPDF_GetMetaText(_document, tag, buffer, length);
249 |
250 | return Encoding.Unicode.GetString(buffer, 0, (int)(length - 2));
251 | }
252 |
253 | public DateTime? GetMetaTextAsDate(string tag)
254 | {
255 | string dt = GetMetaText(tag);
256 |
257 | if (string.IsNullOrEmpty(dt))
258 | return null;
259 |
260 | Regex dtRegex =
261 | new Regex(
262 | @"(?:D:)(?\d\d\d\d)(?\d\d)(?\d\d)(?\d\d)(?\d\d)(?\d\d)(?[+-zZ])?(?\d\d)?'?(?\d\d)?'?");
263 |
264 | Match match = dtRegex.Match(dt);
265 |
266 | if (match.Success)
267 | {
268 | var year = match.Groups["year"].Value;
269 | var month = match.Groups["month"].Value;
270 | var day = match.Groups["day"].Value;
271 | var hour = match.Groups["hour"].Value;
272 | var minute = match.Groups["minute"].Value;
273 | var second = match.Groups["second"].Value;
274 | var tzOffset = match.Groups["tz_offset"]?.Value;
275 | var tzHour = match.Groups["tz_hour"]?.Value;
276 | var tzMinute = match.Groups["tz_minute"]?.Value;
277 |
278 | string formattedDate = $"{year}-{month}-{day}T{hour}:{minute}:{second}.0000000";
279 |
280 | if (tzOffset != null && tzOffset.Length == 1)
281 | {
282 | switch (tzOffset[0])
283 | {
284 | case 'Z':
285 | case 'z':
286 | formattedDate += "+0";
287 | break;
288 | case '+':
289 | case '-':
290 | formattedDate += $"{tzOffset}{tzHour}:{tzMinute}";
291 | break;
292 | }
293 | }
294 |
295 | try
296 | {
297 | return DateTime.Parse(formattedDate);
298 | }
299 | catch (FormatException)
300 | {
301 | return null;
302 | }
303 | }
304 |
305 | return null;
306 | }
307 |
308 | public void Dispose()
309 | {
310 | Dispose(true);
311 |
312 | GC.SuppressFinalize(this);
313 | }
314 |
315 | private NativeMethods.FPDF FlagsToFPDFFlags(PdfRenderFlags flags)
316 | {
317 | return (NativeMethods.FPDF)(flags & ~(PdfRenderFlags.Transparent | PdfRenderFlags.CorrectFromDpi));
318 | }
319 |
320 | protected virtual void Dispose(bool disposing)
321 | {
322 | if (!_disposed)
323 | {
324 | StreamManager.Unregister(_id);
325 |
326 | if (_form != IntPtr.Zero)
327 | {
328 | NativeMethods.FORM_DoDocumentAAction(_form, NativeMethods.FPDFDOC_AACTION.WC);
329 | NativeMethods.FPDFDOC_ExitFormFillEnvironment(_form);
330 | _form = IntPtr.Zero;
331 | }
332 |
333 | if (_document != IntPtr.Zero)
334 | {
335 | NativeMethods.FPDF_CloseDocument(_document);
336 | _document = IntPtr.Zero;
337 | }
338 |
339 | if (_formCallbacksHandle.IsAllocated)
340 | _formCallbacksHandle.Free();
341 |
342 | if (_stream != null)
343 | {
344 | _stream.Dispose();
345 | _stream = null;
346 | }
347 |
348 | _disposed = true;
349 | }
350 | }
351 | }
352 | }
--------------------------------------------------------------------------------
/PdfError.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace PdfiumLight
4 | {
5 | public enum PdfError
6 | {
7 | Success = (int)NativeMethods.FPDF_ERR.FPDF_ERR_SUCCESS,
8 | Unknown = (int)NativeMethods.FPDF_ERR.FPDF_ERR_UNKNOWN,
9 | CannotOpenFile = (int)NativeMethods.FPDF_ERR.FPDF_ERR_FILE,
10 | InvalidFormat = (int)NativeMethods.FPDF_ERR.FPDF_ERR_FORMAT,
11 | PasswordProtected = (int)NativeMethods.FPDF_ERR.FPDF_ERR_PASSWORD,
12 | UnsupportedSecurityScheme = (int)NativeMethods.FPDF_ERR.FPDF_ERR_SECURITY,
13 | PageNotFound = (int)NativeMethods.FPDF_ERR.FPDF_ERR_PAGE
14 | }
15 | }
--------------------------------------------------------------------------------
/PdfException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | #pragma warning disable 1591
5 |
6 | namespace PdfiumLight
7 | {
8 | public class PdfException : Exception
9 | {
10 | public PdfError Error { get; private set; }
11 |
12 | public PdfException()
13 | {
14 | }
15 |
16 | public PdfException(PdfError error)
17 | : this(GetMessage(error))
18 | {
19 | Error = error;
20 | }
21 |
22 | private static string GetMessage(PdfError error)
23 | {
24 | switch (error)
25 | {
26 | case PdfError.Success:
27 | return "No error";
28 | case PdfError.CannotOpenFile:
29 | return "File not found or could not be opened";
30 | case PdfError.InvalidFormat:
31 | return "File not in PDF format or corrupted";
32 | case PdfError.PasswordProtected:
33 | return "Password required or incorrect password";
34 | case PdfError.UnsupportedSecurityScheme:
35 | return "Unsupported security scheme";
36 | case PdfError.PageNotFound:
37 | return "Page not found or content error";
38 | default:
39 | return "Unknown error";
40 | }
41 | }
42 |
43 | public PdfException(string message)
44 | : base(message)
45 | {
46 | }
47 |
48 | public PdfException(string message, Exception innerException)
49 | : base(message, innerException)
50 | {
51 | }
52 |
53 | protected PdfException(SerializationInfo info, StreamingContext context)
54 | : base(info, context)
55 | {
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/PdfInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PdfiumLight
4 | {
5 | ///
6 | /// Contains text from metadata of the document.
7 | ///
8 | public class PdfInformation
9 | {
10 | public string Author { get; set; }
11 |
12 | public string Creator { get; set; }
13 |
14 | public DateTime? CreationDate { get; set; }
15 |
16 | public string Keywords { get; set; }
17 |
18 | public DateTime? ModificationDate { get; set; }
19 |
20 | public string Producer { get; set; }
21 |
22 | public string Subject { get; set; }
23 |
24 | public string Title { get; set; }
25 | }
26 | }
--------------------------------------------------------------------------------
/PdfLibrary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PdfiumLight
4 | {
5 | internal class PdfLibrary : IDisposable
6 | {
7 | private static readonly object _syncRoot = new object();
8 | private static PdfLibrary _library;
9 |
10 | public static void EnsureLoaded()
11 | {
12 | lock (_syncRoot)
13 | {
14 | if (_library is null)
15 | _library = new PdfLibrary();
16 | }
17 | }
18 |
19 | private bool _disposed;
20 |
21 | private PdfLibrary()
22 | {
23 | NativeMethods.FPDF_AddRef();
24 | }
25 |
26 | ~PdfLibrary()
27 | {
28 | Dispose(false);
29 | }
30 |
31 | public void Dispose()
32 | {
33 | Dispose(true);
34 |
35 | GC.SuppressFinalize(this);
36 | }
37 |
38 | private void Dispose(bool disposing)
39 | {
40 | if (!_disposed)
41 | {
42 | NativeMethods.FPDF_Release();
43 |
44 | _disposed = true;
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/PdfMatches.cs:
--------------------------------------------------------------------------------
1 | //using System;
2 | //using System.Collections.Generic;
3 | //using System.Collections.ObjectModel;
4 | //using System.Text;
5 |
6 | //#pragma warning disable 1591
7 |
8 | //namespace PdfiumLight
9 | //{
10 | // public class PdfMatches
11 | // {
12 | // public int StartPage { get; private set; }
13 |
14 | // public int EndPage { get; private set; }
15 |
16 | // public IList Items { get; private set; }
17 |
18 | // public PdfMatches(int startPage, int endPage, IList matches)
19 | // {
20 | // if (matches is null)
21 | // throw new ArgumentNullException("matches");
22 |
23 | // StartPage = startPage;
24 | // EndPage = endPage;
25 | // Items = new ReadOnlyCollection(matches);
26 | // }
27 | // }
28 | //}
29 |
--------------------------------------------------------------------------------
/PdfPage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Drawing.Imaging;
5 | using System.Text;
6 |
7 | namespace PdfiumLight
8 | {
9 | ///
10 | /// Represents a page of a PDF document.
11 | ///
12 | public class PdfPage : IDisposable
13 | {
14 | private static readonly Encoding FPDFEncoding = new UnicodeEncoding(false, false, false);
15 |
16 | private readonly IntPtr _form;
17 | private bool _disposed;
18 |
19 | ///
20 | /// Handle to the page.
21 | ///
22 | public IntPtr Page { get; private set; }
23 |
24 | ///
25 | /// Handle to the text page
26 | ///
27 | public IntPtr TextPage { get; private set; }
28 |
29 | ///
30 | /// Width of the page in pt
31 | ///
32 | public double Width { get; private set; }
33 |
34 | ///
35 | /// Height of th page in pt
36 | ///
37 | public double Height { get; private set; }
38 |
39 | ///
40 | /// The index og this page in the document
41 | ///
42 | public int PageNumber { get; private set; }
43 |
44 | ///
45 | /// Initializes a new instance of PdfPage
46 | ///
47 | /// The PDF document
48 | ///
49 | /// Number of this page in the document
50 | public PdfPage(IntPtr document, IntPtr form, int pageNumber)
51 | {
52 | _form = form;
53 |
54 | PageNumber = pageNumber;
55 |
56 | Page = NativeMethods.FPDF_LoadPage(document, pageNumber);
57 | TextPage = NativeMethods.FPDFText_LoadPage(Page);
58 | NativeMethods.FORM_OnAfterLoadPage(Page, form);
59 | NativeMethods.FORM_DoPageAAction(Page, form, NativeMethods.FPDFPAGE_AACTION.OPEN);
60 |
61 | Width = NativeMethods.FPDF_GetPageWidth(Page);
62 | Height = NativeMethods.FPDF_GetPageHeight(Page);
63 | }
64 |
65 | ///
66 | /// Dispose
67 | ///
68 | public void Dispose()
69 | {
70 | if (!_disposed)
71 | {
72 | NativeMethods.FORM_DoPageAAction(Page, _form, NativeMethods.FPDFPAGE_AACTION.CLOSE);
73 | NativeMethods.FORM_OnBeforeClosePage(Page, _form);
74 | NativeMethods.FPDFText_ClosePage(TextPage);
75 | NativeMethods.FPDF_ClosePage(Page);
76 |
77 | _disposed = true;
78 | }
79 | }
80 |
81 | private RectangleF GetBounds(int index)
82 | {
83 | NativeMethods.FPDFText_GetCharBox(
84 | Page,
85 | index,
86 | out double left,
87 | out double right,
88 | out double bottom,
89 | out double top
90 | );
91 |
92 | return new RectangleF(
93 | (float)left,
94 | (float)top,
95 | (float)(right - left),
96 | (float)(bottom - top)
97 | );
98 | }
99 |
100 | private bool RenderPDFPageToDC(IntPtr dc, int dpiX, int dpiY, int boundsOriginX, int boundsOriginY, int boundsWidth, int boundsHeight, NativeMethods.FPDF flags)
101 | {
102 | if (_disposed)
103 | {
104 | throw new ObjectDisposedException(nameof(PdfPage));
105 | }
106 |
107 | NativeMethods.FPDF_RenderPage(dc, Page, boundsOriginX, boundsOriginY, boundsWidth, boundsHeight, 0, flags);
108 |
109 | return true;
110 | }
111 |
112 | ///
113 | /// Renders the page.
114 | ///
115 | ///
116 | /// The full width of the rendered image in px or percentage (if dpiX and dpiY are specified).
117 | /// If 0, width will be calculated from height using the correct apsect ratio.
118 | /// Height and width can not be both set to zero.
119 | ///
120 | ///
121 | /// The full wiheightth of the rendered image in px or percentage (if dpiX and dpiY are specified).
122 | /// If 0, height will be calculated from height using the correct apsect ratio.
123 | /// Height and width can not be both set to zero.
124 | ///
125 | /// X value of the start point of the clipping area
126 | /// Y value of the start point of the clipping area
127 | /// Width of the clip area
128 | /// Height of the clip area
129 | /// DPI to render page. If set, width and height will accept percentage.
130 | /// DPI to render page. If set, width and height will accept percentage.
131 | /// Specify rotation.
132 | /// Specify flags.
133 | /// Image from the page.
134 | public Image Render(int width, int height, int clipX, int clipY, int clipWidth, int clipHeight, float dpiX, float dpiY, PdfRotation rotate, PdfRenderFlags flags)
135 | {
136 | if (_disposed)
137 | {
138 | throw new ObjectDisposedException(nameof(PdfPage));
139 | }
140 |
141 | if (height == 0 && width != 0)
142 | {
143 | height = width * (int)(Height / Width);
144 | }
145 | else if (height != 0 && width == 0)
146 | {
147 | width = height * (int)(Width / Height);
148 | }
149 | else if (height == 0 && width == 0)
150 | {
151 | throw new ArgumentException();
152 | }
153 |
154 | if (dpiX != 0 && dpiY != 0)
155 | {
156 | clipWidth = (int)(clipWidth / 100f * width / 100f * Width * 0.013888888888889 * dpiX);
157 | clipHeight = (int)(clipHeight / 100f * height / 100f * Height * 0.013888888888889 * dpiY);
158 | width = (int)(width / 100f * Width * 0.013888888888889 * dpiX);
159 | height = (int)(height / 100f * Height * 0.013888888888889 * dpiY);
160 | }
161 |
162 | var bitmap = new Bitmap(clipWidth, clipHeight, PixelFormat.Format32bppArgb);
163 |
164 | var data = bitmap.LockBits(new Rectangle(0, 0, clipWidth, clipHeight), ImageLockMode.ReadWrite, bitmap.PixelFormat);
165 |
166 | try
167 | {
168 | var handle = NativeMethods.FPDFBitmap_CreateEx(clipWidth, clipHeight, 4, data.Scan0, clipWidth * 4);
169 |
170 | try
171 | {
172 | uint background = (flags & PdfRenderFlags.Transparent) == 0 ? 0xFFFFFFFF : 0x00FFFFFF;
173 |
174 | NativeMethods.FPDFBitmap_FillRect(handle, 0, 0, clipWidth, clipHeight, background);
175 |
176 | bool success = RenderPDFPageToBitmap(
177 | handle,
178 | (int)dpiX, (int)dpiY, -clipX, -clipY, width, height,
179 | (int)rotate,
180 | FlagsToFPDFFlags(flags),
181 | (flags & PdfRenderFlags.Annotations) != 0
182 | );
183 |
184 | if (!success)
185 | throw new Exception();
186 | }
187 | finally
188 | {
189 | NativeMethods.FPDFBitmap_Destroy(handle);
190 | }
191 |
192 | }
193 | finally
194 | {
195 | bitmap.UnlockBits(data);
196 | }
197 |
198 | return bitmap;
199 | }
200 |
201 | ///
202 | /// Renders the page.
203 | ///
204 | ///
205 | /// The full width of the rendered image in px.
206 | /// If 0, width will be calculated from height using the correct apsect ratio.
207 | /// Height and width can not be both set to zero.
208 | ///
209 | ///
210 | /// The full wiheightth of the rendered image in px .
211 | /// If 0, height will be calculated from height using the correct apsect ratio.
212 | /// Height and width can not be both set to zero.
213 | ///
214 | /// Specify rotation.
215 | /// Specify flags.
216 | /// Image from the page.
217 | public Image Render(int width, int height, PdfRotation rotate, PdfRenderFlags flags)
218 | {
219 | if (height == 0 && width != 0) height = (int)((float)width * (Height / Width));
220 | else if (height != 0 && width == 0) width = (int)((float)height * (int)(Width / Height));
221 | else if (height == 0 && width == 0) throw new ArgumentException();
222 | return Render(width, height, 0, 0, width, height, 0, 0, rotate, flags);
223 | }
224 |
225 | ///
226 | /// Renders the page.
227 | ///
228 | ///
229 | /// The full width of the rendered image in px.
230 | /// If 0, width will be calculated from height using the correct apsect ratio.
231 | /// Height and width can not be both set to zero.
232 | ///
233 | ///
234 | /// The full wiheightth of the rendered image in px .
235 | /// If 0, height will be calculated from height using the correct apsect ratio.
236 | /// Height and width can not be both set to zero.
237 | ///
238 | /// Image from the page.
239 | public Image Render(int width, int height)
240 | {
241 | if (height == 0 && width != 0) height = (int)((float)width * (Height / Width));
242 | else if (height != 0 && width == 0) width = (int)((float)height * (int)(Width / Height));
243 | else if (height == 0 && width == 0) throw new ArgumentException();
244 | return Render(width, height, 0, 0, width, height, 0, 0, PdfRotation.Rotate0, PdfRenderFlags.None);
245 | }
246 |
247 | ///
248 | /// Renders the page.
249 | ///
250 | ///
251 | /// The full width of the rendered image in px or percentage (if dpiX and dpiY are specified).
252 | /// If 0, width will be calculated from height using the correct apsect ratio.
253 | /// Height and width can not be both set to zero.
254 | ///
255 | ///
256 | /// The full wiheightth of the rendered image in px or percentage (if dpiX and dpiY are specified).
257 | /// If 0, height will be calculated from height using the correct apsect ratio.
258 | /// Height and width can not be both set to zero.
259 | ///
260 | /// DPI to render page. If set, width and height will accept percentage.
261 | /// DPI to render page. If set, width and height will accept percentage.
262 | /// Specify rotation.
263 | /// Specify flags.
264 | /// Image from the page.
265 | public Image Render(int width, int height, float dpiX, float dpiY, PdfRotation rotate, PdfRenderFlags flags)
266 | {
267 | return Render(width, height, 0, 0, width, height, dpiX, dpiY, rotate, flags);
268 | }
269 |
270 | ///
271 | /// Renders the page.
272 | ///
273 | ///
274 | /// The full width of the rendered image in px.
275 | /// If 0, width will be calculated from height using the correct apsect ratio.
276 | /// Height and width can not be both set to zero.
277 | ///
278 | ///
279 | /// The full wiheightth of the rendered image in px.
280 | /// If 0, height will be calculated from height using the correct apsect ratio.
281 | /// Height and width can not be both set to zero.
282 | ///
283 | /// X value of the start point of the clipping area
284 | /// Y value of the start point of the clipping area
285 | /// Width of the clip area
286 | /// Height of the clip area
287 | /// Specify rotation.
288 | /// Specify flags.
289 | /// Image from the page.
290 | public Image Render(int width, int height, int clipX, int clipY, int clipWidth, int clipHeight, PdfRotation rotate, PdfRenderFlags flags)
291 | {
292 | return Render(width, height, clipX, clipY, clipWidth, clipHeight, 0, 0, rotate, flags);
293 | }
294 |
295 | private bool RenderPDFPageToBitmap(IntPtr bitmapHandle, int dpiX, int dpiY, int boundsOriginX, int boundsOriginY, int boundsWidth, int boundsHeight, int rotate, NativeMethods.FPDF flags, bool renderFormFill)
296 | {
297 | if (_disposed)
298 | {
299 | throw new ObjectDisposedException(nameof(PdfPage));
300 | }
301 |
302 | if (renderFormFill)
303 | flags &= ~NativeMethods.FPDF.ANNOT;
304 |
305 | NativeMethods.FPDF_RenderPageBitmap(bitmapHandle, Page, boundsOriginX, boundsOriginY, boundsWidth, boundsHeight, rotate, flags);
306 |
307 | if (renderFormFill)
308 | {
309 | NativeMethods.FPDF_FFLDraw(_form, bitmapHandle, Page, boundsOriginX, boundsOriginY, boundsWidth, boundsHeight, rotate, flags);
310 | }
311 |
312 | return true;
313 | }
314 |
315 | ///
316 | /// Gets the index of the character at the provided position
317 | ///
318 | /// x
319 | /// y
320 | /// The tolerance
321 | /// The zero-based index of the character at, or nearby the point (x,y). If there is no character at or nearby the point, return value will be -1. If an error occurs, -3 will be returned.
322 | public int GetCharIndexAtPos(double x, double y, double tol = 12)
323 | {
324 | return NativeMethods.FPDFText_GetCharIndexAtPos(TextPage, x, y, tol, tol);
325 | }
326 |
327 | ///
328 | /// Transforms a Point in device coordinates to PDF coordinates.
329 | ///
330 | /// The point in device coordinates
331 | /// Render with of the page
332 | /// Render height of the page
333 | /// The transformed Point
334 | public PointF PointToPdf(Point point, int renderWidth, int renderHeight)
335 | {
336 |
337 | NativeMethods.FPDF_DeviceToPage(
338 | Page,
339 | 0,
340 | 0,
341 | renderWidth,
342 | renderHeight,
343 | 0,
344 | point.X,
345 | point.Y,
346 | out double deviceX,
347 | out double deviceY
348 | );
349 |
350 | return new PointF((float)deviceX, (float)deviceY);
351 | }
352 |
353 | ///
354 | /// Transforms a Rectangle in device coordinates to PDF coordinates.
355 | /// Will also make sure to return a Rectangle with positive height and width.
356 | ///
357 | /// The Rectangle in device coordinates
358 | /// Render with of the page
359 | /// Render height of the page
360 | /// The transformed Rectangle
361 | public RectangleF RectangleToPdf(Rectangle rect, int renderWidth, int renderHeight)
362 | {
363 |
364 | NativeMethods.FPDF_DeviceToPage(
365 | Page,
366 | 0,
367 | 0,
368 | renderWidth,
369 | renderHeight,
370 | 0,
371 | rect.Left,
372 | rect.Top,
373 | out double deviceX1,
374 | out double deviceY1
375 | );
376 |
377 | NativeMethods.FPDF_DeviceToPage(
378 | Page,
379 | 0,
380 | 0,
381 | renderWidth,
382 | renderHeight,
383 | 0,
384 | rect.Right,
385 | rect.Bottom,
386 | out double deviceX2,
387 | out double deviceY2
388 | );
389 |
390 | return new RectangleF(
391 | (float)deviceX1,
392 | (float)deviceY1,
393 | (float)Math.Abs((deviceX2 - deviceX1)),
394 | (float)Math.Abs((deviceY2 - deviceY1))
395 | );
396 |
397 | }
398 |
399 | ///
400 | /// Gets the text fromf page
401 | ///
402 | /// The text/returns>
403 | public string GetPdfText()
404 | {
405 | int length = NativeMethods.FPDFText_CountChars(TextPage);
406 | return GetPdfText(0, length);
407 | }
408 |
409 | ///
410 | /// Gets the text from page specified by offset and length
411 | ///
412 | /// The text/returns>
413 | public string GetPdfText(int offset, int length)
414 | {
415 | var result = new byte[(length + 1) * 2];
416 | NativeMethods.FPDFText_GetText(TextPage, offset, length, result);
417 | return FPDFEncoding.GetString(result, 0, length * 2);
418 | }
419 |
420 | ///
421 | /// Rotates the page.
422 | ///
423 | /// Specify the rotation.
424 | public void RotatePage(PdfRotation rotation) => NativeMethods.FPDFPage_SetRotation(Page, rotation);
425 |
426 | ///
427 | /// Get the bounds of the text (specified by index and length) from the page.
428 | ///
429 | /// The start index of the text
430 | /// The length of the text
431 | /// List of the bounds for the text
432 | public PdfRectangle[] GetTextBounds(int startIndex, int length)
433 | {
434 | int countRects = NativeMethods.FPDFText_CountRects(TextPage, startIndex, length);
435 |
436 | var result = new PdfRectangle[countRects];
437 |
438 | for (int i = 0; i < countRects; i++)
439 | {
440 | NativeMethods.FPDFText_GetRect(TextPage, i, out double left, out double top, out double right, out double bottom);
441 |
442 | RectangleF bounds = new RectangleF(
443 | (float)left,
444 | (float)top,
445 | (float)(right - left),
446 | (float)(bottom - top));
447 |
448 | if (bounds.Width == 0 || bounds.Height == 0)
449 | continue;
450 |
451 | result[i] = new PdfRectangle(PageNumber, bounds);
452 | }
453 |
454 | return result;
455 | }
456 |
457 | ///
458 | /// Transforms a Rectangle in PDF coordinates to device coordinates.
459 | /// Will also make sure to return a Rectangle with positive height and width.
460 | ///
461 | /// The rect in PDF coordinates
462 | /// Render width of the page
463 | /// Render height of the page
464 | /// The transformed Rectangle
465 | public Rectangle RectangleFromPdf(RectangleF rect, int renderWidth, int renderHeight)
466 | {
467 | NativeMethods.FPDF_PageToDevice(
468 | Page,
469 | 0,
470 | 0,
471 | renderWidth,
472 | renderHeight,
473 | 0,
474 | rect.Left,
475 | rect.Top,
476 | out int deviceX1,
477 | out int deviceY1
478 | );
479 |
480 | NativeMethods.FPDF_PageToDevice(
481 | Page,
482 | 0,
483 | 0,
484 | renderWidth,
485 | renderHeight,
486 | 0,
487 | rect.Right,
488 | rect.Bottom,
489 | out int deviceX2,
490 | out int deviceY2
491 | );
492 |
493 | return new Rectangle(
494 | Math.Min(deviceX1, deviceX2),
495 | Math.Min(deviceY1, deviceY2),
496 | Math.Abs(deviceX2 - deviceX1),
497 | Math.Abs(deviceY2 - deviceY1)
498 | );
499 |
500 | }
501 |
502 | private NativeMethods.FPDF FlagsToFPDFFlags(PdfRenderFlags flags)
503 | {
504 | return (NativeMethods.FPDF)(flags & ~(PdfRenderFlags.Transparent | PdfRenderFlags.CorrectFromDpi));
505 | }
506 |
507 |
508 | ///
509 | /// Extract unicode text within a rectangular boundary on the page,
510 | /// rectangle defined by device coordinates: left, top, right, bottom.
511 | ///
512 | /// X device coordinate of the rectangle
513 | /// Y device coordinate of the rectangle
514 | /// X2 device coordinate of the rectangle
515 | /// Y2 device coordinate of the rectangle
516 | /// Render width of the page
517 | /// Render height of the page
518 | /// unicode text in the described rectangle
519 | public string GetBoundedText(int left,int top,int right,int bottom, int renderWidth, int renderHeight)
520 | {
521 |
522 | //double deviceX1, deviceY1, deviceX2, deviceY2 = 0;
523 | NativeMethods.FPDF_DeviceToPage(
524 | Page,
525 | 0,
526 | 0,
527 | renderWidth,
528 | renderHeight,
529 | 0,
530 | left,
531 | top,
532 | out double deviceX1,
533 | out double deviceY1
534 | );
535 |
536 | NativeMethods.FPDF_DeviceToPage(
537 | Page,
538 | 0,
539 | 0,
540 | renderWidth,
541 | renderHeight,
542 | 0,
543 | right,
544 | bottom,
545 | out double deviceX2,
546 | out double deviceY2
547 | );
548 |
549 | uint number_of_characters_not_bytes_needed = NativeMethods.FPDFText_GetBoundedText(TextPage,deviceX1,deviceY1,deviceX2,deviceY2, null, 0);
550 |
551 | uint length = ( number_of_characters_not_bytes_needed + 1) * 2;
552 | if (length <= 2)
553 | {
554 | return string.Empty;
555 | }
556 |
557 | byte[] buffer = new byte[length];
558 | NativeMethods.FPDFText_GetBoundedText(TextPage, deviceX1, deviceY1, deviceX2, deviceY2, buffer, length);
559 |
560 | return Encoding.Unicode.GetString(buffer, 0, (int)(length - 2));
561 | }
562 | }
563 | }
--------------------------------------------------------------------------------
/PdfPageLink.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace PdfiumLight
4 | {
5 | ///
6 | /// Describes a link on a page.
7 | ///
8 | public class PdfPageLink
9 | {
10 | ///
11 | /// Creates a new instance of the PdfPageLink class.
12 | ///
13 | /// The location of the link
14 | /// The target page of the link
15 | /// The target URI of the link
16 | public PdfPageLink(RectangleF bounds, int? targetPage, string uri)
17 | {
18 | Bounds = bounds;
19 | TargetPage = targetPage;
20 | Uri = uri;
21 | }
22 |
23 | ///
24 | /// The location of the link.
25 | ///
26 | public RectangleF Bounds { get; private set; }
27 |
28 | ///
29 | /// The target of the link.
30 | ///
31 | public int? TargetPage { get; private set; }
32 |
33 | ///
34 | /// The target URI of the link.
35 | ///
36 | public string Uri { get; private set; }
37 | }
38 | }
--------------------------------------------------------------------------------
/PdfPageLinks.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 |
5 | namespace PdfiumLight
6 | {
7 | ///
8 | /// Describes all links on a page.
9 | ///
10 | public class PdfPageLinks
11 | {
12 | ///
13 | /// All links of the page.
14 | ///
15 | public IList Links { get; private set; }
16 |
17 | ///
18 | /// Creates a new instance of the PdfPageLinks class.
19 | ///
20 | /// The links on the PDF page.
21 | public PdfPageLinks(IList links)
22 | {
23 | if (links is null)
24 | throw new ArgumentNullException(nameof(links));
25 |
26 | Links = new ReadOnlyCollection(links);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/PdfPoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | #pragma warning disable 1591
5 |
6 | namespace PdfiumLight
7 | {
8 | public readonly struct PdfPoint : IEquatable
9 | {
10 | public static readonly PdfPoint Empty = new PdfPoint();
11 |
12 | // _page is offset by 1 so that Empty returns an invalid point.
13 | private readonly int _page;
14 |
15 | public int Page => _page - 1;
16 |
17 | public PointF Location { get; }
18 |
19 | public bool IsValid => _page != 0;
20 |
21 | public PdfPoint(int page, PointF location)
22 | {
23 | _page = page + 1;
24 | Location = location;
25 | }
26 |
27 | public bool Equals(PdfPoint other)
28 | {
29 | return
30 | Page == other.Page &&
31 | Location == other.Location;
32 | }
33 |
34 | public override bool Equals(object obj)
35 | {
36 | return obj is PdfPoint other && Equals(other);
37 | }
38 |
39 | public override int GetHashCode()
40 | {
41 | unchecked
42 | {
43 | return (Page * 397) ^ Location.GetHashCode();
44 | }
45 | }
46 |
47 | public static bool operator ==(PdfPoint left, PdfPoint right)
48 | {
49 | return left.Equals(right);
50 | }
51 |
52 | public static bool operator !=(PdfPoint left, PdfPoint right)
53 | {
54 | return !left.Equals(right);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/PdfRectangle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | namespace PdfiumLight
5 | {
6 | public readonly struct PdfRectangle : IEquatable
7 | {
8 | // _page is offset by 1 so that Empty returns an invalid rectangle.
9 | private readonly int _page;
10 |
11 | public static readonly PdfRectangle Empty = new PdfRectangle();
12 |
13 | public PdfRectangle(int page, RectangleF bounds)
14 | {
15 | _page = page + 1;
16 | Bounds = bounds;
17 | }
18 |
19 | public PdfRectangle(int page, RectangleF bounds, int astartIndex, int asize)
20 | {
21 | _page = page + 1;
22 | Bounds = bounds;
23 | }
24 |
25 | public int Page => _page - 1;
26 |
27 | public RectangleF Bounds { get; }
28 |
29 | public bool IsValid => _page != 0;
30 |
31 | public bool Equals(PdfRectangle other)
32 | {
33 | return
34 | Page == other.Page &&
35 | Bounds == other.Bounds;
36 | }
37 |
38 | public override bool Equals(object obj)
39 | {
40 | return obj is PdfRectangle other && Equals(other);
41 | }
42 |
43 | public override int GetHashCode()
44 | {
45 | unchecked
46 | {
47 | return (Page * 397) ^ Bounds.GetHashCode();
48 | }
49 | }
50 |
51 | public static bool operator ==(PdfRectangle left, PdfRectangle right)
52 | {
53 | return left.Equals(right);
54 | }
55 |
56 | public static bool operator !=(PdfRectangle left, PdfRectangle right)
57 | {
58 | return !left.Equals(right);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/PdfRenderFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PdfiumLight
4 | {
5 | ///
6 | /// Flags that influence the page rendering process.
7 | ///
8 | [Flags]
9 | public enum PdfRenderFlags
10 | {
11 | ///
12 | /// No flags.
13 | ///
14 | None = 0,
15 | ///
16 | /// Render for printing.
17 | ///
18 | ForPrinting = NativeMethods.FPDF.PRINTING,
19 | ///
20 | /// Set if annotations are to be rendered.
21 | ///
22 | Annotations = NativeMethods.FPDF.ANNOT,
23 | ///
24 | /// Set if using text rendering optimized for LCD display.
25 | ///
26 | LcdText = NativeMethods.FPDF.LCD_TEXT,
27 | ///
28 | /// Don't use the native text output available on some platforms.
29 | ///
30 | NoNativeText = NativeMethods.FPDF.NO_NATIVETEXT,
31 | ///
32 | /// Grayscale output.
33 | ///
34 | Grayscale = NativeMethods.FPDF.GRAYSCALE,
35 | ///
36 | /// Limit image cache size.
37 | ///
38 | LimitImageCacheSize = NativeMethods.FPDF.RENDER_LIMITEDIMAGECACHE,
39 | ///
40 | /// Always use halftone for image stretching.
41 | ///
42 | ForceHalftone = NativeMethods.FPDF.RENDER_FORCEHALFTONE,
43 | ///
44 | /// Render with a transparent background.
45 | ///
46 | Transparent = 0x1000,
47 | ///
48 | /// Correct height/width for DPI.
49 | ///
50 | CorrectFromDpi = 0x2000
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/PdfRotation.cs:
--------------------------------------------------------------------------------
1 | namespace PdfiumLight
2 | {
3 | ///
4 | /// Specifies the rotation of pages shown in the PDF renderer.
5 | ///
6 | public enum PdfRotation
7 | {
8 | ///
9 | /// Rotates the output 0 degrees.
10 | ///
11 | Rotate0,
12 | ///
13 | /// Rotates the output 90 degrees.
14 | ///
15 | Rotate90,
16 | ///
17 | /// Rotates the output 180 degrees.
18 | ///
19 | Rotate180,
20 | ///
21 | /// Rotates the output 270 degrees.
22 | ///
23 | Rotate270
24 | }
25 | }
--------------------------------------------------------------------------------
/PdfTextSpan.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PdfiumLight
4 | {
5 | public readonly struct PdfTextSpan : IEquatable
6 | {
7 | public PdfTextSpan(int page, int offset, int length)
8 | {
9 | Page = page;
10 | Offset = offset;
11 | Length = length;
12 | }
13 |
14 | public int Page { get; }
15 |
16 | public int Offset { get; }
17 |
18 | public int Length { get; }
19 |
20 | public bool Equals(PdfTextSpan other)
21 | {
22 | return
23 | Page == other.Page &&
24 | Offset == other.Offset &&
25 | Length == other.Length;
26 | }
27 |
28 | public override bool Equals(object obj)
29 | {
30 | return obj is PdfTextSpan other && Equals((PdfTextSpan)obj);
31 | }
32 |
33 | public override int GetHashCode()
34 | {
35 | unchecked
36 | {
37 | int hashCode = Page;
38 | hashCode = (hashCode * 397) ^ Offset;
39 | hashCode = (hashCode * 397) ^ Length;
40 | return hashCode;
41 | }
42 | }
43 |
44 | public static bool operator ==(PdfTextSpan left, PdfTextSpan right)
45 | {
46 | return left.Equals(right);
47 | }
48 |
49 | public static bool operator !=(PdfTextSpan left, PdfTextSpan right)
50 | {
51 | return !left.Equals(right);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/PdfiumLight.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | PdfiumLight
6 | PdfiumLight
7 | 7.3
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PdfiumLight.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PdfiumLight
6 |
7 |
8 | 0.0.4
9 |
10 |
11 | Marc Pabst
12 |
13 |
17 | marcpabst
18 |
19 |
20 | https://opensource.org/licenses/MIT
21 | https://github.com/marcpabst/PdfiumLight
22 |
23 |
24 |
28 | false
29 |
30 |
31 | Initial release
32 |
33 |
37 | A lightweight C# Library to render PDFs with Google's Pdfium in .NET Apps.
38 |
39 |
40 |
41 |
42 |
43 | pdf pdfium pdfrenderer
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/PdfiumLight.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2000
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfiumLight", "PdfiumLight.csproj", "{438914B6-5D1C-482C-B942-5C0E057EEF6F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {438914B6-5D1C-482C-B942-5C0E057EEF6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {438914B6-5D1C-482C-B942-5C0E057EEF6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {438914B6-5D1C-482C-B942-5C0E057EEF6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {438914B6-5D1C-482C-B942-5C0E057EEF6F}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {DD9D26EE-BF58-4219-B855-DD43DBCE1B5D}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PdfiumLight
2 | A lightweight C# Library to render PDFs with Google's Pdfium in .NET Apps. This is basically a much slimmer version of [Pieter van Ginkel's PdfiumViewer](https://github.com/pvginkel/PdfiumViewer) with some added functionality.
3 |
4 | ## Getting started
5 | Getting started is easy. Just add `PdfiumLight`, `PdfiumViewer.Native.x86.v8-xfa` and / or `PdfiumViewer.Native.x86_64.v8-xfa` (see below) as NuGet dependencies to your project and you're good to go:
6 | ```c#
7 | // Load the pdf file and create a new document object
8 | PdfDocument document = new PdfDocument("C:/Users/Tom/Documents/sample.pdf");
9 | // Load the first page
10 | PdfPage page = document.GetPage(0);
11 | // Render the page with a width of 1000px and automatically computed height
12 | var renderedPage = page.Render(1000, 0);
13 | ```
14 | ### Render part of a page
15 | You can specify a clipping rectangle within the original image that would have been rendered only specifying `widht` and `height`. This will render only part of the page, thus beeing much faster than rendering the whole page and clipping afterwards.
16 | ```c#
17 | // Load the pdf file and create a new document object
18 | PdfDocument document = new PdfDocument("C:/Users/Marc/Documents/sample.pdf");
19 | // Load the first page
20 | PdfPage page = document.GetPage(0);
21 | // Render the page
22 | var renderedPage = page.Render(
23 | 10000, // width in px
24 | 0, // '0' to compute height according to aspect ratio
25 | 0, // x of the top/left of clipping rectangle
26 | 0, // y of the top/left point of clipping rectangle
27 | 1000, // width of clipping reactangle
28 | 1000, // height of clipping reactangle
29 | PdfRotation.Rotate0, // no rotation
30 | PdfRenderFlags.None // no render flags
31 | );
32 | ```
33 | ### You have to provide pdfium.dll
34 | There are many ways to include pdfium.dll, the most easy one is by adding one or both of the following NuGet-dependencies created by @pvginkel:
35 |
36 | - `PdfiumViewer.Native.x86.v8-xfa`
37 | - `PdfiumViewer.Native.x86_64.v8-xfa`
38 |
39 | A very basic packages.config could look like this:
40 | ```xm
41 |
42 |
43 |
44 |
45 |
46 |
47 | ```
48 | ## Features
49 | ### (already implemented)
50 | - load PDF-documents
51 | - render pages as a whole or partly
52 | - convert device coordinates to page coordinates and vice versa
53 | - extract text from page
54 | - check if there is text at a specific point on the page (very usefull if implementing a text layer)
55 | ### (still to come)
56 | - support for internal and external links
57 | - search
58 | - annoatation support
59 | - form support
60 | ### (wishlist)
61 | - caching
62 | - simple editing features such as reorder and deleting pages and merging documents
63 |
--------------------------------------------------------------------------------
/StreamExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace PdfiumLight
5 | {
6 | internal static class StreamExtensions
7 | {
8 | public static byte[] ToByteArray(Stream stream)
9 | {
10 | if (stream is null)
11 | throw new ArgumentNullException(nameof(stream));
12 |
13 | if (stream is MemoryStream memoryStream)
14 | {
15 | return memoryStream.ToArray();
16 | }
17 |
18 | if (stream.CanSeek)
19 | return ReadBytesFast(stream);
20 | else
21 | return ReadBytesSlow(stream);
22 | }
23 |
24 | private static byte[] ReadBytesFast(Stream stream)
25 | {
26 | byte[] data = new byte[stream.Length];
27 |
28 | int offset = 0;
29 |
30 | while (offset < data.Length)
31 | {
32 | int read = stream.Read(data, offset, data.Length - offset);
33 |
34 | if (read <= 0)
35 | break;
36 |
37 | offset += read;
38 | }
39 |
40 | if (offset < data.Length)
41 | throw new InvalidOperationException("Incorrect length reported");
42 |
43 | return data;
44 | }
45 |
46 | private static byte[] ReadBytesSlow(Stream stream)
47 | {
48 | using (var memoryStream = new MemoryStream())
49 | {
50 | CopyStream(stream, memoryStream);
51 |
52 | return memoryStream.ToArray();
53 | }
54 | }
55 |
56 | public static void CopyStream(Stream from, Stream to)
57 | {
58 | if (@from is null)
59 | throw new ArgumentNullException(nameof(from));
60 |
61 | if (to is null)
62 | throw new ArgumentNullException(nameof(to));
63 |
64 | var buffer = new byte[4096];
65 |
66 | while (true)
67 | {
68 | int read = from.Read(buffer, 0, buffer.Length);
69 |
70 | if (read == 0)
71 | return;
72 |
73 | to.Write(buffer, 0, read);
74 | }
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/StreamManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 |
5 | namespace PdfiumLight
6 | {
7 | internal static class StreamManager
8 | {
9 | private static readonly object _syncRoot = new object();
10 | private static int _nextId = 1;
11 | private static readonly Dictionary _files = new Dictionary();
12 |
13 | public static int Register(Stream stream)
14 | {
15 | if (stream is null)
16 | throw new ArgumentNullException(nameof(stream));
17 |
18 | lock (_syncRoot)
19 | {
20 | int id = _nextId++;
21 | _files.Add(id, stream);
22 | return id;
23 | }
24 | }
25 |
26 | public static void Unregister(int id)
27 | {
28 | lock (_syncRoot)
29 | {
30 | _files.Remove(id);
31 | }
32 | }
33 |
34 | public static Stream Get(int id)
35 | {
36 | lock (_syncRoot)
37 | {
38 | _files.TryGetValue(id, out Stream stream);
39 | return stream;
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------