/*============================================================================= GNU UnRTF, a command-line program to convert RTF documents to other formats. Copyright (C) 2000,2001 Zachary Thayer Smith This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA The author is reachable by electronic mail at tuorfa@yahoo.com. =============================================================================*/ /*---------------------------------------------------------------------- * Module name: ps * Author name: Zach Smith * Create date: 18 Sep 01 * Purpose: PostScript(TM)-specific output module *---------------------------------------------------------------------- * Changes: * 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks * 23 Sep 01, tuorfa@yahoo.com: added shadow, outline, strikethru, underline * 23 Sep 01, tuorfa@yahoo.com: revised PS program to use ISOLatin1Encoding * 28 Sep 01, tuorfa@yahoo.com: added support for Helvetica,Courier,Symbol *--------------------------------------------------------------------*/ #include #include #include "malloc.h" #include "defs.h" #include "error.h" #include "main.h" #include "output.h" static char* ascii [96] = { /* 0x20 */ " ", "!", "\"", "#", "$", "\%", "&", "'", /* 0x28 */ "\\(", "\\)", "*", "+", ",", "-", ".", "/", /* 0x30 */ "0", "1", "2", "3", "4", "5", "6", "7", /* 0x38 */ "8", "9", ":", ";", "<", "=", ">", "?", /* 0x40 */ "@", "A", "B", "C", "D", "E", "F", "G", /* 0x48 */ "H", "I", "J", "K", "L", "M", "N", "O", /* 0x50 */ "P", "Q", "R", "S", "T", "U", "V", "W", /* 0x58 */ "X", "Y", "Z", "\\[", "\\\\", "\\]", "^", "_", /* 0x60 */ "`", "a", "b", "c", "d", "e", "f", "g", /* 0x68 */ "h", "i", "j", "k", "l", "m", "n", "o", /* 0x70 */ "p", "q", "r", "s", "t", "u", "v", "w", /* 0x78 */ "x", "y", "z", "{", "|", "}", "~", "", }; static char* ansi [] = { /* 0x80 */ "\\200","\\201","\\202","\\203", /* 0x84 */ "\\204","\\205","\\206","\\207", /* 0x88 */ "\\210","\\211","\\212","\\213", /* 0x8c */ "\\214","\\215","\\216","\\217", /* 0x90 */ "\\220","\\221","\\222","\\223", /* 0x94 */ "\\224","\\225","\\226","\\227", /* 0x98 */ "\\230","\\231","\\232","\\233", /* 0x9c */ "\\234","\\235","\\236","\\237", /* 0xa0 */ "\\240","\\241","\\242","\\243", /* 0xa4 */ "\\244","\\245","\\246","\\247", /* 0xa8 */ "\\250","\\251","\\252","\\253", /* 0xac */ "\\254","\\255","\\256","\\257", /* 0xb0 */ "\\260","\\261","\\262","\\263", /* 0xb4 */ "\\264","\\265","\\266","\\267", /* 0xb8 */ "\\270","\\271","\\272","\\273", /* 0xbc */ "\\274","\\275","\\276","\\277", /* 0xc0 */ "\\300","\\301","\\302","\\303", /* 0xc4 */ "\\304","\\305","\\306","\\307", /* 0xc8 */ "\\310","\\311","\\312","\\313", /* 0xcc */ "\\314","\\315","\\316","\\317", /* 0xd0 */ "\\320","\\321","\\322","\\323", /* 0xd4 */ "\\324","\\325","\\326","\\327", /* 0xd8 */ "\\330","\\331","\\332","\\333", /* 0xdc */ "\\334","\\335","\\336","\\337", /* 0xe0 */ "\\340","\\341","\\342","\\343", /* 0xe4 */ "\\344","\\345","\\346","\\347", /* 0xe8 */ "\\350","\\351","\\352","\\353", /* 0xec */ "\\354","\\355","\\356","\\357", /* 0xf0 */ "\\360","\\361","\\362","\\363", /* 0xf4 */ "\\364","\\365","\\366","\\367", /* 0xf8 */ "\\370","\\371","\\372","\\373", /* 0xfc */ "\\374","\\375","\\376","\\377", }; static char* mac [] = { "?", }; static char* cp437 [] = { "?", }; static char* cp850 [] = { "?", }; #define PS_END "\ %% --------- \n\n\ didShowPage not { \n\ showpage \n\ } if\n\n\ %%%%EOF\n" #define PS_START "\ %%%%!PS\n\ %%--------------------------------------------------------------------------\n\ %% GNU UnRTF, a command-line program to convert RTF documents to other formats.\n\ %% Copyright (C) 2000,2001 Zachary Thayer Smith\n\ %%\n\ %% This program is free software; you can redistribute it and/or modify\n\ %% it under the terms of the GNU General Public License as published by\n\ %% the Free Software Foundation; either version 2 of the License, or\n\ %% (at your option) any later version.\n\ %%\n\ %% This program is distributed in the hope that it will be useful,\n\ %% but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ %% GNU General Public License for more details.\n\ %%\n\ %% You should have received a copy of the GNU General Public License\n\ %% along with this program; if not, write to the Free Software\n\ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\ %%\n\ %% The author is reachable by electronic mail at tuorfa@yahoo.com.\n\ %%--------------------------------------------------------------------------\n\ %%%%EndComments \n\ %%\n\ %% --------- Note, this PS code is unfinished -------- \n\ %% --------- Note, this PS code is unfinished -------- \n\ %% --------- Note, this PS code is unfinished -------- \n\ %% --------- Note, this PS code is unfinished -------- \n\ %% --------- Note, this PS code is unfinished -------- \n\ %%\n\ %% ----------- Variables ------------\n\ /fontFamily /Times def\n\ /fontAscent 0 def %% ascent for current font\n\ /fontDescent 0 def %% descent for current font\n\ /lineAscent 0 def \n\ /lineDescent 0 def \n\ /pageWidthInches 8.5 def \n\ /pageHeightInches 11 def \n\ /leftMargin 20 def \n\ /rightMargin 20 def \n\ /topMargin 20 def \n\ /bottomMargin 20 def \n\ /DPI 72 def \n\ /pageWidth pageWidthInches DPI mul def \n\ /rightLimit pageWidth rightMargin sub def \n\ /pageHeight pageHeightInches DPI mul def \n\ /x 0 def \n\ /y 0 def \n\ /bold false def \n\ /italic false def \n\ /underline false def \n\ /overline false def \n\ /intercharSpace 0 def \n\ /strike false def \n\ /outline false def \n\ /shadow false def \n\ /fontSize 12 def \n\ /didBR false def \n\ /didParSkip false def \n\ /didShowPage false def \n\ %%------------------------------------------------------\n\ %% Set up the ISO fonts \n\ %% Times \n\ %% ----- \n\ /Times-Roman findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /TRomanISO exch definefont pop \n\ /Times-Bold findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /TBoldISO exch definefont pop \n\ /Times-BoldItalic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /TBoldItalicISO exch definefont pop \n\ /Times-Italic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /TItalicISO exch definefont pop \n\ %% Courier \n\ %% ----- \n\ /Courier-Roman findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /CRomanISO exch definefont pop \n\ /Courier-Bold findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /CBoldISO exch definefont pop \n\ /Courier-BoldItalic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /CBoldItalicISO exch definefont pop \n\ /Courier-Italic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /CItalicISO exch definefont pop \n\ %% Symbol \n\ %% ----- \n\ /Symbol-Roman findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /SRomanISO exch definefont pop \n\ /Symbol-Bold findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /SBoldISO exch definefont pop \n\ /Symbol-BoldItalic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /SBoldItalicISO exch definefont pop \n\ /Symbol-Italic findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /SItalicISO exch definefont pop \n\ %% Helvetica \n\ %% --------- \n\ /Helvetica-Roman findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /HRomanISO exch definefont pop \n\ /Helvetica-Bold findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /HBoldISO exch definefont pop \n\ /Helvetica-BoldOblique findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /HBoldItalicISO exch definefont pop \n\ /Helvetica-Oblique findfont dup length dict begin { \n\ 1 index /FID ne { def } { pop pop } ifelse \n\ } forall \n\ /Encoding ISOLatin1Encoding def \n\ currentdict end \n\ /HItalicISO exch definefont pop \n\ %% \n\ %% Ideally, before we can draw a line of text, we need to collect all the\n\ %% words that will be on it, just as I do in my Beest HTML viewer, as well\n\ %% as character attributes for each word. But for now, this implementation \n\ %% does not bother. It determines the maximize ascent and descent after\n\ %% drawing the text, not before. XX\n\ %% \n\ %% ----------- Functions ------------\n\ /updateFont { \n\ /f0 null def \n\ (Times) fontFamily eq (Times New Roman) fontFamily eq or { bold { \n\ italic { /TBoldItalicISO } { /TBoldISO } ifelse \n\ } { \n\ italic { /TItalicISO } { /TRomanISO } ifelse \n\ } \n\ ifelse \n\ } if (Helvetica) fontFamily eq (Arial) fontFamily eq or { bold { \n\ italic { /HBoldItalicISO } { /HBoldISO } ifelse \n\ } { \n\ italic { /HItalicISO } { /HRomanISO } ifelse \n\ } \n\ ifelse \n\ } if (Courier) fontFamily eq (Courier New) fontFamily eq or { bold { \n\ italic { /CBoldItalicISO } { /CBoldISO } ifelse \n\ } { \n\ italic { /CItalicISO } { /CRomanISO } ifelse \n\ } \n\ ifelse \n\ } if (Symbol) fontFamily eq { bold { \n\ italic { /SBoldItalicISO } { /SBoldISO } ifelse \n\ } { \n\ italic { /SItalicISO } { /SRomanISO } ifelse \n\ } \n\ ifelse \n\ } if findfont /f0 exch def \n\ /bboxBottom f0 /FontBBox get 1 get 1000 div fontSize mul -1 mul def \n\ /bboxTop f0 /FontBBox get 3 get 1000 div fontSize mul def \n\ f0 fontSize scalefont setfont \n\ lineAscent bboxTop lt { /lineAscent bboxTop def } if \n\ lineDescent bboxBottom lt { /lineDescent bboxBottom def } if \n\ /fontAscent bboxTop def \n\ /fontDescent bboxBottom def \n\ } def\n\ /FS { \n\ /fontSize exch def updateFont \n\ } def \n\ /F { \n\ /fontFamily exch def updateFont \n\ } def \n\ /resetX { \n\ /x leftMargin def\n\ } def \n\ /resetY { \n\ /y pageHeight topMargin sub def \n\ } def \n\ /BR { \n\ /oldx x def \n\ /y y lineAscent lineDescent add sub def \n\ resetX \n\ y bottomMargin lt { \n\ showpage \n\ /didShowPage true \n\ resetY \n\ } if \n\ oldx 0 eq didBR and { /didParSkip true def } if \n\ /didBR true def \n\ % /lineAscent 0 def \n\ % /lineDescent 0 def \n\ } def \n\ /P { \n\ didParSkip not { BR } if \n\ didParSkip not { BR } if \n\ } \n\ def \n\ /acharpath { \n\ /acstr exch def pop /acsp exch def newpath str { /ch exch def 1 string 0 ch put false charpath acsp 0 rmoveto } forall} def \n\ /A { \n\ /str exch def \n\ /w str stringwidth pop \n\ str length intercharSpace mul add \n\ def \n\ x w add rightLimit ge { BR } if \n\ x y moveto \n\ outline { \n\ shadow { \n\ 1 -0.1 0 { \n\ /offset exch def \n\ offset setgray \n\ x offset 3 mul add y offset 3 mul sub moveto intercharSpace 0 str acharpath \n\ %% str false charpath \n\ fontSize 30 div setlinewidth stroke \n\ } for \n\ 0 setgray \n\ } { \n\ intercharSpace 0 str acharpath \n\ %% str false charpath \n\ fontSize 30 div setlinewidth stroke \n\ } ifelse \n\ } { \n\ shadow { \n\ 1 -0.1 0 { \n\ /offset exch def \n\ offset setgray \n\ x offset 3 mul add y offset 3 mul sub moveto intercharSpace 0 str ashow \n\ %% str show \n\ } for \n\ 0 setgray } { \n\ intercharSpace 0 str ashow \n\ %% str show \n\ } ifelse \n\ } ifelse \n\ strike { \n\ newpath fontSize 20 div setlinewidth \n\ x y fontAscent 0.32 mul add dup /y2 exch def moveto \n\ x w add y2 lineto stroke \n\ } if \n\ underline { \n\ newpath fontSize 20 div setlinewidth \n\ x y fontAscent 0.2 mul sub dup /y2 exch def moveto \n\ x w add y2 lineto stroke \n\ } if \n\ overline { \n\ %% I don't think RTF supports this, but it can be used later. \n\ newpath fontSize 20 div setlinewidth \n\ x y fontAscent 1.2 mul add dup /y2 exch def moveto \n\ x w add y2 lineto stroke \n\ } if \n\ /x x w add def \n\ /didBR false def \n\ /didShowPage false def \n\ } def \n\ \n\ %% These are only binary for now \n\ /X1 { /intercharSpace exch def } def\n\ /X0 { /intercharSpace 0 def } def\n\ /O1 { /outline false def } def\n\ /O0 { /outline false def } def\n\ /H1 { /shadow true def } def\n\ /H0 { /shadow false def } def\n\ /S1 { /strike true def } def\n\ /S0 { /strike false def } def\n\ /B1 { /bold true def updateFont } def\n\ /B0 { /bold false def updateFont } def\n\ /I1 { /italic true def updateFont } def\n\ /I0 { /italic false def updateFont } def\n\ /U1 { /underline true def } def\n\ /U0 { /underline false def } def\n\ updateFont \n\ resetX resetY \n\ \n\ " /*======================================================================== * Name: ps_init * Purpose: Generates an OutputPersonality object for the PostScript(TM) * format. * Args: None. * Returns: OutputPersonality. *=======================================================================*/ OutputPersonality * ps_init (void) { OutputPersonality* op; op = op_create(); op->comment_begin = "%% "; op->comment_end = "\n"; op->word_begin = "("; op->word_end = ")A "; op->document_begin = PS_START; op->document_end = PS_END; op->header_begin = "%% header begin\n"; op->header_end = "%% header end\n"; op->document_title_begin = "%%%%Title: "; op->document_title_end = "\n"; op->document_author_begin = "%%%%Creator: "; op->document_author_end = "\n"; op->document_changedate_begin = "%% CHANGED: "; op->document_changedate_end = "\n"; op->body_begin = "\n\n%% ---------- Document Body ------------\n"; op->body_end = "\n"; op->paragraph_begin = "P "; op->paragraph_end = "\n"; op->center_begin = ""; op->center_end = ""; op->justify_begin = ""; op->justify_end = ""; op->align_left_begin = ""; op->align_left_end = ""; op->align_right_begin = ""; op->align_right_end = ""; op->forced_space = " "; op->line_break = "BR\n"; op->page_break = "\n"; op->hyperlink_begin = "U1("; op->hyperlink_end = ")A U0 "; op->imagelink_begin = ""; op->imagelink_end = ""; op->table_begin = "\n% TABLE BEGINS (not implemented)\nP\n(TABLE)A BR\n"; op->table_end = "\n% TABLE ENDS (not implemented)\nP\n"; op->table_row_begin = "( )A "; op->table_row_end = "( |)A BR\n"; op->table_cell_begin = "( | )A "; op->table_cell_end = ""; /* Character attributes */ op->font_begin = "(%s) F "; op->font_end = ""; op->fontsize_begin = "%s FS "; op->fontsize_end = ""; op->smaller_begin = ""; op->smaller_end = ""; op->bigger_begin = ""; op->bigger_end = ""; op->foreground_begin = ""; op->foreground_end = ""; op->background_begin = ""; op->background_end = ""; op->bold_begin = "B1 "; op->bold_end = "B0 "; op->italic_begin = "I1 "; op->italic_end = "I0 "; op->underline_begin = "U1 "; op->underline_end = "U0 "; op->dbl_underline_begin = "U1 "; op->dbl_underline_end = "U0 "; op->superscript_begin = ""; op->superscript_end = ""; op->subscript_begin = ""; op->subscript_end = ""; op->strikethru_begin = "S1 "; op->strikethru_end = "S0 "; op->dbl_strikethru_begin = "S1 "; op->dbl_strikethru_end = "S0 "; op->emboss_begin=""; op->emboss_end = ""; op->engrave_begin = ""; op->engrave_end = ""; op->shadow_begin= "H1 "; op->shadow_end= "H0 "; op->outline_begin= "O1 "; op->outline_end= "O0 "; op->expand_begin = "%s X1 "; op->expand_end = "X0 "; op->simulate_small_caps = TRUE; op->simulate_all_caps = TRUE; op->simulate_word_underline = TRUE; op->ascii_translation_table = ascii; op->ansi_translation_table = ansi; op->ansi_first_char = 0x80; op->ansi_last_char = 0xff; op->cp437_translation_table = cp437; op->cp437_first_char = 0x80; op->cp437_last_char = 0x80; op->cp850_translation_table = cp850; op->cp850_first_char = 0x80; op->cp850_last_char = 0x80; op->mac_translation_table = mac; op->mac_first_char = 0x80; op->mac_last_char = 0x80; op->chars.right_quote = "'"; op->chars.left_quote = "`"; op->chars.right_dbl_quote = "''"; op->chars.left_dbl_quote = "``"; return op; }