Skip to content

Commit

Permalink
[29_1] attach tm doc in exporting pdf and load the pdf
Browse files Browse the repository at this point in the history
  • Loading branch information
tangdouer1005 authored Sep 8, 2023
1 parent 7ebc87f commit 57315d9
Show file tree
Hide file tree
Showing 12 changed files with 690 additions and 0 deletions.
4 changes: 4 additions & 0 deletions TeXmacs/progs/texmacs/texmacs/tm-files.scm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions TeXmacs/tests/29_1_1.tm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<TeXmacs|2.1.2>

<style|<tuple|generic|british>>

<\initial>
<\collection>
<associate|page-medium|paper>
</collection>
</initial>
Binary file added TeXmacs/tests/images/29_1_1.pdf
Binary file not shown.
144 changes: 144 additions & 0 deletions src/Edit/Editor/edit_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "observers.hpp"


#include "Pdf/pdf_hummus_make_attachment.hpp"

#ifdef EXPERIMENTAL
#include "../../Style/Memorizer/clean_copy.hpp"
#endif
Expand Down Expand Up @@ -317,13 +319,155 @@ edit_main_rep::print_doc (url name, bool conform, int first, int last) {
}
#endif
}
static hashset<string> 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<tree> st (new_t);
list<url> 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;
Expand Down
1 change: 1 addition & 0 deletions src/Edit/Editor/edit_main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> print_snippet (url u, tree t, bool conserve_preamble);
Expand Down
162 changes: 162 additions & 0 deletions src/Plugins/Pdf/pdf_hummus_get_attachment.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/
#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 <utility>
using namespace IOBasicTypes;
#include "pdf_hummus_get_attachment.hpp"

bool
get_tm_attachments_in_pdf (url pdf_path, array<url>& 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<PDFDictionary> catalog (
parser.QueryDictionaryObject (parser.GetTrailer (), "Root"));
// return 0;
if (!catalog) {
cout << "Can't find catalog. fail\n";
status= PDFHummus::eFailure;
break;
}

PDFObjectCastPtr<PDFDictionary> d_1 (catalog->QueryDirectObject ("Names"));
if (!d_1) {
cout << "Can't find d1. fail\n";
status= PDFHummus::eFailure;
break;
}
PDFObjectCastPtr<PDFDictionary> d_2 (
d_1->QueryDirectObject ("EmbeddedFiles"));
if (!d_2) {
cout << "Can't find d2. fail\n";
status= PDFHummus::eFailure;
break;
}

PDFObjectCastPtr<PDFArray> 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<PDFLiteralString> name (arr->QueryObject (i));
if (!name) {
cout << "Can't find name\n";
status= PDFHummus::eFailure;
break;
}
PDFObjectCastPtr<PDFDictionary> arr_d1 (arr->QueryObject (i + 1));
if (!arr_d1) {
cout << "Can't find arr_d1\n";
status= PDFHummus::eFailure;
break;
}
PDFObjectCastPtr<PDFDictionary> arr_d2 (arr_d1->QueryDirectObject ("EF"));
if (!arr_d2) {
cout << "Can't find arr_d2\n";
status= PDFHummus::eFailure;
break;
}
PDFObjectCastPtr<PDFStreamInput> 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<url> 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<url> attachments_paths;
return get_tm_attachments_in_pdf (pdf_path, attachments_paths);
}
25 changes: 25 additions & 0 deletions src/Plugins/Pdf/pdf_hummus_get_attachment.hpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/gpl-3.0.html>.
******************************************************************************/
#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<url>& 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
Loading

0 comments on commit 57315d9

Please sign in to comment.