# Converting a text file into a .tex file using C++

I have a text file which contains data like this:

word: 'Swine';      conf: 92.03;pointsize:'48':,font_name:'Verdana_Bold',X1:'152', X2:'283', Y1: '166', Y2: '202
word: 'flu';    conf: 93.43;pointsize:'48':,font_name:'Verdana_Bold',X1:'299', X2:'354', Y1: '164', Y2: '202
word: 'tightens';   conf: 90.12;pointsize:'48':,font_name:'Verdana_Bold',X1:'370', X2:'551', Y1: '164', Y2: '211
word: 'its';    conf: 96.04;pointsize:'48':,font_name:'Verdana_Bold',X1:'568', X2:'617', Y1: '166', Y2: '202
word: 'grip';   conf: 90.41;pointsize:'48':,font_name:'Verdana_Bold',X1:'632', X2:'716', Y1: '166', Y2: '211
word: 'over';   conf: 94.29;pointsize:'48':,font_name:'Verdana_Bold',X1:'732', X2:'831', Y1: '175', Y2: '202
word: 'India';      conf: 94.00;pointsize:'48':,font_name:'Verdana_Bold',X1:'848', X2:'953', Y1: '164', Y2: '202

With the following meanings:

Word: Actual word to be printed
Pointsize : Font size
Font name: Name of font used
X1,X2,Y1,Y2: Coordinates of location of word in the document

I want to take all this data, and put it as it is in a latex document. Now, I know I have to make a C++ code for this, by first opening a .tex file and start writing down the data by reading from the text file. The problem I am facing is, how to set the exact fonts and size of the text as mentioned in the file? Thanks!

Edit: Finally, I want to make a pdf file from the generated .tex file using the terminal commands. Also, I referred the link: https://priyankacool10.wordpress.com/2012/05/10/creating-tex-file-using-c-program/ and I just need to know, what all do I have to write as part of my C++ code in order to make the .tex file. I am not asking for the entire C++ code, just the exact syntax and package details for the same.

Sample Output:

Edit2: I will need a C++ code for reading the input words from the text file and writing it into a tex file. Is their any other way of doing it?

Edit3: (Error)

* Redefining document command \oldstylenums with arg. spec. 'm' on line 128.
*************************************************
) (/usr/share/texlive/texmf-dist/tex/latex/fontspec/fontspec-luatex.sty
(/usr/share/texlive/texmf-dist/tex/latex/base/fontenc.sty

(fontenc)                You might have misspelt the name of the encoding.

See the fontenc package documentation for explanation.
Type  H <return>  for immediate help.
...

l.99 \ProcessOptions*
• How should one interpret an integer as "a location where word is located", or is that irrelevant to the formatting? – Mike Renfro Mar 5 '16 at 19:04
• @MikeRenfro, yes that is irrelevant to the formatting needed. – John Mar 5 '16 at 19:04
• Do you mean, you want the conversion to do something like pointsize:'48' to turn into (say) \fontsize{48}{72}\selectfont and you just don't know the LaTeX commands for font stuff? – jon Mar 5 '16 at 19:08
• Your question is very unclear. What do you want the generated tex file to do? Do you just want to print a list of words in a list, or is the intention that these words occur in some other context and if they do, the specified font should be used? Also if using system fonts like Verdana it would be much easier to use xetex or luatex than pdftex, is that an option? And why is it tagged biblatex? – David Carlisle Mar 5 '16 at 19:12
• BoundingBox is irrelevant here. TeX is able to calculate it if needed. What you will do if coordinates of BoundingBox given in your file doesn't correspond to the real BoundingBox? – wipet Mar 6 '16 at 0:41

It seems that TeX can read the file directly, I don't think you need C++

If your input text is text1.txt then the above is made by the following tex, processed by xelatex.

\documentclass{article}
\usepackage{fontspec}

\openin\dfile=text1.txt

\def\printword#1: '#2'#3pointsize:'#4'#5font_name:'#6'#7\relax{%
\fontsize{#4}{\numexpr#4+6\relax}\selectfont\dofont{#6}#2 }

\def\dofont#1{\csname do #1\endcsname}
\expandafter\def\csname do Verdana_Bold\endcsname{\bfseries\fontspec{Verdana}}

\def\partest{\par}
\begin{document}

\raggedright
\loop
\ifeof\dfile\else
\ifx\tmp\partest
\par
\else
\expandafter\printword\tmp\relax
\fi
\repeat

\end{document}

With the new question and new data file you want to use picture mode

This does what asked although the coordinates seem rather close for 48pt text?

The font could be scaled to a proportion (say half) of the specified size.

\documentclass{article}
\usepackage{fontspec}
\textwidth60cm
\pdfpagewidth80cm

\makeatletter
\openin\dfile=text2.txt

\def\printword#1: '#2'#3pointsize:'#4'#5font_name:'#6'#7\relax{%
\edef\tmp{\zap@space#7 \@empty}%
\expandafter\getcoords\tmp\relax
{\fontsize{#4}{\numexpr#4+6\relax}\selectfont\dofont{#6}#2}}

\def\dofont#1{\csname do #1\endcsname}
\expandafter\def\csname do Verdana_Bold\endcsname{\bfseries\fontspec{Verdana}}

\def\getcoords#1X1:'#2'#3Y1:'#4'#5\relax{%
\typeout{#2/#4}%
\put(#2,4)}
\def\partest{\par}
\begin{document}

\hspace*{-10cm}\begin{picture}(200,200)
\loop
\ifeof\dfile\else
\ifx\tmp\partest
\par
\else
\expandafter\printword\tmp\relax
\fi
\repeat
\end{picture}

\end{document}
• if my input file contains the exact location of the words in terms of x and y coordinates, how can I incorporate that in this code? – John Mar 5 '16 at 19:59
• That's why I repeatedly asked under the question for you to say what you wanted the latex to do, what part of the text file should be typeset. You can put the loop inside a picture environment, and then use \put(x,y){...} to position the text by coordinate. – David Carlisle Mar 5 '16 at 20:02
• I am sorry for not able to get you properly earlier. Can you tell me in the above code how do I do this specifically? I am relatively new to Latex. Also, I think the above code will work only for Verdana Bold. But if the font of different words is different, how do I introduce a placeholder sort of thing for font? For ex, if it sees some other font, it writes that particular word in that font. – John Mar 5 '16 at 20:11
• @John No it will work for any font you just need to add a line like \expandafter\def\csname do Verdana_Bold\endcsname{\bfseries\fontspec{Verdana}} to map the names used in your file to the system font name. I added a picture mode version using coordinates – David Carlisle Mar 5 '16 at 20:25
• thanks a ton for the extended help. Just one small thing regarding the font thing, if the input text file contains word with different fonts, let's assume Verdana for the first word and Comic Sans for the second word, will I have to include the above statement for every font? Or will the above code automatically replace the font name picked up from the text file into the above statement? – John Mar 5 '16 at 20:28

I know, Python is not C++, but I wanted some exercise in this language.

The specified font size and the area locations do not fit too well, even if the font size would be scaled down by around 75%. Therefore I have used \resizebox to force the text to the size of the specified area location. The word is placed via \put of the picture environment. There are more powerful environments for drawings like TikZ or pstricks. But advanced features are not needed here and picture is much more efficient and faster.

The coordinates are transformed, since the vertical axis has the opposite direction of the y values need for the picture environment. The program calculates the minimum and maximum values and sets the lower left corner as new origin.

Before the word is set, the program sets some lines to show the specified rectangle.

The Python program can be called with the text file name as argument. Without argument, the text data are taken from the standard input. Output is standard output, which can be redirected to a TeX file.

The font and size settings are optimized, thus that the font is only defined once. Also the font is only set for a word, if the font has changed.

The generated file is processed with LuaLaTeX or XeLaTeX because of package fontspec. Then it is easier to use arbitrary font names, as long as LuaTeX or XeTeX know, where to find them.

Some characters need special treatment in TeX, see the program code for an example, how to deal with these characters.

A little more elegant would be to put the TeX preamble into a new LaTeX class file. Then the generated TeX file would just contain \documentclass{...} as whole preamble.

#!/usr/bin/env python

import fileinput;
import re;

line_pattern = re.compile(
r"word:\s*'(?P<word>[^']+)';\s*"
r"conf:\s*[0-9\.]+;\s*"
r"pointsize:\s*'(?P<pointsize>\d+)':,"
r"font_name:\s*'(?P<font_name>[^']+)',\s*"
r"X1:\s*'(?P<X1>\d+)',\s*"
r"X2:\s*'(?P<X2>\d+)',\s*"
r"Y1:\s*'(?P<Y1>\d+)',\s*"
r"Y2:\s*'(?P<Y2>\d+)'\s*")

# Mapping from character to TeX representation
tex_char_map = {}
for c in "%#\$&":
tex_char_map[c] = "\\" + c
for c in "_^~\\{}":
tex_char_map[c] = r"\symbol{" + str(ord(c)) + "}"

fonts = set()
words = []
x_min = None
x_max = None
y_min = None
y_max = None

for line in fileinput.input():
match = line_pattern.match(line)
if match:
word = match.group("word")
pointsize = match.group("pointsize")
font_name = match.group("font_name")
X1 = int(match.group("X1"))
X2 = int(match.group("X2"))
Y1 = int(match.group("Y1"))
Y2 = int(match.group("Y2"))
data = (word, pointsize, font_name, X1, X2, Y1, Y2)
words.append(data)
# assuming X1 <= X2 and Y1 <= Y2
if x_min is None or X1 < x_min:
x_min = X1
if x_max is None or X2 > x_max:
x_max = X2
if y_min is None or Y1 < y_min:
y_min = Y1
if y_max is None or Y2 > y_max:
y_max = Y2

tex_preamble = r"""\NeedsTeXFormat{LaTeX2e}
\documentclass[border=10pt]{standalone}
\usepackage{fontspec}
\newcommand*{\NewFont}[1]{%
\expandafter\newfontfamily\csname#1\endcsname{#1}%
}
\newcommand*{\SetFont}[1]{%
\csname#1\endcsname
\ignorespaces
}
\newdimen\FontSize
\newdimen\FontUnitLength
\setlength{\FontUnitLength}{.75bp}
\newcommand*{\SetSize}[1]{%
\setlength{\FontSize}{#1\FontUnitLength}%
\fontsize{\FontSize}{1.2\FontSize}\selectfont
\ignorespaces
}
%\usepackage{graphicx}
\newcommand*{\Put}{}
\def\Put(#1,#2)(#3,#4)#5{%
\put(#1,#2){\line(1,0){#3}\line(0,1){#4}}%
\put(#1,#2){\line(0,1){#4}}%
\put(#1,#2){\put(0,#4){\line(1,0){#3}}}%
%\put(#1,#2){\makebox(#3,#4)[lb]{\resizebox{#3\unitlength}{!}{#5}}}%
\put(#1,#2){%
\makebox(#3,#4)[lb]{%
\resizebox{#3\unitlength}{#4\unitlength}{%
\raisebox{\depth}{#5}%
}%
}%
}%
%\put(#1,#2){\makebox(#3,#4)[lb]{#5}}%
}
\setlength{\unitlength}{1bp}"""
print(tex_preamble)

for font in fonts:
print(r"\NewFont{" + font + "}")

print(r"\begin{document}")

picture_width = x_max - x_min
picture_height = y_max - y_min
print(r"\begin{picture}(%d,%d)" % (picture_width, picture_height))

current_font = ""
current_pointsize = ""
for word, pointsize, font_name, X1, X2, Y1, Y2 in words:
if font != current_font:
print(r"\SetFont{" + font + "}")
current_font = font

if pointsize != current_pointsize:
print(r"\SetSize{" + pointsize + "}")
current_pointsize = pointsize

w = ""
for c in word:
if c in tex_char_map:
w += tex_char_map[c]
else:
w += c
width = X2 - X1
height = Y2 - Y1
x = X1 - x_min
y = picture_height - (Y2 - y_min)
print(r"\Put(%d,%d)(%d,%d){%s}" % (x, y, width, height, w))

print(r"\end{picture}")

print(r"\end{document}")

The input data (with closing single quote added for the value of Y2):

word: 'Swine';      conf: 92.03;pointsize:'48':,font_name:'Verdana_Bold',X1:'152', X2:'283', Y1: '166', Y2: '202'
word: 'flu';    conf: 93.43;pointsize:'48':,font_name:'Verdana_Bold',X1:'299', X2:'354', Y1: '164', Y2: '202'
word: 'tightens';   conf: 90.12;pointsize:'48':,font_name:'Verdana_Bold',X1:'370', X2:'551', Y1: '164', Y2: '211'
word: 'its';    conf: 96.04;pointsize:'48':,font_name:'Verdana_Bold',X1:'568', X2:'617', Y1: '166', Y2: '202'
word: 'grip';   conf: 90.41;pointsize:'48':,font_name:'Verdana_Bold',X1:'632', X2:'716', Y1: '166', Y2: '211'
word: 'over';   conf: 94.29;pointsize:'48':,font_name:'Verdana_Bold',X1:'732', X2:'831', Y1: '175', Y2: '202'
word: 'India';      conf: 94.00;pointsize:'48':,font_name:'Verdana_Bold',X1:'848', X2:'953', Y1: '164', Y2: '202'

The generated LaTeX file:

\NeedsTeXFormat{LaTeX2e}
\documentclass[border=10pt]{standalone}
\usepackage{fontspec}
\newcommand*{\NewFont}[1]{%
\expandafter\newfontfamily\csname#1\endcsname{#1}%
}
\newcommand*{\SetFont}[1]{%
\csname#1\endcsname
\ignorespaces
}
\newdimen\FontSize
\newdimen\FontUnitLength
\setlength{\FontUnitLength}{.75bp}
\newcommand*{\SetSize}[1]{%
\setlength{\FontSize}{#1\FontUnitLength}%
\fontsize{\FontSize}{1.2\FontSize}\selectfont
\ignorespaces
}
%\usepackage{graphicx}
\newcommand*{\Put}{}
\def\Put(#1,#2)(#3,#4)#5{%
\put(#1,#2){\line(1,0){#3}\line(0,1){#4}}%
\put(#1,#2){\line(0,1){#4}}%
\put(#1,#2){\put(0,#4){\line(1,0){#3}}}%
%\put(#1,#2){\makebox(#3,#4)[lb]{\resizebox{#3\unitlength}{!}{#5}}}%
\put(#1,#2){%
\makebox(#3,#4)[lb]{%
\resizebox{#3\unitlength}{#4\unitlength}{%
\raisebox{\depth}{#5}%
}%
}%
}%
%\put(#1,#2){\makebox(#3,#4)[lb]{#5}}%
}
\setlength{\unitlength}{1bp}
\NewFont{Verdana_Bold}
\begin{document}
\begin{picture}(801,47)
\SetFont{Verdana_Bold}
\SetSize{48}
\Put(0,9)(131,36){Swine}
\Put(147,9)(55,38){flu}
\Put(218,0)(181,47){tightens}
\Put(416,9)(49,36){its}
\Put(480,0)(84,45){grip}
\Put(580,9)(99,27){over}
\Put(696,9)(105,38){India}
\end{picture}
\end{document}

• No python3? still not hanging out with the cool guys eh? :D – percusse Mar 5 '16 at 22:11
• @percusse Fixed, you can now use python3. – Heiko Oberdiek Mar 5 '16 at 22:17
• @HeikoOberdiek, so I ran the python code that you supplied on my original text input file (with proper single quotes around Y2), and it generated the .tex file. Post that, I am trying to convert the .tex file generated into a PDF (which was my final goal), but it gives the following error This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) restricted \write18 enabled. entering extended mode (./abc.tex ! Undefined control sequence. l.1 \NeedsTeXFormat {LaTeX2e} – John Mar 6 '16 at 7:20
• @John The purpose of \NeedsTeXFormat{LaTeX2e} is that the macro name is program. You need LaTeX, not plain TeX for a LaTeX file. Also LuaTeX or XeTeX are required because of package fontspec and the non-TeX-Font Verdana_Bold. Try lualatex abc or xelatex abc. – Heiko Oberdiek Mar 6 '16 at 7:48
• @HeikoOberdiek, so I tried the lualtex abc step. It asked me to download the lualatex package and I did that. On then executing the command, now it gives the error (exact error mentioned as part of the original post, see edit). I tried to search for what causes the fontec error, and found this, http://tex.stackexchange.com/questions/219622/package-fontenc-error-encoding-file-eu2enc-def-not-found. I tried tlmgr install eunec but it doesn't let me install that and gives the error (running on Debian,switching to user mode!) cannot setup TLPDB in /home/texmf at /usr/bin/tlmgr line 5336. – John Mar 6 '16 at 11:46