PdfObject.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. #include "mupdf/fitz.h"
  2. #include "mupdf/pdf.h"
  3. #include "Collection.h"
  4. #include "Stream.h"
  5. #ifndef __PDFOBJECT
  6. #define __PDFOBJECT
  7. #pragma once
  8. using namespace System;
  9. using namespace System::Collections::Generic;
  10. using namespace System::Text;
  11. struct pdf_obj {
  12. short refs;
  13. unsigned char kind;
  14. unsigned char flags;
  15. };
  16. namespace MuPDF {
  17. public enum class Kind {
  18. Null,
  19. Boolean,
  20. Name,
  21. Integer,
  22. Float,
  23. String,
  24. Array,
  25. Dictionary,
  26. Reference,
  27. Stream,
  28. Unknown
  29. };
  30. /// <summary>
  31. /// Encapsulates the PDF obj used by MuPDF
  32. /// </summary>
  33. public ref class PdfObject : IDisposable, IEquatable<PdfObject^> {
  34. public:
  35. /// <summary>
  36. /// Gets or sets whether this object is dirty (modified).
  37. /// </summary>
  38. property bool IsDirty {
  39. bool get() { return pdf_obj_is_dirty(_ctx, _obj); }
  40. void set(bool value) {
  41. if (value) {
  42. pdf_dirty_obj(_ctx, _obj);
  43. }
  44. else {
  45. pdf_clean_obj(_ctx, _obj);
  46. }
  47. }
  48. }
  49. /// <summary>
  50. /// Provides direct object kind info.
  51. /// </summary>
  52. property Kind TypeKind {
  53. virtual Kind get();
  54. }
  55. property bool IsIndirect {
  56. bool get() { return pdf_is_indirect(_ctx, _obj); }
  57. }
  58. property bool IsStream {
  59. bool get() { return pdf_is_stream(_ctx, _obj); }
  60. }
  61. property bool IsName {
  62. bool get() { return pdf_is_name(_ctx, _obj); }
  63. }
  64. property bool IsNull {
  65. bool get() { return pdf_is_null(_ctx, _obj); }
  66. }
  67. property bool IsBoolean {
  68. bool get() { return pdf_is_bool(_ctx, _obj); }
  69. }
  70. property bool IsInteger {
  71. bool get() { return pdf_is_int(_ctx, _obj); }
  72. }
  73. property bool IsFloat {
  74. bool get() { return pdf_is_real(_ctx, _obj); }
  75. }
  76. property bool IsNumber {
  77. bool get() { return pdf_is_number(_ctx, _obj); }
  78. }
  79. property bool IsString {
  80. bool get() { return pdf_is_string(_ctx, _obj); }
  81. }
  82. property bool IsArray {
  83. bool get() { return pdf_is_array(_ctx, _obj); }
  84. }
  85. property bool IsDictionary {
  86. bool get() { return pdf_is_dict(_ctx, _obj); }
  87. }
  88. property bool IsPredefined {
  89. bool get() { return _obj < PDF_LIMIT; }
  90. }
  91. property int IntegerValue {
  92. int get() { return pdf_to_int(_ctx, _obj); }
  93. }
  94. property int LongValue {
  95. int get() { return pdf_to_int64(_ctx, _obj); }
  96. }
  97. property float FloatValue {
  98. float get() { return pdf_to_real(_ctx, _obj); }
  99. }
  100. property PdfObject^ UnderlyingObject {
  101. PdfObject^ get() {
  102. return pdf_is_indirect(_ctx, _obj)
  103. ? Wrap(pdf_resolve_indirect_chain(_ctx, _obj))
  104. : this;
  105. }
  106. }
  107. void MarkDirty() {
  108. pdf_dirty_obj(_ctx, _obj);
  109. }
  110. static bool operator == (PdfObject^ x, PdfObject^ y) {
  111. return Object::ReferenceEquals(x, y) || x && y && pdf_objcmp(x->_ctx, x->Ptr, y->Ptr) == 0;
  112. }
  113. static bool operator != (PdfObject^ x, PdfObject^ y) {
  114. return !Object::ReferenceEquals(x, y) && x && y && pdf_objcmp(x->_ctx, x->Ptr, y->Ptr) != 0;
  115. }
  116. virtual bool Equals(PdfObject^ other);
  117. virtual bool Equals(Object^ obj) override {
  118. PdfObject^ p;
  119. return (p = dynamic_cast<PdfObject^>(obj)) && _obj == p->_obj;
  120. }
  121. virtual int GetHashCode() override {
  122. return (int)_obj;
  123. }
  124. virtual String^ ToString() override {
  125. return TypeKind.ToString();
  126. }
  127. internal:
  128. PdfObject(pdf_obj* obj) : _obj(obj) {
  129. if (obj >= PDF_LIMIT) {
  130. pdf_keep_obj(_ctx = Context::Ptr, obj);
  131. }
  132. }
  133. ~PdfObject() {
  134. ReleaseHandle();
  135. }
  136. !PdfObject() {
  137. ReleaseHandle();
  138. }
  139. property fz_context* Ctx { fz_context* get() { return _ctx; } }
  140. property pdf_obj* Ptr { pdf_obj* get() { return _obj; } }
  141. static PdfObject^ Wrap(pdf_obj* obj);
  142. private:
  143. pdf_obj* _obj;
  144. fz_context* _ctx;
  145. void ReleaseHandle() {
  146. if (_obj && _ctx) {
  147. pdf_drop_obj(_ctx, _obj);
  148. _obj = NULL;
  149. _ctx = NULL;
  150. }
  151. }
  152. };
  153. public ref class PdfNull : PdfObject {
  154. public:
  155. property Kind TypeKind {
  156. virtual Kind get() override { return Kind::Null; }
  157. }
  158. static const PdfNull^ Instance = gcnew PdfNull();
  159. virtual String^ ToString() override { return "<null>"; }
  160. internal:
  161. PdfNull() : PdfObject(PDF_NULL) {}
  162. };
  163. public ref class PdfBoolean : PdfObject {
  164. public:
  165. property Kind TypeKind {
  166. virtual Kind get() override { return Kind::Boolean; }
  167. }
  168. static const PdfBoolean^ True = gcnew PdfBoolean(true);
  169. static const PdfBoolean^ False = gcnew PdfBoolean(false);
  170. property bool Value {
  171. bool get() { return Ptr == PDF_TRUE; }
  172. }
  173. virtual String^ ToString() override { return Ptr == PDF_TRUE ? "<true>" : "<false>"; }
  174. internal:
  175. PdfBoolean(bool value) : PdfObject(value ? PDF_TRUE : PDF_FALSE) {}
  176. };
  177. #define PDF_MAKE_NAME(STRING,NAME) NAME,
  178. public enum class PdfNames {
  179. Undefined,
  180. True,
  181. False,
  182. #include "name-table.h"
  183. AllPredefinedNames
  184. };
  185. public ref class PdfName : PdfObject {
  186. public:
  187. property Kind TypeKind {
  188. virtual Kind get() override { return Kind::Name; }
  189. }
  190. property String^ Name {
  191. String^ get() { return gcnew String(pdf_to_name(Context::Ptr, Ptr)); }
  192. }
  193. static operator PdfName^(PdfNames value) {
  194. return gcnew PdfName((pdf_obj*)value);
  195. }
  196. virtual String^ ToString() override { return "/" + Name; }
  197. internal:
  198. PdfName(pdf_obj* obj) : PdfObject(obj) {};
  199. };
  200. public ref class PdfInteger : PdfObject {
  201. public:
  202. property Kind TypeKind {
  203. virtual Kind get() override { return Kind::Integer; }
  204. }
  205. property int Value {
  206. int get() { return pdf_to_int(Context::Ptr, Ptr); }
  207. void set(int value) { pdf_set_int(Context::Ptr, Ptr, value); }
  208. }
  209. property long LongValue {
  210. long get() { return pdf_to_int64(Context::Ptr, Ptr); }
  211. void set(long value) { pdf_set_int(Context::Ptr, Ptr, value); }
  212. }
  213. virtual String^ ToString() override { return LongValue.ToString(); }
  214. internal:
  215. PdfInteger(pdf_obj* obj) : PdfObject(obj) {};
  216. };
  217. public ref class PdfFloat : PdfObject {
  218. public:
  219. property Kind TypeKind {
  220. virtual Kind get() override { return Kind::Float; }
  221. }
  222. property float Value {
  223. float get() { return pdf_to_real(Context::Ptr, Ptr); }
  224. }
  225. virtual String^ ToString() override { return Value.ToString(); }
  226. internal:
  227. PdfFloat(pdf_obj* obj) : PdfObject(obj) {};
  228. };
  229. public ref class PdfString : PdfObject {
  230. public:
  231. property Kind TypeKind {
  232. virtual Kind get() override { return Kind::String; }
  233. }
  234. property String^ Value {
  235. String^ get();
  236. }
  237. property int Length {
  238. int get() { return pdf_to_str_len(Context::Ptr, Ptr); }
  239. }
  240. /// <summary>
  241. /// Gets underlying bytes in a PDF string.
  242. /// </summary>
  243. array<Byte>^ GetBytes();
  244. virtual String^ ToString() override { return Value; }
  245. internal:
  246. PdfString(pdf_obj* obj) : PdfObject(obj) {};
  247. private:
  248. String^ _string;
  249. String^ DecodePdfString();
  250. };
  251. public ref class PdfContainer abstract : PdfObject {
  252. public:
  253. property int Count {
  254. virtual int get() abstract;
  255. }
  256. protected:
  257. pdf_obj* NewPdfString(String^ text);
  258. PdfContainer(pdf_obj* obj) : PdfObject(obj) {};
  259. private:
  260. static Encoding^ AsciiEncoding = Encoding::ASCII;
  261. };
  262. public ref class PdfDictionary : PdfContainer, System::Collections::Generic::IEnumerable<KeyValuePair<PdfName^, PdfObject^>>, IIndexableCollection<KeyValuePair<PdfName^, PdfObject^>> {
  263. public:
  264. property int Count {
  265. virtual int get() override { return pdf_dict_len(Context::Ptr, Ptr); }
  266. }
  267. property PdfName^ Type {
  268. PdfName^ get() {
  269. auto o = pdf_dict_get(Context::Ptr, Ptr, PDF_NAME(Type));
  270. return pdf_is_name(Context::Ptr, o) ? gcnew PdfName(o) : nullptr;
  271. }
  272. }
  273. property Kind TypeKind {
  274. virtual Kind get() override { return Kind::Dictionary; }
  275. }
  276. PdfName^ GetKey(int index) {
  277. return gcnew PdfName(pdf_dict_get_key(Context::Ptr, Ptr, index));
  278. }
  279. PdfObject^ GetValue(int index) {
  280. return PdfObject::Wrap(pdf_dict_get_val(Context::Ptr, Ptr, index));
  281. }
  282. PdfObject^ GetValue(PdfNames key) {
  283. return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, (pdf_obj*)key));
  284. }
  285. PdfObject^ GetValue(PdfNames key, PdfNames abbrev) {
  286. return PdfObject::Wrap(pdf_dict_geta(Context::Ptr, Ptr, (pdf_obj*)key, (pdf_obj*)abbrev));
  287. }
  288. PdfObject^ InheritableGet(PdfNames key) {
  289. return PdfObject::Wrap(pdf_dict_get_inheritable(Context::Ptr, Ptr, (pdf_obj*)key));
  290. }
  291. PdfObject^ Locate(... array<PdfNames>^ names);
  292. void Set(PdfNames key, PdfNames value) {
  293. pdf_dict_put_drop(Context::Ptr, Ptr, (pdf_obj*)key, (pdf_obj*)value);
  294. }
  295. void Set(PdfNames key, String^ value) {
  296. pdf_dict_put_drop(Context::Ptr, Ptr, (pdf_obj*)key, NewPdfString(value));
  297. }
  298. void Set(PdfNames key, DateTime dateTime) {
  299. pdf_dict_put_date(Context::Ptr, Ptr, (pdf_obj*)key, dateTime.ToUniversalTime().Subtract(DateTime(1970, 1, 1)).TotalSeconds);
  300. }
  301. void Sort() {
  302. pdf_sort_dict(Context::Ptr, Ptr);
  303. }
  304. bool Remove(PdfNames key) {
  305. int i = pdf_dict_len(Context::Ptr, Ptr);
  306. pdf_dict_del(Context::Ptr, Ptr, (pdf_obj*)key);
  307. return i != pdf_dict_len(Context::Ptr, Ptr);
  308. }
  309. PdfDictionary^ DeepClone() {
  310. return gcnew PdfDictionary(pdf_deep_copy_obj(Context::Ptr, Ptr));
  311. }
  312. virtual String^ ToString() override {
  313. PdfName^ type = Type;
  314. return type ? String::Concat("{", type->ToString(), "}") : "{}";
  315. }
  316. virtual System::Collections::Generic::IEnumerator<KeyValuePair<PdfName^, PdfObject^>>^ GetEnumerator() sealed = System::Collections::Generic::IEnumerable<KeyValuePair<PdfName^, PdfObject^>>::GetEnumerator {
  317. return gcnew IndexableEnumerator<PdfDictionary^, KeyValuePair<PdfName^, PdfObject^>>(this);
  318. }
  319. virtual System::Collections::IEnumerator^ GetEnumeratorBase() sealed =
  320. System::Collections::IEnumerable::GetEnumerator {
  321. return GetEnumerator();
  322. }
  323. internal:
  324. PdfDictionary(pdf_obj* obj) : PdfContainer(obj) {};
  325. public:
  326. property KeyValuePair<PdfName^, PdfObject^> default[int] {
  327. virtual KeyValuePair<PdfName^, PdfObject^> get(int index) {
  328. return KeyValuePair<PdfName^, PdfObject^>(GetKey(index), GetValue(index));
  329. };
  330. }
  331. property PdfObject^ default[PdfNames] {
  332. PdfObject^ get(PdfNames key) { return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, (pdf_obj*)key)); }
  333. void set(PdfNames key, PdfObject^ value) { pdf_dict_put(Context::Ptr, Ptr, (pdf_obj*)key, value->Ptr); }
  334. }
  335. property PdfObject^ default[PdfName^] {
  336. PdfObject^ get(PdfName^ key) { return PdfObject::Wrap(pdf_dict_get(Context::Ptr, Ptr, key->Ptr)); }
  337. void set(PdfName^ key, PdfObject^ value) { pdf_dict_put(Context::Ptr, Ptr, key->Ptr, value->Ptr); }
  338. }
  339. };
  340. public ref class PdfStream : PdfDictionary {
  341. public:
  342. property Kind TypeKind {
  343. virtual Kind get() override { return Kind::Stream; }
  344. }
  345. Stream^ Open() {
  346. return gcnew Stream(pdf_open_stream(Context::Ptr, Ptr));
  347. }
  348. Stream^ OpenRaw() {
  349. return gcnew Stream(pdf_open_raw_stream(Context::Ptr, Ptr));
  350. }
  351. array<Byte>^ GetBytes() {
  352. Stream^ s = Open();
  353. try {
  354. return s->ReadAll();
  355. }
  356. finally {
  357. delete s;
  358. }
  359. }
  360. array<Byte>^ GetRawBytes() {
  361. Stream^ s = OpenRaw();
  362. try {
  363. return s->ReadAll();
  364. }
  365. finally {
  366. delete s;
  367. }
  368. }
  369. /// <summary>
  370. /// Replaces bytes in the stream. The data must match /Filter, if <paramref name="compress"/> is true.
  371. /// </summary>
  372. /// <param name="data">The data to be placed into the stream.</param>
  373. /// <param name="compress">Whether the data is compressed. If not compressed, /Filter and /DecodeParms will be removed.</param>
  374. void SetBytes(array<Byte>^ data, bool compress);
  375. internal:
  376. PdfStream(pdf_obj* obj) : PdfDictionary(obj) {};
  377. };
  378. public ref class PdfDocumentInfo : PdfDictionary {
  379. public:
  380. property String^ Title {
  381. String^ get() { return GetString(PdfNames::Title); }
  382. }
  383. property String^ Subject {
  384. String^ get() { return GetString(PdfNames::Subject); }
  385. }
  386. property String^ Producer {
  387. String^ get() { return GetString(PdfNames::Producer); }
  388. }
  389. property String^ Creator {
  390. String^ get() { return GetString(PdfNames::Creator); }
  391. }
  392. property String^ Author {
  393. String^ get() { return GetString(PdfNames::Author); }
  394. }
  395. property String^ Keywords {
  396. String^ get() { return GetString(PdfNames::Keywords); }
  397. }
  398. property String^ CreationDate {
  399. String^ get() { return GetString(PdfNames::CreationDate); }
  400. }
  401. property String^ ModificationDate {
  402. String^ get() { return GetString(PdfNames::ModDate); }
  403. }
  404. internal:
  405. PdfDocumentInfo(pdf_obj* obj) : PdfDictionary(obj) {};
  406. private:
  407. String^ GetString(PdfNames key) {
  408. return GetValue(key)->ToString();
  409. }
  410. };
  411. public ref class PdfArray : PdfContainer, System::Collections::Generic::IEnumerable<PdfObject^>, IIndexableCollection<PdfObject^> {
  412. public:
  413. property int Count {
  414. virtual int get() override { return pdf_array_len(Context::Ptr, Ptr); }
  415. }
  416. property Kind TypeKind {
  417. virtual Kind get() override { return Kind::Array; }
  418. }
  419. PdfObject^ Get(int index) {
  420. return Wrap(pdf_array_get(Context::Ptr, Ptr, index));
  421. }
  422. bool Contains(PdfObject^ obj) {
  423. return pdf_array_contains(Context::Ptr, Ptr, obj->Ptr);
  424. }
  425. int IndexOf(PdfObject^ obj) {
  426. return pdf_array_find(Context::Ptr, Ptr, obj->Ptr);
  427. }
  428. void Append(bool value) {
  429. pdf_array_push_bool(Context::Ptr, Ptr, value);
  430. }
  431. void Append(long value) {
  432. pdf_array_push_int(Context::Ptr, Ptr, value);
  433. }
  434. void Append(double value) {
  435. pdf_array_push_real(Context::Ptr, Ptr, value);
  436. }
  437. void Append(PdfNames value) {
  438. pdf_array_push_drop(Context::Ptr, Ptr, (pdf_obj*)value);
  439. }
  440. void Append(String^ value) {
  441. pdf_array_push_drop(Context::Ptr, Ptr, NewPdfString(value));
  442. }
  443. void Append(PdfObject^ value) {
  444. pdf_array_push_drop(Context::Ptr, Ptr, value->Ptr);
  445. }
  446. void Set(int index, bool value) {
  447. pdf_array_put_bool(Context::Ptr, Ptr, index, value);
  448. }
  449. void Set(int index, long value) {
  450. pdf_array_put_int(Context::Ptr, Ptr, index, value);
  451. }
  452. void Set(int index, double value) {
  453. pdf_array_put_real(Context::Ptr, Ptr, index, value);
  454. }
  455. void Set(int index, PdfNames value) {
  456. pdf_array_put(Context::Ptr, Ptr, index, (pdf_obj*)value);
  457. }
  458. void Set(int index, String^ value) {
  459. pdf_array_put_drop(Context::Ptr, Ptr, index, NewPdfString(value));
  460. }
  461. void Set(int index, PdfObject^ value) {
  462. pdf_array_put_drop(Context::Ptr, Ptr, index, value->Ptr);
  463. }
  464. void InsertAt(int index, PdfObject^ value) {
  465. pdf_array_insert_drop(Context::Ptr, Ptr, value->Ptr, index);
  466. }
  467. void RemoveAt(int index) {
  468. pdf_array_delete(Context::Ptr, Ptr, index);
  469. }
  470. PdfArray^ DeepClone() {
  471. return gcnew PdfArray(pdf_deep_copy_obj(Context::Ptr, Ptr));
  472. }
  473. virtual String^ ToString() override { return String::Concat("[", Count.ToString(), "]"); }
  474. virtual System::Collections::Generic::IEnumerator<PdfObject^>^ GetEnumerator() sealed = System::Collections::Generic::IEnumerable<PdfObject^>::GetEnumerator{
  475. return gcnew IndexableEnumerator<PdfArray^, PdfObject^>(this);
  476. }
  477. virtual System::Collections::IEnumerator^ GetEnumeratorBase() sealed = System::Collections::IEnumerable::GetEnumerator {
  478. return GetEnumerator();
  479. }
  480. internal:
  481. PdfArray(pdf_obj* obj) : PdfContainer(obj) {};
  482. public:
  483. property PdfObject^ default[int] {
  484. virtual PdfObject^ get(int index) { return Wrap(pdf_array_get(Context::Ptr, Ptr, index)); }
  485. void set(int index, PdfObject^ value) { pdf_array_put_drop(Context::Ptr, Ptr, index, value->Ptr); }
  486. }
  487. };
  488. public ref class PdfReference : PdfObject {
  489. public:
  490. property int Number {
  491. int get() { return pdf_to_num(Context::Ptr, Ptr); }
  492. }
  493. property int Generation {
  494. int get() { return pdf_to_gen(Context::Ptr, Ptr); }
  495. }
  496. property Kind TypeKind {
  497. virtual Kind get() override { return Kind::Reference; }
  498. }
  499. PdfObject^ Resolve() {
  500. return Wrap(pdf_resolve_indirect_chain(Context::Ptr, Ptr));
  501. }
  502. virtual String^ ToString() override {
  503. return Number.ToString() + " " + Generation.ToString() + " R";
  504. }
  505. internal:
  506. PdfReference(pdf_obj* obj) : PdfObject(obj) {};
  507. };
  508. };
  509. #endif // !__PDFOBJECT