Writing text to a document (with fonts and whatnot)

Hello Everyone! First time, long time.

I’ve written a short program that reads data from several text files and then compiles it into a new text file. But this output file will include several paragraphs of text that folks are going to need to read, probably after printing it, so UTF-8 is not going to be a great format.

Is there a good path to writing to a document and being able to choose fonts and line spacing and so forth? I see how to write to a PDF, which is great, but that still leaves the issue of treating text as a graphic rather than as text with some formatting.

Thanks in advance for any thoughts!

1 Like

Hi,
I suggest you could write the output as html file

1 Like

Thank you - that’s a solid and very doable idea.

I would be interested in the results- this could become a nice library. Do you have something already?

Ironically, the originally text input was in html, so my current code strips out the tags and turns it into plain text … which I am now going to turn back into html! So I’ll probably just deal with the original html as a practical matter, but will see if I can produce some text -> html code while I’m at it.

1 Like

converting an html file into another html file (formatted differently) may also be an option. for example you could replace styles with your own; convert <div> to <p> (or back); remove scripts; whatever suits your needs

Probably there is already a library for both

I am also writing a small demo

small demo of making an HTML file

it saves an HTML file

// That's the core class: Tools to make a HTML file
ToolHTMLMaker toolHTMLMaker = new ToolHTMLMaker(); 

// class with tools, especially for making an example table  
Tools tools = new Tools(); 

// the example table
Table tResources1; 

// a list for a bullet point list 
String[] listTest={
  "banana", 
  "apple", 
  "fig"
}; 

void setup() {
  size(900, 1200);

  // make example table tResources
  tResources1 = makeATable(); 

  // start HTML 
  toolHTMLMaker.makeHTML("Test HTML page from processing");

  toolHTMLMaker.bodyAppendH1("Headline 1");
  toolHTMLMaker.bodyAppend("Hello.");
  toolHTMLMaker.bodyAppend("you.");

  toolHTMLMaker.bodyAppendH2("Headline 2");
  toolHTMLMaker.bodyAppend("Test.");
  toolHTMLMaker.bodyAppend("Test.");

  // ----

  // horiz line 
  toolHTMLMaker.bodyAppendHr();
  // Headline 
  toolHTMLMaker.bodyAppendH1("Show a table ");
  // append table 
  toolHTMLMaker.bodyAppendTable(tResources1);
  // horiz line 
  toolHTMLMaker.bodyAppendHr();

  // ----

  // Headline: show list 
  toolHTMLMaker.bodyAppendH1("Show a list ");
  // list (ul) 
  toolHTMLMaker.bodyAppendList(listTest); 

  // not working
  // toolHTMLMaker.bodyAppendAside("Side Remark. Yes");

  // save file 
  toolHTMLMaker.save();
}

void draw() {
  background(0);
  toolHTMLMaker.display();
}

//------------------------------------------------------------------------
// Tools 

Table makeATable() {
  // example table 

  // setting up table (define column names / headlines)
  Table tableTest1 = tools.newTable("Item", "brick", "wood", "sheep", "wheat", "ore", "points");

  // adding data (must match headlines)
  tableTest1 = tools.tableAddData ( tableTest1, "Street", "1x", "1x", "", "", "", "0" );  
  tableTest1 = tools.tableAddData ( tableTest1, "Settlement", "1x", "1x", "1x", "1x", "", "1" );  
  tableTest1 = tools.tableAddData ( tableTest1, "City", "", "", "", "2x", "3x", "2");  
  tableTest1 = tools.tableAddData ( tableTest1, "Dev Card", "", "", "1x", "1x", "1x", "?"  );

  return tableTest1;
}

// ======================================================================================

class ToolHTMLMaker {

  String[] headStart= {
    "<!DOCTYPE html>", 
    "<html lang=\"en\">", 
    "<head>", 
    "    <meta charset=\"utf-8\" />", 
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />", 
    "    <title>TitelReplace</title>", 
    " ", 
    "    <style>", 
    "    table, th, td {", 
    "     border: 1px solid gainsboro;", 
    "    }", 
    " ", 
    "   #Example1 {", 
    "    border-collapse: separate;", 
    "    border-spacing: 10px;", 
    "   }", 
    "   ", 
    "     #Example2 {", 
    "       border-collapse: separate;", 
    "       border-spacing: 50px 10px;", 
    "      }", 
    "   </style>", 
    " "
  };

  String[] headEnd = {
    "</head>", 
    ""
  };

  String[] bodyStart= {
    "<body>", 
    "<header>", 
    "</header>"
  };
  String[] bodyEnd = {
    "</main>", 
    "</body>", 
    "</html>"
  };
  //----
  String[] headContent = {
    " "
  };
  String[] bodyContent = {
    "<main> "
  };

  // no constr 

  void makeHTML(String title1) {
    // some preparations 
    for (int i=0; i<headStart.length; i++) {
      headStart[i] = headStart[i].replace ("TitelReplace", title1);
    }
    for (String s1 : headStart) { 
      // println(s1);
    }
  }//method

  void bodyAppend(String s1) {
    bodyContent = (String[]) append(bodyContent, "<p>"+s1+"</p>");
  }

  void bodyAppendH1(String s1) {
    // header 1
    bodyContent = (String[]) append(bodyContent, "<h1>"+s1+"</h1>");
  }

  void bodyAppendH2(String s1) {
    // header 2
    bodyContent = (String[]) append(bodyContent, "<h2>"+s1+"</h2>");
  }


  void bodyAppendH3(String s1) {
    // header 3
    bodyContent = (String[]) append(bodyContent, "<h3>"+s1+"</h3>");
  }

  void bodyAppendHr() {
    // horiz ruler 
    bodyContent = (String[]) append(bodyContent, "<hr />");
  }

  void bodyAppendTable( Table t1 ) {
    // table
    bodyContent = (String[]) append(bodyContent, "<table id=\"Example1\">");
    bodyContent = (String[]) append(bodyContent, getTableHeadline(t1));

    for (int i=0; i<t1.getRowCount(); i++) {
      bodyContent = (String[]) append(bodyContent, "  <tr>");
      bodyContent = (String[]) append(bodyContent, getTableRow(t1, i));
      bodyContent = (String[]) append(bodyContent, "  </tr>");
    }//for

    bodyContent = (String[]) append(bodyContent, "</table>");
  }//method

  void bodyAppendList( String[] list_ ) {
    // list
    bodyContent = (String[]) append(bodyContent, "<ul>");

    for (int i=0; i<list_.length; i++) {
      bodyContent = (String[]) append(bodyContent, "  <li>");
      bodyContent = (String[]) append(bodyContent, list_[i]);
      bodyContent = (String[]) append(bodyContent, "  </li>");
    }//for

    bodyContent = (String[]) append(bodyContent, "</ul>");
  }//method

  void bodyAppendAside(String s1) {
    // aside 
    // not working
    bodyContent = (String[]) append(bodyContent, "<aside>\n<p>"+s1+"</p></aside>\n");
  }

  // ----------------------------------------------------

  String getTableHeadline(Table tableBtn) { 
    // headline for table
    TableRow row0 = tableBtn.getRow(0);
    String result="  <tr>";  
    for (int i=0; i<tableBtn.getColumnCount(); i++) {
      // headline 
      // fill(GREEN);
      // text(row0.getColumnTitle(i),  i*factorX+x, y-2);
      result+="<th>"
        +row0.getColumnTitle(i)
        +"</th>";
    }
    result+="</tr>";
    return result;
  }//method 

  String getTableRow(Table tableBtn, int i_) { 
    // for table
    TableRow row0 = tableBtn.getRow(i_);
    String result="";  
    for (int i=0; i<tableBtn.getColumnCount(); i++) {

      String content = "&nbsp;"; 
      if (row0.getString(i)!=null && !row0.getString(i).equals("")) {
        content = row0.getString(i);
      }//if
      result+="    <td>"
        +content
        +"</td>";
    }
    result+="</tr>";
    return result;
  }//method 

  //--------------------------------------------------

  void display() {
    String[] result = concat(headStart, headContent);
    result = concat(result, headEnd);
    result = concat(result, bodyStart);
    result = concat(result, bodyContent);
    result = concat(result, bodyEnd);

    int i=0;
    for (String s1 : result) { 
      text(s1, 30, i*22+40);
      i++;
    }
  }

  //--------------------------------------------------

  void save() {
    String[] result = concat(headStart, headContent);
    result = concat(result, headEnd);
    result = concat(result, bodyStart);
    result = concat(result, bodyContent);
    result = concat(result, bodyEnd);

    saveStrings( "test1.html", result);
  }
}//class

//===============================================================================
// Tools collection 

class Tools {

  // class not like a car class Car for an object but a collection of tools. 

  final color RED   = color(255, 0, 0); 
  final color GREEN = color(0, 255, 0); 
  final color BLUE  = color(0, 0, 255); 

  final color WHITE = color(255); 
  final color BLACK = color(0); 
  final color GRAY  = color(255/2); 

  // ----------------------------------------------------------------

  void showTable(Table tableBtn, 
    int x, int y) { 

    int factorX=78; // column width 

    // rect
    stroke(WHITE);
    noFill();
    rect( x, y, 
      tableBtn.getColumnCount()*78-6, (tableBtn.getRowCount()+1) * 22 + 10 );

    // headline 
    showTableHeadline(tableBtn, x+6, y+19, factorX);

    // horizontal line 
    stroke(WHITE);
    line( x+2, y+5+19, 
      6+x+(tableBtn.getColumnCount())*factorX-13, y+5+19);

    // grid 
    // loop over rows (y)
    for (int i=0; i<tableBtn.getRowCount(); i++) {

      // current data row
      TableRow row = tableBtn.getRow(i);

      // loop over columns in that row (i2 is for x) 
      for (int i2=0; i2<tableBtn.getColumnCount(); i2++) {

        fill(WHITE);
        text(row.getString(i2), 
          i2*factorX+x+6, 25+ i * 22 +y+8, 
          factorX-8, 15);

        if (mouseInside(i2*factorX+x+6, 25+ i * 22 +y+8, 
          factorX-8, 15)) {
          text (row.getString(i2), 
            20, height-22);
        }//if

        // vertical line 
        line( i2*factorX+x, +y, 
          i2*factorX+x, tableBtn.getRowCount() * 22 + y + 31);
      }//for
    }//for
  }// method 

  boolean mouseInside( float x_, float y_, 
    float w_, float h_) {
    return mouseX>x_ &&
      mouseX<x_+w_ &&
      mouseY>y_ &&
      mouseY<y_+h_;
  }

  void showTableHeadline(Table tableBtn, 
    int x, int y, 
    int factorX) { 
    // headline for table 
    TableRow row0 = tableBtn.getRow(0);
    for (int i=0; i<tableBtn.getColumnCount(); i++) {
      // headline 
      fill(GREEN);
      text(row0.getColumnTitle(i), 
        i*factorX+x, y-2);
    }
  }//method 

  // ---
  // make table 

  Table newTable (String... listColumnNames) { 

    Table newT = new Table();

    // make columns
    for (String s1 : listColumnNames) {
      newT.addColumn(s1);
    }

    return newT;
  }//method

  Table tableAddData(  Table table1, String... data1  ) {
    // adding data (must match headlines)

    // check if data matches length of number of headlines / columns 
    if (table1.getColumnCount() != data1.length) { 
      println("Problem: Number of Columns ("
        +table1.getColumnCount()
        +") not equal length of data array ("
        +data1.length
        +") given to method tableAddData: "); 
      printArray(data1);
      println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 
      exit();
      return table1;
    }

    // add rows with data 
    TableRow newRow = table1.addRow();

    // add rows with data 
    int i=0; 
    for (String s1 : data1) {
      newRow.setString(newRow.getColumnTitle(i), s1);
      i++;
    }

    return table1;
  }//method

  // --- 

  void printlnTable(Table tableBtn) { 

    // rect
    stroke(WHITE);
    noFill();

    println("------------------------------------");

    // headline 
    printlnTableHeadline(tableBtn);

    // grid 
    // loop over rows (y)
    for (int i=0; i<tableBtn.getRowCount(); i++) {

      // current data row
      TableRow row = tableBtn.getRow(i);

      // loop over columns in that row (i2 is for x)
      String s1="";
      for (int i2=0; i2<tableBtn.getColumnCount(); i2++) {
        s1+="   "+row.getString(i2);
        //
      }//for
      println(s1);
    }//for
    println("===========================================");
    //
  } // method 

  void printlnTableHeadline(Table tableBtn ) { 
    // headline for table 
    TableRow row0 = tableBtn.getRow(0);
    for (int i=0; i<tableBtn.getColumnCount(); i++) {
      // headline 
      print("   "+row0.getColumnTitle(i));
    }
    println("");
  }//method 
  //
}//class
//
2 Likes

Great example, thanks!

Although I would have generalized the bodyAppend() like

void bodyAppend(String tag, String content) {
  bodyContent = (String[]) append(bodyContent, "<"+tag+">"+content+"</"+tag+">");
}

and I think it lacks the parseInput() part :slight_smile:

1 Like

Thank you!

What’s this please?

I mean the task was to transfer one html file into another, so one would need to parse the input html file first: like throw out unneeded tags or styles, whatever.

I’ve been doing such tasks a few times (not on Processing). The main thing about them is that they are never too general: there is always something we know and safely assume about the input: it’s content is formatted in a certain way, that’s why all you do is replace one tags with others.

A particular example I did was downloading and formatting long articles from the web, where all the text is in several pages and quite ugly formatted.
So for each page I had to:

  • remove headers, footers and inner advertising banners, scripts, styles;
  • replace <div> or <br> with <p>
  • format headings properly (webmasters often like to do it like <p class=header1> instead of <h1>)
  • collect all the headers to form a “Contents” links
  • and so on…
  • and finally applying a css of my own (which was the goal)
2 Likes

Yeah, I did only the output.

When you say, use a css for the HTML output, the Paragraphs would all look the same or you need to pass the style via <p id=#one>.

Is that correct?

That would probably go off topic already but

basically you would assign a style to each basic element (tag) you use in your output html file, but you also would like to assign classes to some of them to look different.

My examples include classes like epigraph or author or subtitle. The advantage of using classes here is that they can be assigned to any tag: <P> or <H1> or <h2>, they would keep their level of hierarchy though look different. For example a subtitle in some cases can be <h2> and sometimes <h3>

Here is a minimal example of how it can be used:

<HTML><HEAD>
<META content="text/html; charset=utf-8" http-equiv=Content-Type>
<STYLE type=text/css>
BODY {
	TEXT-DECORATION: none; FONT-FAMILY: Candara; FONT-VARIANT: normal; FONT-WEIGHT: normal; FONT-STYLE: normal
}
H1 {
	FONT-FAMILY: Calibri
}
H2 {
	FONT-FAMILY: Calibri
}
H3 {
	FONT-FAMILY: Calibri; FONT-STYLE: italic
}
.epigraph {
	MARGIN-LEFT: 50%
}
.textauthor {
	FONT-WEIGHT: bold; FONT-STYLE: italic; TEXT-ALIGN: right
}
.subtitle {
	TEXT-ALIGN: center
}
</STYLE>
</HEAD>
<BODY>
<H1>Example of using styles and classes in HTML</H1>
<H2 class=subtitle>Try it in your favourite browser</H2>
<H3 class=textauthor>by Luck$mith</H3>
<p class=epigraph>There are more things in heaven and earth, Horatio,<BR>
Than are dreamt of in your philosophy.</p>
<p class=textauthor>Shakespeare, Hamlet (1.5.167-8)</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</BODY></HTML>
2 Likes

Thanks for that!!

I haven’t done a general appendTag() method in the class but sounds like a good idea

BTW, in some simple cases, the built-in support of XML can be used :wink:

2 Likes

Another option – if your formatting is structured, and depending on your needs – is to use a minimal markup format internally and then drop it into a post-processor library. For example, if you can extract your text and then format it as Markdown (which is fairly simple) then you could dump a block of formatted markdown into a Java Markdown library, get back html, and put it into a document with CSS for your styling.

2 Likes