From 57315d9754a90f3a5342a6018833b33d91799f5e Mon Sep 17 00:00:00 2001 From: tangdouer1005 <884746853@qq.com> Date: Fri, 8 Sep 2023 12:41:59 +0800 Subject: [PATCH] [29_1] attach tm doc in exporting pdf and load the pdf --- TeXmacs/progs/texmacs/texmacs/tm-files.scm | 4 + TeXmacs/tests/29_1_1.tm | 9 + TeXmacs/tests/images/29_1_1.pdf | Bin 0 -> 3308 bytes src/Edit/Editor/edit_main.cpp | 144 ++++++++++ src/Edit/Editor/edit_main.hpp | 1 + src/Plugins/Pdf/pdf_hummus_get_attachment.cpp | 162 +++++++++++ src/Plugins/Pdf/pdf_hummus_get_attachment.hpp | 25 ++ .../Pdf/pdf_hummus_make_attachment.cpp | 269 ++++++++++++++++++ .../Pdf/pdf_hummus_make_attachment.hpp | 27 ++ src/Scheme/Plugins/glue_pdf.lua | 8 + src/Scheme/Plugins/init_glue_plugins.cpp | 2 + .../Plugins/Pdf/pdf_make_attachment_test.cpp | 39 +++ 12 files changed, 690 insertions(+) create mode 100644 TeXmacs/tests/29_1_1.tm create mode 100644 TeXmacs/tests/images/29_1_1.pdf create mode 100644 src/Plugins/Pdf/pdf_hummus_get_attachment.cpp create mode 100644 src/Plugins/Pdf/pdf_hummus_get_attachment.hpp create mode 100644 src/Plugins/Pdf/pdf_hummus_make_attachment.cpp create mode 100644 src/Plugins/Pdf/pdf_hummus_make_attachment.hpp create mode 100644 tests/Plugins/Pdf/pdf_make_attachment_test.cpp diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files.scm b/TeXmacs/progs/texmacs/texmacs/tm-files.scm index 02f450cd63..49a577f32e 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files.scm @@ -513,6 +513,10 @@ (if (current-buffer) (set! name (url-relative (current-buffer) name)) (set! name (url-append (url-pwd) name)))) + (if (and (string=? (url-format name) "pdf") (get-attachments name)) + (let* ((tm-name (url-glue (url-relative name (url-basename name)) ".tm"))) + (if(url-exists? tm-name) + (set! name tm-name)))) (load-buffer-check-autosave name opts)) (tm-define (load-buffer name . opts) diff --git a/TeXmacs/tests/29_1_1.tm b/TeXmacs/tests/29_1_1.tm new file mode 100644 index 0000000000..d1ccab8ea1 --- /dev/null +++ b/TeXmacs/tests/29_1_1.tm @@ -0,0 +1,9 @@ + + +> + +<\initial> + <\collection> + + + \ No newline at end of file diff --git a/TeXmacs/tests/images/29_1_1.pdf b/TeXmacs/tests/images/29_1_1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1e3209c296f34996c9447e3543de657cb691ffe1 GIT binary patch literal 3308 zcmcIn3se(l76w*p6G^q}sim&yUpy?h6f!f(GpC;pz75*>iSs zl9~U`z4yQOzu$c%G%ZdaiATvL;?Pq~CnaJWV1Ugll!&9FfplfDg9cJv5g%{lDV~;y zrOBB9kHXM{76`ZH!Yw5k;Fv%+Bm${{wo*K^f!4BCmSb!*&oL$_vLX!>P*x{W!#YMD z^-xrhG-^g@u_-{B%5pZ!3VDqwlyeKQ9fb3m$xM$&P#iOq-nB55*hH}e)CgUkkxyp!i>$|eyPRoix_h`(4C zxP5SIcVDE-7m ztQUO7Nf;d;RpFyXLn)Crs%ey2@H>s-Xgd#-9=}D>6gr=wV%Z|F22wCUs>vuqsg}uc zppxTJDm6)9ILJnN478JVaVFXc1id0@8poQ9G!G@E5LFO9bP+GGibgTyWUuHI1jJVgrs6MBJw9RQ>VIbbY6RHIVJ zFQY4u7l4o8k82U>=P{!mHN+Q?qH0tAS}JdCe!hF-6#p>WrOrbSO5Lr|{SUfJJImc6 zS07Zk4@LJJe9+x`@}T=}XLW0cc3bH$%VyWl4+vaZ``nf`Y`Bbm`26P~XRehU=!gjG zXnB6{mE3{!<}K>2=N@r;uD?V-7ZgMeX=+b^vixg)_@n7t6EggtDA0e|wpTq+S6rvt z5n8uU%;rQ zre@hw@tNkZv?s!Qd%K=8obSTx7{eL&-Ui8!bNWfg--mxF`q%Xui{k#Bf$vMsgtZU6 zO|HKf_r}uYx8~gHxv=CJ$?@G1GWd9nE_nMAUC-Prw|aW6R^D&idhOH9X=OLkbJ}y< z+3pN?X4jhYUGfj9O_y#ByfnA|%4bWdN8hydE;+Kfu)ktJR5N_L#5QYnnh!RUV zX#wm~4Z30@bS{o{(3D-v+8i!eo>E{{;_Q(I)<)S4wAp2)I2>~b+Vl+P%Ljn1UpR()a)SL3;?LKxc<#l(Cy(7l2#Bq=ZMnX4n~2Tmg=Hia%8~R zu546SPa>{7&6Teg`)7SCG0pLn@EujJ~q-+mK*dP?$#N!@;ijdu32Ss1ZB|h8=|n0U?#L!QtY6z(17LQ#Qt048nbB1AKV{Jc+Z=w}}z< zaNcAY9Va|{XVQ$>!UH)bq!6+u*35C+jp$ z6Y83fK|mbDG+H7_wANCN1kVl%6)X}W=_>D1E)(7xdD`}(M-fV7)HB1SaK7=FZKcdk zAR~M(Kv>c;fO^z~W`|n#q_akC-6`0>x}ZfkdQ4*SQ6``q|s4-d?)*c53 zI}jeXh`}ycO_w internal_styles; + +static void +declare_style (url u) { + if (is_or (u)) { + declare_style (u[1]); + declare_style (u[2]); + } + else if (is_concat (u)) { + string dir= upcase_first (as_string (u[1])); + if (dir == "CVS" || dir == ".svn"); + else declare_style (u[2]); + } + else if (is_atomic (u)) { + string s= as_string (u); + if (ends (s, ".ts") && !starts (s, "source")) { + internal_styles->insert (s(0,N(s)-3)); + if (starts (s, "old-")) + internal_styles->insert (s(4,N(s)-3)); + if (starts (s, "old2-")) + internal_styles->insert (s(5,N(s)-3)); + } + } +} + +static bool +is_internal_style (string style) { + return true; + + if (N (internal_styles) == 0) { + url sty_u= descendance ("$TEXMACS_STYLE_ROOT"); + declare_style (sty_u); + } + return internal_styles->contains (style); +} void edit_main_rep::print_to_file (url name, string first, string last) { print_doc (name, false, as_int (first), as_int (last)); + + if ((suffix (name) == "pdf")) { + if (as_bool (call ("get-boolean-preference", + "gui:export PDF with tm attachment"))) { + if (!attach_doc_to_exported_pdf (name)) { + debug_convert << "fail : attach_doc_to_exported_pdf" << LF; + } + } + } set_message ("Done printing", "print to file"); } +bool +edit_main_rep::attach_doc_to_exported_pdf (url pdf_name) { + // copy the current buffer to a new buffer + string dir ("$TEXMACS_HOME_PATH/texts/scratch/"); + string name_= basename (pdf_name) * string (".tm"); + url tmp_save_path (dir, name_); + + url new_u= make_new_buffer (); + rename_buffer (new_u, tmp_save_path); + new_u = tmp_save_path; + url cur_u= get_current_buffer (); + call ("buffer-copy", cur_u, new_u); + buffer_save (new_u); + + // Re-read the saved file to update the buffer, otherwise there is no style in + // the export tree + tree new_t= import_tree (new_u, "texmacs"); + set_buffer_tree (new_u, new_t); + new_t= get_buffer_tree (new_u); + + // dfs search all style and link + list st (new_t); + list tm_and_linked_file (new_u); + while (N (st) != 0) { + auto la= last_item (st); + st = suppress_last (st); + for (int i= 0; i < arity (la); i++) { + if (is_compound (la[i])) { + string label= get_label (la[i]); + if (label == "image" || label == "include") { + if (is_atomic (la[i][0])) { + url pre_url= url (la[i][0]->label); + if (!exists (pre_url)) { + pre_url= head (cur_u) * pre_url; + if (!exists (pre_url)) { + debug_convert << pre_url << "do not exist" << LF; + } + } + tm_and_linked_file= tm_and_linked_file * pre_url; + string name = as_string (tail (pre_url)); + la[i][0]->label = string (name); + } + } + else if (label == "style") { + if (is_func (la[i][0], TUPLE)) { + for (int j= 0; j < N (la[i][0]); j++) { + string style_name= get_label (la[i][0][j]); + if (!is_internal_style (style_name)) { + url style_url= url (style_name); + style_url = glue (style_url, ".ts"); + if (!exists (style_url)) { + style_url= head (cur_u) * style_url; + if (!exists (style_url)) { + debug_convert << style_url << "do not exist" << LF; + } + } + tm_and_linked_file= tm_and_linked_file * style_url; + string name = basename (style_url); + la[i][0][j]->label= name; + } + } + } + else { + if (!is_atomic (la[i][0])) { + debug_convert << get_label (la[i][0]) << "is not atomic tree" << LF; + } + string style_name= get_label (la[i][0]); + if (!is_internal_style (style_name)) { + url style_url= url (style_name); + style_url = glue (style_url, ".ts"); + if (!exists (style_url)) { + style_url= head (cur_u) * style_url; + if (!exists (style_url)) { + debug_convert << style_url << "do not exist" << LF; + } + } + tm_and_linked_file= tm_and_linked_file * style_url; + string name= basename (style_url); + la[i][0]->label= name; + } + } + } + else st= st * la[i]; + } + } + } + + set_buffer_tree (new_u, new_t); + buffer_save (new_u); + new_t= get_buffer_tree (new_u); + + if (!pdf_hummus_make_attachments (pdf_name, tm_and_linked_file, pdf_name)) { + debug_convert << "fail : pdf_hummus_make_attachments" << LF; + return false; + } + return true; +} + void edit_main_rep::print_buffer (string first, string last) { url target; diff --git a/src/Edit/Editor/edit_main.hpp b/src/Edit/Editor/edit_main.hpp index 9d72f21e36..0f24893c4d 100644 --- a/src/Edit/Editor/edit_main.hpp +++ b/src/Edit/Editor/edit_main.hpp @@ -68,6 +68,7 @@ class edit_main_rep: int nr_pages (); void print_doc (url ps_name, bool to_file, int first, int last); void print_to_file (url ps_name, string first="1", string last="1000000"); + bool attach_doc_to_exported_pdf (url pdf_name); void print_buffer (string first="1", string last="1000000"); void export_ps (url ps_name, string first="1", string last="1000000"); array print_snippet (url u, tree t, bool conserve_preamble); diff --git a/src/Plugins/Pdf/pdf_hummus_get_attachment.cpp b/src/Plugins/Pdf/pdf_hummus_get_attachment.cpp new file mode 100644 index 0000000000..b2d20496be --- /dev/null +++ b/src/Plugins/Pdf/pdf_hummus_get_attachment.cpp @@ -0,0 +1,162 @@ +/****************************************************************************** + * MODULE : pdf_hummus_get_attachment.cpp + * DESCRIPTION: Interface for getting attachment file in pdf + * COPYRIGHT : (C) 2023 Tangdouer + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ +#include "PDFWriter/PDFWriter.h" +#include "PDFWriter/SafeBufferMacrosDefs.h" +#include "PDFWriter/Trace.h" + +#include "PDFWriter/InputFileStream.h" +#include "PDFWriter/OutputBufferedStream.h" +#include "PDFWriter/OutputFileStream.h" +#include "PDFWriter/OutputStreamTraits.h" +#include "PDFWriter/PDFArray.h" +#include "PDFWriter/PDFLiteralString.h" +#include "PDFWriter/PDFObjectCast.h" +#include "PDFWriter/PDFParser.h" +#include "PDFWriter/PDFStreamInput.h" +using namespace PDFHummus; +#include +using namespace IOBasicTypes; +#include "pdf_hummus_get_attachment.hpp" + +bool +get_tm_attachments_in_pdf (url pdf_path, array& names) { + EStatusCode status= PDFHummus::eSuccess; + InputFile pdfFile; + PDFParser parser; + do { + status= pdfFile.OpenFile (as_charp (as_string (pdf_path))); + if (status != PDFHummus::eSuccess) { + cout << "fail to open " << as_string (pdf_path) << LF; + break; + } + parser.StartPDFParsing (pdfFile.GetInputStream ()); + PDFObjectCastPtr catalog ( + parser.QueryDictionaryObject (parser.GetTrailer (), "Root")); + // return 0; + if (!catalog) { + cout << "Can't find catalog. fail\n"; + status= PDFHummus::eFailure; + break; + } + + PDFObjectCastPtr d_1 (catalog->QueryDirectObject ("Names")); + if (!d_1) { + cout << "Can't find d1. fail\n"; + status= PDFHummus::eFailure; + break; + } + PDFObjectCastPtr d_2 ( + d_1->QueryDirectObject ("EmbeddedFiles")); + if (!d_2) { + cout << "Can't find d2. fail\n"; + status= PDFHummus::eFailure; + break; + } + + PDFObjectCastPtr arr (d_2->QueryDirectObject ("Names")); + if (!arr) { + cout << "Can't find arr. fail\n"; + status= PDFHummus::eFailure; + break; + } + unsigned long n= arr->GetLength (); + if (n & 1) { + cout << "n is wrong\n"; + break; + } + for (unsigned long i= 0; i < n; i+= 2) { + PDFObjectCastPtr name (arr->QueryObject (i)); + if (!name) { + cout << "Can't find name\n"; + status= PDFHummus::eFailure; + break; + } + PDFObjectCastPtr arr_d1 (arr->QueryObject (i + 1)); + if (!arr_d1) { + cout << "Can't find arr_d1\n"; + status= PDFHummus::eFailure; + break; + } + PDFObjectCastPtr arr_d2 (arr_d1->QueryDirectObject ("EF")); + if (!arr_d2) { + cout << "Can't find arr_d2\n"; + status= PDFHummus::eFailure; + break; + } + PDFObjectCastPtr stream ( + parser.QueryDictionaryObject (arr_d2.GetPtr (), "F")); + if (!stream) { + cout << "Can't find stream\n"; + status= PDFHummus::eFailure; + break; + } + PDFDictionary* dir= stream->QueryStreamDictionary (); + + IByteReader* streamReader= + parser.CreateInputStreamReader (stream.GetPtr ()); + if (!streamReader) { + cout << "Can't find streamReader\n"; + status= PDFHummus::eFailure; + break; + } + + url attachment_path= + relative (pdf_path, url (string (name->GetValue ().c_str ()))); + OutputFile attachment_file; + status= attachment_file.OpenFile ( + std::string (as_charp (as_string (attachment_path)))); + if (status != PDFHummus::eSuccess) { + cout << "fail to open " << as_string (attachment_path) << LF; + break; + } + pdfFile.GetInputStream ()->SetPosition (stream->GetStreamContentStart ()); + OutputStreamTraits copy_help ( + (IByteWriter*) attachment_file.GetOutputStream ()); + status= copy_help.CopyToOutputStream (streamReader); + if (status != PDFHummus::eSuccess) { + cout << "Can't CopyToOutputStream\n"; + break; + } + status= attachment_file.CloseFile (); + if (status != PDFHummus::eSuccess) { + cout << "fail to close " << as_string (attachment_path) << LF; + break; + } + + names= append (attachment_path, names); + cout << "\n\n" << names << LF; + delete streamReader; + } + } while (0); + if (status == PDFHummus::eFailure) return false; + else return true; +} + +bool +get_tm_attachment_in_pdf (url pdf_path, url& name) { + array names; + if (get_tm_attachments_in_pdf (pdf_path, names)) { + if (N (names) != 1) { + cout << "TODO: many attachment" << LF; + return false; + } + name= names[0]; + return true; + } + else { + return false; + } +} + +bool +scm_get_attachments (url pdf_path) { + array attachments_paths; + return get_tm_attachments_in_pdf (pdf_path, attachments_paths); +} diff --git a/src/Plugins/Pdf/pdf_hummus_get_attachment.hpp b/src/Plugins/Pdf/pdf_hummus_get_attachment.hpp new file mode 100644 index 0000000000..efdbe8673e --- /dev/null +++ b/src/Plugins/Pdf/pdf_hummus_get_attachment.hpp @@ -0,0 +1,25 @@ +/****************************************************************************** + * MODULE : pdf_hummus_get_attachment.cpp + * DESCRIPTION: Interface for getting attachment file in pdf + * COPYRIGHT : (C) 2023 Tangdouer + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ +#ifndef PDF_HUMMUS_GET_ATTACHMENT_H +#define PDF_HUMMUS_GET_ATTACHMENT_H +#include "hashmap.hpp" +#include "iterator.hpp" +#include "list.hpp" +#include "string.hpp" +#include "tm_ostream.hpp" +#include "url.hpp" + +bool get_tm_attachments_in_pdf (url pdf_path, array& names); + +bool get_tm_attachment_in_pdf (url pdf_path, url& name); + +bool scm_get_attachments (url pdf_path); + +#endif // ifdef PDF_HUMMUS_MAKE_ATTACHMENT_H diff --git a/src/Plugins/Pdf/pdf_hummus_make_attachment.cpp b/src/Plugins/Pdf/pdf_hummus_make_attachment.cpp new file mode 100644 index 0000000000..36bbb23979 --- /dev/null +++ b/src/Plugins/Pdf/pdf_hummus_make_attachment.cpp @@ -0,0 +1,269 @@ +/****************************************************************************** + * MODULE : pdf_hummus_make_attachment.cpp + * DESCRIPTION: Interface for embedding text files into pdf files + * COPYRIGHT : (C) 2023 Tangdouer + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ +#include "pdf_hummus_make_attachment.hpp" + +#include "PDFWriter/DictionaryContext.h" +#include "PDFWriter/ObjectsContext.h" +#include "PDFWriter/PDFRectangle.h" +#include "PDFWriter/PDFStream.h" +#include "PDFWriter/PDFWriter.h" +#include "PDFWriter/SafeBufferMacrosDefs.h" +#include "PDFWriter/Trace.h" + +#include "PDFWriter/InputFileStream.h" +#include "PDFWriter/OutputBufferedStream.h" +#include "PDFWriter/OutputFileStream.h" +using namespace PDFHummus; + +using namespace IOBasicTypes; +class PDFAttachment { +public: + PDFAttachment (void); + PDFAttachment (string attachment_path); + PDFAttachment (Byte inByte[], size_t inLenth, string inName); + ~PDFAttachment (void); + + Byte* file_content; + size_t lenth; + string name; +}; + +class PDFWriter; + +typedef hashmap PDFAttachmentToObjectIDTypeMap; + +class PDFAttachmentWriter : public DocumentContextExtenderAdapter { +public: + PDFAttachmentWriter (PDFWriter* inPDFWriter); + ~PDFAttachmentWriter (void); + + EStatusCode AttachToAllPage (PDFAttachment* inAttachment); + + virtual EStatusCode + OnCatalogWrite (CatalogInformation* inCatalogInformation, + DictionaryContext* inCatalogDictionaryContext, + ObjectsContext* inPDFWriterObjectContext, + DocumentContext* inPDFWriterDocumentContext); + +private: + PDFWriter* mPDFWriter; + PDFAttachmentToObjectIDTypeMap mAttachment; + void ListenOnCatalogWrite (); + EStatusCodeAndObjectIDType WriteAttachment (PDFAttachment* inAttachment); + void CleanupAttachment (); +}; +bool +pdf_hummus_make_attachments (url pdf_path, list attachment_paths, + url out_path) { + PDFWriter pdfWriter; + EStatusCode status; + do { + status= pdfWriter.ModifyPDF (as_charp (as_string (pdf_path)), ePDFVersion16, + as_charp (as_string (out_path))); + + if (status != eSuccess) { + cout << "start fail\n"; + break; + } + PDFAttachmentWriter attachmentWriter (&pdfWriter); + + for (int i= 0; i < (int) N (attachment_paths); i++) { + string attachment_path= as_string (attachment_paths[i]); + InputFileStream tm_file_stream; + status= tm_file_stream.Open (as_charp (attachment_path)); + + if (status != PDFHummus::eSuccess) { + cout << "failed to open " << attachment_path << "\n"; + continue; + } + else { + cout << "success to open " << attachment_path << "\n"; + } + + LongFilePositionType file_size= tm_file_stream.GetFileSize (); + + Byte* file_content= new Byte[file_size + 16]; + tm_file_stream.Read (file_content, file_size); + + string attachment_name= as_string (tail (attachment_paths[i])); + + PDFAttachment* aAttachment= + new PDFAttachment (file_content, file_size, attachment_name); + status= attachmentWriter.AttachToAllPage (aAttachment); + // return status; + if (status != eSuccess) { + cout << "fail to attach " << attachment_path << "\n"; + continue; + } + else { + cout << "success to attach " << attachment_path << "\n"; + continue; + } + } + status= pdfWriter.EndPDF (); + } while (false); + + if (eSuccess == status) { + cout << "Succeeded in creating PDF file\n"; + return true; + } + else { + cout << "Failed in creating PDF file\n"; + return false; + } +} + +bool +pdf_hummus_make_attachment (url pdf_path, url attachment_path, url out_path) { + if ((suffix (pdf_path) == "pdf")) + return pdf_hummus_make_attachments (pdf_path, list (attachment_path), + out_path); + else return false; +} +PDFAttachment::PDFAttachment (void) { + file_content= NULL; + lenth = 0; +} + +PDFAttachment::PDFAttachment (string attachment_path) { + InputFileStream tm_file_stream; + EStatusCode status= tm_file_stream.Open (as_charp (attachment_path)); + if (status != PDFHummus::eSuccess) { + cout << "failed to open tm\n"; + return; + } + + lenth= (size_t) tm_file_stream.GetFileSize (); + + file_content= new Byte[lenth + 16]; + tm_file_stream.Read (file_content, lenth); + + int i, last_slash_index= 0; + for (i= 0; i < N (attachment_path); i++) { + if (attachment_path[i] == '/') last_slash_index= i; + } + name= attachment_path (last_slash_index + 1, N (attachment_path)); +} +PDFAttachment::PDFAttachment (Byte inByte[], size_t inLenth, string inName) { + file_content= inByte; + lenth = inLenth; + name = inName; +} + +PDFAttachment::~PDFAttachment (void) { + if (file_content) delete file_content; +} + +PDFAttachmentWriter::PDFAttachmentWriter (PDFWriter* inPDFWriter) { + mPDFWriter= inPDFWriter; + ListenOnCatalogWrite (); +} + +void +PDFAttachmentWriter::ListenOnCatalogWrite () { + mPDFWriter->GetDocumentContext ().AddDocumentContextExtender (this); +} + +PDFAttachmentWriter::~PDFAttachmentWriter (void) { + if (N (mAttachment) != 0) + TRACE_LOG ("PDFAttachmentWriter::~PDFAttachmentWriter, Exception. Has " + "attachement that were not associated with pages"); + CleanupAttachment (); +} + +EStatusCode +PDFAttachmentWriter::OnCatalogWrite ( + CatalogInformation* inCatalogInformation, + DictionaryContext* inCatalogDictionaryContext, + ObjectsContext* inPDFWriterObjectContext, + DocumentContext* inPDFWriterDocumentContext) { + if (N (mAttachment) == 0) return eSuccess; + + inCatalogDictionaryContext->WriteKey ("Names"); + + DictionaryContext* dictionaryContext_0= + inPDFWriterObjectContext->StartDictionary (); + dictionaryContext_0->WriteKey ("EmbeddedFiles"); + DictionaryContext* dictionaryContext_1= + inPDFWriterObjectContext->StartDictionary (); + dictionaryContext_0->WriteKey ("Names"); + inPDFWriterObjectContext->StartArray (); + + iterator it= iterate (mAttachment); + + while (it->busy ()) { + PDFAttachment* cur_attachment= it->next (); + inPDFWriterObjectContext->WriteLiteralString ( + as_charp (cur_attachment->name)); + DictionaryContext* dictionaryContext_2= + inPDFWriterObjectContext->StartDictionary (); + dictionaryContext_2->WriteKey ("EF"); + DictionaryContext* dictionaryContext_3= + inPDFWriterObjectContext->StartDictionary (); + dictionaryContext_3->WriteKey ("F"); + inPDFWriterObjectContext->WriteIndirectObjectReference ( + mAttachment[cur_attachment]); + inPDFWriterObjectContext->EndDictionary (dictionaryContext_3); + dictionaryContext_2->WriteKey ("F"); + dictionaryContext_2->WriteLiteralStringValue ( + as_charp (cur_attachment->name)); + dictionaryContext_2->WriteKey ("Type"); + dictionaryContext_2->WriteNameValue ("F"); + inPDFWriterObjectContext->EndDictionary (dictionaryContext_2); + } + inPDFWriterObjectContext->EndArray (); + inPDFWriterObjectContext->EndDictionary (dictionaryContext_1); + inPDFWriterObjectContext->EndDictionary (dictionaryContext_0); + CleanupAttachment (); + return eSuccess; +} + +void +PDFAttachmentWriter::CleanupAttachment () { + + iterator it= iterate (mAttachment); + while (it->busy ()) { + delete it->next (); + } + mAttachment= PDFAttachmentToObjectIDTypeMap (); +} + +EStatusCode +PDFAttachmentWriter::AttachToAllPage (PDFAttachment* inAttachment) { + return WriteAttachment (inAttachment).first; +} + +EStatusCodeAndObjectIDType +PDFAttachmentWriter::WriteAttachment (PDFAttachment* inAttachment) { + EStatusCodeAndObjectIDType result; + if (mAttachment->contains (inAttachment)) { + result.first = eSuccess; + result.second= mAttachment[inAttachment]; + return result; + } + + do { + ObjectsContext& objectsContext= mPDFWriter->GetObjectsContext (); + + result.second= objectsContext.StartNewIndirectObject (); + + DictionaryContext* dictionaryContext= objectsContext.StartDictionary (); + dictionaryContext->WriteKey ("Type"); + dictionaryContext->WriteNameValue ("EmbeddedFile"); + PDFStream* pdfStream= objectsContext.StartPDFStream (dictionaryContext); + IByteWriter* mwriter = pdfStream->GetWriteStream (); + mwriter->Write (inAttachment->file_content, inAttachment->lenth); + objectsContext.EndPDFStream (pdfStream); + + mAttachment (inAttachment)= result.second; + result.first = eSuccess; + } while (false); + return result; +} diff --git a/src/Plugins/Pdf/pdf_hummus_make_attachment.hpp b/src/Plugins/Pdf/pdf_hummus_make_attachment.hpp new file mode 100644 index 0000000000..25d7392693 --- /dev/null +++ b/src/Plugins/Pdf/pdf_hummus_make_attachment.hpp @@ -0,0 +1,27 @@ +/****************************************************************************** + * MODULE : pdf_hummus_make_attachment.hpp + * DESCRIPTION: Interface for embedding text files into pdf files + * COPYRIGHT : (C) 2023 Tangdouer + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#ifndef PDF_HUMMUS_MAKE_ATTACHMENT_H +#define PDF_HUMMUS_MAKE_ATTACHMENT_H + +#include "hashmap.hpp" +#include "iterator.hpp" +#include "list.hpp" +#include "string.hpp" +#include "tm_ostream.hpp" +#include "url.hpp" + +bool pdf_hummus_make_attachments (url pdf_path, list attachment_path, + url out_path); + +bool pdf_hummus_make_attachment (url pdf_path, url attachment_path, + url out_path); + +#endif // ifdef PDF_HUMMUS_MAKE_ATTACHMENT_H diff --git a/src/Scheme/Plugins/glue_pdf.lua b/src/Scheme/Plugins/glue_pdf.lua index fe284a3092..15bc84cb89 100644 --- a/src/Scheme/Plugins/glue_pdf.lua +++ b/src/Scheme/Plugins/glue_pdf.lua @@ -25,6 +25,14 @@ function main() cpp_name = "pdfhummus_version", ret_type = "string" }, + { + scm_name = "get-attachments", + cpp_name = "scm_get_attachments", + ret_type = "bool", + arg_list = { + "url" + } + }, } } end diff --git a/src/Scheme/Plugins/init_glue_plugins.cpp b/src/Scheme/Plugins/init_glue_plugins.cpp index 7b1310223a..38c5a08b15 100644 --- a/src/Scheme/Plugins/init_glue_plugins.cpp +++ b/src/Scheme/Plugins/init_glue_plugins.cpp @@ -56,6 +56,8 @@ pdfhummus_version () { } #include "glue_ghostscript.cpp" + +#include "Pdf/pdf_hummus_get_attachment.hpp" #include "glue_pdf.cpp" void diff --git a/tests/Plugins/Pdf/pdf_make_attachment_test.cpp b/tests/Plugins/Pdf/pdf_make_attachment_test.cpp new file mode 100644 index 0000000000..495b85d9ae --- /dev/null +++ b/tests/Plugins/Pdf/pdf_make_attachment_test.cpp @@ -0,0 +1,39 @@ + +/****************************************************************************** + * MODULE : pdf_make_attachment_test.cpp + * COPYRIGHT : (C) Tangdouer + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "file.hpp" +#include "pdf_hummus_make_attachment.hpp" +#include "sys_utils.hpp" +#include + +class TestHummusPdfMakeAttachment : public QObject { + Q_OBJECT + +private slots: + void init () { lolly::init_tbox (); } + void test_pdf_hummus_make_attachment (); +}; + +void +TestHummusPdfMakeAttachment::test_pdf_hummus_make_attachment () { + + bool attach_judge= pdf_hummus_make_attachment ( + url ("$TEXMACS_PATH/tests/images/29_1_1.pdf"), + url ("$TEXMACS_PATH/tests/29_1_1.tm"), + url ("$TEXMACS_PATH/tests/images/29_1_1_attach.pdf")); + QVERIFY (attach_judge); + + bool out_pdf_judge= + is_regular (url ("$TEXMACS_PATH/tests/images/29_1_1_attach.pdf")); + QVERIFY (out_pdf_judge); +} + +QTEST_MAIN (TestHummusPdfMakeAttachment) +#include "pdf_make_attachment_test.moc"