From ed3349623c8d9bb9d62eab706569bf768f576606 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 20 May 2008 11:39:39 +0000 Subject: [PATCH] 2008-05-20 13:30 UTC+0100 Viktor Szakats (harbour.01 syenar hu) + contrib/hbvpdf + contrib/hbvpdf/common.mak + contrib/hbvpdf/hbvpdf.prg + contrib/hbvpdf/hbvpdf.ch + contrib/hbvpdf/make_gcc.sh + contrib/hbvpdf/tests + contrib/hbvpdf/tests/fonts.dat + contrib/hbvpdf/tests/files + contrib/hbvpdf/tests/files/color.tif + contrib/hbvpdf/tests/files/test.txt + contrib/hbvpdf/tests/files/color.jpg + contrib/hbvpdf/tests/pdf_demo.prg + contrib/hbvpdf/tests/tstpdf.prg + contrib/hbvpdf/tests/bld_b32.bat + contrib/hbvpdf/tests/bld_vc.bat + contrib/hbvpdf/hbvpdft.prg + contrib/hbvpdf/make_b32.bat + contrib/hbvpdf/make_vc.bat + contrib/hbvpdf/Makefile + Added Viktor K's pure Clipper pdf lib. + Added Pritpal's OOP version. + Added make files, reorged dir layout, named files to avoid collision. + Added minor #define tweak to compile as-is. * Renamed pdf.ch to hbvpdf.ch for above reasons, if this hurts anybody, I will correct it. ! Fixed unused vars and a few other things. ; TOFIX: - ShellExecute(), GetDeskTopWindow() dependencies commented out. - fonts.dat dependency is a PITA, so this file should be moved inside the .prg somehow. - There are some hard-wired non porable things like acrobat executable path. * contrib/Makefile * contrib/make_b32_all.bat * contrib/make_gcc_all.sh * contrib/make_vc_all.bat + hbvpdf added to make systems. --- harbour/ChangeLog | 42 + harbour/contrib/Makefile | 1 + harbour/contrib/hbvpdf/Makefile | 16 + harbour/contrib/hbvpdf/common.mak | 17 + harbour/contrib/hbvpdf/hbvpdf.ch | 223 ++ harbour/contrib/hbvpdf/hbvpdf.prg | 2624 +++++++++++++++++ harbour/contrib/hbvpdf/hbvpdft.prg | 2649 ++++++++++++++++++ harbour/contrib/hbvpdf/make_b32.bat | 6 + harbour/contrib/hbvpdf/make_gcc.sh | 7 + harbour/contrib/hbvpdf/make_vc.bat | 6 + harbour/contrib/hbvpdf/tests/bld_b32.bat | 22 + harbour/contrib/hbvpdf/tests/bld_vc.bat | 22 + harbour/contrib/hbvpdf/tests/files/color.jpg | Bin 0 -> 52799 bytes harbour/contrib/hbvpdf/tests/files/color.tif | Bin 0 -> 40188 bytes harbour/contrib/hbvpdf/tests/files/test.txt | 12 + harbour/contrib/hbvpdf/tests/fonts.dat | Bin 0 -> 5376 bytes harbour/contrib/hbvpdf/tests/pdf_demo.prg | 224 ++ harbour/contrib/hbvpdf/tests/tstpdf.prg | 191 ++ harbour/contrib/make_b32_all.bat | 2 +- harbour/contrib/make_gcc_all.sh | 2 +- harbour/contrib/make_vc_all.bat | 2 +- 21 files changed, 6065 insertions(+), 3 deletions(-) create mode 100644 harbour/contrib/hbvpdf/Makefile create mode 100644 harbour/contrib/hbvpdf/common.mak create mode 100644 harbour/contrib/hbvpdf/hbvpdf.ch create mode 100644 harbour/contrib/hbvpdf/hbvpdf.prg create mode 100644 harbour/contrib/hbvpdf/hbvpdft.prg create mode 100644 harbour/contrib/hbvpdf/make_b32.bat create mode 100644 harbour/contrib/hbvpdf/make_gcc.sh create mode 100644 harbour/contrib/hbvpdf/make_vc.bat create mode 100644 harbour/contrib/hbvpdf/tests/bld_b32.bat create mode 100644 harbour/contrib/hbvpdf/tests/bld_vc.bat create mode 100644 harbour/contrib/hbvpdf/tests/files/color.jpg create mode 100644 harbour/contrib/hbvpdf/tests/files/color.tif create mode 100644 harbour/contrib/hbvpdf/tests/files/test.txt create mode 100644 harbour/contrib/hbvpdf/tests/fonts.dat create mode 100644 harbour/contrib/hbvpdf/tests/pdf_demo.prg create mode 100644 harbour/contrib/hbvpdf/tests/tstpdf.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 4d521fb745..cca76b8ed0 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,48 @@ 2008-12-31 13:59 UTC+0100 Foo Bar */ +2008-05-20 13:30 UTC+0100 Viktor Szakats (harbour.01 syenar hu) + + contrib/hbvpdf + + contrib/hbvpdf/common.mak + + contrib/hbvpdf/hbvpdf.prg + + contrib/hbvpdf/hbvpdf.ch + + contrib/hbvpdf/make_gcc.sh + + contrib/hbvpdf/tests + + contrib/hbvpdf/tests/fonts.dat + + contrib/hbvpdf/tests/files + + contrib/hbvpdf/tests/files/color.tif + + contrib/hbvpdf/tests/files/test.txt + + contrib/hbvpdf/tests/files/color.jpg + + contrib/hbvpdf/tests/pdf_demo.prg + + contrib/hbvpdf/tests/tstpdf.prg + + contrib/hbvpdf/tests/bld_b32.bat + + contrib/hbvpdf/tests/bld_vc.bat + + contrib/hbvpdf/hbvpdft.prg + + contrib/hbvpdf/make_b32.bat + + contrib/hbvpdf/make_vc.bat + + contrib/hbvpdf/Makefile + + Added Viktor K's pure Clipper pdf lib. + + Added Pritpal's OOP version. + + Added make files, reorged dir layout, named + files to avoid collision. + + Added minor #define tweak to compile as-is. + * Renamed pdf.ch to hbvpdf.ch for above reasons, + if this hurts anybody, I will correct it. + ! Fixed unused vars and a few other things. + ; TOFIX: - ShellExecute(), GetDeskTopWindow() + dependencies commented out. + - fonts.dat dependency is a PITA, so + this file should be moved inside + the .prg somehow. + - There are some hard-wired non porable + things like acrobat executable path. + + * contrib/Makefile + * contrib/make_b32_all.bat + * contrib/make_gcc_all.sh + * contrib/make_vc_all.bat + + hbvpdf added to make systems. + 2008-05-20 09:30 UTC+0100 Viktor Szakats (harbour.01 syenar hu) * contrib/hbwhat32/wincorec.c ! Removed old-style Clipper comment from C code. diff --git a/harbour/contrib/Makefile b/harbour/contrib/Makefile index 37b4f91796..40e9308621 100644 --- a/harbour/contrib/Makefile +++ b/harbour/contrib/Makefile @@ -11,6 +11,7 @@ DIRS=\ hbmisc \ hbnf \ hbclipsm \ + hbvpdf \ xhb \ # examples \ # hbzlib \ diff --git a/harbour/contrib/hbvpdf/Makefile b/harbour/contrib/hbvpdf/Makefile new file mode 100644 index 0000000000..1e6df9b80e --- /dev/null +++ b/harbour/contrib/hbvpdf/Makefile @@ -0,0 +1,16 @@ +# +# $Id$ +# + +ROOT = ../../ + +PRG_SOURCES=\ + hbvpdf.prg \ + hbvpdft.prg \ + +PRG_HEADERS=\ + hbvpdf.ch \ + +LIBNAME=hbvpdf + +include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/contrib/hbvpdf/common.mak b/harbour/contrib/hbvpdf/common.mak new file mode 100644 index 0000000000..f9df38606b --- /dev/null +++ b/harbour/contrib/hbvpdf/common.mak @@ -0,0 +1,17 @@ +# +# $Id$ +# + +LIBNAME = $(LIBPREF)hbvpdf + +LIB_PATH = $(LIB_DIR)$(LIBNAME)$(LIBEXT) + +PRG_HEADERS = \ + hbvpdf.ch \ + +LIB_OBJS = \ + $(OBJ_DIR)hbvpdf$(OBJEXT) \ + $(OBJ_DIR)hbvpdft$(OBJEXT) \ + +all: \ + $(LIB_PATH) \ diff --git a/harbour/contrib/hbvpdf/hbvpdf.ch b/harbour/contrib/hbvpdf/hbvpdf.ch new file mode 100644 index 0000000000..4081063d1c --- /dev/null +++ b/harbour/contrib/hbvpdf/hbvpdf.ch @@ -0,0 +1,223 @@ +#include "fileio.ch" +#include "common.ch" + +#define CRLF chr(13)+chr(10) + +#define NORMAL 0 +#define BOLD 1 +#define ITALIC 2 +#define BOLDITALIC 3 + +#define BOOKLEVEL 1 +#define BOOKTITLE 2 +#define BOOKPARENT 3 +#define BOOKPREV 4 +#define BOOKNEXT 5 +#define BOOKFIRST 6 +#define BOOKLAST 7 +#define BOOKCOUNT 8 +#define BOOKPAGE 9 +#define BOOKCOORD 10 + +#define FONTNAME 1 // font name +#define FONTSIZE 2 // font size +#define LPI 3 // lines per inch +#define PAGESIZE 4 // page size +#define PAGEORIENT 5 // page orientation +#define PAGEX 6 +#define PAGEY 7 +#define REPORTWIDTH 8 // report width +#define REPORTPAGE 9 // report page +#define REPORTLINE 10 // report line +#define FONTNAMEPREV 11 // prev font name +#define FONTSIZEPREV 12 // prev font size +#define PAGEBUFFER 13 // page buffer +#define REPORTOBJ 14 // current obj +#define DOCLEN 15 // document length +#define TYPE1 16 // array of type 1 fonts +#define MARGINS 17 // recalc margins ? +#define HEADEREDIT 18 // edit header ? +#define NEXTOBJ 19 // next obj +#define PDFTOP 20 // top row +#define PDFLEFT 21 // left & right margin in mm +#define PDFBOTTOM 22 // bottom row +#define HANDLE 23 // handle +#define PAGES 24 // array of pages +#define REFS 25 // array of references +#define BOOKMARK 26 // array of bookmarks +#define HEADER 27 // array of headers +#define FONTS 28 // array of report fonts +#define IMAGES 29 // array of report images +#define PAGEIMAGES 30 // array of current page images +#define PAGEFONTS 31 // array of current page fonts +#define FONTWIDTH 32 // array of fonts width's +#define OPTIMIZE 33 // optimized ? +#define PARAMLEN 33 // number of report elements + +#define ALIGN_LEFT 1 +#define ALIGN_CENTER 2 +#define ALIGN_RIGHT 3 +#define ALIGN_JUSTIFY 4 + +#define IMAGE_WIDTH 1 +#define IMAGE_HEIGHT 2 +#define IMAGE_XRES 3 +#define IMAGE_YRES 4 +#define IMAGE_BITS 5 +#define IMAGE_FROM 6 +#define IMAGE_LENGTH 7 + +#define BYTE 1 +#define ASCII 2 +#define SHORT 3 +#define LONG 4 +#define RATIONAL 5 +#define SBYTE 6 +#define UNDEFINED 7 +#define SSHORT 8 +#define SLONG 9 +#define SRATIONAL 10 +#define FLOAT 11 +#define DOUBLE 12 + +#define pdf_ALICEBLUE "F0F8FF" +#define pdf_ANTIQUEWHITE "FAEBD7" +#define pdf_AQUA "00FFFF" +#define pdf_AQUAMARINE "7FFFD4" +#define pdf_AZURE "F0FFFF" +#define pdf_BEIGE "F5F5DC" +#define pdf_BISQUE "FFE4C4" +#define pdf_BLACK "000000" +#define pdf_BLANCHEDALMOND "FFEBCD" +#define pdf_BLUE "0000FF" +#define pdf_BLUEVIOLET "8A2BE2" +#define pdf_BROWN "A52A2A" +#define pdf_BURLYWOOD "DEB887" +#define pdf_CADETBLUE "5F9EA0" +#define pdf_CHARTREUSE "7FFF00" +#define pdf_CHOCOLATE "D2691E" +#define pdf_CORAL "FF7F50" +#define pdf_CORNFLOWERBLUE "6495ED" +#define pdf_CORNSILK "FFF8DC" +#define pdf_CRIMSON "DC143C" +#define pdf_CYAN "00FFFF" +#define pdf_DARKBLUE "00008B" +#define pdf_DARKCYAN "008B8B" +#define pdf_DARKGOLDENROD "B8860B" +#define pdf_DARKGRAY "A9A9A9" +#define pdf_DARKGREEN "006400" +#define pdf_DARKKHAKI "BDB76B" +#define pdf_DARKMAGENTA "8B008B" +#define pdf_DARKOLIVEGREEN "556B2F" +#define pdf_DARKORANGE "FF8C00" +#define pdf_DARKORCHID "9932CC" +#define pdf_DARKRED "8B0000" +#define pdf_DARKSALMON "E9967A" +#define pdf_DARKSEAGREEN "8FBC8F" +#define pdf_DARKSLATEBLUE "483D8B" +#define pdf_DARKSLATEGRAY "2F4F4F" +#define pdf_DARKTURQUOISE "00CED1" +#define pdf_DARKVIOLET "9400D3" +#define pdf_DEEPPINK "FF1493" +#define pdf_DEEPSKYBLUE "00BFFF" +#define pdf_DIMGRAY "696969" +#define pdf_DODGERBLUE "1E90FF" +#define pdf_FIREBRICK "B22222" +#define pdf_FLORALWHITE "FFFAF0" +#define pdf_FORESTGREEN "228B22" +#define pdf_FUCHSIA "FF00FF" +#define pdf_GAINSBORO "DCDCDC" +#define pdf_GHOSTWHITE "F8F8FF" +#define pdf_GOLD "FFD700" +#define pdf_GOLDENROD "DAA520" +#define pdf_GRAY "808080" +#define pdf_GREEN "008000" +#define pdf_GREENYELLOW "ADFF2F" +#define pdf_HONEYDEW "F0FFF0" +#define pdf_HOTPINK "FF69B4" +#define pdf_INDIANRED "CD5C5C" +#define pdf_INDIGO "4B0082" +#define pdf_IVORY "FFFFF0" +#define pdf_KHAKI "F0E68C" +#define pdf_LAVENDER "E6E6FA" +#define pdf_LAVENDERBLUSH "FFF0F5" +#define pdf_LAWNGREEN "7CFC00" +#define pdf_LEMONCHIFFON "FFFACD" +#define pdf_LIGHTBLUE "ADD8E6" +#define pdf_LIGHTCORAL "F08080" +#define pdf_LIGHTCYAN "E0FFFF" +#define pdf_LIGHTGOLDENRODYELLOW "FAFAD2" +#define pdf_LIGHTGREEN "90EE90" +#define pdf_LIGHTGREY "D3D3D3" +#define pdf_LIGHTPINK "FFB6C1" +#define pdf_LIGHTSALMON "FFA07A" +#define pdf_LIGHTSEAGREEN "20B2AA" +#define pdf_LIGHTSKYBLUE "87CEFA" +#define pdf_LIGHTSLATEGRAY "778899" +#define pdf_LIGHTSTEELBLUE "B0C4DE" +#define pdf_LIGHTYELLOW "FFFFE0" +#define pdf_LIME "00FF00" +#define pdf_LIMEGREEN "32CD32" +#define pdf_LINEN "FAF0E6" +#define pdf_MAGENTA "FF00FF" +#define pdf_MAROON "800000" +#define pdf_MEDIUMAQUAMARINE "66CDAA" +#define pdf_MEDIUMBLUE "0000CD" +#define pdf_MEDIUMORCHID "BA55D3" +#define pdf_MEDIUMPURPLE "9370DB" +#define pdf_MEDIUMSEAGREEN "3CB371" +#define pdf_MEDIUMSLATEBLUE "7B68EE" +#define pdf_MEDIUMSPRINGGREEN "00FA9A" +#define pdf_MEDIUMTURQUOISE "48D1CC" +#define pdf_MEDIUMVIOLETRED "C71585" +#define pdf_MIDNIGHTBLUE "191970" +#define pdf_MINTCREAM "F5FFFA" +#define pdf_MISTYROSE "FFE4E1" +#define pdf_MOCCASIN "FFE4B5" +#define pdf_NAVAJOWHITE "FFDEAD" +#define pdf_NAVY "000080" +#define pdf_OLDLACE "FDF5E6" +#define pdf_OLIVE "808000" +#define pdf_OLIVEDRAB "6B8E23" +#define pdf_ORANGE "FFA500" +#define pdf_ORANGERED "FF4500" +#define pdf_ORCHID "DA70D6" +#define pdf_PALEGOLDENROD "EEE8AA" +#define pdf_PALEGREEN "98FB98" +#define pdf_PALETURQUOISE "AFEEEE" +#define pdf_PALEVIOLETRED "DB7093" +#define pdf_PAPAYAWHIP "FFEFD5" +#define pdf_PEACHPUFF "FFDAB9" +#define pdf_PERU "CD853F" +#define pdf_PINK "FFC0CB" +#define pdf_PLUM "DDADDD" +#define pdf_POWDERBLUE "B0E0E6" +#define pdf_PURPLE "800080" +#define pdf_RED "FF0000" +#define pdf_ROSYBROWN "BC8F8F" +#define pdf_ROYALBLUE "4169E1" +#define pdf_SADDLEBROWN "8B4513" +#define pdf_SALMON "FA8072" +#define pdf_SANDYBROWN "F4A460" +#define pdf_SEAGREEN "2E8B57" +#define pdf_SEASHELL "FFF5EE" +#define pdf_SIENNA "A0522D" +#define pdf_SILVER "C0C0C0" +#define pdf_SKYBLUE "87CEEB" +#define pdf_SLATEBLUE "6A5ACD" +#define pdf_SLATEGRAY "708090" +#define pdf_SNOW "FFFAFA" +#define pdf_SPRINGGREEN "00FF7F" +#define pdf_STEELBLUE "4682B4" +#define pdf_TAN "D2B48C" +#define pdf_TEAL "008080" +#define pdf_THISTLE "D8BFD8" +#define pdf_TOMATO "FF6347" +#define pdf_TURQUOISE "40E0D0" +#define pdf_VIOLET "EE82EE" +#define pdf_WHEAT "F5DEB3" +#define pdf_WHITE "FFFFFF" +#define pdf_WHITESMOKE "F5F5F5" +#define pdf_YELLOW "FFFF00" +#define pdf_YELLOWGREEN "9ACD32" + diff --git a/harbour/contrib/hbvpdf/hbvpdf.prg b/harbour/contrib/hbvpdf/hbvpdf.prg new file mode 100644 index 0000000000..3d227df6ed --- /dev/null +++ b/harbour/contrib/hbvpdf/hbvpdf.prg @@ -0,0 +1,2624 @@ +/* + * $Id$ + */ + +#include "hbvpdf.ch" + +memvar aReport + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfAtSay( cString, nRow, nCol, cUnits, lExact, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local _nFont, lReverse, nAt + +DEFAULT nRow to aReport[ REPORTLINE ] +DEFAULT cUnits to "R" +DEFAULT lExact to .f. +DEFAULT cId to "" + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFATSAY", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( pdfPageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + lReverse = .f. + IF cUnits == "M" + nRow := pdfM2Y( nRow ) + nCol := pdfM2X( nCol ) + ELSEIF cUnits == "R" + IF .not. lExact + pdfCheckLine( nRow ) + nRow := nRow + aReport[ PDFTOP ] + ENDIF + nRow := pdfR2D( nRow ) + nCol := pdfM2X( aReport[ PDFLEFT ] ) + ; + nCol * 100.00 / aReport[ REPORTWIDTH ] * ; + ( aReport[ PAGEX ] - pdfM2X( aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + ENDIF + IF !empty( cString ) + cString := pdfStringB( cString ) + IF right( cString, 1 ) == chr(255) //reverse + cString := left( cString, len( cString ) - 1 ) + //pdfBox( nCol, nRow + aReport[ FONTSIZE ] - 2.0, nCol + pdfM2X( pdfLen( cString )) + 1, nRow + 2 * aReport[ FONTSIZE ] - 1.5,,100, "D") + pdfBox( aReport[ PAGEY ] - nRow - aReport[ FONTSIZE ] + 2.0 , nCol, aReport[ PAGEY ] - nRow + 2.0, nCol + pdfM2X( pdfLen( cString )) + 1,,100, "D") + aReport[ PAGEBUFFER ] += " 1 g " + lReverse = .t. + ELSEIF right( cString, 1 ) == chr(254) //underline + cString := left( cString, len( cString ) - 1 ) + //pdfBox( nCol, nRow - 1.5, nCol + pdfM2X( pdfLen( cString )) + 1, nRow - 1,,100, "D") + pdfBox( aReport[ PAGEY ] - nRow + 0.5, nCol, aReport[ PAGEY ] - nRow + 1, nCol + pdfM2X( pdfLen( cString )) + 1,,100, "D") + ENDIF + + // version 0.01 + IF ( nAt := at( chr(253), cString )) > 0 // some color text inside + aReport[ PAGEBUFFER ] += CRLF + ; + Chr_RGB( substr( cString, nAt + 1, 1 )) + " " + ; + Chr_RGB( substr( cString, nAt + 2, 1 )) + " " + ; + Chr_RGB( substr( cString, nAt + 3, 1 )) + " rg " + cString := stuff( cString, nAt, 4, "") + ENDIF + // version 0.01 + + _nFont := ascan( aReport[ FONTS ], {|arr| arr[1] == aReport[ FONTNAME ]} ) + IF aReport[ FONTNAME ] <> aReport[ FONTNAMEPREV ] + aReport[ FONTNAMEPREV ] := aReport[ FONTNAME ] + aReport[ PAGEBUFFER ] += CRLF + "BT /Fo" + ltrim(str( _nFont )) + " " + ltrim(transform( aReport[ FONTSIZE ], "999.99")) + " Tf " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ELSEIF aReport[ FONTSIZE ] <> aReport[ FONTSIZEPREV ] + aReport[ FONTSIZEPREV ] := aReport[ FONTSIZE ] + aReport[ PAGEBUFFER ] += CRLF + "BT /Fo" + ltrim(str( _nFont )) + " " + ltrim(transform( aReport[ FONTSIZE ], "999.99")) + " Tf " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ELSE + aReport[ PAGEBUFFER ] += CRLF + "BT " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ENDIF + IF lReverse + aReport[ PAGEBUFFER ] += " 0 g " + ENDIF + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBold() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF pdfGetFontInfo("NAME") = "Times" + aReport[ FONTNAME ] := 2 + ELSEIF pdfGetFontInfo("NAME") = "Helvetica" + aReport[ FONTNAME ] := 6 + ELSE + aReport[ FONTNAME ] := 10 // Courier // 0.04 + ENDIF + aadd( aReport[ PAGEFONTS ], aReport[ FONTNAME ] ) + IF ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ FONTNAME ] } ) == 0 + aadd( aReport[ FONTS ], { aReport[ FONTNAME ], ++aReport[ NEXTOBJ ] } ) + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBoldItalic() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF pdfGetFontInfo("NAME") = "Times" + aReport[ FONTNAME ] := 4 + ELSEIF pdfGetFontInfo("NAME") = "Helvetica" + aReport[ FONTNAME ] := 8 + ELSE + aReport[ FONTNAME ] := 12 // 0.04 + ENDIF + aadd( aReport[ PAGEFONTS ], aReport[ FONTNAME ] ) + IF ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ FONTNAME ] } ) == 0 + aadd( aReport[ FONTS ], { aReport[ FONTNAME ], ++aReport[ NEXTOBJ ] } ) + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBookAdd( cTitle, nLevel, nPage, nLine ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + aadd( aReport[ BOOKMARK ], { nLevel, alltrim( cTitle ), 0, 0, 0, 0, 0, 0, nPage, IIF( nLevel == 1, aReport[ PAGEY ], aReport[ PAGEY ] - nLine * 72 / aReport[ LPI ] ) }) +return Nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBookClose( ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + aReport[ BOOKMARK ] := nil +return Nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookCount( nRecno, nCurLevel ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nTempLevel := 0, nCount := 0, nLen := len( aReport[ BOOKMARK ] ) + ++nRecno + while nRecno <= nLen + nTempLevel := aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nTempLevel <= nCurLevel + exit + ELSE + IF nCurLevel + 1 == nTempLevel + ++nCount + ENDIF + ENDIF + ++nRecno + enddo +return -1 * nCount + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookFirst( nRecno, nCurLevel, nObj ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nFirst := 0, nLen := len( aReport[ BOOKMARK ] ) + ++nRecno + IF nRecno <= nLen + IF nCurLevel + 1 == aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + nFirst := nRecno + ENDIF + ENDIF +return IIF( nFirst == 0, nFirst, nObj + nFirst ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookLast( nRecno, nCurLevel, nObj ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nLast := 0, nLen := len( aReport[ BOOKMARK ] ) + ++nRecno + IF nRecno <= nLen + IF nCurLevel + 1 == aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + while nRecno <= nLen .and. nCurLevel + 1 <= aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel + 1 == aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + nLast := nRecno + ENDIF + ++nRecno + enddo + ENDIF + ENDIF +return IIF( nLast == 0, nLast, nObj + nLast ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookNext( nRecno, nCurLevel, nObj ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nTempLevel := 0, nNext := 0, nLen := len( aReport[ BOOKMARK ] ) + ++nRecno + while nRecno <= nLen + nTempLevel := aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel > nTempLevel + exit + ELSEIF nCurLevel == nTempLevel + nNext := nRecno + exit + ELSE + // keep going + ENDIF + ++nRecno + enddo +return IIF( nNext == 0, nNext, nObj + nNext ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBookOpen( ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + aReport[ BOOKMARK ] := {} +return Nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookParent( nRecno, nCurLevel, nObj ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nTempLevel := 0 +local nParent := 0 + --nRecno + while nRecno > 0 + nTempLevel := aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nTempLevel < nCurLevel + nParent := nRecno + exit + ENDIF + --nRecno + enddo +return IIF( nParent == 0, nObj - 1, nObj + nParent ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfBookPrev( nRecno, nCurLevel, nObj ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nTempLevel := 0 +local nPrev := 0 + --nRecno + while nRecno > 0 + nTempLevel := aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel > nTempLevel + exit + ELSEIF nCurLevel == nTempLevel + nPrev := nRecno + exit + ELSE + // keep going + ENDIF + --nRecno + enddo +return IIF( nPrev == 0, nPrev, nObj + nPrev ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBox( x1, y1, x2, y2, nBorder, nShade, cUnits, cColor, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local cBoxColor +DEFAULT nBorder to 0 +DEFAULT nShade to 0 +DEFAULT cUnits to "M" +DEFAULT cColor to "" + + // version 0.02 + cBoxColor := "" + IF !empty( cColor ) + cBoxColor := " " + Chr_RGB( substr( cColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cColor, 3, 1 )) + " " + ; + Chr_RGB( substr( cColor, 4, 1 )) + " rg " + IF empty( alltrim( cBoxColor ) ) + cBoxColor := "" + ENDIF + ENDIF + // version 0.02 + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFBOX", cId, { x1, y1, x2, y2, nBorder, nShade, cUnits } ) + ENDIF + + IF cUnits == "M" + y1 += 0.5 + y2 += 0.5 + + IF nShade > 0 + // version 0.02 + aReport[ PAGEBUFFER ] += CRLF + transform( 1.00 - nShade / 100.00, "9.99") + " g " + cBoxColor + ltrim(str(pdfM2X( y1 ))) + " " + ltrim(str(pdfM2Y( x1 ))) + " " + ltrim(str(pdfM2X( y2 - y1 ))) + " -" + ltrim(str(pdfM2X( x2 - x1 ))) + " re f 0 g" + ENDIF + + IF nBorder > 0 + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(pdfM2X( y1 ))) + " " + ltrim(str(pdfM2Y( x1 ))) + " " + ltrim(str(pdfM2X( y2 - y1 ))) + " -" + ltrim(str(pdfM2X( nBorder ))) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(pdfM2X( y2 - nBorder ))) + " " + ltrim(str(pdfM2Y( x1 ))) + " " + ltrim(str(pdfM2X( nBorder ))) + " -" + ltrim(str(pdfM2X( x2 - x1 ))) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(pdfM2X( y1 ))) + " " + ltrim(str(pdfM2Y( x2 - nBorder ))) + " " + ltrim(str(pdfM2X( y2 - y1 ))) + " -" + ltrim(str(pdfM2X( nBorder ))) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(pdfM2X( y1 ))) + " " + ltrim(str(pdfM2Y( x1 ))) + " " + ltrim(str(pdfM2X( nBorder ))) + " -" + ltrim(str(pdfM2X( x2 - x1 ))) + " re f" + ENDIF + ELSEIF cUnits == "D"// "Dots" + //x1, y1, x2, y2 - nTop, nLeft, nBottom, nRight + IF nShade > 0 + // version 0.02 + aReport[ PAGEBUFFER ] += CRLF + transform( 1.00 - nShade / 100.00, "9.99") + " g " + cBoxColor + ltrim(str( y1 )) + " " + ltrim(str( aReport[ PAGEY ] - x1 )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( x2 - x1 )) + " re f 0 g" + ENDIF + + IF nBorder > 0 +/* + 1 + ÚÄÄÄÄÄ¿ + 4 ³ ³ 2 + ÀÄÄÄÄÄÙ + 3 +*/ + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( aReport[ PAGEY ] - x1 )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( nBorder )) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y2 - nBorder )) + " " + ltrim(str( aReport[ PAGEY ] - x1 )) + " " + ltrim(str( nBorder )) + " -" + ltrim(str( x2 - x1 )) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( aReport[ PAGEY ] - x2 + nBorder )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( nBorder )) + " re f" + aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( aReport[ PAGEY ] - x1 )) + " " + ltrim(str( nBorder )) + " -" + ltrim(str( x2 - x1 )) + " re f" + ENDIF + ENDIF + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfBox1( nTop, nLeft, nBottom, nRight, nBorderWidth, cBorderColor, cBoxColor ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +DEFAULT nBorderWidth to 0.5 +DEFAULT cBorderColor to chr(0) + chr(0) + chr(0) +DEFAULT cBoxColor to chr(255) + chr(255) + chr(255) + + aReport[ PAGEBUFFER ] += CRLF + ; + Chr_RGB( substr( cBorderColor, 1, 1 )) + " " + ; + Chr_RGB( substr( cBorderColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cBorderColor, 3, 1 )) + ; + " RG" + ; + CRLF + ; + Chr_RGB( substr( cBoxColor, 1, 1 )) + " " + ; + Chr_RGB( substr( cBoxColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cBoxColor, 3, 1 )) + ; + " rg" + ; + CRLF + ltrim(str( nBorderWidth )) + " w" + ; + CRLF + ltrim( str ( nLeft + nBorderWidth / 2 )) + " " + ; + CRLF + ltrim( str ( aReport[ PAGEY ] - nBottom + nBorderWidth / 2)) + " " + ; + CRLF + ltrim( str ( nRight - nLeft - nBorderWidth )) + ; + CRLF + ltrim( str ( nBottom - nTop - nBorderWidth )) + " " + ; + " re" + ; + CRLF + "B" +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfCenter( cString, nRow, nCol, cUnits, lExact, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nLen, nAt +DEFAULT nRow to aReport[ REPORTLINE ] +DEFAULT cUnits to "R" +DEFAULT lExact to .f. +DEFAULT nCol to IIF( cUnits == "R", aReport[ REPORTWIDTH ] / 2, aReport[ PAGEX ] / 72 * 25.4 / 2 ) + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFCENTER", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( pdfPageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + nLen := pdfLen( cString ) / 2 + IF cUnits == "R" + IF .not. lExact + pdfCheckLine( nRow ) + nRow := nRow + aReport[ PDFTOP ] + ENDIF + ENDIF + pdfAtSay( cString, pdfR2M( nRow ), IIF( cUnits == "R", aReport[ PDFLEFT ] + ( aReport[ PAGEX ] / 72 * 25.4 - 2 * aReport[ PDFLEFT ] ) * nCol / aReport[ REPORTWIDTH ], nCol ) - nLen, "M", lExact ) +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfCheckLine( nRow ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF nRow + aReport[ PDFTOP ] > aReport[ PDFBOTTOM ] + pdfNewPage() + nRow := aReport[ REPORTLINE ] + ENDIF + aReport[ REPORTLINE ] := nRow +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfClose() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nI, cTemp, nCurLevel, nObj1, nLast, nCount, nFirst, nRecno, nBooklen + + FIELD FIRST, PREV, NEXT, LAST, COUNT, PARENT, PAGE, COORD, TITLE, LEVEL + + pdfClosePage() + + // kids + aReport[ REFS ][ 2 ] := aReport[ DOCLEN ] + cTemp := ; + "1 0 obj"+CRLF+; + "<<"+CRLF+; + "/Type /Pages /Count " + ltrim(str(aReport[ REPORTPAGE ])) + CRLF +; + "/Kids [" + + for nI := 1 to aReport[ REPORTPAGE ] + cTemp += " " + ltrim(str( aReport[ PAGES ][ nI ] )) + " 0 R" + next + + cTemp += " ]" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + // info + ++aReport[ REPORTOBJ ] + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + cTemp := ltrim(str( aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Producer ()" + CRLF + ; + "/Title ()" + CRLF + ; + "/Author ()" + CRLF + ; + "/Creator ()" + CRLF + ; + "/Subject ()" + CRLF + ; + "/Keywords ()" + CRLF + ; + "/CreationDate (D:" + str(year(date()), 4) + padl( month(date()), 2, "0") + padl( day(date()), 2, "0") + substr( time(), 1, 2 ) + substr( time(), 4, 2 ) + substr( time(), 7, 2 ) + ")" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + // root + ++aReport[ REPORTOBJ ] + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + cTemp := ltrim(str( aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<< /Type /Catalog /Pages 1 0 R /Outlines " + ltrim(str( aReport[ REPORTOBJ ] + 1 )) + " 0 R" + IIF( ( nBookLen := len( aReport[ BOOKMARK ] )) > 0, " /PageMode /UseOutlines", "") + " >>" + CRLF + "endobj" + CRLF + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + ++aReport[ REPORTOBJ ] + nObj1 := aReport[ REPORTOBJ ] + + IF nBookLen > 0 + + nRecno := 1 + nFirst := aReport[ REPORTOBJ ] + 1 + nLast := 0 + nCount := 0 + while nRecno <= nBookLen + nCurLevel := aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + aReport[ BOOKMARK ][ nRecno ][ BOOKPARENT ] := pdfBookParent( nRecno, nCurLevel, aReport[ REPORTOBJ ] ) + aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ] := pdfBookPrev( nRecno, nCurLevel, aReport[ REPORTOBJ ] ) + aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ] := pdfBookNext( nRecno, nCurLevel, aReport[ REPORTOBJ ] ) + aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ] := pdfBookFirst( nRecno, nCurLevel, aReport[ REPORTOBJ ] ) + aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ] := pdfBookLast( nRecno, nCurLevel, aReport[ REPORTOBJ ] ) + aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ] := pdfBookCount( nRecno, nCurLevel ) + IF nCurLevel == 1 + nLast := nRecno + ++nCount + ENDIF + ++nRecno + enddo + + nLast += aReport[ REPORTOBJ ] + + cTemp := ltrim(str( aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + "<< /Type /Outlines /Count " + ltrim(str( nCount )) + " /First " + ltrim(str( nFirst )) + " 0 R /Last " + ltrim(str( nLast )) + " 0 R >>" + CRLF + "endobj" //+ CRLF + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + ++aReport[ REPORTOBJ ] + nRecno := 1 + FOR nI := 1 to nBookLen + //cTemp := IIF ( nI > 1, CRLF, "") + ltrim(str( aReport[ REPORTOBJ ] + nI - 1)) + " 0 obj" + CRLF + ; + cTemp := CRLF + ltrim(str( aReport[ REPORTOBJ ] + nI - 1)) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Parent " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKPARENT ])) + " 0 R" + CRLF + ; + "/Dest [" + ltrim(str( aReport[ PAGES ][ aReport[ BOOKMARK ][ nRecno ][ BOOKPAGE ] ] )) + " 0 R /XYZ 0 " + ltrim( str( aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; + "/Title (" + alltrim( aReport[ BOOKMARK ][ nRecno ][ BOOKTITLE ]) + ")" + CRLF + ; + IIF( aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ] > 0, "/Prev " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ])) + " 0 R" + CRLF, "") + ; + IIF( aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ] > 0, "/Next " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ])) + " 0 R" + CRLF, "") + ; + IIF( aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ] > 0, "/First " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ])) + " 0 R" + CRLF, "") + ; + IIF( aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ] > 0, "/Last " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ])) + " 0 R" + CRLF, "") + ; + IIF( aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ] <> 0, "/Count " + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ])) + CRLF, "") + ; + ">>" + CRLF + "endobj" + CRLF +// "/Dest [" + ltrim(str( aReport[ BOOKMARK ][ nRecno ][ BOOKPAGE ] * 3 )) + " 0 R /XYZ 0 " + ltrim( str( aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; +// "/Dest [" + ltrim(str( aReport[ PAGES ][ nRecno ] )) + " 0 R /XYZ 0 " + ltrim( str( aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; + + aadd( aReport[ REFS ], aReport[ DOCLEN ] + 2 ) + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + ++nRecno + NEXT + pdfBookClose() + + aReport[ REPORTOBJ ] += nBookLen - 1 + ELSE + cTemp := ltrim(str( aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + "<< /Type /Outlines /Count 0 >>" + CRLF + "endobj" + CRLF + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + ENDIF + + cTemp := CRLF + aReport[ DOCLEN ] += len( cTemp ) + + ++aReport[ REPORTOBJ ] + cTemp += "xref" + CRLF + ; + "0 " + ltrim(str( aReport[ REPORTOBJ ] )) + CRLF +; + padl( aReport[ REFS ][ 1 ], 10, "0") + " 65535 f" + CRLF + + for nI := 2 to len( aReport[ REFS ] ) + cTemp += padl( aReport[ REFS ][ nI ], 10, "0") + " 00000 n" + CRLF + next + + cTemp += "trailer << /Size " + ltrim(str( aReport[ REPORTOBJ ] )) + " /Root " + ltrim(str( nObj1 - 1 )) + " 0 R /Info " + ltrim(str( nObj1 - 2 )) + " 0 R >>" + CRLF + ; + "startxref" + CRLF + ; + ltrim(str( aReport[ DOCLEN ] )) + CRLF + ; + "%%EOF" + CRLF + fwrite( aReport[ HANDLE ], cTemp ) +/* + IF aReport[ OPTIMIZE ] + pdfOptimize( ) coming ! + ENDIF +*/ + fclose( aReport[ HANDLE ] ) + + aReport := nil + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfClosePage() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local cTemp, cBuffer, nBuffer, nRead, nI, k, nImage, nFont, nImageHandle + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + + aadd( aReport[ PAGES ], aReport[ REPORTOBJ ] + 1 ) + + cTemp := ; + ltrim(str( ++aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /Page /Parent 1 0 R" + CRLF + ; + "/Resources " + ltrim(str( ++aReport[ REPORTOBJ ] )) + " 0 R" + CRLF + ; + "/MediaBox [ 0 0 " + ltrim(transform( aReport[ PAGEX ], "9999.99")) + " " + ; + ltrim(transform(aReport[ PAGEY ], "9999.99")) + " ]" + CRLF + ; + "/Contents " + ltrim(str( ++aReport[ REPORTOBJ ] )) + " 0 R" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF +// "/Contents [ " + ltrim(str( ++aReport[ REPORTOBJ ] )) + " 0 R ]" + CRLF + ; + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + cTemp := ; + ltrim(str(aReport[ REPORTOBJ ] - 1)) + " 0 obj" + CRLF + ; + "<<"+CRLF+; + "/ColorSpace << /DeviceRGB /DeviceGray >>" + CRLF + ; //version 0.01 + "/ProcSet [ /PDF /Text /ImageB /ImageC ]" + + IF len( aReport[ PAGEFONTS ] ) > 0 + cTemp += CRLF + ; + "/Font" + CRLF + ; + "<<" + + for nI := 1 to len( aReport[ PAGEFONTS ] ) + nFont := ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ PAGEFONTS ][ nI ] } ) + //IF nFont == 0 + // alert("New font after!!!") + //ENDIF + cTemp += CRLF + "/Fo" + ltrim(str( nFont )) + " " + ltrim(str( aReport[ FONTS ][ nFont ][ 2 ])) + " 0 R" + next + + cTemp += CRLF + ">>" + ENDIF + + IF len( aReport[ PAGEIMAGES ] ) > 0 + cTemp += CRLF + "/XObject" + CRLF + "<<" + for nI := 1 to len( aReport[ PAGEIMAGES ] ) + nImage := ascan( aReport[ IMAGES ], { |arr| arr[1] == aReport[ PAGEIMAGES ][ nI ][ 1 ] } ) + IF nImage == 0 + aadd( aReport[ IMAGES ], { aReport[ PAGEIMAGES ][ nI ][ 1 ], ++aReport[ NEXTOBJ ], pdfImageInfo( aReport[ PAGEIMAGES ][ nI ][ 1 ] ) } ) + nImage := len( aReport[ IMAGES ] ) + ENDIF + cTemp += CRLF + "/Image" + ltrim(str( nImage )) + " " + ltrim(str( aReport[ IMAGES ][ nImage ][ 2 ])) + " 0 R" + next + cTemp += CRLF + ">>" + ENDIF + + cTemp += CRLF + ">>" + CRLF + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + cTemp := ltrim(str( aReport[ REPORTOBJ ] )) + " 0 obj << /Length " + ; + ltrim(str( aReport[ REPORTOBJ ] + 1 )) + " 0 R >>" + CRLF +; + "stream" + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + IF len( aReport[ PAGEIMAGES ] ) > 0 + cTemp := "" + for nI := 1 to len( aReport[ PAGEIMAGES ] ) + cTemp += CRLF + "q" + nImage := ascan( aReport[ IMAGES ], { |arr| arr[1] == aReport[ PAGEIMAGES ][ nI ][ 1 ] } ) + cTemp += CRLF + ltrim(str( IIF( aReport[ PAGEIMAGES ][ nI ][ 5 ] == 0, pdfM2X( aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_WIDTH ] / aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_XRES ] * 25.4 ), aReport[ PAGEIMAGES ][ nI ][ 5 ]))) + ; + " 0 0 " + ; + ltrim(str( IIF( aReport[ PAGEIMAGES ][ nI ][ 4 ] == 0, pdfM2X( aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_HEIGHT ] / aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_YRES ] * 25.4 ), aReport[ PAGEIMAGES ][ nI ][ 4 ]))) + ; + " " + ltrim(str( aReport[ PAGEIMAGES ][ nI ][ 3 ] )) + ; + " " + ltrim(str( aReport[ PAGEY ] - aReport[ PAGEIMAGES ][ nI ][ 2 ] - ; + IIF( aReport[ PAGEIMAGES ][ nI ][ 4 ] == 0, pdfM2X( aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_HEIGHT ] / aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_YRES ] * 25.4 ), aReport[ PAGEIMAGES ][ nI ][ 4 ]))) + " cm" + cTemp += CRLF + "/Image" + ltrim(str( nImage )) + " Do" + cTemp += CRLF + "Q" + next + aReport[ PAGEBUFFER ] := cTemp + aReport[ PAGEBUFFER ] + ENDIF + + cTemp := aReport[ PAGEBUFFER ] + + cTemp += CRLF + "endstream" + CRLF + ; + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + cTemp := ltrim(str( ++aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + ltrim(str(len( aReport[ PAGEBUFFER ] ))) + CRLF + ; + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + for nI := 1 to len( aReport[ FONTS ] ) + IF aReport[ FONTS ][ nI ][ 2 ] > aReport[ REPORTOBJ ] + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + + cTemp := ; + ltrim(str( aReport[ FONTS ][ nI ][ 2 ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /Font" + CRLF + ; + "/Subtype /Type1" + CRLF + ; + "/Name /Fo" + ltrim(str( nI )) + CRLF + ; + "/BaseFont /" + aReport[ TYPE1 ][ aReport[ FONTS ][ nI ][ 1 ] ] + CRLF + ; + "/Encoding /WinAnsiEncoding" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + ENDIF + next + + for nI := 1 to len( aReport[ IMAGES ] ) + IF aReport[ IMAGES ][ nI ][ 2 ] > aReport[ REPORTOBJ ] + + aadd( aReport[ REFS ], aReport[ DOCLEN ] ) + + // "/Filter /CCITTFaxDecode" for B&W only ? + cTemp := ; + ltrim(str( aReport[ IMAGES ][ nI ][ 2 ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /XObject" + CRLF + ; + "/Subtype /Image" + CRLF + ; + "/Name /Image" + ltrim(str(nI)) + CRLF + ; + "/Filter [" + IIF( at( ".JPG", upper( aReport[ IMAGES ][ nI ][ 1 ]) ) > 0, " /DCTDecode", "" ) + " ]" + CRLF + ; + "/Width " + ltrim(str( aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_WIDTH ] )) + CRLF + ; + "/Height " + ltrim(str( aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_HEIGHT ] )) + CRLF + ; + "/BitsPerComponent " + ltrim(str( aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_BITS ] )) + CRLF + ; + "/ColorSpace /" + IIF( aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_BITS ] == 1, "DeviceGray", "DeviceRGB") + CRLF + ; + "/Length " + ltrim(str( aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ])) + CRLF + ; + ">>" + CRLF + ; + "stream" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + nImageHandle := fopen( aReport[ IMAGES ][ nI ][ 1 ] ) + fseek( nImageHandle, aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_FROM ] ) + + nBuffer := 8192 + cBuffer := space( nBuffer ) + k := 0 + while k < aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] + IF k + nBuffer <= aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] + nRead := nBuffer + ELSE + nRead := aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] - k + ENDIF + fread( nImageHandle, @cBuffer, nRead ) + + aReport[ DOCLEN ] += nRead + fwrite( aReport[ HANDLE ], cBuffer, nRead ) + k += nRead + enddo + + cTemp := CRLF + "endstream" + CRLF + ; + "endobj" + CRLF + + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + ENDIF + next + + aReport[ REPORTOBJ ] := aReport[ NEXTOBJ ] + + aReport[ NEXTOBJ ] := aReport[ REPORTOBJ ] + 4 + + aReport[ PAGEBUFFER ] := "" + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfGetFontInfo( cParam ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local cRet + IF cParam == "NAME" + IF left( aReport[ TYPE1 ][ aReport[ FONTNAME ] ], 5 ) == "Times" + cRet := "Times" + ELSEIF left( aReport[ TYPE1 ][ aReport[ FONTNAME ] ], 9 ) == "Helvetica" + cRet := "Helvetica" + ELSE + cRet := "Courier" // 0.04 + ENDIF + ELSE // size + cRet := int(( aReport[ FONTNAME ] - 1 ) % 4) + ENDIF +return cRet + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfImage( cFile, nRow, nCol, cUnits, nHeight, nWidth, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + +DEFAULT nRow to aReport[ REPORTLINE ] +DEFAULT nCol to 0 +DEFAULT nHeight to 0 +DEFAULT nWidth to 0 +DEFAULT cUnits to "R" +DEFAULT cId to "" + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFIMAGE", cId, { cFile, nRow, nCol, cUnits, nHeight, nWidth } ) + ENDIF + + IF cUnits == "M" + nRow := aReport[ PAGEY ] - pdfM2Y( nRow ) + nCol := pdfM2X( nCol ) + nHeight := aReport[ PAGEY ] - pdfM2Y( nHeight ) + nWidth := pdfM2X( nWidth ) + ELSEIF cUnits == "R" + //IF .not. lExact + // pdfCheckLine( nRow ) + // nRow := nRow + aReportStyle[ PDFTOP ] + //ENDIF + nRow := aReport[ PAGEY ] - pdfR2D( nRow ) + nCol := pdfM2X( aReport[ PDFLEFT ] ) + ; + nCol * 100.00 / aReport[ REPORTWIDTH ] * ; + ( aReport[ PAGEX ] - pdfM2X( aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + nHeight := aReport[ PAGEY ] - pdfR2D( nHeight ) + nWidth := pdfM2X( aReport[ PDFLEFT ] ) + ; + nWidth * 100.00 / aReport[ REPORTWIDTH ] * ; + ( aReport[ PAGEX ] - pdfM2X( aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + ELSEIF cUnits == "D" + ENDIF + + aadd( aReport[ PAGEIMAGES ], { cFile, nRow, nCol, nHeight, nWidth } ) + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfItalic() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF pdfGetFontInfo("NAME") = "Times" + aReport[ FONTNAME ] := 3 + ELSEIF pdfGetFontInfo("NAME") = "Helvetica" + aReport[ FONTNAME ] := 7 + ELSE + aReport[ FONTNAME ] := 11 // 0.04 + ENDIF + aadd( aReport[ PAGEFONTS ], aReport[ FONTNAME ] ) + IF ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ FONTNAME ] } ) == 0 + aadd( aReport[ FONTS ], { aReport[ FONTNAME ], ++aReport[ NEXTOBJ ] } ) + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfLen( cString ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nWidth := 0.00, nI, nLen, nArr, nAdd := ( aReport[ FONTNAME ] - 1 ) % 4 + + nLen := len( cString ) + IF right( cString, 1 ) == chr(255) .or. right( cString, 1 ) == chr(254 )// reverse or underline + --nLen + ENDIF + IF pdfGetFontInfo("NAME") = "Times" + nArr := 1 + ELSEIF pdfGetFontInfo("NAME") = "Helvetica" + nArr := 2 + ELSE + nArr := 3 // 0.04 + ENDIF + For nI:= 1 To nLen + nWidth += aReport[ FONTWIDTH ][ nArr ][ ( asc( substr( cString, nI, 1 )) - 32 ) * 4 + 1 + nAdd ] * 25.4 * aReport[ FONTSIZE ] / 720.00 / 100.00 + Next +return nWidth + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfM2R( mm ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return int( aReport[ LPI ] * mm / 25.4 ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfM2X( n ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return n * 72 / 25.4 + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfM2Y( n ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return aReport[ PAGEY ] - n * 72 / 25.4 + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfNewLine( n ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +DEFAULT n to 1 + IF aReport[ REPORTLINE ] + n + aReport[ PDFTOP ] > aReport[ PDFBOTTOM ] + pdfNewPage() + aReport[ REPORTLINE ] += 1 + ELSE + aReport[ REPORTLINE ] += n + ENDIF +return aReport[ REPORTLINE ] + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +function pdfNewPage( _cPageSize, _cPageOrient, _nLpi, _cFontName, _nFontType, _nFontSize )/* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +local nAdd := 76.2 +DEFAULT _cPageSize to aReport[ PAGESIZE ] +DEFAULT _cPageOrient to aReport[ PAGEORIENT ] +DEFAULT _nLpi to aReport[ LPI ] +DEFAULT _cFontName to pdfGetFontInfo("NAME") +DEFAULT _nFontType to pdfGetFontInfo("TYPE") +DEFAULT _nFontSize to aReport[ FONTSIZE ] + + IF !empty(aReport[ PAGEBUFFER ]) + pdfClosePage() + ENDIF + + aReport[ PAGEFONTS ] := {} + aReport[ PAGEIMAGES ] := {} + + ++aReport[ REPORTPAGE ] // NEW !!! + + pdfPageSize( _cPageSize ) + pdfPageOrient( _cPageOrient ) + pdfSetLPI( _nLpi ) + + pdfSetFont( _cFontName, _nFontType, _nFontSize ) + + pdfDrawHeader() + + aReport[ REPORTLINE ] := 0//5 + aReport[ FONTNAMEPREV ] := 0 + aReport[ FONTSIZEPREV ] := 0 +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfNormal() /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF pdfGetFontInfo("NAME") = "Times" + aReport[ FONTNAME ] := 1 + ELSEIF pdfGetFontInfo("NAME") = "Helvetica" + aReport[ FONTNAME ] := 5 + ELSE + aReport[ FONTNAME ] := 9 // 0.04 + ENDIF + aadd( aReport[ PAGEFONTS ], aReport[ FONTNAME ] ) + IF ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ FONTNAME ] } ) == 0 + aadd( aReport[ FONTS ], { aReport[ FONTNAME ], ++aReport[ NEXTOBJ ] } ) + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfOpen( cFile, nLen, lOptimize ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local cTemp, nI, nJ, n1, n2 := 896, n12 +DEFAULT nLen to 200 +DEFAULT lOptimize to .f. + + aReport[ FONTNAME ] := 1 + aReport[ FONTSIZE ] := 10 + aReport[ LPI ] := 6 + aReport[ PAGESIZE ] := "LETTER" + aReport[ PAGEORIENT ] := "P" + aReport[ PAGEX ] := 8.5 * 72 + aReport[ PAGEY ] := 11.0 * 72 + aReport[ REPORTWIDTH ] := nLen // 200 // should be as parameter + aReport[ REPORTPAGE ] := 0 + aReport[ REPORTLINE ] := 0 //5 + aReport[ FONTNAMEPREV ] := 0 + aReport[ FONTSIZEPREV ] := 0 + aReport[ PAGEBUFFER ] := "" + aReport[ REPORTOBJ ] := 1 //2 + aReport[ DOCLEN ] := 0 + aReport[ TYPE1 ] := { "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique" } // 0.04 + aReport[ MARGINS ] := .t. + aReport[ HEADEREDIT ] := .f. + aReport[ NEXTOBJ ] := 0 + aReport[ PDFTOP ] := 1 // top + aReport[ PDFLEFT ] := 10 // left & right + aReport[ PDFBOTTOM ] := aReport[ PAGEY ] / 72 * aReport[ LPI ] - 1 // bottom, default "LETTER", "P", 6 + aReport[ HANDLE ] := fcreate( cFile ) + aReport[ PAGES ] := {} + aReport[ REFS ] := { 0, 0 } + aReport[ BOOKMARK ] := {} + aReport[ HEADER ] := {} + aReport[ FONTS ] := {} + aReport[ IMAGES ] := {} + aReport[ PAGEIMAGES ] := {} + aReport[ PAGEFONTS ] := {} + + // TOFIX: This external file dependency should be removed. + + cTemp := memoread("fonts.dat") // times, times-bold, times-italic, times-bolditalic, helvetica..., courier... // 0.04 + n1 := len( cTemp ) / ( 2 * n2 ) + aReport[ FONTWIDTH ] := array( n1, n2 ) + + aReport[ OPTIMIZE ] := lOptimize + + aReport[ NEXTOBJ ] := aReport[ REPORTOBJ ] + 4 + + n12 := 2 * n2 // 0.04 + for nI := 1 to n1 + for nJ := 1 to n2 + aReport[ FONTWIDTH ][ nI ][ nJ ] := bin2i(substr( cTemp, ( nI - 1 ) * n12 + ( nJ - 1 ) * 2 + 1, 2 )) + next + next + +/* + aReportStyle := { ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 3 , 64.0 , "P6", 60, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 6 , 85.35, "P8", 78, 10 }, ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 2.9, 48.9 , "L6", 45, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 5.85, 65.2 , "L8", 58, 10 }, ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 2.9, 82.0 , "P6", 78, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 6 , 109.35 , "P8", 102, 10 } ; + } +*/ + + aReport[ DOCLEN ] := 0 + cTemp := "%PDF-1.3" + CRLF + aReport[ DOCLEN ] += len( cTemp ) + fwrite( aReport[ HANDLE ], cTemp ) + + //pdfNewPage( "LETTER", "P", 6 ) + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfPageSize( _cPageSize ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nSize, aSize := { { "LETTER", 8.50, 11.00 }, ; + { "LEGAL" , 8.50, 14.00 }, ; + { "LEDGER", 11.00, 17.00 }, ; + { "EXECUTIVE", 7.25, 10.50 }, ; + { "A4", 8.27, 11.69 }, ; + { "A3", 11.69, 16.54 }, ; + { "JIS B4", 10.12, 14.33 }, ; + { "JIS B5", 7.16, 10.12 }, ; + { "JPOST", 3.94, 5.83 }, ; + { "JPOSTD", 5.83, 7.87 }, ; + { "COM10", 4.12, 9.50 }, ; + { "MONARCH", 3.87, 7.50 }, ; + { "C5", 6.38, 9.01 }, ; + { "DL", 4.33, 8.66 }, ; + { "B5", 6.93, 9.84 } } + +DEFAULT _cPageSize to "LETTER" + + nSize := ascan( aSize, { |arr| arr[ 1 ] = _cPageSize } ) + + IF nSize = 0 //.or. nSize > 2 //0.05 + nSize := 1 + ENDIF + + aReport[ PAGESIZE ] := aSize[ nSize ][ 1 ] + + IF aReport[ PAGEORIENT ] = "P" + aReport[ PAGEX ] := aSize[ nSize ][ 2 ] * 72 + aReport[ PAGEY ] := aSize[ nSize ][ 3 ] * 72 + ELSE + aReport[ PAGEX ] := aSize[ nSize ][ 3 ] * 72 + aReport[ PAGEY ] := aSize[ nSize ][ 2 ] * 72 + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfPageOrient( _cPageOrient ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +DEFAULT _cPageOrient to "P" + + aReport[ PAGEORIENT ] := _cPageOrient + pdfPageSize( aReport[ PAGESIZE ] ) +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfR2D( nRow ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return aReport[ PAGEY ] - nRow * 72 / aReport[ LPI ] + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfR2M( nRow ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return 25.4 * nRow / aReport[ LPI ] + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfPageNumber( n ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +DEFAULT n to 0 + IF n > 0 + aReport[ REPORTPAGE ] := n // NEW !!! + ENDIF +return aReport[ REPORTPAGE ] + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfReverse( cString ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return cString + chr(255) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfRJust( cString, nRow, nCol, cUnits, lExact, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nLen, nAdj := 1.0, nAt +DEFAULT nRow to aReport[ REPORTLINE ] +DEFAULT cUnits to "R" +DEFAULT lExact to .f. + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFRJUST", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( pdfPageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + nLen := pdfLen( cString ) + + IF cUnits == "R" + IF .not. lExact + pdfCheckLine( nRow ) + nRow := nRow + aReport[ PDFTOP ] + ENDIF + ENDIF + pdfAtSay( cString, pdfR2M( nRow ), IIF( cUnits == "R", aReport[ PDFLEFT ] + ( aReport[ PAGEX ] / 72 * 25.4 - 2 * aReport[ PDFLEFT ] ) * nCol / aReport[ REPORTWIDTH ] - nAdj, nCol ) - nLen, "M", lExact ) +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfSetFont( _cFont, _nType, _nSize, cId ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + +DEFAULT _cFont to "Times" +DEFAULT _nType to 0 +DEFAULT _nSize to 10 + + IF aReport[ HEADEREDIT ] + return pdfHeader( "PDFSETFONT", cId, { _cFont, _nType, _nSize } ) + ENDIF + + _cFont := upper( _cFont ) + aReport[ FONTSIZE ] := _nSize + + IF _cFont == "TIMES" + aReport[ FONTNAME ] := _nType + 1 + ELSEIF _cFont == "HELVETICA" + aReport[ FONTNAME ] := _nType + 5 + ELSE + aReport[ FONTNAME ] := _nType + 9 // 0.04 + ENDIF + + aadd( aReport[ PAGEFONTS ], aReport[ FONTNAME ] ) + + IF ascan( aReport[ FONTS ], { |arr| arr[1] == aReport[ FONTNAME ] } ) == 0 + aadd( aReport[ FONTS ], { aReport[ FONTNAME ], ++aReport[ NEXTOBJ ] } ) + ENDIF +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfSetLPI(_nLpi) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local cLpi := alltrim(str(_nLpi)) +DEFAULT _nLpi to 6 + + cLpi := iif(cLpi$"1;2;3;4;6;8;12;16;24;48",cLpi,"6") + aReport[ LPI ] := val( cLpi ) + + pdfPageSize( aReport[ PAGESIZE ] ) +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfStringB( cString ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + cString := strtran( cString, "(", "\(" ) + cString := strtran( cString, ")", "\)" ) +return cString + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +function pdfTextCount( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits )/* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +return pdfText( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits, .f. ) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +function pdfText( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits, cColor, lPrint )/* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +local cDelim := chr(0)+chr(9)+chr(10)+chr(13)+chr(26)+chr(32)+chr(138)+chr(141) +local nI, cTemp, cToken, k, nL, nRow, nLines, nLineLen, nStart +local lParagraph, nSpace, nNew, nTokenLen, nCRLF, nTokens, nLen +DEFAULT nTab to -1 +DEFAULT cUnits to 'R' +DEFAULT nJustify to 4 // justify +DEFAULT lPrint to .t. +DEFAULT cColor to "" + + IF cUnits == "M" + nTop := pdfM2R( nTop ) + ELSEIF cUnits == "R" + nLeft := pdfX2M( pdfM2X( aReport[ PDFLEFT ] ) + ; + nLeft * 100.00 / aReport[ REPORTWIDTH ] * ; + ( aReport[ PAGEX ] - pdfM2X( aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 ) + ENDIF + + aReport[ REPORTLINE ] := nTop - 1 + + nSpace := pdfLen( " " ) + nLines := 0 + nCRLF := 0 + + nNew := nTab + + cString := alltrim( cString ) + nTokens := numtoken( cString, cDelim ) + nTokenLen := 0.00 + nStart := 1 + + IF nJustify == 1 .or. nJustify == 4 + nLeft := nLeft + ELSEIF nJustify == 2 + nLeft := nLeft - nLength / 2 + ELSEIF nJustify == 3 + nLeft := nLeft - nLength + ENDIF + + nL := nLeft + nL += nNew * nSpace // first always paragraph + nLineLen := nSpace * nNew - nSpace + + lParagraph := .t. + nI := 1 + + while nI <= nTokens + cToken := token( cString, cDelim, nI ) + nTokenLen := pdfLen( cToken ) + nLen := len( cToken ) + + IF nLineLen + nSpace + nTokenLen > nLength + IF nStart == nI // single word > nLength + k := 1 + while k <= nLen + cTemp := "" + nLineLen := 0.00 + nL := nLeft + IF lParagraph + nLineLen += nSpace * nNew + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + lParagraph := .f. + ENDIF + IF nJustify == 2 + nL := nLeft + ( nLength - pdfLen( cTemp ) ) / 2 + ELSEIF nJustify == 3 + nL := nLeft + nLength - pdfLen( cTemp ) + ENDIF + while k <= nLen .and. ( ( nLineLen += pdfLen( substr( cToken, k, 1 ))) <= nLength ) + nLineLen += pdfLen( substr( cToken, k, 1 )) + cTemp += substr( cToken, k, 1 ) + ++k + enddo + IF empty( cTemp ) // single character > nlength + cTemp := substr( cToken, k, 1 ) + ++k + ENDIF + ++nLines + IF lPrint + nRow := pdfNewLine( 1 ) + // version 0.02 + pdfAtSay( cColor + cTemp, pdfR2M( nRow + aReport[ PDFTOP ] ), nL, "M" ) + ENDIF + enddo + ++nI + nStart := nI + ELSE + pdfTextPrint( nI - 1, nLeft, @lParagraph, nJustify, nSpace, nNew, nLength, @nLineLen, @nLines, @nStart, cString, cDelim, cColor, lPrint ) + ENDIF +/* + nFinish := nI - 1 + + nL := nLeft + IF lParagraph + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + ENDIF + + IF nJustify == 3 // right + nL += nLength - nLineLen + ELSEIF nJustify == 2 // center + nL += ( nLength - nLineLen ) / 2 + ENDIF + + ++nLines + IF lPrint + nRow := pdfNewLine( 1 ) + ENDIF + nB := nSpace + IF nJustify == 4 + nB := ( nLength - nLineLen + ( nFinish - nStart ) * nSpace ) / ( nFinish - nStart ) + ENDIF + for nJ := nStart to nFinish + cToken := token( cString, cDelim, nJ ) + IF lPrint + pdfAtSay( cToken, pdfR2M( nRow + aReportStyle[ aReport[ REPORTSTYLE ] ][ 6 ] ), nL, "M" ) + ENDIF + nL += pdfLen ( cToken ) + nB + next + nStart := nFinish + 1 + ENDIF + + lParagraph := .f. + + nLineLen := 0.00 + nLineLen += nSpace * nNew +*/ + ELSEIF ( nI == nTokens ) .or. ( nI < nTokens .and. ( nCRLF := pdfTextNextPara( cString, cDelim, nI ) ) > 0 ) + IF nI == nTokens + nLineLen += nSpace + nTokenLen + ENDIF + pdfTextPrint( nI, nLeft, @lParagraph, nJustify, nSpace, nNew, nLength, @nLineLen, @nLines, @nStart, cString, cDelim, cColor, lPrint ) + /* + nFinish := nI + + nL := nLeft + IF lParagraph + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + ENDIF + + IF nJustify == 3 // right + nL += nLength - nLineLen + ELSEIF nJustify == 2 // center + nL += ( nLength - nLineLen ) / 2 + ENDIF + + ++nLines + IF lPrint + nRow := pdfNewLine( 1 ) + ENDIF + nB := nSpace + IF nJustify == 4 + nB := ( nLength - nLineLen + ( nFinish - nStart ) * nSpace ) / ( nFinish - 1 - nStart ) + ENDIF + for nJ := nStart to nFinish + cToken := token( cString, cDelim, nJ ) + IF lPrint + pdfAtSay( cToken, pdfR2M( nRow + aReportStyle[ aReport[ REPORTSTYLE ] ][ 6 ] ), nL, "M" ) + ENDIF + nL += pdfLen ( cToken ) + nB + next + nStart := nFinish + 1 + + lParagraph := .f. + + nLineLen := 0.00 + nLineLen += nSpace * nNew + */ + ++nI + + IF nCRLF > 1 + nLines += nCRLF - 1 + ENDIF + IF lPrint + nRow := pdfNewLine( nCRLF - 1 ) + ENDIF + + ELSE + nLineLen += nSpace + nTokenLen + ++nI + ENDIF + enddo + +return nLines + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +static function pdfTextPrint( nI, nLeft, lParagraph, nJustify, nSpace, nNew, nLength, nLineLen, nLines, nStart, cString, cDelim, cColor, lPrint )/* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/ +local nFinish, nL, nB, nJ, cToken, nRow + + nFinish := nI + + nL := nLeft + IF lParagraph + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + ENDIF + + IF nJustify == 3 // right + nL += nLength - nLineLen + ELSEIF nJustify == 2 // center + nL += ( nLength - nLineLen ) / 2 + ENDIF + + ++nLines + IF lPrint + nRow := pdfNewLine( 1 ) + ENDIF + nB := nSpace + IF nJustify == 4 + nB := ( nLength - nLineLen + ( nFinish - nStart ) * nSpace ) / ( nFinish - nStart ) + ENDIF + for nJ := nStart to nFinish + cToken := token( cString, cDelim, nJ ) + IF lPrint + // version 0.02 + pdfAtSay( cColor + cToken, pdfR2M( nRow + aReport[ PDFTOP ] ), nL, "M" ) + ENDIF + nL += pdfLen ( cToken ) + nB + next + + nStart := nFinish + 1 + + lParagraph := .f. + + nLineLen := 0.00 + nLineLen += nSpace * nNew + +return nil + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfTextNextPara( cString, cDelim, nI ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +local nAt, cAt, nCRLF, nNew, nRat, nRet := 0 + // check if next spaces paragraph(s) + nAt := attoken( cString, cDelim, nI ) + len( token( cString, cDelim, nI ) ) + cAt := substr( cString, nAt, attoken( cString, cDelim, nI + 1 ) - nAt ) + nCRLF := numat( chr(13) + chr(10), cAt ) + nRat := rat( chr(13) + chr(10), cAt ) + nNew := len( cAt ) - nRat - IIF( nRat > 0, 1, 0 ) + IF nCRLF > 1 .or. ( nCRLF == 1 .and. nNew > 0 ) + nRet := nCRLF + ENDIF +return nRet + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +function pdfUnderLine( cString ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return cString + chr(254) + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function pdfX2M( n ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +return n * 25.4 / 72 + /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ +static function TimeAsAMPM( cTime ) /* +ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ */ + IF VAL(cTime) < 12 + cTime += " am" + ELSEIF VAL(cTime) = 12 + cTime += " pm" + ELSE + cTime := STR(VAL(cTime) - 12, 2) + SUBSTR(cTime, 3) + " pm" + ENDIF + cTime := left( cTime, 5 ) + substr( cTime, 10 ) +return cTime + +function pdfOpenHeader( cFile ) +local nErrorCode := 0, nAt +DEFAULT cFile to "" + IF !empty( cFile ) + cFile := alltrim( cFile ) + IF len( cFile ) > 12 .or. ; + at( ' ', cFile ) > 0 .or. ; + ( at( ' ', cFile ) == 0 .and. len( cFile ) > 8 ) .or. ; + ( ( nAt := at( '.', cFile )) > 0 .and. len( substr( cFile, nAt + 1 )) > 3 ) + SWPRUNCMD( "copy " + cFile + " temp.tmp > nul", 0, "", "") + cFile := "temp.tmp" + ENDIF + //aReport[ HEADER ] := FT_RestArr( cFile, @nErrorCode ) + aReport[ HEADER ] := File2Array( cFile ) + ELSE + aReport[ HEADER ] := {} + ENDIF + aReport[ MARGINS ] := .t. +return nil + +function pdfEditOnHeader() + aReport[ HEADEREDIT ] := .t. + aReport[ MARGINS ] := .t. +return nil + +function pdfEditOffHeader() + aReport[ HEADEREDIT ] := .f. + aReport[ MARGINS ] := .t. +return nil + +function pdfCloseHeader() + aReport[ HEADER ] := {} + aReport[ MARGINS ] := .f. +return nil + +function pdfDeleteHeader( cId ) +local nRet := -1, nId + cId := upper( cId ) + nId := ascan( aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + nRet := len( aReport[ HEADER ] ) - 1 + aDel( aReport[ HEADER ], nId ) + aSize( aReport[ HEADER ], nRet ) + aReport[ MARGINS ] := .t. + ENDIF +return nRet + +function pdfEnableHeader( cId ) +local nId + cId := upper( cId ) + nId := ascan( aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + aReport[ HEADER ][ nId ][ 1 ] := .t. + aReport[ MARGINS ] := .t. + ENDIF +return nil + +function pdfDisableHeader( cId ) +local nId + cId := upper( cId ) + nId := ascan( aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + aReport[ HEADER ][ nId ][ 1 ] := .f. + aReport[ MARGINS ] := .t. + ENDIF +return nil + +function pdfSaveHeader( cFile ) +local nErrorCode := 0 + //FT_SaveArr( aReport[ HEADER ], 'temp.tmp', @nErrorCode ) + Array2File( 'temp.tmp', aReport[ HEADER ] ) + SWPRUNCMD( "copy temp.tmp " + cFile + " > nul", 0, "", "") +return nil + +function pdfHeader( cFunction, cId, arr ) +local nId, nI, nLen, nIdLen + nId := 0 + IF !empty( cId ) + cId := upper( cId ) + nId := ascan( aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + ENDIF + IF nId == 0 + nLen := len( aReport[ HEADER ] ) + IF empty( cId ) + cId := cFunction + nIdLen := len( cId ) + for nI := 1 to nLen + IF aReport[ HEADER ][ nI ][ 2 ] == cId + IF val( substr( aReport[ HEADER ][ nI ][ 3 ], nIdLen + 1 ) ) > nId + nId := val( substr( aReport[ HEADER ][ nI ][ 3 ], nIdLen + 1 ) ) + ENDIF + ENDIF + next + ++nId + cId += ltrim(str(nId)) + ENDIF + aadd( aReport[ HEADER ], { .t., cFunction, cId } ) + ++nLen + for nI := 1 to len( arr ) + aadd( aReport[ HEADER ][ nLen ], arr[ nI ] ) + next + ELSE + aSize( aReport[ HEADER ][ nId ], 3 ) + for nI := 1 to len( arr ) + aadd( aReport[ HEADER ][ nId ], arr[ nI ] ) + next + ENDIF +return cId + +function pdfDrawHeader() +local nI, _nFont, _nSize, nLen := len( aReport[ HEADER ] ) + + IF nLen > 0 + + // save font + _nFont := aReport[ FONTNAME ] + _nSize := aReport[ FONTSIZE ] + + for nI := 1 to nLen + IF aReport[ HEADER ][ nI ][ 1 ] // enabled + do case + case aReport[ HEADER ][ nI ][ 2 ] == "PDFATSAY" + pdfAtSay( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 7 ], aReport[ HEADER ][ nI ][ 8 ], aReport[ HEADER ][ nI ][ 3 ] ) + + case aReport[ HEADER ][ nI ][ 2 ] == "PDFCENTER" + pdfCenter( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 7 ], aReport[ HEADER ][ nI ][ 8 ], aReport[ HEADER ][ nI ][ 3 ] ) + + case aReport[ HEADER ][ nI ][ 2 ] == "PDFRJUST" + pdfRJust( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 7 ], aReport[ HEADER ][ nI ][ 8 ], aReport[ HEADER ][ nI ][ 3 ] ) + + case aReport[ HEADER ][ nI ][ 2 ] == "PDFBOX" + pdfBox( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 7 ], aReport[ HEADER ][ nI ][ 8 ], aReport[ HEADER ][ nI ][ 9 ], aReport[ HEADER ][ nI ][ 10 ], aReport[ HEADER ][ nI ][ 3 ] ) + + case aReport[ HEADER ][ nI ][ 2 ] == "PDFSETFONT" + pdfSetFont( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 3 ] ) + + case aReport[ HEADER ][ nI ][ 2 ] == "PDFIMAGE" + pdfImage( aReport[ HEADER ][ nI ][ 4 ], aReport[ HEADER ][ nI ][ 5 ], aReport[ HEADER ][ nI ][ 6 ], aReport[ HEADER ][ nI ][ 7 ], aReport[ HEADER ][ nI ][ 8 ], aReport[ HEADER ][ nI ][ 9 ], aReport[ HEADER ][ nI ][ 3 ] ) + + endcase + ENDIF + next + aReport[ FONTNAME ] := _nFont + aReport[ FONTSIZE ] := _nSize + + IF aReport[ MARGINS ] + pdfMargins() + ENDIF + + ELSE + IF aReport[ MARGINS ] + aReport[ PDFTOP ] := 1 // top + aReport[ PDFLEFT ] := 10 // left & right + aReport[ PDFBOTTOM ] := aReport[ PAGEY ] / 72 * aReport[ LPI ] - 1 // bottom, default "LETTER", "P", 6 + + aReport[ MARGINS ] := .f. + ENDIF + ENDIF +return nil + +function pdfMargins( nTop, nLeft, nBottom ) +local nI, nLen := len( aReport[ HEADER ] ), nTemp, aTemp, nHeight + + for nI := 1 to nLen + IF aReport[ HEADER ][ nI ][ 1 ] // enabled + + IF aReport[ HEADER ][ nI ][ 2 ] == "PDFSETFONT" + + ELSEIF aReport[ HEADER ][ nI ][ 2 ] == "PDFIMAGE" + IF aReport[ HEADER ][ nI ][ 8 ] == 0 // picture in header, first at all, not at any page yet + aTemp := pdfImageInfo( aReport[ HEADER ][ nI ][ 4 ] ) + nHeight := aTemp[ IMAGE_HEIGHT ] / aTemp[ IMAGE_YRES ] * 25.4 + IF aReport[ HEADER ][ nI ][ 7 ] == "D" + nHeight := pdfM2X( nHeight ) + ENDIF + ELSE + nHeight := aReport[ HEADER ][ nI ][ 8 ] + ENDIF + + IF aReport[ HEADER ][ nI ][ 7 ] == "M" + + nTemp := aReport[ PAGEY ] / 72 * 25.4 / 2 + + IF aReport[ HEADER ][ nI ][ 5 ] < nTemp + nTemp := ( aReport[ HEADER ][ nI ][ 5 ] + nHeight ) * aReport[ LPI ] / 25.4 // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ELSE + nTemp := aReport[ HEADER ][ nI ][ 5 ] * aReport[ LPI ] / 25.4 // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ELSEIF aReport[ HEADER ][ nI ][ 7 ] == "D" + nTemp := aReport[ PAGEY ] / 2 + + IF aReport[ HEADER ][ nI ][ 5 ] < nTemp + nTemp := ( aReport[ HEADER ][ nI ][ 5 ] + nHeight ) * aReport[ LPI ] / 72 // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ELSE + nTemp := aReport[ HEADER ][ nI ][ 5 ] * aReport[ LPI ] / 72 // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ENDIF + + ENDIF + + ELSEIF aReport[ HEADER ][ nI ][ 2 ] == "PDFBOX" + + IF aReport[ HEADER ][ nI ][ 10 ] == "M" + + nTemp := aReport[ PAGEY ] / 72 * 25.4 / 2 + + IF aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] < nTemp + nTemp := aReport[ HEADER ][ nI ][ 6 ] * aReport[ LPI ] / 25.4 // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ELSEIF aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] > nTemp + + nTemp := ( aReport[ HEADER ][ nI ][ 4 ] + aReport[ HEADER ][ nI ][ 8 ] ) * aReport[ LPI ] / 25.4 // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + + nTemp := ( aReport[ HEADER ][ nI ][ 6 ] - aReport[ HEADER ][ nI ][ 8 ] ) * aReport[ LPI ] / 25.4 // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ELSEIF aReport[ HEADER ][ nI ][ 4 ] > nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] > nTemp + nTemp := aReport[ HEADER ][ nI ][ 4 ] * aReport[ LPI ] / 25.4 // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ELSEIF aReport[ HEADER ][ nI ][ 10 ] == "D" + nTemp := aReport[ PAGEY ] / 2 + + IF aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] < nTemp + nTemp := aReport[ HEADER ][ nI ][ 6 ] / aReport[ LPI ] // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ELSEIF aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] > nTemp + + nTemp := ( aReport[ HEADER ][ nI ][ 4 ] + aReport[ HEADER ][ nI ][ 8 ] ) / aReport[ LPI ] // top + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + + nTemp := ( aReport[ HEADER ][ nI ][ 6 ] - aReport[ HEADER ][ nI ][ 8 ] ) / aReport[ LPI ] // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ELSEIF aReport[ HEADER ][ nI ][ 4 ] > nTemp .and. ; + aReport[ HEADER ][ nI ][ 6 ] > nTemp + nTemp := aReport[ HEADER ][ nI ][ 4 ] / aReport[ LPI ] // top + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ENDIF + + ELSE + IF aReport[ HEADER ][ nI ][ 7 ] == "R" + nTemp := aReport[ HEADER ][ nI ][ 5 ] // top + IF aReport[ HEADER ][ nI ][ 5 ] > aReport[ PAGEY ] / 72 * aReport[ LPI ] / 2 + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ENDIF + ELSEIF aReport[ HEADER ][ nI ][ 7 ] == "M" + nTemp := aReport[ HEADER ][ nI ][ 5 ] * aReport[ LPI ] / 25.4 // top + IF aReport[ HEADER ][ nI ][ 5 ] > aReport[ PAGEY ] / 72 * 25.4 / 2 + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ENDIF + ELSEIF aReport[ HEADER ][ nI ][ 7 ] == "D" + nTemp := aReport[ HEADER ][ nI ][ 5 ] / aReport[ LPI ] // top + IF aReport[ HEADER ][ nI ][ 5 ] > aReport[ PAGEY ] / 2 + IF nTemp < aReport[ PDFBOTTOM ] + aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > aReport[ PDFTOP ] + aReport[ PDFTOP ] := nTemp + ENDIF + ENDIF + ENDIF + ENDIF + ENDIF + next + + IF nTop <> NIL + aReport[ PDFTOP ] := nTop + ENDIF + IF nLeft <> NIL + aReport[ PDFLEFT ] := nLeft + ENDIF + IF nBottom <> NIL + aReport[ PDFBOTTOM ] := nBottom + ENDIF + + aReport[ MARGINS ] := .f. + +return nil + +/* + aReportStyle := { ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 3 , 64.0 , "P6", 60, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 6 , 85.35, "P8", 78, 10 }, ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 2.9, 48.9 , "L6", 45, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 5.85, 65.2 , "L8", 58, 10 }, ; + { 2.475, 4.0, 4.9, 6.4, 7.5, 2.9, 82.0 , "P6", 78, 10 }, ; + { 3.3 , 5.4, 6.5, 8.6, 10.0, 6 , 109.35 , "P8", 102, 10 } ; + } +*/ +function pdfCreateHeader( _file, _size, _orient, _lpi, _width ) +local ; + aReportStyle := { ; + { 1, 2, 3, 4, 5, 6 }, ; //"Default" + { 2.475, 4.0, 4.9, 6.4, 7.5, 64.0 }, ; //"P6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 85.35 }, ; //"P8" + { 2.475, 4.0, 4.9, 6.4, 7.5, 48.9 }, ; //"L6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 65.2 }, ; //"L8" + { 2.475, 4.0, 4.9, 6.4, 7.5, 82.0 }, ; //"P6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 109.35 } ; //"P8" + } +local nStyle := 1, nAdd := 0.00 + +DEFAULT _size to aReport[ PAGESIZE ] +DEFAULT _orient to aReport[ PAGEORIENT ] +DEFAULT _lpi to aReport[ LPI ] +DEFAULT _width to 200 + + IF _size == "LETTER" + IF _orient == "P" + IF _lpi == 6 + nStyle := 2 + ELSEIF _lpi == 8 + nStyle := 3 + ENDIF + ELSEIF _orient == "L" + IF _lpi == 6 + nStyle := 4 + ELSEIF _lpi == 8 + nStyle := 5 + ENDIF + ENDIF + ELSEIF _size == "LEGAL" + IF _orient == "P" + IF _lpi == 6 + nStyle := 6 + ELSEIF _lpi == 8 + nStyle := 7 + ENDIF + ELSEIF _orient == "L" + IF _lpi == 6 + nStyle := 4 + ELSEIF _lpi == 8 + nStyle := 5 + ENDIF + ENDIF + ENDIF + + pdfEditOnHeader() + + IF _size == "LEGAL" + nAdd := 76.2 + ENDIF + + IF _orient == "P" + pdfBox( 5.0, 5.0, 274.0 + nAdd, 210.0, 1.0 ) + pdfBox( 6.5, 6.5, 272.5 + nAdd, 208.5, 0.5 ) + + pdfBox( 11.5, 9.5, 22.0 , 205.5, 0.5, 5 ) + pdfBox( 23.0, 9.5, 33.5 , 205.5, 0.5, 5 ) + pdfBox( 34.5, 9.5, 267.5 + nAdd, 205.5, 0.5 ) + + ELSE + pdfBox( 5.0, 5.0, 210.0, 274.0 + nAdd, 1.0 ) + pdfBox( 6.5, 6.5, 208.5, 272.5 + nAdd, 0.5 ) + + pdfBox( 11.5, 9.5, 22.0, 269.5 + nAdd, 0.5, 5 ) + pdfBox( 23.0, 9.5, 33.5, 269.5 + nAdd, 0.5, 5 ) + pdfBox( 34.5, 9.5, 203.5, 269.5 + nAdd, 0.5 ) + ENDIF + + pdfSetFont("Helvetica", BOLD, 10) // 0.04 + pdfAtSay( "Test Line 1", aReportStyle[ nStyle ][ 1 ], 1, "R", .t. ) + + pdfSetFont("Times", BOLD, 18) + pdfCenter( "Test Line 2", aReportStyle[ nStyle ][ 2 ],,"R", .t. ) + + pdfSetFont("Times", BOLD, 12) + pdfCenter( "Test Line 3", aReportStyle[ nStyle ][ 3 ],,"R", .t. ) + + pdfSetFont("Helvetica", BOLD, 10) // 0.04 + pdfAtSay( "Test Line 4", aReportStyle[ nStyle ][ 4 ], 1, "R", .t. ) + + pdfSetFont("Helvetica", BOLD, 10) // 0.04 + pdfAtSay( "Test Line 5", aReportStyle[ nStyle ][ 5 ], 1, "R", .t. ) + + pdfAtSay( dtoc( date()) + " " + TimeAsAMPM( time() ), aReportStyle[ nStyle ][ 6 ], 1, "R", .t. ) + pdfRJust( "Page: #pagenumber#", aReportStyle[ nStyle ][ 6 ], aReport[ REPORTWIDTH ], "R", .t. ) + + pdfEditOffHeader() + pdfSaveHeader( _file ) + +return nil + +function pdfImageInfo( cFile ) +local cTemp := upper(substr( cFile, rat('.', cFile) + 1 )), aTemp := {} + do case + case cTemp == "TIF" + aTemp := pdfTIFFInfo( cFile ) + case cTemp == "JPG" + aTemp := pdfJPEGInfo( cFile ) + endcase +return aTemp + +function pdfTIFFInfo( cFile ) +local c40 := chr(0)+chr(0)+chr(0)+chr(0) +local aType := {"BYTE","ASCII","SHORT","LONG","RATIONAL","SBYTE","UNDEFINED","SSHORT","SLONG","SRATIONAL","FLOAT","DOUBLE"} +local aCount := { 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 } +local nTemp, nHandle, cValues, c2, nFieldType, nCount, nPos, nTag, nValues +local nOffset, cTemp, cIFDNext, nIFD, nFields, cTag, nPages, nn + +local nWidth := 0, nHeight := 0, nBits := 0, nFrom := 0, nLength := 0, xRes := 0, yRes := 0, aTemp := {} + + nHandle := fopen( cFile ) + + c2 := ' ' + fread( nHandle, @c2, 2 ) +/* +if c2 == 'II' .or. c2 == 'MM' +else + alert("Not II or MM") +endif +*/ + fread( nHandle, @c2, 2 ) +/* +if c2 <> '*' + chr(0) + alert("Not *") +endif +*/ + cIFDNext := ' ' + fread( nHandle, @cIFDNext, 4 ) + + cTemp := space(12) + nPages := 0 + + while cIFDNext <> c40 //read IFD's + + nIFD := bin2l( cIFDNext ) + + fseek( nHandle, nIFD ) + //?'*** IFD ' + ltrim(str( ++nPages )) + + fread( nHandle, @c2, 2 ) + nFields := bin2i( c2 ) + + for nn := 1 to nFields + fread( nHandle, @cTemp, 12 ) + + nTag := bin2w( substr( cTemp, 1, 2 ) ) + nFieldType := bin2w(substr( cTemp, 3, 2 )) + /* + 1 = BYTE 8-bit unsigned integer. + 2 = ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte + must be NUL (binary zero). + 3 = SHORT 16-bit (2-byte) unsigned integer. + 4 = LONG 32-bit (4-byte) unsigned integer. + 5 = RATIONAL Two LONGs: the first represents the numerator of a + fraction; the second, the denominator. + + In TIFF 6.0, some new field types have been defined: + + 6 = SBYTE An 8-bit signed (twos-complement) integer. + 7 = UNDEFINED An 8-bit byte that may contain anything, depending on + the definition of the field. + 8 = SSHORT A 16-bit (2-byte) signed (twos-complement) integer. + 9 = SLONG A 32-bit (4-byte) signed (twos-complement) integer. + 10 = SRATIONAL Two SLONG’s: the first represents the numerator of a + fraction, the second the denominator. + 11 = FLOAT Single precision (4-byte) IEEE format. + 12 = DOUBLE Double precision (8-byte) IEEE format. + */ + nCount := bin2l(substr( cTemp, 5, 4 )) + nOffset := bin2l(substr( cTemp, 9, 4 )) + + IF nCount > 1 .or. nFieldType == RATIONAL .or. nFieldType == SRATIONAL + nPos := filepos( nHandle ) + fseek( nHandle, nOffset) + + nValues := nCount * aCount[ nFieldType ] + cValues := space( nValues ) + fread( nHandle, @cValues, nValues ) + fseek( nHandle, nPos ) + ELSE + cValues := substr( cTemp, 9, 4 ) + ENDIF + + IF nFieldType == ASCII + --nCount + ENDIF + //?'Tag' + //??' ' + padr( nTag, 10 ) + cTag := '' + do case + case nTag == 256 + /* + ImageWidth + Tag = 256 (100.H) + Type = SHORT or LONG + The number of columns in the image, i.e., the number of pixels per scanline. + */ + //??'ImageWidth' + cTag := 'ImageWidth' +/* + IF nFieldType <> SHORT .and. nFieldType <> LONG + alert('Wrong Type for ImageWidth') + ENDIF +*/ + IF nFieldType == SHORT + nWidth := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nWidth := bin2l(substr( cValues, 1, 4 )) + ENDIF + + case nTag == 257 + /* + ImageLength + Tag = 257 (101.H) + Type = SHORT or LONG + The number of rows (sometimes described as scanlines) in the image. + */ + //??'ImageLength' + cTag := 'ImageLength' +/* + IF nFieldType <> SHORT .and. nFieldType <> LONG + alert('Wrong Type for ImageLength') + ENDIF +*/ + IF nFieldType == SHORT + nHeight := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nHeight := bin2l(substr( cValues, 1, 4 )) + ENDIF + + case nTag == 258 + /* + BitsPerSample + Tag = 258 (102.H) + Type = SHORT + The number of bits per component. + Allowable values for Baseline TIFF grayscale images are 4 and 8, allowing either + 16 or 256 distinct shades of gray. + */ + //??'BitsPerSample' + cTag := 'BitsPerSample' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ELSE + //alert('Wrong Type for BitsPerSample') + ENDIF + nBits := nTemp + //IF nTemp <> 4 .and. nTemp <> 8 + // alert('Wrong Value for BitsPerSample') + //ENDIF + case nTag == 259 + /* + Compression + Tag = 259 (103.H) + Type = SHORT + Values: + 1 = No compression, but pack data into bytes as tightly as possible, leaving no unused + bits (except at the end of a row). The component values are stored as an array of + type BYTE. Each scan line (row) is padded to the next BYTE boundary. + 2 = CCITT Group 3 1-Dimensional Modified Huffman run length encoding. See + Section 10 for a description of Modified Huffman Compression. + 32773 = PackBits compression, a simple byte-oriented run length scheme. See the + PackBits section for details. + Data compression applies only to raster image data. All other TIFF fields are + unaffected. + Baseline TIFF readers must handle all three compression schemes. + */ + //??'Compression' + cTag := 'Compression' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ELSE + //alert('Wrong Type for Compression') + ENDIF + //IF nTemp <> 1 .and. nTemp <> 2 .and. nTemp <> 32773 + // alert('Wrong Value for Compression') + //ENDIF + case nTag == 262 + /* + PhotometricInterpretation + Tag = 262 (106.H) + Type = SHORT + Values: + 0 = WhiteIsZero. For bilevel and grayscale images: 0 is imaged as white. The maxi-mum + value is imaged as black. This is the normal value for Compression=2. + 1 = BlackIsZero. For bilevel and grayscale images: 0 is imaged as black. The maxi-mum + value is imaged as white. If this value is specified for Compression=2, the + image should display and print reversed. + */ + //??'PhotometricInterpretation' + cTag := 'PhotometricInterpretation' + nTemp := -1 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ELSE + //alert('Wrong Type for PhotometricInterpretation') + ENDIF + IF nTemp <> 0 .and. nTemp <> 1 .and. nTemp <> 2 .and. nTemp <> 3 + //alert('Wrong Value for PhotometricInterpretation') + ENDIF + case nTag == 264 + /* + CellWidth + The width of the dithering or halftoning matrix used to create a dithered or + halftoned bilevel file.Tag = 264 (108.H) + Type = SHORT + N = 1 + No default. See also Threshholding. + */ + //??'CellWidth' + cTag := 'CellWidth' + IF nFieldType <> SHORT + //alert('Wrong Type for CellWidth') + ENDIF + case nTag == 265 + /* + CellLength + The length of the dithering or halftoning matrix used to create a dithered or + halftoned bilevel file. + Tag = 265 (109.H) + Type = SHORT + N = 1 + This field should only be present if Threshholding = 2 + No default. See also Threshholding. + */ + //??'CellLength' + cTag := 'CellLength' + IF nFieldType <> SHORT + //alert('Wrong Type for CellLength') + ENDIF + case nTag == 266 + /* + FillOrder + The logical order of bits within a byte. + Tag = 266 (10A.H) + Type = SHORT + N = 1 + */ + //??'FillOrder' + cTag := 'FillOrder' + IF nFieldType <> SHORT + //alert('Wrong Type for FillOrder') + ENDIF + case nTag == 273 + /* + StripOffsets + Tag = 273 (111.H) + Type = SHORT or LONG + For each strip, the byte offset of that strip. + */ + //??'StripOffsets' + cTag := 'StripOffsets' + IF nFieldType <> SHORT .and. nFieldType <> LONG + //alert('Wrong Type for StripOffsets') + ENDIF + + IF nFieldType == SHORT + nFrom := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nFrom := bin2l(substr( cValues, 1, 4 )) + ENDIF + + case nTag == 277 + /* + SamplesPerPixel + Tag = 277 (115.H) + Type = SHORT + The number of components per pixel. This number is 3 for RGB images, unless + extra samples are present. See the ExtraSamples field for further information. + */ + //??'SamplesPerPixel' + cTag := 'SamplesPerPixel' + IF nFieldType <> SHORT + //alert('Wrong Type for SamplesPerPixel') + ENDIF + case nTag == 278 + /* + RowsPerStrip + Tag = 278 (116.H) + Type = SHORT or LONG + The number of rows in each strip (except possibly the last strip.) + For example, if ImageLength is 24, and RowsPerStrip is 10, then there are 3 + strips, with 10 rows in the first strip, 10 rows in the second strip, and 4 rows in the + third strip. (The data in the last strip is not padded with 6 extra rows of dummy + data.) + */ + //??'RowsPerStrip' + cTag := 'RowsPerStrip' + IF nFieldType <> SHORT .and. nFieldType <> LONG + //alert('Wrong Type for RowsPerStrip') + ENDIF + case nTag == 279 + /* + StripByteCounts + Tag = 279 (117.H) + Type = SHORT or LONG + For each strip, the number of bytes in that strip after any compression. + */ + //??'StripByteCounts' + cTag := 'StripByteCounts' + IF nFieldType <> SHORT .and. nFieldType <> LONG + //alert('Wrong Type for StripByteCounts') + ENDIF + + IF nFieldType == SHORT + nLength := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nLength := bin2l(substr( cValues, 1, 4 )) + ENDIF + + nLength *= nCount // Count all strips !!! + + case nTag == 282 + /* + XResolution + Tag = 282 (11A.H) + Type = RATIONAL + The number of pixels per ResolutionUnit in the ImageWidth (typically, horizontal + - see Orientation) direction. + */ + //??'XResolution' + cTag := 'XResolution' + IF nFieldType <> RATIONAL + //alert('Wrong Type for XResolution') + ENDIF + xRes := bin2l(substr( cValues, 1, 4 )) + case nTag == 283 + /* + YResolution + Tag = 283 (11B.H) + Type = RATIONAL + The number of pixels per ResolutionUnit in the ImageLength (typically, vertical) + direction. + */ + //??'YResolution' + cTag := 'YResolution' + IF nFieldType <> RATIONAL + //alert('Wrong Type for YResolution') + ENDIF + yRes := bin2l(substr( cValues, 1, 4 )) + case nTag == 284 + //??'PlanarConfiguration' + cTag := 'PlanarConfiguration' + IF nFieldType <> SHORT + //alert('Wrong Type for PlanarConfiguration') + ENDIF + case nTag == 288 + /* + FreeOffsets + For each string of contiguous unused bytes in a TIFF file, the byte offset of the + string. + Tag = 288 (120.H) + Type = LONG + Not recommended for general interchange. + See also FreeByteCounts. + */ + //??'FreeOffsets' + cTag := 'FreeOffsets' + IF nFieldType <> LONG + //alert('Wrong Type for FreeOffsets') + ENDIF + case nTag == 289 + /* + FreeByteCounts + For each string of contiguous unused bytes in a TIFF file, the number of bytes in + the string. + Tag = 289 (121.H) + Type = LONG + Not recommended for general interchange. + See also FreeOffsets. + */ + //??'FreeByteCounts' + cTag := 'FreeByteCounts' + IF nFieldType <> LONG + //alert('Wrong Type for FreeByteCounts') + ENDIF + case nTag == 296 + /* + ResolutionUnit + Tag = 296 (128.H) + Type = SHORT + Values: + 1 = No absolute unit of measurement. Used for images that may have a non-square + aspect ratio but no meaningful absolute dimensions. + 2 = Inch. + 3 = Centimeter. + Default = 2 (inch). + */ + //??'ResolutionUnit' + cTag := 'ResolutionUnit' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ELSE + //alert('Wrong Type for ResolutionUnit') + ENDIF + IF nTemp <> 1 .and. nTemp <> 2 .and. nTemp <> 3 + //alert('Wrong Value for ResolutionUnit') + ENDIF + case nTag == 305 + //??'Software' + cTag := 'Software' + IF nFieldType <> ASCII + //alert('Wrong Type for Software') + ENDIF + case nTag == 306 + /* + DateTime + Date and time of image creation. + Tag = 306 (132.H) + Type = ASCII + N = 2 0 + The format is: YYYY:MM:DD HH:MM:SS, with hours like those on a 24-hour + clock, and one space character between the date and the time. The length of the + string, including the terminating NUL, is 20 bytes. + */ + //??'DateTime' + cTag := 'DateTime' + IF nFieldType <> ASCII + //alert('Wrong Type for DateTime') + ENDIF + case nTag == 315 + /* + Artist + Person who created the image. + Tag = 315 (13B.H) + Type = ASCII + Note: some older TIFF files used this tag for storing Copyright information. + */ + //??'Artist' + cTag := 'Artist' + IF nFieldType <> ASCII + //alert('Wrong Type for Artist') + ENDIF + case nTag == 320 + /* + ColorMap + Tag = 320 (140.H) + Type = SHORT + N = 3 * (2**BitsPerSample) + This field defines a Red-Green-Blue color map (often called a lookup table) for + palette color images. In a palette-color image, a pixel value is used to index into an + RGB-lookup table. For example, a palette-color pixel having a value of 0 would + be displayed according to the 0th Red, Green, Blue triplet. + In a TIFF ColorMap, all the Red values come first, followed by the Green values, + then the Blue values. In the ColorMap, black is represented by 0,0,0 and white is + represented by 65535, 65535, 65535. + */ + //??'ColorMap' + cTag := 'ColorMap' + IF nFieldType <> SHORT + //alert('Wrong Type for ColorMap') + ENDIF + case nTag == 338 + /* + ExtraSamples + Description of extra components. + Tag = 338 (152.H) + Type = SHORT + N = m + */ + //??'ExtraSamples' + cTag := 'ExtraSamples' + IF nFieldType <> SHORT + //alert('Wrong Type for ExtraSamples') + ENDIF + case nTag == 33432 + /* + Copyright + Copyright notice. + Tag = 33432 (8298.H) + Type = ASCII + Copyright notice of the person or organization that claims the copyright to the + image. The complete copyright statement should be listed in this field including + any dates and statements of claims. For example, “Copyright, John Smith, 19xx. + All rights reserved. + */ + //??'Copyright' + cTag := 'Copyright' + IF nFieldType <> ASCII + //alert('Wrong Type for Copyright') + ENDIF + otherwise + //??'Unknown' + cTag := 'Unknown' + endcase + /* + ??padr( cTag, 30 ) + ??' type ' + padr(aType[ nFieldType ], 10) + ' count ' + ltrim(str(nCount)) + ' <' + do case + case nFieldType == BYTE + for nI := 1 to nCount + ??' ' + ltrim(str(asc( substr( cValues, nI, 1 )))) + next + case nFieldType == ASCII + ??' ' + for nI := 1 to nCount + ??substr( cValues, nI, 1 ) + next + case nFieldType == SHORT + for nI := 1 to nCount + ??' ' + ltrim(str(bin2w(substr( cValues, ( nI - 1 ) * 2 + 1, 2 )))) + next + case nFieldType == LONG + for nI := 1 to nCount + ??' ' + ltrim(str(bin2l(substr( cValues, ( nI - 1 ) * 4 + 1, 4 )))) + next + case nFieldType == RATIONAL + for nI := 1 to nCount + ??' ' + ltrim(str(bin2l(substr( cValues, ( nI - 1 ) * 8 + 1, 4 )))) + '/' + ltrim(str(bin2l(substr( cValues, nI + 4, 4 )))) + next + case nFieldType == SBYTE + for nI := 1 to nCount + ??' ' + ltrim(str(asc( substr( cValues, nI, 1 )))) + next + case nFieldType == UNDEFINED + for nI := 1 to nCount + ??' ' + substr( cValues, nI, 1 ) + next + case nFieldType == SSHORT + for nI := 1 to nCount + ??' ' + ltrim(str(bin2i(substr( cValues, ( nI - 1 ) * 2 + 1, 2 )))) + next + case nFieldType == SLONG + for nI := 1 to nCount + ??' ' + ltrim(str(bin2l(substr( cValues, ( nI - 1 ) * 4 + 1, 4 )))) + next + case nFieldType == SRATIONAL + for nI := 1 to nCount + ??' ' + ltrim(str(bin2l(substr( cValues, ( nI - 1 ) * 8 + 1, 4 )))) + '/' + ltrim(str(bin2l(substr( cValues, nI + 4, 4 )))) + next + case nFieldType == FLOAT + case nFieldType == DOUBLE + for nI := 1 to nCount + ??' ' + ltrim(str(ctof(substr( cValues, ( nI - 1 ) * 8 + 1, 8 )))) + next + + endcase + ??' >' + */ + next + fread( nHandle, @cIFDNext, 4 ) + enddo + + fclose( nHandle ) + + aadd( aTemp, nWidth ) + aadd( aTemp, nHeight ) + aadd( aTemp, xRes ) + aadd( aTemp, yRes ) + aadd( aTemp, nBits ) + aadd( aTemp, nFrom ) + aadd( aTemp, nLength ) + +return aTemp + +function pdfJPEGInfo( cFile ) +local c255, nAt, nHandle +local nWidth := 0, nHeight := 0, nBits := 8, nFrom := 0, nLength := 0, xRes := 0, yRes := 0, aTemp := {} + + nHandle := fopen( cFile ) + + c255 := space(1024) + fread( nHandle, @c255, 1024 ) + + xRes := asc(substr( c255, 15, 1 )) * 256 + asc(substr( c255, 16, 1 )) + yRes := asc( substr( c255, 17, 1 )) * 256 + asc(substr( c255, 18, 1 )) + + nAt := at( chr(255) + chr(192), c255 ) + 5 + nHeight := asc(substr( c255, nAt, 1 )) * 256 + asc(substr( c255, nAt + 1, 1 )) + nWidth := asc( substr( c255, nAt + 2, 1 )) * 256 + asc(substr( c255, nAt + 3, 1 )) + + fclose( nHandle ) + + nLength := filesize( cFile ) + + aadd( aTemp, nWidth ) + aadd( aTemp, nHeight ) + aadd( aTemp, xRes ) + aadd( aTemp, yRes ) + aadd( aTemp, nBits ) + aadd( aTemp, nFrom ) + aadd( aTemp, nLength ) + +return aTemp + +FUNCTION FilePos( nHandle ) +RETURN ( FSEEK( nHandle, 0, FS_RELATIVE ) ) + +FUNCTION pdfFilePrint( cFile ) +LOCAL cRun := "d:\progra~2\Adobe\Acroba~2.0\Reader\AcroRd32.exe /t " + cFile + " " + chr(34) + "HP LaserJet 5/5M PostScript" + chr(34) + " " + chr(34) + "LPT1" + chr(34) + +IF (!SWPRUNCMD( cRun, 0, "", "")) + alert("Error printing to PDF reader.") + break +ENDIF +//"C:\Program Files\Adobe\Acrobat 4.0\Reader\acrord32.exe" /t "%1" +//"HP LJ4 Legal" "HP Laserjet 4 Plus" "LPT3" +RETURN nil + +/* +function pdfAtSay( cString, nRow, nCol, cUnits, lExact ) +function pdfBold() +function pdfBoldItalic() +function pdfBookAdd( cTitle, nLevel, nPage, nLine ) +function pdfBookClose( ) +function pdfBookCount( nRecno, nCurLevel ) +function pdfBookFirst( nRecno, nCurLevel, nObj ) +function pdfBookLast( nRecno, nCurLevel, nObj ) +function pdfBookNext( nRecno, nCurLevel, nObj ) +function pdfBookOpen( ) +function pdfBookParent( nRecno, nCurLevel, nObj ) +function pdfBookPrev( nRecno, nCurLevel, nObj ) +function pdfBox( x1, y1, x2, y2, nBorder, nShade, cUnits ) +function pdfCenter( cString, nRow, nCol, cUnits, lExact ) +function pdfCheckLine( nRow ) +function pdfClose() +function pdfClosePage() +function pdfGetFontInfo( cParam ) +function pdfItalic() +function pdfLen( cString ) +function pdfM2X( n ) +function pdfM2Y( n ) +function pdfNewPage( _cPageSize, _cPageOrient, _nLpi, _cFontName, _nFontType, _nFontSize ) +function pdfNormal() +function pdfOpen() +function pdfPageSize( _cPageSize ) +function pdfPageOrient( _cPageOrient ) +function pdfR2D( nRow ) +function pdfR2M( nRow ) +function pdfReverse( cString ) +function pdfRJust( cString, nRow, nCol, cUnits, lExact ) +function pdfSetFont( _cFont, _nType, _nSize ) +function pdfSetLPI(_nLpi) +function pdfStringB( cString ) +function pdfUnderLine( cString ) +function TimeAsAMPM( cTime ) +*/ + +FUNCTION Chr_RGB( cChar ) +RETURN str(asc( cChar ) / 255, 4, 2) + +FUNCTION NumToken( cString, cDelimiter ) +RETURN AllToken( cString, cDelimiter ) + +FUNCTION Token( cString, cDelimiter, nPointer ) +RETURN AllToken( cString, cDelimiter, nPointer, 1 ) + +FUNCTION AtToken( cString, cDelimiter, nPointer ) +RETURN AllToken( cString, cDelimiter, nPointer, 2 ) + +FUNCTION AllToken( cString, cDelimiter, nPointer, nAction ) +LOCAL nTokens := 0, nPos := 1, nLen := len( cString ), nStart := 0, cToken := "", cRet +DEFAULT cDelimiter to chr(0)+chr(9)+chr(10)+chr(13)+chr(26)+chr(32)+chr(138)+chr(141) +DEFAULT nAction to 0 + +// nAction == 0 - numtoken +// nAction == 1 - token +// nAction == 2 - attoken + + while nPos <= nLen + if .not. substr( cString, nPos, 1 ) $ cDelimiter + nStart := nPos + while nPos <= nLen .and. .not. substr( cString, nPos, 1 ) $ cDelimiter + ++nPos + enddo + ++nTokens + IF nAction > 0 + IF nPointer == nTokens + IF nAction == 1 + cRet := substr( cString, nStart, nPos - nStart ) + ELSE + cRet := nStart + ENDIF + exit + ENDIF + ENDIF + endif + if substr( cString, nPos, 1 ) $ cDelimiter + while nPos <= nLen .and. substr( cString, nPos, 1 ) $ cDelimiter + ++nPos + enddo + endif + cRet := nTokens + ENDDO +RETURN cRet + +FUNCTION NumAt( cSearch, cString ) + LOCAL n := 0, nAt := 0, nPos := 0 + WHILE ( nAt := at( cSearch, substr( cString, nPos + 1 ) )) > 0 + nPos += nAt + ++n + ENDDO +RETURN n + +FUNCTION FileSize( cFile ) + + LOCAL nLength + LOCAL nHandle + + nHandle := fopen( cFile ) + nLength := FSEEK( nHandle, 0, FS_END ) + fclose( nHandle ) + +RETURN ( nLength ) + +// next 3 function written by Peter Kulek +//modified for compatibility with common.ch by V.K. +//modified DATE processing by V.K. +function Array2File(cFile,aRay,nDepth,hFile) +local nBytes := 0 +local i +nDepth := if(ISNUMBER(nDepth),nDepth,0) +if hFile == NIL + if (hFile := fCreate(cFile,FC_NORMAL)) == -1 + return(nBytes) + endif +endif +nDepth++ +nBytes += WriteData(hFile,aRay) +if ISARRAY(aRay) + for i := 1 to len(aRay) + nBytes += Array2File(cFile,aRay[i],nDepth,hFile) + next +endif +nDepth-- +if nDepth == 0 + fClose(hFile) +endif +return(nBytes) + +static function WriteData(hFile,xData) +local cData := valtype(xData) + if ISCHARACTER(xData) + cData += i2bin(len(xData))+xData + elseif ISNUMBER(xData) + cData += i2bin(len(alltrim(str(xData))) )+alltrim(str(xData)) + elseif ISDATE(xData) + cData += i2bin(8)+dtos(xData) + elseif ISLOGICAL(xData) + cData += i2bin(1)+if(xData,'T','F') + elseif ISARRAY(xData) + cData += i2bin(len(xData)) + else + cData += i2bin(0) // NIL + endif +return( fWrite(hFile,cData,len(cData)) ) + +function File2Array(cFile,nLen,hFile) +LOCAL cData,cType,nDataLen,nBytes +local nDepth := 0 +local aRay := {} +if hFile == NIL + if (hFile:=fOpen(cFile,FO_READ)) == -1 + return(aRay) + endif + cData := space(3) + fRead(hFile,@cData,3) + if left(cData,1) != 'A' + return( aRay) + endif + nLen := bin2i(right(cData,2)) +endif +do while nDepth < nLen + cData := space(3) + nBytes := fRead(hFile,@cData,3) + if nBytes<3 + exit + endif + cType:= padl(cData,1) + nDataLen:= bin2i(right(cData,2)) + if cType != 'A' + cData := space(nDataLen) + nBytes:= fRead(hFile,@cData,nDataLen) + if nBytes [ FROM ] => CLASS [ FROM ] + #command MESSAGE METHOD => METHOD IS + #command CLASS MESSAGE METHOD => CLASS METHOD IS +#endif + +#ifdef __CLP__ // Clipper + #include 'class(y).ch' +#endif + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#include 'hbvpdf.ch' + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +CREATE CLASS tPdf + +#ifndef __HARBOUR__ +EXPORT: +#endif + +VAR aReport + +#ifndef __HARBOUR__ +EXPORT: +#endif + +#ifdef __HARBOUR__ +METHOD Init( cFile, nLen, lOptimize ) CONSTRUCTOR +#else +METHOD Init +#endif + +METHOD AtSay +METHOD Normal +METHOD Bold +METHOD Italic +METHOD UnderLine +METHOD BoldItalic +METHOD BookAdd +METHOD BookClose +METHOD BookOpen +METHOD Box +METHOD Box1 +METHOD Center +METHOD Close +METHOD Image +METHOD Length +METHOD NewLine +METHOD NewPage +METHOD PageSize +METHOD PageOrient +METHOD PageNumber +METHOD Reverse +METHOD RJust +METHOD SetFont +METHOD SetLPI +METHOD StringB +METHOD TextCount +METHOD Text +METHOD OpenHeader +METHOD EditOnHeader +METHOD EditOffHeader +METHOD CloseHeader +METHOD DeleteHeader +METHOD EnableHeader +METHOD DisableHeader +METHOD SaveHeader +METHOD Header +METHOD DrawHeader +METHOD Margins +METHOD CreateHeader +METHOD ImageInfo +METHOD TIFFInfo +METHOD JPEGInfo +METHOD FilePrint +METHOD BookCount +METHOD BookFirst +METHOD BookLast +METHOD BookNext +METHOD BookParent +METHOD BookPrev +METHOD CheckLine +METHOD ClosePage +METHOD GetFontInfo +METHOD M2R +METHOD M2X +METHOD M2Y +METHOD R2D +METHOD R2M +METHOD X2M +METHOD TextPrint +METHOD TextNextPara +METHOD Execute + +ENDCLASS + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Init( cFile, nLen, lOptimize ) +#else +METHOD Init( cFile, nLen, lOptimize ) +#endif + +local cTemp, nI, nJ, n1, n2 := 896, n12 + +DEFAULT nLen TO 200 +DEFAULT lOptimize TO .f. + +::aReport := array( PARAMLEN ) + +::aReport[ FONTNAME ] := 1 +::aReport[ FONTSIZE ] := 10 +::aReport[ LPI ] := 6 +::aReport[ PAGESIZE ] := "LETTER" +::aReport[ PAGEORIENT ] := "P" +::aReport[ PAGEX ] := 8.5 * 72 +::aReport[ PAGEY ] := 11.0 * 72 +::aReport[ REPORTWIDTH ] := nLen // 200 // should be as parameter +::aReport[ REPORTPAGE ] := 0 +::aReport[ REPORTLINE ] := 0 // 5 +::aReport[ FONTNAMEPREV ] := 0 +::aReport[ FONTSIZEPREV ] := 0 +::aReport[ PAGEBUFFER ] := "" +::aReport[ REPORTOBJ ] := 1 //2 +::aReport[ DOCLEN ] := 0 +::aReport[ TYPE1 ] := { "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", ; + "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", ; + "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique" } +::aReport[ MARGINS ] := .t. +::aReport[ HEADEREDIT ] := .f. +::aReport[ NEXTOBJ ] := 0 +::aReport[ PDFTOP ] := 1 // top +::aReport[ PDFLEFT ] := 10 // left & right +::aReport[ PDFBOTTOM ] := ::aReport[ PAGEY ] / 72 * ::aReport[ LPI ] - 1 // bottom, default "LETTER", "P", 6 +::aReport[ HANDLE ] := fcreate( cFile ) +::aReport[ PAGES ] := {} +::aReport[ REFS ] := { 0, 0 } +::aReport[ BOOKMARK ] := {} +::aReport[ HEADER ] := {} +::aReport[ FONTS ] := {} +::aReport[ IMAGES ] := {} +::aReport[ PAGEIMAGES ] := {} +::aReport[ PAGEFONTS ] := {} + +// TOFIX: This external file dependency should be removed. + +cTemp := memoread( "fonts.dat" ) +n1 := len( cTemp ) / ( 2 * n2 ) +::aReport[ FONTWIDTH ] := array( n1, n2 ) + +::aReport[ OPTIMIZE ] := lOptimize +::aReport[ NEXTOBJ ] := ::aReport[ REPORTOBJ ] + 4 + +n12 := 2 * n2 +for nI := 1 to n1 + for nJ := 1 to n2 + ::aReport[ FONTWIDTH ][ nI ][ nJ ] := bin2i( substr( cTemp, ( nI - 1 ) * n12 + ( nJ - 1 ) * 2 + 1, 2 ) ) + next +next + +::aReport[ DOCLEN ] := 0 +cTemp := "%PDF-1.3" + CRLF +::aReport[ DOCLEN ] += len( cTemp ) + +fwrite( ::aReport[ HANDLE ], cTemp ) + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:AtSay( cString, nRow, nCol, cUnits, lExact, cId ) +#else +METHOD AtSay( cString, nRow, nCol, cUnits, lExact, cId ) +#endif + +local _nFont, lReverse, nAt + +DEFAULT nRow TO ::aReport[ REPORTLINE ] +DEFAULT cUnits TO "R" +DEFAULT lExact TO .f. +DEFAULT cId TO "" + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFATSAY", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( ::PageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + lReverse = .f. + IF cUnits == "M" + nRow := ::M2Y( nRow ) + nCol := ::M2X( nCol ) + ELSEIF cUnits == "R" + IF .not. lExact + ::CheckLine( nRow ) + nRow := nRow + ::aReport[ PDFTOP] + ENDIF + nRow := ::R2D( nRow ) + nCol := ::M2X( ::aReport[ PDFLEFT ] ) + ; + nCol * 100.00 / ::aReport[ REPORTWIDTH ] * ; + ( ::aReport[ PAGEX ] - ::M2X( ::aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + ENDIF + IF !empty( cString ) + cString := ::StringB( cString ) + IF right( cString, 1 ) == chr(255) //reverse + cString := left( cString, len( cString ) - 1 ) + ::Box( ::aReport[ PAGEY ] - nRow - ::aReport[ FONTSIZE ] + 2.0 , nCol, ::aReport[ PAGEY ] - nRow + 2.0, nCol + ::M2X( ::length( cString )) + 1,,100, "D") + ::aReport[ PAGEBUFFER ] += " 1 g " + lReverse = .t. + ELSEIF right( cString, 1 ) == chr(254) //underline + cString := left( cString, len( cString ) - 1 ) + ::Box( ::aReport[ PAGEY ] - nRow + 0.5, nCol, ::aReport[ PAGEY ] - nRow + 1, nCol + ::M2X( ::length( cString )) + 1,,100, "D") + ENDIF + + // version 0.01 + IF ( nAt := at( chr(253), cString )) > 0 // some color text inside + ::aReport[ PAGEBUFFER ] += CRLF + ; + Chr_RGB( substr( cString, nAt + 1, 1 )) + " " + ; + Chr_RGB( substr( cString, nAt + 2, 1 )) + " " + ; + Chr_RGB( substr( cString, nAt + 3, 1 )) + " rg " + cString := stuff( cString, nAt, 4, "") + ENDIF + // version 0.01 + + _nFont := ascan( ::aReport[ FONTS ], {|arr| arr[1] == ::aReport[ FONTNAME ]} ) + IF ::aReport[ FONTNAME ] <> ::aReport[ FONTNAMEPREV ] + ::aReport[ FONTNAMEPREV ] := ::aReport[ FONTNAME ] + ::aReport[ PAGEBUFFER ] += CRLF + "BT /Fo" + ltrim(str( _nFont )) + " " + ltrim(transform( ::aReport[ FONTSIZE ], "999.99")) + " Tf " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ELSEIF ::aReport[ FONTSIZE ] <> ::aReport[ FONTSIZEPREV ] + ::aReport[ FONTSIZEPREV ] := ::aReport[ FONTSIZE ] + ::aReport[ PAGEBUFFER ] += CRLF + "BT /Fo" + ltrim(str( _nFont )) + " " + ltrim(transform( ::aReport[ FONTSIZE ], "999.99")) + " Tf " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ELSE + ::aReport[ PAGEBUFFER ] += CRLF + "BT " + ltrim(transform( nCol, "9999.99" )) + " " + ltrim(transform( nRow, "9999.99" )) + " Td (" + cString + ") Tj ET" + ENDIF + IF lReverse + ::aReport[ PAGEBUFFER ] += " 0 g " + ENDIF + ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Normal() +#else +METHOD Normal() +#endif +local cName := ::GetFontInfo( "NAME" ) + + IF cName = "Times" + ::aReport[ FONTNAME ] := 1 + ELSEIF cName = "Helvetica" + ::aReport[ FONTNAME ] := 5 + ELSE + ::aReport[ FONTNAME ] := 9 + ENDIF + aadd( ::aReport[ PAGEFONTS ], ::aReport[ FONTNAME ] ) + IF ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ FONTNAME ] } ) == 0 + aadd( ::aReport[ FONTS ], { ::aReport[ FONTNAME ], ++::aReport[ NEXTOBJ ] } ) + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Italic() +#else +METHOD Italic() +#endif +local cName := ::GetFontInfo( "NAME" ) + + IF cName = "Times" + ::aReport[ FONTNAME ] := 3 + ELSEIF cName = "Helvetica" + ::aReport[ FONTNAME ] := 7 + ELSE + ::aReport[ FONTNAME ] := 11 + ENDIF + aadd( ::aReport[ PAGEFONTS ], ::aReport[ FONTNAME ] ) + IF ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ FONTNAME ] } ) == 0 + aadd( ::aReport[ FONTS ], { ::aReport[ FONTNAME ], ++::aReport[ NEXTOBJ ] } ) + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Bold() +#else +METHOD Bold() +#endif +local cName := ::GetFontInfo( "NAME" ) + + IF cName == "Times" + ::aReport[ FONTNAME ] := 2 + ELSEIF cName == "Helvetica" + ::aReport[ FONTNAME ] := 6 + ELSEIF cName == 'Courier' + ::aReport[ FONTNAME ] := 10 // Courier // 0.04 + ENDIF + + aadd( ::aReport[ PAGEFONTS ], ::aReport[ FONTNAME ] ) + IF ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ FONTNAME ] } ) == 0 + aadd( ::aReport[ FONTS ], { ::aReport[ FONTNAME ], ++::aReport[ NEXTOBJ ] } ) + ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BoldItalic() +#else +METHOD BoldItalic() +#endif +local cName := ::GetFontInfo( "NAME" ) + +IF cName == "Times" + ::aReport[ FONTNAME ] := 4 +ELSEIF cName == "Helvetica" + ::aReport[ FONTNAME ] := 8 +ELSEIF cName == 'Courier' + ::aReport[ FONTNAME ] := 12 // 0.04 +ENDIF + +aadd( ::aReport[ PAGEFONTS ], ::aReport[ FONTNAME ] ) +IF ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ FONTNAME ] } ) == 0 + aadd( ::aReport[ FONTS ], { ::aReport[ FONTNAME ], ++::aReport[ NEXTOBJ ] } ) +ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookAdd( cTitle, nLevel, nPage, nLine ) +#else +METHOD BookAdd( cTitle, nLevel, nPage, nLine ) +#endif + +aadd( ::aReport[ BOOKMARK ], { nLevel, alltrim( cTitle ), 0, 0, 0, 0, 0, 0, nPage, IIF( nLevel == 1, ::aReport[ PAGEY ], ::aReport[ PAGEY ] - nLine * 72 / ::aReport[ LPI ] ) }) + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookClose( ) +#else +METHOD BookClose( ) +#endif + +::aReport[ BOOKMARK ] := nil + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookOpen( ) +#else +METHOD BookOpen( ) +#endif + +::aReport[ BOOKMARK ] := {} + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Box( x1, y1, x2, y2, nBorder, nShade, cUnits, cColor, cId ) +#else +METHOD Box( x1, y1, x2, y2, nBorder, nShade, cUnits, cColor, cId ) +#endif + +local cBoxColor + +DEFAULT nBorder TO 0 +DEFAULT nShade TO 0 +DEFAULT cUnits TO "M" +DEFAULT cColor TO "" + + cBoxColor := "" + IF !empty( cColor ) + cBoxColor := " " + Chr_RGB( substr( cColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cColor, 3, 1 )) + " " + ; + Chr_RGB( substr( cColor, 4, 1 )) + " rg " + IF empty( alltrim( cBoxColor ) ) + cBoxColor := "" + ENDIF + ENDIF + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFBOX", cId, { x1, y1, x2, y2, nBorder, nShade, cUnits } ) + ENDIF + + IF cUnits == "M" + y1 += 0.5 + y2 += 0.5 + + IF nShade > 0 + ::aReport[ PAGEBUFFER ] += CRLF + transform( 1.00 - nShade / 100.00, "9.99") + " g " + cBoxColor + ltrim(str(::M2X( y1 ))) + " " + ltrim(str(::M2Y( x1 ))) + " " + ltrim(str(::M2X( y2 - y1 ))) + " -" + ltrim(str(::M2X( x2 - x1 ))) + " re f 0 g" + ENDIF + + IF nBorder > 0 + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(::M2X( y1 ))) + " " + ltrim(str(::M2Y( x1 ))) + " " + ltrim(str(::M2X( y2 - y1 ))) + " -" + ltrim(str(::M2X( nBorder ))) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(::M2X( y2 - nBorder ))) + " " + ltrim(str(::M2Y( x1 ))) + " " + ltrim(str(::M2X( nBorder ))) + " -" + ltrim(str(::M2X( x2 - x1 ))) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(::M2X( y1 ))) + " " + ltrim(str(::M2Y( x2 - nBorder ))) + " " + ltrim(str(::M2X( y2 - y1 ))) + " -" + ltrim(str(::M2X( nBorder ))) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str(::M2X( y1 ))) + " " + ltrim(str(::M2Y( x1 ))) + " " + ltrim(str(::M2X( nBorder ))) + " -" + ltrim(str(::M2X( x2 - x1 ))) + " re f" + ENDIF + ELSEIF cUnits == "D" // "Dots" + IF nShade > 0 + ::aReport[ PAGEBUFFER ] += CRLF + transform( 1.00 - nShade / 100.00, "9.99") + " g " + cBoxColor + ltrim(str( y1 )) + " " + ltrim(str( ::aReport[ PAGEY ] - x1 )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( x2 - x1 )) + " re f 0 g" + ENDIF + + IF nBorder > 0 +/* + 1 + ÚÄÄÄÄÄ¿ + 4 ³ ³ 2 + ÀÄÄÄÄÄÙ + 3 +*/ + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( ::aReport[ PAGEY ] - x1 )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( nBorder )) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y2 - nBorder )) + " " + ltrim(str( ::aReport[ PAGEY ] - x1 )) + " " + ltrim(str( nBorder )) + " -" + ltrim(str( x2 - x1 )) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( ::aReport[ PAGEY ] - x2 + nBorder )) + " " + ltrim(str( y2 - y1 )) + " -" + ltrim(str( nBorder )) + " re f" + ::aReport[ PAGEBUFFER ] += CRLF + "0 g " + ltrim(str( y1 )) + " " + ltrim(str( ::aReport[ PAGEY ] - x1 )) + " " + ltrim(str( nBorder )) + " -" + ltrim(str( x2 - x1 )) + " re f" + ENDIF + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Box1( nTop, nLeft, nBottom, nRight, nBorderWidth, cBorderColor, cBoxColor ) +#else +METHOD Box1( nTop, nLeft, nBottom, nRight, nBorderWidth, cBorderColor, cBoxColor ) +#endif + +DEFAULT nBorderWidth to 0.5 +DEFAULT cBorderColor to chr(0) + chr(0) + chr(0) +DEFAULT cBoxColor to chr(255) + chr(255) + chr(255) + + ::aReport[ PAGEBUFFER ] += CRLF + ; + Chr_RGB( substr( cBorderColor, 1, 1 )) + " " + ; + Chr_RGB( substr( cBorderColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cBorderColor, 3, 1 )) + ; + " RG" + ; + CRLF + ; + Chr_RGB( substr( cBoxColor, 1, 1 )) + " " + ; + Chr_RGB( substr( cBoxColor, 2, 1 )) + " " + ; + Chr_RGB( substr( cBoxColor, 3, 1 )) + ; + " rg" + ; + CRLF + ltrim(str( nBorderWidth )) + " w" + ; + CRLF + ltrim( str ( nLeft + nBorderWidth / 2 )) + " " + ; + CRLF + ltrim( str ( ::aReport[ PAGEY ] - nBottom + nBorderWidth / 2)) + " " + ; + CRLF + ltrim( str ( nRight - nLeft - nBorderWidth )) + ; + CRLF + ltrim( str ( nBottom - nTop - nBorderWidth )) + " " + ; + " re" + ; + CRLF + "B" +return nil + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Center( cString, nRow, nCol, cUnits, lExact, cId ) +#else +METHOD Center( cString, nRow, nCol, cUnits, lExact, cId ) +#endif + +local nLen, nAt +DEFAULT nRow TO ::aReport[ REPORTLINE ] +DEFAULT cUnits TO "R" +DEFAULT lExact TO .f. +DEFAULT nCol TO IIF( cUnits == "R", ::aReport[ REPORTWIDTH ] / 2, ::aReport[ PAGEX ] / 72 * 25.4 / 2 ) + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFCENTER", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( ::PageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + nLen := ::length( cString ) / 2 + IF cUnits == "R" + IF .not. lExact + ::CheckLine( nRow ) + nRow := nRow + ::aReport[ PDFTOP] + ENDIF + ENDIF + ::AtSay( cString, ::R2M( nRow ), IIF( cUnits == "R", ::aReport[ PDFLEFT ] + ( ::aReport[ PAGEX ] / 72 * 25.4 - 2 * ::aReport[ PDFLEFT ] ) * nCol / ::aReport[ REPORTWIDTH ], nCol ) - nLen, "M", lExact ) +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Close() +#else +METHOD Close() +#endif + +local nI, cTemp, nCurLevel, nObj1, nLast, nCount, nFirst, nRecno, nBooklen + +// FIELD FIRST, PREV, NEXT, LAST, COUNT, PARENT, PAGE, COORD, TITLE, LEVEL + + ::ClosePage() + + // kids + ::aReport[ REFS ][ 2 ] := ::aReport[ DOCLEN ] + cTemp := ; + "1 0 obj"+CRLF+; + "<<"+CRLF+; + "/Type /Pages /Count " + ltrim(str(::aReport[ REPORTPAGE ])) + CRLF +; + "/Kids [" + + for nI := 1 to ::aReport[ REPORTPAGE ] + cTemp += " " + ltrim(str( ::aReport[ PAGES ][ nI ] )) + " 0 R" + next + + cTemp += " ]" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + // info + ++::aReport[ REPORTOBJ ] + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + cTemp := ltrim(str( ::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Producer ()" + CRLF + ; + "/Title ()" + CRLF + ; + "/Author ()" + CRLF + ; + "/Creator ()" + CRLF + ; + "/Subject ()" + CRLF + ; + "/Keywords ()" + CRLF + ; + "/CreationDate (D:" + str(year(date()), 4) + padl( month(date()), 2, "0") + padl( day(date()), 2, "0") + substr( time(), 1, 2 ) + substr( time(), 4, 2 ) + substr( time(), 7, 2 ) + ")" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + // root + ++::aReport[ REPORTOBJ ] + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + cTemp := ltrim(str( ::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<< /Type /Catalog /Pages 1 0 R /Outlines " + ltrim(str( ::aReport[ REPORTOBJ ] + 1 )) + " 0 R" + IIF( ( nBookLen := len( ::aReport[ BOOKMARK ] )) > 0, " /PageMode /UseOutlines", "") + " >>" + CRLF + "endobj" + CRLF + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + ++::aReport[ REPORTOBJ ] + nObj1 := ::aReport[ REPORTOBJ ] + + IF nBookLen > 0 + + nRecno := 1 + nFirst := ::aReport[ REPORTOBJ ] + 1 + nLast := 0 + nCount := 0 + while nRecno <= nBookLen + nCurLevel := ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + ::aReport[ BOOKMARK ][ nRecno ][ BOOKPARENT ] := ::BookParent( nRecno, nCurLevel, ::aReport[ REPORTOBJ ] ) + ::aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ] := ::BookPrev( nRecno, nCurLevel, ::aReport[ REPORTOBJ ] ) + ::aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ] := ::BookNext( nRecno, nCurLevel, ::aReport[ REPORTOBJ ] ) + ::aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ] := ::BookFirst( nRecno, nCurLevel, ::aReport[ REPORTOBJ ] ) + ::aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ] := ::BookLast( nRecno, nCurLevel, ::aReport[ REPORTOBJ ] ) + ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ] := ::BookCount( nRecno, nCurLevel ) + IF nCurLevel == 1 + nLast := nRecno + ++nCount + ENDIF + ++nRecno + enddo + + nLast += ::aReport[ REPORTOBJ ] + + cTemp := ltrim(str( ::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + "<< /Type /Outlines /Count " + ltrim(str( nCount )) + " /First " + ltrim(str( nFirst )) + " 0 R /Last " + ltrim(str( nLast )) + " 0 R >>" + CRLF + "endobj" //+ CRLF + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + ++::aReport[ REPORTOBJ ] + nRecno := 1 + FOR nI := 1 to nBookLen + //cTemp := IIF ( nI > 1, CRLF, "") + ltrim(str( ::aReport[ REPORTOBJ ] + nI - 1)) + " 0 obj" + CRLF + ; + cTemp := CRLF + ltrim(str( ::aReport[ REPORTOBJ ] + nI - 1)) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Parent " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKPARENT ])) + " 0 R" + CRLF + ; + "/Dest [" + ltrim(str( ::aReport[ PAGES ][ ::aReport[ BOOKMARK ][ nRecno ][ BOOKPAGE ] ] )) + " 0 R /XYZ 0 " + ltrim( str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; + "/Title (" + alltrim( ::aReport[ BOOKMARK ][ nRecno ][ BOOKTITLE ]) + ")" + CRLF + ; + IIF( ::aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ] > 0, "/Prev " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKPREV ])) + " 0 R" + CRLF, "") + ; + IIF( ::aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ] > 0, "/Next " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKNEXT ])) + " 0 R" + CRLF, "") + ; + IIF( ::aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ] > 0, "/First " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKFIRST ])) + " 0 R" + CRLF, "") + ; + IIF( ::aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ] > 0, "/Last " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKLAST ])) + " 0 R" + CRLF, "") + ; + IIF( ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ] <> 0, "/Count " + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOUNT ])) + CRLF, "") + ; + ">>" + CRLF + "endobj" + CRLF +// "/Dest [" + ltrim(str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKPAGE ] * 3 )) + " 0 R /XYZ 0 " + ltrim( str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; +// "/Dest [" + ltrim(str( ::aReport[ PAGES ][ nRecno ] )) + " 0 R /XYZ 0 " + ltrim( str( ::aReport[ BOOKMARK ][ nRecno ][ BOOKCOORD ])) + " 0]" + CRLF + ; + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] + 2 ) + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + ++nRecno + NEXT + ::BookClose() + + ::aReport[ REPORTOBJ ] += nBookLen - 1 + ELSE + cTemp := ltrim(str( ::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + "<< /Type /Outlines /Count 0 >>" + CRLF + "endobj" + CRLF + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + ENDIF + + cTemp := CRLF + ::aReport[ DOCLEN ] += len( cTemp ) + + ++::aReport[ REPORTOBJ ] + cTemp += "xref" + CRLF + ; + "0 " + ltrim(str( ::aReport[ REPORTOBJ ] )) + CRLF +; + padl( ::aReport[ REFS ][ 1 ], 10, "0") + " 65535 f" + CRLF + + for nI := 2 to len( ::aReport[ REFS ] ) + cTemp += padl( ::aReport[ REFS ][ nI ], 10, "0") + " 00000 n" + CRLF + next + + cTemp += "trailer << /Size " + ltrim(str( ::aReport[ REPORTOBJ ] )) + " /Root " + ltrim(str( nObj1 - 1 )) + " 0 R /Info " + ltrim(str( nObj1 - 2 )) + " 0 R >>" + CRLF + ; + "startxref" + CRLF + ; + ltrim(str( ::aReport[ DOCLEN ] )) + CRLF + ; + "%%EOF" + CRLF + fwrite( ::aReport[ HANDLE ], cTemp ) + + fclose( ::aReport[ HANDLE ] ) + + ::aReport := nil + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Image( cFile, nRow, nCol, cUnits, nHeight, nWidth, cId ) +#else +METHOD Image( cFile, nRow, nCol, cUnits, nHeight, nWidth, cId ) +#endif + +DEFAULT nRow TO ::aReport[ REPORTLINE ] +DEFAULT nCol TO 0 +DEFAULT nHeight TO 0 +DEFAULT nWidth TO 0 +DEFAULT cUnits TO "R" +DEFAULT cId TO "" + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFIMAGE", cId, { cFile, nRow, nCol, cUnits, nHeight, nWidth } ) + ENDIF + + IF cUnits == "M" + nRow := ::aReport[ PAGEY ] - ::M2Y( nRow ) + nCol := ::M2X( nCol ) + nHeight := ::aReport[ PAGEY ] - ::M2Y( nHeight ) + nWidth := ::M2X( nWidth ) + ELSEIF cUnits == "R" + //IF .not. lExact + // ::CheckLine( nRow ) + // nRow := nRow + ::aReportStyle[ PDFTOP] + //ENDIF + nRow := ::aReport[ PAGEY ] - ::R2D( nRow ) + nCol := ::M2X( ::aReport[ PDFLEFT ] ) + ; + nCol * 100.00 / ::aReport[ REPORTWIDTH ] * ; + ( ::aReport[ PAGEX ] - ::M2X( ::aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + nHeight := ::aReport[ PAGEY ] - ::R2D( nHeight ) + nWidth := ::M2X( ::aReport[ PDFLEFT ] ) + ; + nWidth * 100.00 / ::aReport[ REPORTWIDTH ] * ; + ( ::aReport[ PAGEX ] - ::M2X( ::aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 + ELSEIF cUnits == "D" + ENDIF + + aadd( ::aReport[ PAGEIMAGES ], { cFile, nRow, nCol, nHeight, nWidth } ) + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Length( cString ) +#else +METHOD Length( cString ) +#endif + +local nWidth := 0.00, nI, nLen, nArr, nAdd := ( ::aReport[ FONTNAME ] - 1 ) % 4 + + nLen := len( cString ) + IF right( cString, 1 ) == chr( 255 ) .or. right( cString, 1 ) == chr( 254 ) + --nLen + ENDIF + IF ::GetFontInfo("NAME") = "Times" + nArr := 1 + ELSEIF ::GetFontInfo("NAME") = "Helvetica" + nArr := 2 + ELSE + nArr := 3 + ENDIF + + For nI:= 1 To nLen + nWidth += ::aReport[ FONTWIDTH ][ nArr ][ ( asc( substr( cString, nI, 1 )) - 32 ) * 4 + 1 + nAdd ] * 25.4 * ::aReport[ FONTSIZE ] / 720.00 / 100.00 + Next +RETURN nWidth + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:NewLine( n ) +#else +METHOD NewLine( n ) +#endif + +DEFAULT n TO 1 + IF ::aReport[ REPORTLINE ] + n + ::aReport[ PDFTOP] > ::aReport[ PDFBOTTOM ] + ::NewPage() + ::aReport[ REPORTLINE ] += 1 + ELSE + ::aReport[ REPORTLINE ] += n + ENDIF + +RETURN ::aReport[ REPORTLINE ] + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:NewPage( _cPageSize, _cPageOrient, _nLpi, _cFontName, _nFontType, _nFontSize ) +#else +METHOD NewPage( _cPageSize, _cPageOrient, _nLpi, _cFontName, _nFontType, _nFontSize ) +#endif + +local nAdd := 76.2 + +DEFAULT _cPageSize TO ::aReport[ PAGESIZE ] +DEFAULT _cPageOrient TO ::aReport[ PAGEORIENT ] +DEFAULT _nLpi TO ::aReport[ LPI ] +DEFAULT _cFontName TO ::GetFontInfo( "NAME" ) +DEFAULT _nFontType TO ::GetFontInfo( "TYPE" ) +DEFAULT _nFontSize TO ::aReport[ FONTSIZE ] + + IF !empty( ::aReport[ PAGEBUFFER ] ) + ::ClosePage() + ENDIF + + ::aReport[ PAGEFONTS ] := {} + ::aReport[ PAGEIMAGES ] := {} + + ++::aReport[ REPORTPAGE ] + + ::PageSize( _cPageSize ) + ::PageOrient( _cPageOrient ) + ::SetLPI( _nLpi ) + + ::SetFont( _cFontName, _nFontType, _nFontSize ) + + ::DrawHeader() + + ::aReport[ REPORTLINE ] := 0 + ::aReport[ FONTNAMEPREV ] := 0 + ::aReport[ FONTSIZEPREV ] := 0 + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:PageSize( _cPageSize ) +#else +METHOD PageSize( _cPageSize ) +#endif + +local nSize, aSize := { { "LETTER", 8.50, 11.00 }, ; + { "LEGAL" , 8.50, 14.00 }, ; + { "LEDGER", 11.00, 17.00 }, ; + { "EXECUTIVE", 7.25, 10.50 }, ; + { "A4", 8.27, 11.69 }, ; + { "A3", 11.69, 16.54 }, ; + { "JIS B4", 10.12, 14.33 }, ; + { "JIS B5", 7.16, 10.12 }, ; + { "JPOST", 3.94, 5.83 }, ; + { "JPOSTD", 5.83, 7.87 }, ; + { "COM10", 4.12, 9.50 }, ; + { "MONARCH", 3.87, 7.50 }, ; + { "C5", 6.38, 9.01 }, ; + { "DL", 4.33, 8.66 }, ; + { "B5", 6.93, 9.84 } } + +DEFAULT _cPageSize TO "LETTER" + + nSize := ascan( aSize, { |arr| arr[ 1 ] = _cPageSize } ) + + IF nSize = 0 .or. nSize > 2 + nSize := 1 + ENDIF + + ::aReport[ PAGESIZE ] := aSize[ nSize ][ 1 ] + + IF ::aReport[ PAGEORIENT ] = "P" + ::aReport[ PAGEX ] := aSize[ nSize ][ 2 ] * 72 + ::aReport[ PAGEY ] := aSize[ nSize ][ 3 ] * 72 + ELSE + ::aReport[ PAGEX ] := aSize[ nSize ][ 3 ] * 72 + ::aReport[ PAGEY ] := aSize[ nSize ][ 2 ] * 72 + ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:PageOrient( _cPageOrient ) +#else +METHOD PageOrient( _cPageOrient ) +#endif + +DEFAULT _cPageOrient TO "P" + + ::aReport[ PAGEORIENT ] := _cPageOrient + ::PageSize( ::aReport[ PAGESIZE ] ) +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:PageNumber( n ) +#else +METHOD PageNumber( n ) +#endif + +DEFAULT n TO 0 + IF n > 0 + ::aReport[ REPORTPAGE ] := n // NEW !!! + ENDIF +RETURN ::aReport[ REPORTPAGE ] + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Reverse( cString ) +#else +METHOD Reverse( cString ) +#endif + +RETURN cString + chr(255) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:RJust( cString, nRow, nCol, cUnits, lExact, cId ) +#else +METHOD RJust( cString, nRow, nCol, cUnits, lExact, cId ) +#endif + +local nLen, nAdj := 1.0, nAt + +DEFAULT nRow TO ::aReport[ REPORTLINE ] +DEFAULT cUnits TO "R" +DEFAULT lExact TO .f. + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFRJUST", cId, { cString, nRow, nCol, cUnits, lExact } ) + ENDIF + + IF ( nAt := at( "#pagenumber#", cString ) ) > 0 + cString := left( cString, nAt - 1 ) + ltrim(str( ::PageNumber())) + substr( cString, nAt + 12 ) + ENDIF + + nLen := ::length( cString ) + + IF cUnits == "R" + IF .not. lExact + ::CheckLine( nRow ) + nRow := nRow + ::aReport[ PDFTOP] + ENDIF + ENDIF + ::AtSay( cString, ::R2M( nRow ), IIF( cUnits == "R", ::aReport[ PDFLEFT ] + ( ::aReport[ PAGEX ] / 72 * 25.4 - 2 * ::aReport[ PDFLEFT ] ) * nCol / ::aReport[ REPORTWIDTH ] - nAdj, nCol ) - nLen, "M", lExact ) +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:SetFont( _cFont, _nType, _nSize, cId ) +#else +METHOD SetFont( _cFont, _nType, _nSize, cId ) +#endif + +DEFAULT _cFont TO "Times" +DEFAULT _nType TO 0 +DEFAULT _nSize TO 10 + + IF ::aReport[ HEADEREDIT ] + return ::Header( "PDFSETFONT", cId, { _cFont, _nType, _nSize } ) + ENDIF + + _cFont := upper( _cFont ) + ::aReport[ FONTSIZE ] := _nSize + + IF _cFont == "TIMES" + ::aReport[ FONTNAME ] := _nType + 1 + ELSEIF _cFont == "HELVETICA" + ::aReport[ FONTNAME ] := _nType + 5 + ELSE + ::aReport[ FONTNAME ] := _nType + 9 // 0.04 + ENDIF + + aadd( ::aReport[ PAGEFONTS ], ::aReport[ FONTNAME ] ) + + IF ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ FONTNAME ] } ) == 0 + aadd( ::aReport[ FONTS ], { ::aReport[ FONTNAME ], ++::aReport[ NEXTOBJ ] } ) + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:SetLPI(_nLpi) +#else +METHOD SetLPI(_nLpi) +#endif + +local cLpi := alltrim(str(_nLpi)) +DEFAULT _nLpi TO 6 + + cLpi := iif(cLpi$"1;2;3;4;6;8;12;16;24;48",cLpi,"6") + ::aReport[ LPI ] := val( cLpi ) + + ::PageSize( ::aReport[ PAGESIZE ] ) +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:StringB( cString ) +#else +METHOD StringB( cString ) +#endif + +cString := strtran( cString, "(", "\(" ) +cString := strtran( cString, ")", "\)" ) + +RETURN cString + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:TextCount( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits ) +#else +METHOD TextCount( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits ) +#endif + +RETURN ::Text( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits, .f. ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Text( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits, cColor, lPrint ) +#else +METHOD Text( cString, nTop, nLeft, nLength, nTab, nJustify, cUnits, cColor, lPrint ) +#endif + +local cDelim := chr(0)+chr(9)+chr(10)+chr(13)+chr(26)+chr(32)+chr(138)+chr(141) +local nI, cTemp, cToken, k, nL, nRow, nLines, nLineLen, nStart +local lParagraph, nSpace, nNew, nTokenLen, nCRLF, nTokens, nLen + +DEFAULT nTab TO -1 +DEFAULT cUnits TO 'R' +DEFAULT nJustify TO 4 +DEFAULT lPrint TO .t. +DEFAULT cColor TO "" + + IF cUnits == "M" + nTop := ::M2R( nTop ) + ELSEIF cUnits == "R" + nLeft := ::X2M( ::M2X( ::aReport[ PDFLEFT ] ) + ; + nLeft * 100.00 / ::aReport[ REPORTWIDTH ] * ; + ( ::aReport[ PAGEX ] - ::M2X( ::aReport[ PDFLEFT ] ) * 2 - 9.0 ) / 100.00 ) + ENDIF + + ::aReport[ REPORTLINE ] := nTop - 1 + + nSpace := ::length( " " ) + nLines := 0 + nCRLF := 0 + nNew := nTab + cString := alltrim( cString ) + nTokens := numtoken( cString, cDelim ) + nTokenLen := 0.00 + nStart := 1 + + IF nJustify == 1 .or. nJustify == 4 + nLeft := nLeft + ELSEIF nJustify == 2 + nLeft := nLeft - nLength / 2 + ELSEIF nJustify == 3 + nLeft := nLeft - nLength + ENDIF + + nL := nLeft + nL += nNew * nSpace + nLineLen := nSpace * nNew - nSpace + + lParagraph := .t. + nI := 1 + + while nI <= nTokens + cToken := token( cString, cDelim, nI ) + nTokenLen := ::length( cToken ) + nLen := len( cToken ) + + IF nLineLen + nSpace + nTokenLen > nLength + IF nStart == nI // single word > nLength + k := 1 + while k <= nLen + cTemp := "" + nLineLen := 0.00 + nL := nLeft + IF lParagraph + nLineLen += nSpace * nNew + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + lParagraph := .f. + ENDIF + IF nJustify == 2 + nL := nLeft + ( nLength - ::length( cTemp ) ) / 2 + ELSEIF nJustify == 3 + nL := nLeft + nLength - ::length( cTemp ) + ENDIF + while k <= nLen .and. ( ( nLineLen += ::length( substr( cToken, k, 1 ))) <= nLength ) + nLineLen += ::length( substr( cToken, k, 1 )) + cTemp += substr( cToken, k, 1 ) + ++k + enddo + IF empty( cTemp ) // single character > nlength + cTemp := substr( cToken, k, 1 ) + ++k + ENDIF + ++nLines + IF lPrint + nRow := ::NewLine( 1 ) + ::AtSay( cColor + cTemp, ::R2M( nRow + ::aReport[ PDFTOP] ), nL, "M" ) + ENDIF + enddo + ++nI + nStart := nI + ELSE + ::TextPrint( nI - 1, nLeft, @lParagraph, nJustify, nSpace, nNew, nLength, @nLineLen, @nLines, @nStart, cString, cDelim, cColor, lPrint ) + ENDIF + + ELSEIF ( nI == nTokens ) .or. ( nI < nTokens .and. ( nCRLF := ::TextNextPara( cString, cDelim, nI ) ) > 0 ) + IF nI == nTokens + nLineLen += nSpace + nTokenLen + ENDIF + ::TextPrint( nI, nLeft, @lParagraph, nJustify, nSpace, nNew, nLength, @nLineLen, @nLines, @nStart, cString, cDelim, cColor, lPrint ) + ++nI + + IF nCRLF > 1 + nLines += nCRLF - 1 + ENDIF + IF lPrint + nRow := ::NewLine( nCRLF - 1 ) + ENDIF + + ELSE + nLineLen += nSpace + nTokenLen + ++nI + ENDIF + enddo + +RETURN nLines + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:UnderLine( cString ) +#else +METHOD UnderLine( cString ) +#endif + +RETURN cString + chr(254) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:OpenHeader( cFile ) +#else +METHOD OpenHeader( cFile ) +#endif + +local nErrorCode := 0, nAt, cCmd + +DEFAULT cFile TO '' + + IF !empty( cFile ) + cFile := alltrim( cFile ) + IF len( cFile ) > 12 .or. ; + at( ' ', cFile ) > 0 .or. ; + ( at( ' ', cFile ) == 0 .and. len( cFile ) > 8 ) .or. ; + ( ( nAt := at( '.', cFile )) > 0 .and. len( substr( cFile, nAt + 1 )) > 3 ) + + cCmd := "copy " + cFile + " temp.tmp > nul" + RunExternal( cCmd ) + + cFile := "temp.tmp" + ENDIF + // ::aReport[ HEADER ] := FT_RestArr( cFile, @nErrorCode ) + ::aReport[ HEADER ] := File2Array( cFile ) + ELSE + ::aReport[ HEADER ] := {} + ENDIF + ::aReport[ MARGINS ] := .t. + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:EditOnHeader() +#else +METHOD EditOnHeader() +#endif + +::aReport[ HEADEREDIT ] := .t. +::aReport[ MARGINS ] := .t. + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:EditOffHeader() +#else +METHOD EditOffHeader() +#endif + +::aReport[ HEADEREDIT ] := .f. +::aReport[ MARGINS ] := .t. + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:CloseHeader() +#else +METHOD CloseHeader() +#endif + + ::aReport[ HEADER ] := {} + ::aReport[ MARGINS ] := .f. +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:DeleteHeader( cId ) +#else +METHOD DeleteHeader( cId ) +#endif + +local nRet := -1, nId + cId := upper( cId ) + nId := ascan( ::aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + nRet := len( ::aReport[ HEADER ] ) - 1 + aDel( ::aReport[ HEADER ], nId ) + aSize( ::aReport[ HEADER ], nRet ) + ::aReport[ MARGINS ] := .t. + ENDIF +RETURN nRet + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:EnableHeader( cId ) +#else +METHOD EnableHeader( cId ) +#endif + +local nId + cId := upper( cId ) + nId := ascan( ::aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + ::aReport[ HEADER ][ nId ][ 1 ] := .t. + ::aReport[ MARGINS ] := .t. + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:DisableHeader( cId ) +#else +METHOD DisableHeader( cId ) +#endif + +local nId + cId := upper( cId ) + nId := ascan( ::aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + IF nId > 0 + ::aReport[ HEADER ][ nId ][ 1 ] := .f. + ::aReport[ MARGINS ] := .t. + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:SaveHeader( cFile ) +#else +METHOD SaveHeader( cFile ) +#endif + +local nErrorCode := 0, cCmd + +Array2File( 'temp.tmp', ::aReport[ HEADER ] ) + +cCmd := "copy temp.tmp " + cFile + " > nul" +RunExternal( cCmd ) + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Header( cFunction, cId, arr ) +#else +METHOD Header( cFunction, cId, arr ) +#endif + +local nId, nI, nLen, nIdLen + nId := 0 + IF !empty( cId ) + cId := upper( cId ) + nId := ascan( ::aReport[ HEADER ], {| arr | arr[ 3 ] == cId }) + ENDIF + IF nId == 0 + nLen := len( ::aReport[ HEADER ] ) + IF empty( cId ) + cId := cFunction + nIdLen := len( cId ) + for nI := 1 to nLen + IF ::aReport[ HEADER ][ nI ][ 2 ] == cId + IF val( substr( ::aReport[ HEADER ][ nI ][ 3 ], nIdLen + 1 ) ) > nId + nId := val( substr( ::aReport[ HEADER ][ nI ][ 3 ], nIdLen + 1 ) ) + ENDIF + ENDIF + next + ++nId + cId += ltrim(str(nId)) + ENDIF + aadd( ::aReport[ HEADER ], { .t., cFunction, cId } ) + ++nLen + for nI := 1 to len( arr ) + aadd( ::aReport[ HEADER ][ nLen ], arr[ nI ] ) + next + ELSE + aSize( ::aReport[ HEADER ][ nId ], 3 ) + for nI := 1 to len( arr ) + aadd( ::aReport[ HEADER ][ nId ], arr[ nI ] ) + next + ENDIF +RETURN cId + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:DrawHeader() +#else +METHOD DrawHeader() +#endif + +local nI, _nFont, _nSize, nLen := len( ::aReport[ HEADER ] ) + + IF nLen > 0 + + // save font + _nFont := ::aReport[ FONTNAME ] + _nSize := ::aReport[ FONTSIZE ] + + for nI := 1 to nLen + IF ::aReport[ HEADER ][ nI ][ 1 ] // enabled + do case + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFATSAY" + ::AtSay( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 7 ], ::aReport[ HEADER ][ nI ][ 8 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFCENTER" + ::Center( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 7 ], ::aReport[ HEADER ][ nI ][ 8 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFRJUST" + ::RJust( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 7 ], ::aReport[ HEADER ][ nI ][ 8 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFBOX" + ::Box( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 7 ], ::aReport[ HEADER ][ nI ][ 8 ], ::aReport[ HEADER ][ nI ][ 9 ], ::aReport[ HEADER ][ nI ][ 10 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFSETFONT" + ::SetFont( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + case ::aReport[ HEADER ][ nI ][ 2 ] == "PDFIMAGE" + ::Image( ::aReport[ HEADER ][ nI ][ 4 ], ::aReport[ HEADER ][ nI ][ 5 ], ::aReport[ HEADER ][ nI ][ 6 ], ::aReport[ HEADER ][ nI ][ 7 ], ::aReport[ HEADER ][ nI ][ 8 ], ::aReport[ HEADER ][ nI ][ 9 ], ::aReport[ HEADER ][ nI ][ 3 ] ) + + endcase + ENDIF + next + ::aReport[ FONTNAME ] := _nFont + ::aReport[ FONTSIZE ] := _nSize + + IF ::aReport[ MARGINS ] + ::Margins() + ENDIF + + ELSE + IF ::aReport[ MARGINS ] + ::aReport[ PDFTOP] := 1 // top + ::aReport[ PDFLEFT ] := 10 // left & right + ::aReport[ PDFBOTTOM ] := ::aReport[ PAGEY ] / 72 * ::aReport[ LPI ] - 1 // bottom, default "LETTER", "P", 6 + + ::aReport[ MARGINS ] := .f. + ENDIF + ENDIF +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Margins( nTop, nLeft, nBottom ) +#else +METHOD Margins( nTop, nLeft, nBottom ) +#endif + +local nI, nLen := len( ::aReport[ HEADER ] ), nTemp, aTemp, nHeight + + for nI := 1 to nLen + IF ::aReport[ HEADER ][ nI ][ 1 ] // enabled + + IF ::aReport[ HEADER ][ nI ][ 2 ] == "PDFSETFONT" + + ELSEIF ::aReport[ HEADER ][ nI ][ 2 ] == "PDFIMAGE" + IF ::aReport[ HEADER ][ nI ][ 8 ] == 0 // picture in header, first at all, not at any page yet + aTemp := ::ImageInfo( ::aReport[ HEADER ][ nI ][ 4 ] ) + nHeight := aTemp[ IMAGE_HEIGHT ] / aTemp[ IMAGE_YRES ] * 25.4 + IF ::aReport[ HEADER ][ nI ][ 7 ] == "D" + nHeight := ::M2X( nHeight ) + ENDIF + ELSE + nHeight := ::aReport[ HEADER ][ nI ][ 8 ] + ENDIF + + IF ::aReport[ HEADER ][ nI ][ 7 ] == "M" + + nTemp := ::aReport[ PAGEY ] / 72 * 25.4 / 2 + + IF ::aReport[ HEADER ][ nI ][ 5 ] < nTemp + nTemp := ( ::aReport[ HEADER ][ nI ][ 5 ] + nHeight ) * ::aReport[ LPI ] / 25.4 // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ELSE + nTemp := ::aReport[ HEADER ][ nI ][ 5 ] * ::aReport[ LPI ] / 25.4 // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ELSEIF ::aReport[ HEADER ][ nI ][ 7 ] == "D" + nTemp := ::aReport[ PAGEY ] / 2 + + IF ::aReport[ HEADER ][ nI ][ 5 ] < nTemp + nTemp := ( ::aReport[ HEADER ][ nI ][ 5 ] + nHeight ) * ::aReport[ LPI ] / 72 // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ELSE + nTemp := ::aReport[ HEADER ][ nI ][ 5 ] * ::aReport[ LPI ] / 72 // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ENDIF + + ENDIF + + ELSEIF ::aReport[ HEADER ][ nI ][ 2 ] == "PDFBOX" + + IF ::aReport[ HEADER ][ nI ][ 10 ] == "M" + + nTemp := ::aReport[ PAGEY ] / 72 * 25.4 / 2 + + IF ::aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] < nTemp + nTemp := ::aReport[ HEADER ][ nI ][ 6 ] * ::aReport[ LPI ] / 25.4 // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ELSEIF ::aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] > nTemp + + nTemp := ( ::aReport[ HEADER ][ nI ][ 4 ] + ::aReport[ HEADER ][ nI ][ 8 ] ) * ::aReport[ LPI ] / 25.4 // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + + nTemp := ( ::aReport[ HEADER ][ nI ][ 6 ] - ::aReport[ HEADER ][ nI ][ 8 ] ) * ::aReport[ LPI ] / 25.4 // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ELSEIF ::aReport[ HEADER ][ nI ][ 4 ] > nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] > nTemp + nTemp := ::aReport[ HEADER ][ nI ][ 4 ] * ::aReport[ LPI ] / 25.4 // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ELSEIF ::aReport[ HEADER ][ nI ][ 10 ] == "D" + nTemp := ::aReport[ PAGEY ] / 2 + + IF ::aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] < nTemp + nTemp := ::aReport[ HEADER ][ nI ][ 6 ] / ::aReport[ LPI ] // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ELSEIF ::aReport[ HEADER ][ nI ][ 4 ] < nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] > nTemp + + nTemp := ( ::aReport[ HEADER ][ nI ][ 4 ] + ::aReport[ HEADER ][ nI ][ 8 ] ) / ::aReport[ LPI ] // top + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + + nTemp := ( ::aReport[ HEADER ][ nI ][ 6 ] - ::aReport[ HEADER ][ nI ][ 8 ] ) / ::aReport[ LPI ] // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + + ELSEIF ::aReport[ HEADER ][ nI ][ 4 ] > nTemp .and. ; + ::aReport[ HEADER ][ nI ][ 6 ] > nTemp + nTemp := ::aReport[ HEADER ][ nI ][ 4 ] / ::aReport[ LPI ] // top + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ENDIF + + ENDIF + + ELSE + IF ::aReport[ HEADER ][ nI ][ 7 ] == "R" + nTemp := ::aReport[ HEADER ][ nI ][ 5 ] // top + IF ::aReport[ HEADER ][ nI ][ 5 ] > ::aReport[ PAGEY ] / 72 * ::aReport[ LPI ] / 2 + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ENDIF + ELSEIF ::aReport[ HEADER ][ nI ][ 7 ] == "M" + nTemp := ::aReport[ HEADER ][ nI ][ 5 ] * ::aReport[ LPI ] / 25.4 // top + IF ::aReport[ HEADER ][ nI ][ 5 ] > ::aReport[ PAGEY ] / 72 * 25.4 / 2 + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ENDIF + ELSEIF ::aReport[ HEADER ][ nI ][ 7 ] == "D" + nTemp := ::aReport[ HEADER ][ nI ][ 5 ] / ::aReport[ LPI ] // top + IF ::aReport[ HEADER ][ nI ][ 5 ] > ::aReport[ PAGEY ] / 2 + IF nTemp < ::aReport[ PDFBOTTOM ] + ::aReport[ PDFBOTTOM ] := nTemp + ENDIF + ELSE + IF nTemp > ::aReport[ PDFTOP] + ::aReport[ PDFTOP] := nTemp + ENDIF + ENDIF + ENDIF + ENDIF + ENDIF + next + + IF nTop <> NIL + ::aReport[ PDFTOP] := nTop + ENDIF + IF nLeft <> NIL + ::aReport[ PDFLEFT ] := nLeft + ENDIF + IF nBottom <> NIL + ::aReport[ PDFBOTTOM ] := nBottom + ENDIF + + ::aReport[ MARGINS ] := .f. + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:CreateHeader( _file, _size, _orient, _lpi, _width ) +#else +METHOD CreateHeader( _file, _size, _orient, _lpi, _width ) +#endif + +local ; + aReportStyle := { ; + { 1, 2, 3, 4, 5, 6 }, ; //"Default" + { 2.475, 4.0, 4.9, 6.4, 7.5, 64.0 }, ; //"P6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 85.35 }, ; //"P8" + { 2.475, 4.0, 4.9, 6.4, 7.5, 48.9 }, ; //"L6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 65.2 }, ; //"L8" + { 2.475, 4.0, 4.9, 6.4, 7.5, 82.0 }, ; //"P6" + { 3.3 , 5.4, 6.5, 8.6, 10.0, 109.35 } ; //"P8" + } +local nStyle := 1, nAdd := 0.00 + +DEFAULT _size TO ::aReport[ PAGESIZE ] +DEFAULT _orient TO ::aReport[ PAGEORIENT ] +DEFAULT _lpi TO ::aReport[ LPI ] +DEFAULT _width TO 200 + + IF _size == "LETTER" + IF _orient == "P" + IF _lpi == 6 + nStyle := 2 + ELSEIF _lpi == 8 + nStyle := 3 + ENDIF + ELSEIF _orient == "L" + IF _lpi == 6 + nStyle := 4 + ELSEIF _lpi == 8 + nStyle := 5 + ENDIF + ENDIF + ELSEIF _size == "LEGAL" + IF _orient == "P" + IF _lpi == 6 + nStyle := 6 + ELSEIF _lpi == 8 + nStyle := 7 + ENDIF + ELSEIF _orient == "L" + IF _lpi == 6 + nStyle := 4 + ELSEIF _lpi == 8 + nStyle := 5 + ENDIF + ENDIF + ENDIF + + ::EditOnHeader() + + IF _size == "LEGAL" + nAdd := 76.2 + ENDIF + + IF _orient == "P" + ::Box( 5.0, 5.0, 274.0 + nAdd, 210.0, 1.0 ) + ::Box( 6.5, 6.5, 272.5 + nAdd, 208.5, 0.5 ) + + ::Box( 11.5, 9.5, 22.0 , 205.5, 0.5, 5 ) + ::Box( 23.0, 9.5, 33.5 , 205.5, 0.5, 5 ) + ::Box( 34.5, 9.5, 267.5 + nAdd, 205.5, 0.5 ) + + ELSE + ::Box( 5.0, 5.0, 210.0, 274.0 + nAdd, 1.0 ) + ::Box( 6.5, 6.5, 208.5, 272.5 + nAdd, 0.5 ) + + ::Box( 11.5, 9.5, 22.0, 269.5 + nAdd, 0.5, 5 ) + ::Box( 23.0, 9.5, 33.5, 269.5 + nAdd, 0.5, 5 ) + ::Box( 34.5, 9.5, 203.5, 269.5 + nAdd, 0.5 ) + ENDIF + + ::SetFont("Arial", BOLD, 10) + ::AtSay( "Test Line 1", aReportStyle[ nStyle ][ 1 ], 1, "R", .t. ) + + ::SetFont("Times", BOLD, 18) + ::Center( "Test Line 2", aReportStyle[ nStyle ][ 2 ],,"R", .t. ) + + ::SetFont("Times", BOLD, 12) + ::Center( "Test Line 3", aReportStyle[ nStyle ][ 3 ],,"R", .t. ) + + ::SetFont("Arial", BOLD, 10) + ::AtSay( "Test Line 4", aReportStyle[ nStyle ][ 4 ], 1, "R", .t. ) + + ::SetFont("Arial", BOLD, 10) + ::AtSay( "Test Line 5", aReportStyle[ nStyle ][ 5 ], 1, "R", .t. ) + + ::AtSay( dtoc( date()) + " " + TimeAsAMPM( time() ), aReportStyle[ nStyle ][ 6 ], 1, "R", .t. ) + ::RJust( "Page: #pagenumber#", aReportStyle[ nStyle ][ 6 ], ::aReport[ REPORTWIDTH ], "R", .t. ) + + ::EditOffHeader() + ::SaveHeader( _file ) +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:ImageInfo( cFile ) +#else +METHOD ImageInfo( cFile ) +#endif + +local cTemp := upper(substr( cFile, rat('.', cFile) + 1 )), aTemp := {} + do case + case cTemp == "TIF" + aTemp := ::TIFFInfo( cFile ) + case cTemp == "JPG" + aTemp := ::JPEGInfo( cFile ) + endcase +RETURN aTemp + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:TIFFInfo( cFile ) +#else +METHOD TIFFInfo( cFile ) +#endif + +local c40 := chr(0)+chr(0)+chr(0)+chr(0) +local aType := {"BYTE","ASCII","SHORT","LONG","RATIONAL","SBYTE","UNDEFINED","SSHORT","SLONG","SRATIONAL","FLOAT","DOUBLE"} +local aCount := { 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 } +local nTemp, nHandle, cValues, c2, nFieldType, nCount, nPos, nTag, nValues +local nOffset, cTemp, cIFDNext, nIFD, nFields, cTag, nPages, nn + +local nWidth := 0, nHeight := 0, nBits := 0, nFrom := 0, nLength := 0, xRes := 0, yRes := 0, aTemp := {} + + nHandle := fopen( cFile ) + + c2 := ' ' + fread( nHandle, @c2, 2 ) + fread( nHandle, @c2, 2 ) + + cIFDNext := ' ' + fread( nHandle, @cIFDNext, 4 ) + + cTemp := space(12) + nPages := 0 + + while cIFDNext <> c40 //read IFD's + + nIFD := bin2l( cIFDNext ) + + fseek( nHandle, nIFD ) + + fread( nHandle, @c2, 2 ) + nFields := bin2i( c2 ) + + for nn := 1 to nFields + fread( nHandle, @cTemp, 12 ) + + nTag := bin2w( substr( cTemp, 1, 2 ) ) + nFieldType := bin2w( substr( cTemp, 3, 2 ) ) + nCount := bin2l( substr( cTemp, 5, 4 ) ) + nOffset := bin2l( substr( cTemp, 9, 4 ) ) + + IF nCount > 1 .or. nFieldType == RATIONAL .or. nFieldType == SRATIONAL + nPos := filepos( nHandle ) + fseek( nHandle, nOffset) + + nValues := nCount * aCount[ nFieldType ] + cValues := space( nValues ) + fread( nHandle, @cValues, nValues ) + fseek( nHandle, nPos ) + ELSE + cValues := substr( cTemp, 9, 4 ) + ENDIF + + IF nFieldType == ASCII + --nCount + ENDIF + cTag := '' + do case + case nTag == 256 + cTag := 'ImageWidth' + + IF nFieldType == SHORT + nWidth := bin2w( substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nWidth := bin2l( substr( cValues, 1, 4 )) + ENDIF + + case nTag == 257 + cTag := 'ImageLength' + IF nFieldType == SHORT + nHeight := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nHeight := bin2l(substr( cValues, 1, 4 )) + ENDIF + + case nTag == 258 + cTag := 'BitsPerSample' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ENDIF + nBits := nTemp + case nTag == 259 + cTag := 'Compression' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ENDIF + case nTag == 262 + cTag := 'PhotometricInterpretation' + nTemp := -1 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ENDIF + case nTag == 264 + cTag := 'CellWidth' + case nTag == 265 + cTag := 'CellLength' + case nTag == 266 + cTag := 'FillOrder' + case nTag == 273 + cTag := 'StripOffsets' + IF nFieldType == SHORT + nFrom := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nFrom := bin2l(substr( cValues, 1, 4 )) + ENDIF + + case nTag == 277 + cTag := 'SamplesPerPixel' + case nTag == 278 + cTag := 'RowsPerStrip' + case nTag == 279 + cTag := 'StripByteCounts' + IF nFieldType == SHORT + nLength := bin2w(substr( cValues, 1, 2 )) + ELSEIF nFieldType == LONG + nLength := bin2l(substr( cValues, 1, 4 )) + ENDIF + + nLength *= nCount // Count all strips !!! + + case nTag == 282 + cTag := 'XResolution' + xRes := bin2l(substr( cValues, 1, 4 )) + case nTag == 283 + cTag := 'YResolution' + yRes := bin2l(substr( cValues, 1, 4 )) + case nTag == 284 + cTag := 'PlanarConfiguration' + case nTag == 288 + cTag := 'FreeOffsets' + case nTag == 289 + cTag := 'FreeByteCounts' + case nTag == 296 + cTag := 'ResolutionUnit' + nTemp := 0 + IF nFieldType == SHORT + nTemp := bin2w( cValues ) + ENDIF + case nTag == 305 + cTag := 'Software' + case nTag == 306 + cTag := 'DateTime' + case nTag == 315 + cTag := 'Artist' + case nTag == 320 + cTag := 'ColorMap' + case nTag == 338 + cTag := 'ExtraSamples' + case nTag == 33432 + cTag := 'Copyright' + otherwise + cTag := 'Unknown' + endcase + next + fread( nHandle, @cIFDNext, 4 ) + enddo + + fclose( nHandle ) + + aadd( aTemp, nWidth ) + aadd( aTemp, nHeight ) + aadd( aTemp, xRes ) + aadd( aTemp, yRes ) + aadd( aTemp, nBits ) + aadd( aTemp, nFrom ) + aadd( aTemp, nLength ) + +return aTemp + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:JPEGInfo( cFile ) +#else +METHOD JPEGInfo( cFile ) +#endif + +local c255, nAt, nHandle +local nWidth := 0, nHeight := 0, nBits := 8, nFrom := 0 +local nLength := 0, xRes := 0, yRes := 0, aTemp := {} + + nHandle := fopen( cFile ) + + c255 := space(1024) + fread( nHandle, @c255, 1024 ) + + xRes := asc(substr( c255, 15, 1 )) * 256 + asc(substr( c255, 16, 1 )) + yRes := asc( substr( c255, 17, 1 )) * 256 + asc(substr( c255, 18, 1 )) + + nAt := at( chr(255) + chr(192), c255 ) + 5 + nHeight := asc(substr( c255, nAt, 1 )) * 256 + asc(substr( c255, nAt + 1, 1 )) + nWidth := asc( substr( c255, nAt + 2, 1 )) * 256 + asc(substr( c255, nAt + 3, 1 )) + + fclose( nHandle ) + + nLength := filesize( cFile ) + + aadd( aTemp, nWidth ) + aadd( aTemp, nHeight ) + aadd( aTemp, xRes ) + aadd( aTemp, yRes ) + aadd( aTemp, nBits ) + aadd( aTemp, nFrom ) + aadd( aTemp, nLength ) + +return aTemp + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookCount( nRecno, nCurLevel ) +#else +METHOD BookCount( nRecno, nCurLevel ) +#endif + +local nTempLevel := 0, nCount := 0, nLen := len( ::aReport[ BOOKMARK ] ) + ++nRecno + while nRecno <= nLen + nTempLevel := ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nTempLevel <= nCurLevel + exit + ELSE + IF nCurLevel + 1 == nTempLevel + ++nCount + ENDIF + ENDIF + ++nRecno + enddo +return -1 * nCount + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookFirst( nRecno, nCurLevel, nObj ) +#else +METHOD BookFirst( nRecno, nCurLevel, nObj ) +#endif + +local nFirst := 0, nLen := len( ::aReport[ BOOKMARK ] ) + ++nRecno + IF nRecno <= nLen + IF nCurLevel + 1 == ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + nFirst := nRecno + ENDIF + ENDIF +return IIF( nFirst == 0, nFirst, nObj + nFirst ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookLast( nRecno, nCurLevel, nObj ) +#else +METHOD BookLast( nRecno, nCurLevel, nObj ) +#endif + +local nLast := 0, nLen := len( ::aReport[ BOOKMARK ] ) + ++nRecno + IF nRecno <= nLen + IF nCurLevel + 1 == ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + while nRecno <= nLen .and. nCurLevel + 1 <= ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel + 1 == ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + nLast := nRecno + ENDIF + ++nRecno + enddo + ENDIF + ENDIF +return IIF( nLast == 0, nLast, nObj + nLast ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookNext( nRecno, nCurLevel, nObj ) +#else +METHOD BookNext( nRecno, nCurLevel, nObj ) +#endif + +local nTempLevel := 0, nNext := 0, nLen := len( ::aReport[ BOOKMARK ] ) + ++nRecno + while nRecno <= nLen + nTempLevel := ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel > nTempLevel + exit + ELSEIF nCurLevel == nTempLevel + nNext := nRecno + exit + ELSE + // keep going + ENDIF + ++nRecno + enddo +return IIF( nNext == 0, nNext, nObj + nNext ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookParent( nRecno, nCurLevel, nObj ) +#else +METHOD BookParent( nRecno, nCurLevel, nObj ) +#endif + +local nTempLevel := 0 +local nParent := 0 + --nRecno + while nRecno > 0 + nTempLevel := ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nTempLevel < nCurLevel + nParent := nRecno + exit + ENDIF + --nRecno + enddo +return IIF( nParent == 0, nObj - 1, nObj + nParent ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:BookPrev( nRecno, nCurLevel, nObj ) +#else +METHOD BookPrev( nRecno, nCurLevel, nObj ) +#endif + +local nTempLevel := 0 +local nPrev := 0 + --nRecno + while nRecno > 0 + nTempLevel := ::aReport[ BOOKMARK ][ nRecno ][ BOOKLEVEL ] + IF nCurLevel > nTempLevel + exit + ELSEIF nCurLevel == nTempLevel + nPrev := nRecno + exit + ELSE + // keep going + ENDIF + --nRecno + enddo +return IIF( nPrev == 0, nPrev, nObj + nPrev ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:CheckLine( nRow ) +#else +METHOD CheckLine( nRow ) +#endif + + IF nRow + ::aReport[ PDFTOP] > ::aReport[ PDFBOTTOM ] + ::NewPage() + nRow := ::aReport[ REPORTLINE ] + ENDIF + ::aReport[ REPORTLINE ] := nRow +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:GetFontInfo( cParam ) +#else +METHOD GetFontInfo( cParam ) +#endif + +local cRet + IF cParam == "NAME" + IF left( ::aReport[ TYPE1 ][ ::aReport[ FONTNAME ] ], 5 ) == "Times" + cRet := "Times" + ELSEIF left( ::aReport[ TYPE1 ][ ::aReport[ FONTNAME ] ], 9 ) == "Helvetica" + cRet := "Helvetica" + ELSE + cRet := "Courier" // 0.04 + ENDIF + ELSE // size + cRet := int(( ::aReport[ FONTNAME ] - 1 ) % 4) + ENDIF + +return cRet + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:M2R( mm ) +#else +METHOD M2R( mm ) +#endif + +return int( ::aReport[ LPI ] * mm / 25.4 ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:M2X( n ) +#else +METHOD M2X( n ) +#endif + +return n * 72 / 25.4 + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:M2Y( n ) +#else +METHOD M2Y( n ) +#endif + +return ::aReport[ PAGEY ] - n * 72 / 25.4 + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:R2D( nRow ) +#else +METHOD R2D( nRow ) +#endif + +return ::aReport[ PAGEY ] - nRow * 72 / ::aReport[ LPI ] + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:R2M( nRow ) +#else +METHOD R2M( nRow ) +#endif + +return 25.4 * nRow / ::aReport[ LPI ] + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:X2M( n ) +#else +METHOD X2M( n ) +#endif + +return n * 25.4 / 72 + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:TextPrint( nI, nLeft, lParagraph, nJustify, nSpace, nNew, nLength, nLineLen, nLines, nStart, cString, cDelim, cColor, lPrint ) +#else +METHOD TextPrint( nI, nLeft, lParagraph, nJustify, nSpace, nNew, nLength, nLineLen, nLines, nStart, cString, cDelim, cColor, lPrint ) +#endif + +local nFinish, nL, nB, nJ, cToken, nRow + + nFinish := nI + + nL := nLeft + IF lParagraph + IF nJustify <> 2 + nL += nSpace * nNew + ENDIF + ENDIF + + IF nJustify == 3 // right + nL += nLength - nLineLen + ELSEIF nJustify == 2 // center + nL += ( nLength - nLineLen ) / 2 + ENDIF + + ++nLines + IF lPrint + nRow := ::NewLine( 1 ) + ENDIF + nB := nSpace + IF nJustify == 4 + nB := ( nLength - nLineLen + ( nFinish - nStart ) * nSpace ) / ( nFinish - nStart ) + ENDIF + for nJ := nStart to nFinish + cToken := token( cString, cDelim, nJ ) + IF lPrint + // version 0.02 + ::AtSay( cColor + cToken, ::R2M( nRow + ::aReport[ PDFTOP ] ), nL, "M" ) + ENDIF + nL += ::Length( cToken ) + nB + next + + nStart := nFinish + 1 + + lParagraph := .f. + + nLineLen := 0.00 + nLineLen += nSpace * nNew + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:TextNextPara( cString, cDelim, nI ) +#else +METHOD TextNextPara( cString, cDelim, nI ) +#endif + +local nAt, cAt, nCRLF, nNew, nRat, nRet := 0 + // check if next spaces paragraph(s) + nAt := attoken( cString, cDelim, nI ) + len( token( cString, cDelim, nI ) ) + cAt := substr( cString, nAt, attoken( cString, cDelim, nI + 1 ) - nAt ) + nCRLF := numat( chr(13) + chr(10), cAt ) + nRat := rat( chr(13) + chr(10), cAt ) + nNew := len( cAt ) - nRat - IIF( nRat > 0, 1, 0 ) + IF nCRLF > 1 .or. ( nCRLF == 1 .and. nNew > 0 ) + nRet := nCRLF + ENDIF +return nRet + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:ClosePage() +#else +METHOD ClosePage() +#endif + +local cTemp, cBuffer, nBuffer, nRead, nI, k, nImage, nFont, nImageHandle + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + + aadd( ::aReport[ PAGES ], ::aReport[ REPORTOBJ ] + 1 ) + + cTemp := ; + ltrim(str( ++::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /Page /Parent 1 0 R" + CRLF + ; + "/Resources " + ltrim(str( ++::aReport[ REPORTOBJ ] )) + " 0 R" + CRLF + ; + "/MediaBox [ 0 0 " + ltrim(transform( ::aReport[ PAGEX ], "9999.99")) + " " + ; + ltrim(transform(::aReport[ PAGEY ], "9999.99")) + " ]" + CRLF + ; + "/Contents " + ltrim(str( ++::aReport[ REPORTOBJ ] )) + " 0 R" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + cTemp := ; + ltrim(str(::aReport[ REPORTOBJ ] - 1)) + " 0 obj" + CRLF + ; + "<<"+CRLF+; + "/ColorSpace << /DeviceRGB /DeviceGray >>" + CRLF + ; //version 0.01 + "/ProcSet [ /PDF /Text /ImageB /ImageC ]" + + IF len( ::aReport[ PAGEFONTS ] ) > 0 + cTemp += CRLF + ; + "/Font" + CRLF + ; + "<<" + + for nI := 1 to len( ::aReport[ PAGEFONTS ] ) + nFont := ascan( ::aReport[ FONTS ], { |arr| arr[1] == ::aReport[ PAGEFONTS ][ nI ] } ) + cTemp += CRLF + "/Fo" + ltrim(str( nFont )) + " " + ltrim(str( ::aReport[ FONTS ][ nFont ][ 2 ])) + " 0 R" + next + + cTemp += CRLF + ">>" + ENDIF + + IF len( ::aReport[ PAGEIMAGES ] ) > 0 + cTemp += CRLF + "/XObject" + CRLF + "<<" + for nI := 1 to len( ::aReport[ PAGEIMAGES ] ) + nImage := ascan( ::aReport[ IMAGES ], { |arr| arr[1] == ::aReport[ PAGEIMAGES ][ nI ][ 1 ] } ) + IF nImage == 0 + aadd( ::aReport[ IMAGES ], { ::aReport[ PAGEIMAGES ][ nI ][ 1 ], ++::aReport[ NEXTOBJ ], ::ImageInfo( ::aReport[ PAGEIMAGES ][ nI ][ 1 ] ) } ) + nImage := len( ::aReport[ IMAGES ] ) + ENDIF + cTemp += CRLF + "/Image" + ltrim(str( nImage )) + " " + ltrim(str( ::aReport[ IMAGES ][ nImage ][ 2 ])) + " 0 R" + next + cTemp += CRLF + ">>" + ENDIF + + cTemp += CRLF + ">>" + CRLF + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + cTemp := ltrim(str( ::aReport[ REPORTOBJ ] )) + " 0 obj << /Length " + ; + ltrim(str( ::aReport[ REPORTOBJ ] + 1 )) + " 0 R >>" + CRLF +; + "stream" + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + IF len( ::aReport[ PAGEIMAGES ] ) > 0 + cTemp := "" + for nI := 1 to len( ::aReport[ PAGEIMAGES ] ) + cTemp += CRLF + "q" + nImage := ascan( ::aReport[ IMAGES ], { |arr| arr[1] == ::aReport[ PAGEIMAGES ][ nI ][ 1 ] } ) + cTemp += CRLF + ltrim(str( IIF( ::aReport[ PAGEIMAGES ][ nI ][ 5 ] == 0, ::M2X( ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_WIDTH ] / ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_XRES ] * 25.4 ), ::aReport[ PAGEIMAGES ][ nI ][ 5 ]))) + ; + " 0 0 " + ; + ltrim(str( IIF( ::aReport[ PAGEIMAGES ][ nI ][ 4 ] == 0, ::M2X( ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_HEIGHT ] / ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_YRES ] * 25.4 ), ::aReport[ PAGEIMAGES ][ nI ][ 4 ]))) + ; + " " + ltrim(str( ::aReport[ PAGEIMAGES ][ nI ][ 3 ] )) + ; + " " + ltrim(str( ::aReport[ PAGEY ] - ::aReport[ PAGEIMAGES ][ nI ][ 2 ] - ; + IIF( ::aReport[ PAGEIMAGES ][ nI ][ 4 ] == 0, ::M2X( ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_HEIGHT ] / ::aReport[ IMAGES ][ nImage ][ 3 ][ IMAGE_YRES ] * 25.4 ), ::aReport[ PAGEIMAGES ][ nI ][ 4 ]))) + " cm" + cTemp += CRLF + "/Image" + ltrim(str( nImage )) + " Do" + cTemp += CRLF + "Q" + next + ::aReport[ PAGEBUFFER ] := cTemp + ::aReport[ PAGEBUFFER ] + ENDIF + + cTemp := ::aReport[ PAGEBUFFER ] + + cTemp += CRLF + "endstream" + CRLF + ; + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + cTemp := ltrim(str( ++::aReport[ REPORTOBJ ] )) + " 0 obj" + CRLF + ; + ltrim(str(len( ::aReport[ PAGEBUFFER ] ))) + CRLF + ; + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + for nI := 1 to len( ::aReport[ FONTS ] ) + IF ::aReport[ FONTS ][ nI ][ 2 ] > ::aReport[ REPORTOBJ ] + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + + cTemp := ; + ltrim(str( ::aReport[ FONTS ][ nI ][ 2 ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /Font" + CRLF + ; + "/Subtype /Type1" + CRLF + ; + "/Name /Fo" + ltrim(str( nI )) + CRLF + ; + "/BaseFont /" + ::aReport[ TYPE1 ][ ::aReport[ FONTS ][ nI ][ 1 ] ] + CRLF + ; + "/Encoding /WinAnsiEncoding" + CRLF + ; + ">>" + CRLF + ; + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + ENDIF + next + + for nI := 1 to len( ::aReport[ IMAGES ] ) + IF ::aReport[ IMAGES ][ nI ][ 2 ] > ::aReport[ REPORTOBJ ] + + aadd( ::aReport[ REFS ], ::aReport[ DOCLEN ] ) + + cTemp := ; + ltrim(str( ::aReport[ IMAGES ][ nI ][ 2 ] )) + " 0 obj" + CRLF + ; + "<<" + CRLF + ; + "/Type /XObject" + CRLF + ; + "/Subtype /Image" + CRLF + ; + "/Name /Image" + ltrim(str(nI)) + CRLF + ; + "/Filter [" + IIF( at( ".JPG", upper( ::aReport[ IMAGES ][ nI ][ 1 ]) ) > 0, " /DCTDecode", "" ) + " ]" + CRLF + ; + "/Width " + ltrim(str( ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_WIDTH ] )) + CRLF + ; + "/Height " + ltrim(str( ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_HEIGHT ] )) + CRLF + ; + "/BitsPerComponent " + ltrim(str( ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_BITS ] )) + CRLF + ; + "/ColorSpace /" + IIF( ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_BITS ] == 1, "DeviceGray", "DeviceRGB") + CRLF + ; + "/Length " + ltrim(str( ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ])) + CRLF + ; + ">>" + CRLF + ; + "stream" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + nImageHandle := fopen( ::aReport[ IMAGES ][ nI ][ 1 ] ) + fseek( nImageHandle, ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_FROM ] ) + + nBuffer := 8192 + cBuffer := space( nBuffer ) + k := 0 + while k < ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] + IF k + nBuffer <= ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] + nRead := nBuffer + ELSE + nRead := ::aReport[ IMAGES ][ nI ][ 3 ][ IMAGE_LENGTH ] - k + ENDIF + fread( nImageHandle, @cBuffer, nRead ) + + ::aReport[ DOCLEN ] += nRead + fwrite( ::aReport[ HANDLE ], cBuffer, nRead ) + k += nRead + enddo + + cTemp := CRLF + "endstream" + CRLF + "endobj" + CRLF + + ::aReport[ DOCLEN ] += len( cTemp ) + fwrite( ::aReport[ HANDLE ], cTemp ) + + fClose( nImageHandle ) + ENDIF + next + + ::aReport[ REPORTOBJ ] := ::aReport[ NEXTOBJ ] + + ::aReport[ NEXTOBJ ] := ::aReport[ REPORTOBJ ] + 4 + + ::aReport[ PAGEBUFFER ] := "" + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:FilePrint( cFile ) +#else +METHOD FilePrint( cFile ) +#endif +local cPathAcro := "c:\progra~1\Adobe\Acroba~1.0\Reader" +local cRun := cPathAcro + "\AcroRd32.exe /t " + cFile + " " + ; + chr(34) + "HP LaserJet 5/5M PostScript" + chr(34) + " " + ; + chr(34) + "LPT1" + chr(34) + +IF ( ! RunExternal( cRun, 'print' ) ) + alert( "Error printing to PDF reader." ) + break +ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#ifdef __XPP__ +METHOD tPdf:Execute( cFile ) +#else +METHOD Execute( cFile ) +#endif +// Replace cPathAcro with the path at your system +local cPathAcro := "c:\progra~1\Adobe\Acroba~1.0\Reader" +local cRun := cPathAcro + "\AcroRd32.exe /t " + cFile + " " + chr(34) + "HP LaserJet 5/5M PostScript" + chr(34) + " " + chr(34) + "LPT1" + chr(34) + +IF (! RunExternal( cRun, 'open', cFile ) ) + alert("Error printing to PDF reader.") + break +ENDIF + +RETURN self + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function FilePos( nHandle ) +return ( FSEEK( nHandle, 0, FS_RELATIVE ) ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ +/* +static function stuff( cStr, nBeg, nDel, cIns ) +return PosIns( PosDel( cStr, nBeg, nDel ), cIns, nBeg ) +*/ +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function Chr_RGB( cChar ) +return str(asc( cChar ) / 255, 4, 2) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function TimeAsAMPM( cTime ) + IF VAL(cTime) < 12 + cTime += " am" + ELSEIF VAL(cTime) = 12 + cTime += " pm" + ELSE + cTime := STR(VAL(cTime) - 12, 2) + SUBSTR(cTime, 3) + " pm" + ENDIF + cTime := left( cTime, 5 ) + substr( cTime, 10 ) +return cTime + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function FileSize( cFile ) + + LOCAL nLength + LOCAL nHandle + + nHandle := fOpen( cFile ) + nLength := fSeek( nHandle, 0, FS_END ) + fClose( nHandle ) + +return ( nLength ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static FUNCTION NumToken( cString, cDelimiter ) +RETURN AllToken( cString, cDelimiter ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static FUNCTION Token( cString, cDelimiter, nPointer ) +RETURN AllToken( cString, cDelimiter, nPointer, 1 ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function AtToken( cString, cDelimiter, nPointer ) +return AllToken( cString, cDelimiter, nPointer, 2 ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function AllToken( cString, cDelimiter, nPointer, nAction ) +local nTokens := 0 +local nPos := 1 +local nLen := len( cString ) +local nStart := 0 +local cToken := "" +local cRet := 0 + +DEFAULT cDelimiter TO chr(0)+chr(9)+chr(10)+chr(13)+chr(26)+chr(32)+chr(138)+chr(141) +DEFAULT nAction to 0 + +// nAction == 0 - numtoken +// nAction == 1 - token +// nAction == 2 - attoken + +while nPos <= nLen + if .not. substr( cString, nPos, 1 ) $ cDelimiter + nStart := nPos + while nPos <= nLen .and. .not. substr( cString, nPos, 1 ) $ cDelimiter + ++nPos + enddo + ++nTokens + IF nAction > 0 + IF nPointer == nTokens + IF nAction == 1 + cRet := substr( cString, nStart, nPos - nStart ) + ELSE + cRet := nStart + ENDIF + exit + ENDIF + ENDIF + endif + if substr( cString, nPos, 1 ) $ cDelimiter + while nPos <= nLen .and. substr( cString, nPos, 1 ) $ cDelimiter + ++nPos + enddo + endif + cRet := nTokens +ENDDO + +RETURN cRet + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ +// +// next 3 function written by Peter Kulek +// modified for compatibility with common.ch by V.K. +// modified DATE processing by V.K. +// +static function Array2File( cFile, aRay, nDepth, hFile ) +local nBytes := 0 +local i +local lOpen := ( hFile <> nil ) + +nDepth := if( ISNUMBER( nDepth ), nDepth, 0 ) +//if hFile == NIL +if !lOpen + if ( hFile := fCreate( cFile,FC_NORMAL ) ) == -1 + return ( nBytes ) + endif +endif +nDepth++ +nBytes += WriteData( hFile,aRay ) +if ISARRAY( aRay ) + for i := 1 to len( aRay ) + nBytes += Array2File( cFile,aRay[i],nDepth,hFile ) + next +endif +nDepth-- +// if nDepth == 0 +if !lOpen + fClose(hFile) +endif + +return( nBytes ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function WriteData(hFile,xData) +local cData := valtype(xData) + + if ISCHARACTER(xData) + cData += i2bin( len( xData ) ) + xData + elseif ISNUMBER(xData) + cData += i2bin( len( alltrim( str( xData ) ) ) ) + alltrim( str( xData ) ) + elseif ISDATE( xData ) + cData += i2bin( 8 )+dtos(xData) + elseif ISLOGICAL(xData) + cData += i2bin( 1 )+if( xData,'T','F' ) + elseif ISARRAY( xData ) + cData += i2bin( len( xData ) ) + else + cData += i2bin( 0 ) // NIL + endif + +return( fWrite( hFile, cData, len( cData ) ) ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function File2Array( cFile, nLen, hFile ) +LOCAL cData,cType,nDataLen,nBytes +local nDepth := 0 +local aRay := {} +local lOpen := ( hFile <> nil ) + +if hFile == NIL // First Timer + if ( hFile := fOpen( cFile,FO_READ ) ) == -1 + return( aRay ) + endif + cData := space( 3 ) + fRead( hFile, @cData, 3 ) + if left( cData,1 ) != 'A' // If format of file <> array + fClose( hFile ) ////////// + return( aRay ) + endif + nLen := bin2i( right( cData,2 ) ) +endif + +do while nDepth < nLen + cData := space( 3 ) + nBytes := fRead( hFile, @cData, 3 ) + if nBytes < 3 + exit + endif + cType := padl( cData,1 ) + nDataLen := bin2i( right( cData,2 ) ) + if cType != 'A' + cData := space( nDataLen ) + nBytes:= fRead( hFile, @cData, nDataLen ) + if nBytes < nDataLen + exit + endif + endif + nDepth++ + aadd( aRay,NIL ) + if cType=='C' + aRay[ nDepth ] := cData + elseif cType=='N' + aRay[ nDepth ] := val(cData) + elseif cType=='D' + aRay[ nDepth ] := ctod( left( cData, 4 ) + "/" + substr( cData, 5, 2 ) + "/" + substr( cData, 7, 2 )) //stod(cData) + elseif cType=='L' + aRay[ nDepth ] := ( cData=='T' ) + elseif cType=='A' + aRay[ nDepth ] := File2Array( , nDataLen, hFile ) + endif +enddo + +if !lOpen + fClose( hFile ) +endif + +return ( aRay ) + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static FUNCTION NumAt( cSearch, cString ) + + LOCAL n := 0, nAt := 0, nPos := 0 + WHILE ( nAt := at( cSearch, substr( cString, nPos + 1 ) )) > 0 + nPos += nAt + ++n + ENDDO + +RETURN n + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +static function RunExternal( cCmd, cVerb, cFile ) +local lRet := .t. + +#ifdef __CLP__ + lRet := SwpRunCmd( cCmd, 0, '', '' ) +#endif + +#ifdef __HARBOUR__ + if cVerb <> nil +// TOFIX: This requires hbwhat32, which in turns requires xhb. +// This has to solved differently. +// ShellExecute( GetDeskTopWindow(), cVerb, cFile, , , 1 ) + HB_SYMBOL_UNUSED( cFile ) + else + __Run( cCmd ) + endif +#endif + +#ifdef __XPP__ + RunShell( cCmd, , .t., .t. ) +#endif + +return lRet + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ diff --git a/harbour/contrib/hbvpdf/make_b32.bat b/harbour/contrib/hbvpdf/make_b32.bat new file mode 100644 index 0000000000..c484512c4c --- /dev/null +++ b/harbour/contrib/hbvpdf/make_b32.bat @@ -0,0 +1,6 @@ +@echo off +rem +rem $Id$ +rem + +call ..\mtpl_b32.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/hbvpdf/make_gcc.sh b/harbour/contrib/hbvpdf/make_gcc.sh new file mode 100644 index 0000000000..0593942308 --- /dev/null +++ b/harbour/contrib/hbvpdf/make_gcc.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# +# $Id$ +# + +../mtpl_gcc.sh $1 $2 $3 $4 $5 $6 $7 $8 $9 diff --git a/harbour/contrib/hbvpdf/make_vc.bat b/harbour/contrib/hbvpdf/make_vc.bat new file mode 100644 index 0000000000..4ceb9b9261 --- /dev/null +++ b/harbour/contrib/hbvpdf/make_vc.bat @@ -0,0 +1,6 @@ +@echo off +rem +rem $Id$ +rem + +call ..\mtpl_vc.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/hbvpdf/tests/bld_b32.bat b/harbour/contrib/hbvpdf/tests/bld_b32.bat new file mode 100644 index 0000000000..fb0090c8f7 --- /dev/null +++ b/harbour/contrib/hbvpdf/tests/bld_b32.bat @@ -0,0 +1,22 @@ +@echo off +rem +rem $Id$ +rem + +rem --------------------------------------------------------------- +rem This is a generic template file, if it doesn't fit your own needs +rem please DON'T MODIFY IT. +rem +rem Instead, make a local copy and modify that one, or make a call to +rem this batch file from your customized one. [vszakats] +rem --------------------------------------------------------------- + +set HB_BIN_INSTALL=..\..\..\bin +set HB_INC_INSTALL=..\..\..\include +set HB_LIB_INSTALL=..\..\..\lib + +set HB_ARCHITECTURE=w32 +set HB_COMPILER=bcc32 +set HB_USER_LIBS=hbvpdf.lib + +call %HB_BIN_INSTALL%\bld.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/hbvpdf/tests/bld_vc.bat b/harbour/contrib/hbvpdf/tests/bld_vc.bat new file mode 100644 index 0000000000..ad40d03dc8 --- /dev/null +++ b/harbour/contrib/hbvpdf/tests/bld_vc.bat @@ -0,0 +1,22 @@ +@echo off +rem +rem $Id$ +rem + +rem --------------------------------------------------------------- +rem This is a generic template file, if it doesn't fit your own needs +rem please DON'T MODIFY IT. +rem +rem Instead, make a local copy and modify that one, or make a call to +rem this batch file from your customized one. [vszakats] +rem --------------------------------------------------------------- + +set HB_BIN_INSTALL=..\..\..\bin +set HB_INC_INSTALL=..\..\..\include +set HB_LIB_INSTALL=..\..\..\lib + +set HB_ARCHITECTURE=w32 +set HB_COMPILER=msvc +set HB_USER_LIBS=hbvpdf.lib + +call %HB_BIN_INSTALL%\bld.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/hbvpdf/tests/files/color.jpg b/harbour/contrib/hbvpdf/tests/files/color.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38140c23c6e3affcc0d9f6bfcb4e97a1b6021215 GIT binary patch literal 52799 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�oihU6V|3WCEhl+)fx509F2p;K@-QJ z#1}G5<-G_YwUl(T6iz7Glv_=Y^5* z26E~Ld7%u(>O2$Bo_{Kr&AD-$Hq_0ZPgLZ*c+ag@YjhnLdtphZb=0LP3}{qv zWF!6qK(>hBq0c=}6en`-($H_&cCgHf0XfHdu&_otvHJBC^%I@+9QNmH6_kz&i;CoQ5Atx>f?NZw=(I)dGDYU*9uoWKpN#XZru6fNheujSP zdZEhmrwp5y(A2U*!4;Y^o4RE1Y3{8gCuGx$A8c-6B%^Vjgk)9ZxVVjXxeK4W&MMg{f>9%lhd z55-tYcCNPkjlOQ;kpW;s6o<04&&w zf?LaJNoe6z@p1;bVH@2|+kV4FHjl=<(#!`xR>S+pdYTF=thmtYpF*wd6i#Q)# z^`e3QkV)B{mToIWA?niR43p9>bh_ z1O0vLJ!D33L&^`-06z>=I=bkKjVEnNw@q`C<;@`eTHfOIr`+4*JxOtqLYuj= zg+5nvTHf~QR5Q&IDLBId59w1k??XtkM7^?5wtpPfyv_AE?faX-O=KbURV9kb5Z~$O<{_ zu(>a}PHVYkB(ofz!=*s;91NZXPctu-B0sb`ju?TQ;2Mdf^DIW zn9utp(ApNLa0Kvn;Pm-N^rx=H`^vcDN;;;u;{F~6>*KUW>qD9 zP%GsQ(-`lHNbdqMkrWIZ6T1iUs?l^ZNy_TwiKUL?0K}Z~4oD;M6;xc^+e`|w$b+gs z%n1H3S7%HxWNe`@t&CjwLop{1MN_u zvCs@tjBJUN+@6EQy|RPmAkSlw#aFmpF$N@(IQ#skar}U$+FG$iNxLF68c;%4YY%bT z@~6cvj5#QeobaoReQ8-UMbCZN9M{@ZA1qLiPhF}0CbQ>#K1MQbDeOmIz);e)nNfvA z`J=7MZeo<}hju&e6?WRv&Ox!RiElu-{*%_lj=J6(h5PEYRK?DfY=l07<9A2a#D z0x-uM;+$!;_cN9%Ei0mwkWafFO0M435mE>5ASc{4CZ+tQ(Ucm}T8&@bu2cojT#gM+ YE+c4ytZ$Lm2S3h|v~(Pz<*m>E*}Y%`Pyhe` literal 0 HcmV?d00001 diff --git a/harbour/contrib/hbvpdf/tests/files/color.tif b/harbour/contrib/hbvpdf/tests/files/color.tif new file mode 100644 index 0000000000000000000000000000000000000000..325513e14569f7e28c87ce5148789693644bf9de GIT binary patch literal 40188 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 literal 0 HcmV?d00001 diff --git a/harbour/contrib/hbvpdf/tests/files/test.txt b/harbour/contrib/hbvpdf/tests/files/test.txt new file mode 100644 index 0000000000..5498e372f0 --- /dev/null +++ b/harbour/contrib/hbvpdf/tests/files/test.txt @@ -0,0 +1,12 @@ +(sample text) + +THE HARBOUR PROJECT CONTRIB LICENSE +=================================== + +There is no one single license that applies to the Harbour Project +contrib files. Some files use the Harbour Project Compiler license. +Some files use the Harbour Project Library license. Some files use +the old Harbour Project Library license. Some files may even use other +types of free software or open source software licenses. Some files +have been donated to the public domain. If you use any of the contrib +files, you need to investigate the license that applies to each file. diff --git a/harbour/contrib/hbvpdf/tests/fonts.dat b/harbour/contrib/hbvpdf/tests/fonts.dat new file mode 100644 index 0000000000000000000000000000000000000000..37957e64abc843c1d9fb7daa3ef19535853eb390 GIT binary patch literal 5376 zcmeH}F>6#o5Xax_vyihi917+Wc%`IBWeOn(XKf)iSKHX#2e`({GLlY3+bb*sR)U@I zAQlqDGL=<8NR|2T-0$Aq9*;l>TKI05n>V{N|DBzgxBJek^GstC&FsMLr}xfhwoZHX zX}#w($ULaSe)Au%2WdCGa}M9dAWo+`&?iCSvMnASk>4WVq>q}k8ht^arjuuqvvR7`~dPSV9qd7gx zPne9WZ?xyYi!}m+=a6GxceX;Sc&o7}56W-E8c4(}|6lgXUfVPKTAft4?W98APB+uG z_hr@p)-n+Nq3&I$k5$n6=%)6m8rpYf)trjTivB{5yh~+)B#2GK7~#CY?u*?^w;bX5 zg1}{6BzUL(o=lw~aAYS!2j{A?3#V(Gb%+nUe?hv- zQLd%1SV!LuBJA;x8~1PnkMUSd_hS&_>M;>I5_|SfT`&|4XA!V|v(#W(CuW_0?1{_kaEfcKL+Bf0<3yX5EU zcO}-Bkr+F0k!LpXv#DkBk9{fWU+nIB=Zd-i=r7hqg2TOs1c&zoo%pUQyKuV3S*MH( z`@b#AI9^)NWpVKSa-MZ#8_pMgFDeFpjr I{C^p^0Qi=GfB*mh literal 0 HcmV?d00001 diff --git a/harbour/contrib/hbvpdf/tests/pdf_demo.prg b/harbour/contrib/hbvpdf/tests/pdf_demo.prg new file mode 100644 index 0000000000..538275a56e --- /dev/null +++ b/harbour/contrib/hbvpdf/tests/pdf_demo.prg @@ -0,0 +1,224 @@ +/* + * $Id$ + */ + +#include "hbvpdf.ch" + +memvar aReport + +procedure main() + + local cRun, nWidth, nTab, nI, nJ, nK, nCol, nRow, aStyle, aFonts + local nTop, nLeft, nBottom, nRight + local aColor := { ; + "FF0000", "8B0000", "800000", "FF4500", "D2691E", "B8860B", "FF8C00", "FFA500", "DAA520", "808000", "FFD700", "FFFF00", "ADFF2F", "9ACD32", "7FFF00", "7CFC00", "00FF00", "32CD32", "008000", "006400",; + "66CDAA", "7FFFD4", "87CEFA", "87CEEB", "F0F8FF", "E0FFFF", "B0C4DE", "B0E0E6", "AFEEEE", "ADD8E6", "8FBC8F", "90EE90", "98FB98", "00FA9A", "00FF7F", "3CB371", "2E8B57", "228B22", "556B2F", "6B8E23",; + "5F9EA0", "40E0D0", "48D1CC", "00CED1", "20B2AA", "008B8B", "008080", "2F4F4F", "00BFFF", "00FFFF", "00FFFF", "0000FF", "0000CD", "00008B", "000080", "1E90FF", "4169E1", "4682B4", "6495ED", "7B68EE",; + "C71585", "FF1493", "FF00FF", "FF00FF", "9370DB", "DDADDD", "DB7093", "FF69B4", "DA70D6", "EE82EE", "BA55D3", "9932CC", "8A2BE2", "9400D3", "8B008B", "800080", "4B0082", "191970", "483D8B", "6A5ACD",; + "DC143C", "B22222", "A52A2A", "CD5C5C", "FA8072", "E9967A", "FFA07A", "F5DEB3", "FFDEAD", "EEE8AA", "FFDAB9", "FFE4C4", "FFEFD5", "FFE4E1", "FFE4B5", "D2B48C", "DEB887", "F0E68C", "BDB76B", "F4A460",; + "FDF5E6", "FFF8DC", "FAF0E6", "FAFAD2", "FFFACD", "FFEBCD", "FFFFE0", "FAEBD7", "FFF5EE", "FFF0F5", "D8BFD8", "FFC0CB", "FFB6C1", "BC8F8F", "F08080", "FF7F50", "FF6347", "8B4513", "A0522D", "CD853F",; + "FFFAFA", "FFFFF0", "E6E6FA", "FFFAF0", "F8F8FF", "F0FFF0", "F5F5DC", "F0FFFF", "F5FFFA", "708090", "778899", "F5F5F5", "DCDCDC", "D3D3D3", "C0C0C0", "A9A9A9", "808080", "696969", "000000", "FFFFFF"} + + PUBLIC aReport := array( PARAMLEN ) + + set date format "YYYY/MM/DD" // important for save/load array function!!! + + aStyle := { "Normal", "Bold", "Italic", "BoldItalic" } + + aFonts := { { "Times", .t., .t., .t., .t. },; + { "Helvetica", .t., .t., .t., .t. },; + { "Courier", .t., .t., .t., .t. } } + + pdfOpen('test.pdf', 200, .t.) + + pdfEditOnHeader() + pdfImage( 'files\color.tif', 0, 0, "M" ) // file, row, col, units, height, width + pdfEditOffHeader() + pdfSaveHeader('test.hea') + pdfCloseHeader() + + pdfBookOpen() + + /* + pdfCreateHeader( "letter_portrait_6.hea", "LETTER", "P", 6 ) + pdfCreateHeader( "letter_portrait_8.hea", "LETTER", "P", 8 ) + pdfCreateHeader( "letter_landscape_6.hea", "LETTER", "L", 6 ) + pdfCreateHeader( "letter_landscape_8.hea", "LETTER", "L", 8 ) + pdfCreateHeader( "legal_portrait_6.hea", "LEGAL", "P", 6 ) + pdfCreateHeader( "legal_portrait_8.hea", "LEGAL", "P", 8 ) + pdfCreateHeader( "legal_landscape_6.hea", "LEGAL", "L", 6 ) + pdfCreateHeader( "legal_landscape_8.hea", "LEGAL", "L", 8 ) + */ + + pdfNewPage( "LETTER", "P", 6 ) + + pdfBookAdd( "Grids & Borders", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "Simple Grid", 2, aReport[ REPORTPAGE ], 0 ) + + for nI := 0 to 792 step 36 + pdfBox( nI, 0, nI, 612, 0.01, , "D" ) + next + for nI := 0 to 612 step 36 + pdfBox( 0, nI, 792, nI, 0.01, , "D" ) + next + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "10 dots border ", 2, aReport[ REPORTPAGE ], 0 ) + pdfBox( 0, 0, 792, 612, 10, , "D" ) + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Boxes", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "Boxes", 2, aReport[ REPORTPAGE ], 0 ) + + nRow := 85 + nCol := 85 + pdfBox( nRow , ( nCol * 2 ) , ( nRow * 3 ) , ( nCol * 4 ) , 1.00, 15, "D" ) + pdfBox( nRow + 10, ( nCol * 2 ) + 10, ( nRow * 3 ) + 10, ( nCol * 4 ) + 10, 0.50, 25, "D" ) + pdfBox( nRow + 20, ( nCol * 2 ) + 20, ( nRow * 3 ) + 20, ( nCol * 4 ) + 20, 0.25, 35, "D" ) + pdfBox( nRow + 30, ( nCol * 2 ) + 30, ( nRow * 3 ) + 30, ( nCol * 4 ) + 30, 0.15, 45, "D" ) + pdfBox( nRow + 40, ( nCol * 2 ) + 40, ( nRow * 3 ) + 40, ( nCol * 4 ) + 40, 0.10, 55, "D" ) + pdfBox( nRow + 50, ( nCol * 2 ) + 50, ( nRow * 3 ) + 50, ( nCol * 4 ) + 50, 0.05, 65, "D" ) + pdfBox( nRow + 60, ( nCol * 2 ) + 60, ( nRow * 3 ) + 60, ( nCol * 4 ) + 60, 0.01, 75, "D" ) + pdfBox( nRow + 70, ( nCol * 2 ) + 70, ( nRow * 3 ) + 70, ( nCol * 4 ) + 70, 0.01, 85, "D" ) + pdfBox( nRow + 80, ( nCol * 2 ) + 80, ( nRow * 3 ) + 80, ( nCol * 4 ) + 80, 0.01, 95, "D" ) + pdfBox( nRow + 90, ( nCol * 2 ) + 90, ( nRow * 3 ) + 90, ( nCol * 4 ) + 90, 0.01, 100, "D" ) + + /* + nRow := 12 + nCol := 120 + for nI := 1 to 6 + nRow += 10 + nCol += 10 + pdfBox( nCol, nRow, nCol + 10, nRow + 10, 0.5, nI, "M" ) + next + for nI := 0 to 20 step 10 + nRow += 10 + nCol += 10 + pdfBox( nCol, nRow, nCol + 10, nRow + 10, 0.5, nI,"M" ) + next + for nI := 30 to 100 step 10 + nRow += 10 + nCol -= 10 + pdfBox( nCol, nRow, nCol + 10, nRow + 10, 0.5, nI,"M" ) + next + */ + + for nI := 1 to 7 + nRow := 150 + nI * 10 + for nJ := 1 to 20 + nCol := nJ * 10 - 3 + pdfBox( nRow, nCol, nRow + 10, nCol + 10, 0.01, nI * 10,"M", chr(253) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 1, 2 ), 16) ) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 3, 2 ), 16) ) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 5, 2 ), 16) ) ) + next + next + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Color Boxes ", 2, aReport[ REPORTPAGE ], 0 ) + for nI := 1 to 140 + nTop := ( nI - 1 ) * 2.4 + nLeft := ( nI - 1 ) * 2.1 + nBottom := aReport[ PAGEY ] - ( nI - 1 ) * 2.47 + nRight := aReport[ PAGEX ] - ( nI - 1 ) * 2.18 + pdfBox1( nTop, nLeft, nBottom, nRight, 10, chr( cton( substr( aColor[ nI ], 1, 2 ), 16) ) + chr( cton( substr( aColor[ nI ], 3, 2 ), 16) ) + chr( cton( substr( aColor[ nI ], 5, 2 ), 16) )) + next + + pdfNewPage( "LETTER", "P", 6 ) + pdfBox1( 0, 0, 100, 200, 10, chr(0) + chr(255) + chr(0), chr(255) + chr(255) + chr(0) ) + pdfBookAdd( "Memos", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "Different Styles & Colors", 2, aReport[ REPORTPAGE ], 0 ) + nWidth := 90 + nTab := 0 + + pdfText( memoread('files\test.txt'), 28, 107.95, nWidth, nTab, 3, 'M', chr(253) + chr(0) + chr(0) + chr(255) )//, pdfTextCount( memoread('test.txt'), 28, 107.95, nWidth, nTab, 3, 'M' ) + pdfText( memoread('files\test.txt'), 58, 107.95, nWidth, nTab, 2, 'M', chr(253) + chr(0) + chr(255) + chr(0) )//, pdfTextCount( memoread('test.txt'), 58, 107.95, nWidth, nTab, 2, 'M' ) + pdfText( memoread('files\test.txt'), 88, 107.95, nWidth, nTab, 1, 'M', chr(253) + chr(255) + chr(0) + chr(0) )//, pdfTextCount( memoread('test.txt'), 88, 107.95, nWidth, nTab, 1, 'M' ) + pdfText( memoread('files\test.txt'), 118, 107.95 - nWidth / 2, nWidth, nTab, 4, 'M', chr(253) + chr(255) + chr(255) + chr(0) )//, pdfTextCount( memoread('test.txt'), 118, 107.95 - nWidth / 2, nWidth, nTab, 4, 'M' ) + + pdfText( memoread('files\test.txt'), 34, 100, nWidth, nTab, 3, 'R', chr(253) + chr(0) + chr(128) + chr(128) )//, pdfTextCount( memoread('test.txt'), 33, 100, nWidth, nTab, 3, 'R' ) + pdfText( memoread('files\test.txt'), 41, 100, nWidth, nTab, 2, 'R', chr(253) + chr(0) + chr(191) + chr(255) )//, pdfTextCount( memoread('test.txt'), 40, 100, nWidth, nTab, 2, 'R' ) + pdfText( memoread('files\test.txt'), 48, 100, nWidth, nTab, 1, 'R', chr(253) + chr(244) + chr(164) + chr(96) )//, pdfTextCount( memoread('test.txt'), 47, 100, nWidth, nTab, 1, 'R' ) + pdfText( memoread('files\test.txt'), 55, 35, nWidth, nTab, 4, 'R', chr(253) + chr(0) + chr(0) + chr(0) )//, pdfTextCount( memoread('test.txt'), 54, 35, nWidth, nTab, 4, 'R' ) + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Fonts", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "Different Styles", 2, aReport[ REPORTPAGE ], 0 ) + nK := 6 + for nI := 1 to len( aFonts ) + ++nK + for nJ := 1 to 4 + if aFonts[ nI ][ nJ + 1 ] + pdfSetFont( aFonts[ nI ][ 1 ], nJ - 1, aReport[ FONTSIZE ] ) + pdfRJust("This is a test for " + aFonts[ nI ][ 1 ] + " " + ; + aStyle[ nJ ], nK++, aReport[ REPORTWIDTH ], "R") + endif + next + pdfRJust(pdfUnderline("Underline"), nK++, aReport[ REPORTWIDTH ], "R") + pdfRJust(pdfReverse("Test"), nK, aReport[ REPORTWIDTH ], "R") + next + + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Pictures", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "TIFF", 2, aReport[ REPORTPAGE ], 0 ) + pdfImage( 'files\color.tif', 0, 0, "M" ) // file, row, col, units, height, width + pdfRJust(pdfUnderline("TIFF"), nK++, aReport[ REPORTWIDTH ], "R") + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "JPEG", 2, aReport[ REPORTPAGE ], 0 ) + pdfImage( 'files\color.jpg', 0, 0, "M" ) // file, row, col, units, height, width + pdfRJust(pdfUnderline("JPEG"), nK++, aReport[ REPORTWIDTH ], "R") + + pdfOpenHeader('test.hea') + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Headers", 1, aReport[ REPORTPAGE ], 0 ) + pdfBookAdd( "Picture Header Page 8", 2, aReport[ REPORTPAGE ], 0 ) + + // version 0.01 + pdfAtSay( chr(253) + chr(255) + chr(0) + chr(0) + 'Red Sample of header repeating on pages 8-10', 1, 20, "R" ) + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Picture Header Page 9", 2, aReport[ REPORTPAGE ], 0 ) + + // version 0.01 + pdfAtSay( chr(253) + chr(0) + chr(255) + chr(0) + 'Green Sample of header repeating on pages 8-10', 1, 20, "R" ) + + pdfNewPage( "LETTER", "P", 6 ) + pdfBookAdd( "Picture Header Page 10", 2, aReport[ REPORTPAGE ], 0 ) + + // version 0.01 + pdfAtSay( chr(253) + chr(0) + chr(0) + chr(255) + 'Blue Sample of header repeating on pages 8-10', 1, 20, "R" ) + + pdfClose() + +// pdfFilePrint( "test.pdf" ) // print .pdf file WITHOUT opening acrobat + +/* + cRun := "d:\progra~2\Adobe\Acroba~2.0\Reader\AcroRd32.exe " + "test.pdf" + + IF (!SWPRUNCMD( cRun, 0, "", "")) + alert(" Error running Acrobat Reader.") + break + ENDIF +*/ + +static function cton( cString, nBase ) // this function called only used in pdf_demo.prg +local cTemp, nI, cChar := "", n := 0, nLen + + nLen := len( cString ) + cTemp := "" + for nI := nLen to 1 step -1 + cTemp += substr( cString, nI, 1 ) + next + cTemp = upper( cTemp ) + + for nI = 1 to nLen + cChar = substr( cTemp, nI, 1 ) + if .not. IsDigit( cChar ) + n = n + ((Asc( cChar ) - 65) + 10) * ( nBase ^ ( nI - 1 ) ) + else + n = n + (( nBase ^ ( nI - 1 )) * val( cChar )) + endif + next + +return n + diff --git a/harbour/contrib/hbvpdf/tests/tstpdf.prg b/harbour/contrib/hbvpdf/tests/tstpdf.prg new file mode 100644 index 0000000000..9fed7d7576 --- /dev/null +++ b/harbour/contrib/hbvpdf/tests/tstpdf.prg @@ -0,0 +1,191 @@ +/* + * $Id$ + */ + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +#include "hbvpdf.ch" + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + +function Main() + + local cRun, nWidth, nTab, nI, nJ, nK, nCol, nRow, aStyle, aFonts + local nTop, nLeft, nBottom, nRight, cText, oPdf + local aColor := { ; + "FF0000", "8B0000", "800000", "FF4500", "D2691E", "B8860B", "FF8C00", "FFA500", "DAA520", "808000", "FFD700", "FFFF00", "ADFF2F", "9ACD32", "7FFF00", "7CFC00", "00FF00", "32CD32", "008000", "006400",; + "66CDAA", "7FFFD4", "87CEFA", "87CEEB", "F0F8FF", "E0FFFF", "B0C4DE", "B0E0E6", "AFEEEE", "ADD8E6", "8FBC8F", "90EE90", "98FB98", "00FA9A", "00FF7F", "3CB371", "2E8B57", "228B22", "556B2F", "6B8E23",; + "5F9EA0", "40E0D0", "48D1CC", "00CED1", "20B2AA", "008B8B", "008080", "2F4F4F", "00BFFF", "00FFFF", "00FFFF", "0000FF", "0000CD", "00008B", "000080", "1E90FF", "4169E1", "4682B4", "6495ED", "7B68EE",; + "C71585", "FF1493", "FF00FF", "FF00FF", "9370DB", "DDADDD", "DB7093", "FF69B4", "DA70D6", "EE82EE", "BA55D3", "9932CC", "8A2BE2", "9400D3", "8B008B", "800080", "4B0082", "191970", "483D8B", "6A5ACD",; + "DC143C", "B22222", "A52A2A", "CD5C5C", "FA8072", "E9967A", "FFA07A", "F5DEB3", "FFDEAD", "EEE8AA", "FFDAB9", "FFE4C4", "FFEFD5", "FFE4E1", "FFE4B5", "D2B48C", "DEB887", "F0E68C", "BDB76B", "F4A460",; + "FDF5E6", "FFF8DC", "FAF0E6", "FAFAD2", "FFFACD", "FFEBCD", "FFFFE0", "FAEBD7", "FFF5EE", "FFF0F5", "D8BFD8", "FFC0CB", "FFB6C1", "BC8F8F", "F08080", "FF7F50", "FF6347", "8B4513", "A0522D", "CD853F",; + "FFFAFA", "FFFFF0", "E6E6FA", "FFFAF0", "F8F8FF", "F0FFF0", "F5F5DC", "F0FFFF", "F5FFFA", "708090", "778899", "F5F5F5", "DCDCDC", "D3D3D3", "C0C0C0", "A9A9A9", "808080", "696969", "000000", "FFFFFF"} + + set date format "YYYY/MM/DD" + + aStyle := { "Normal", "Bold", "Italic", "BoldItalic" } + + aFonts := { { "Times", .t., .t., .t., .t. }, ; + { "Helvetica", .t., .t., .t., .t. }, ; + { "Courier", .t., .t., .t., .t. } } + + oPdf := tPdf():New( 'test.pdf', 200, .t. ) + oPdf:EditOnHeader() + oPdf:Image( 'files\color.tif', 0, 0, "M" ) + oPdf:EditOffHeader() + oPdf:SaveHeader( 'test.hea' ) + oPdf:CloseHeader() + oPdf:BookOpen() + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Grids & Borders", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "Simple Grid", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + + for nI := 0 to 792 step 36 + oPdf:Box( nI, 0, nI, 612, 0.01, , "D" ) + next + for nI := 0 to 612 step 36 + oPdf:Box( 0, nI, 792, nI, 0.01, , "D" ) + next + + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "10 dots border ", 2, 2, 0 ) + oPdf:Box( 0, 0, 792, 612, 10, , "D" ) + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Boxes", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "Boxes", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + + nRow := 85 + nCol := 85 + oPdf:Box( nRow , ( nCol * 2 ) , ( nRow * 3 ) , ( nCol * 4 ) , 1.00, 15, "D" ) + oPdf:Box( nRow + 10, ( nCol * 2 ) + 10, ( nRow * 3 ) + 10, ( nCol * 4 ) + 10, 0.50, 25, "D" ) + oPdf:Box( nRow + 20, ( nCol * 2 ) + 20, ( nRow * 3 ) + 20, ( nCol * 4 ) + 20, 0.25, 35, "D" ) + oPdf:Box( nRow + 30, ( nCol * 2 ) + 30, ( nRow * 3 ) + 30, ( nCol * 4 ) + 30, 0.15, 45, "D" ) + oPdf:Box( nRow + 40, ( nCol * 2 ) + 40, ( nRow * 3 ) + 40, ( nCol * 4 ) + 40, 0.10, 55, "D" ) + oPdf:Box( nRow + 50, ( nCol * 2 ) + 50, ( nRow * 3 ) + 50, ( nCol * 4 ) + 50, 0.05, 65, "D" ) + oPdf:Box( nRow + 60, ( nCol * 2 ) + 60, ( nRow * 3 ) + 60, ( nCol * 4 ) + 60, 0.01, 75, "D" ) + oPdf:Box( nRow + 70, ( nCol * 2 ) + 70, ( nRow * 3 ) + 70, ( nCol * 4 ) + 70, 0.01, 85, "D" ) + oPdf:Box( nRow + 80, ( nCol * 2 ) + 80, ( nRow * 3 ) + 80, ( nCol * 4 ) + 80, 0.01, 95, "D" ) + oPdf:Box( nRow + 90, ( nCol * 2 ) + 90, ( nRow * 3 ) + 90, ( nCol * 4 ) + 90, 0.01, 100, "D" ) + + for nI := 1 to 7 + nRow := 150 + nI * 10 + for nJ := 1 to 20 + nCol := nJ * 10 - 3 + oPdf:Box( nRow, nCol, nRow + 10, nCol + 10, 0.01, nI * 10,"M", chr(253) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 1, 2 ), 16) ) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 3, 2 ), 16) ) + chr( cton( substr( aColor[ ( nI - 1 ) * 20 + nJ ], 5, 2 ), 16) ) ) + next + next + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Color Boxes ", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + for nI := 1 to 140 + nTop := ( nI - 1 ) * 2.4 + nLeft := ( nI - 1 ) * 2.1 + nBottom := oPdf:aReport[ PAGEY ] - ( nI - 1 ) * 2.47 + nRight := oPdf:aReport[ PAGEX ] - ( nI - 1 ) * 2.18 + oPdf:Box1( nTop, nLeft, nBottom, nRight, 10, chr( cton( substr( aColor[ nI ], 1, 2 ), 16) ) + chr( cton( substr( aColor[ nI ], 3, 2 ), 16) ) + chr( cton( substr( aColor[ nI ], 5, 2 ), 16) )) + next + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Memos", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "Different Styles & Colors", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + nWidth := 90 + nTab := 0 + cText := memoread('files\test.txt') + + oPdf:Text( cText, 28, 107.95, nWidth, nTab, 3, 'M', chr(253) + chr(0) + chr(0) + chr(255) ) + oPdf:Text( cText, 58, 107.95, nWidth, nTab, 2, 'M', chr(253) + chr(0) + chr(255) + chr(0) ) + oPdf:Text( cText, 88, 107.95, nWidth, nTab, 1, 'M', chr(253) + chr(255) + chr(0) + chr(0) ) + oPdf:Text( cText, 118, 107.95 - nWidth / 2, nWidth, nTab, 4, 'M', chr(253) + chr(255) + chr(255) + chr(0) ) + + oPdf:Text( cText, 34, 100, nWidth, nTab, 3, 'R', chr(253) + chr(0) + chr(128) + chr(128) )//, pdfTextCount( memoread('files\test.txt'), 33, 100, nWidth, nTab, 3, 'R' ) + oPdf:Text( cText, 41, 100, nWidth, nTab, 2, 'R', chr(253) + chr(0) + chr(191) + chr(255) )//, pdfTextCount( memoread('files\test.txt'), 40, 100, nWidth, nTab, 2, 'R' ) + oPdf:Text( cText, 48, 100, nWidth, nTab, 1, 'R', chr(253) + chr(244) + chr(164) + chr(96) )//, pdfTextCount( memoread('files\test.txt'), 47, 100, nWidth, nTab, 1, 'R' ) + oPdf:Text( cText, 55, 35, nWidth, nTab, 4, 'R', chr(253) + chr(0) + chr(0) + chr(0) )//, pdfTextCount( memoread('files\test.txt'), 54, 35, nWidth, nTab, 4, 'R' ) + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Fonts", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "Different Styles", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + nK := 6 + for nI := 1 to len( aFonts ) // Fonts + ++nk + for nJ := 1 to 4 // Styles + if aFonts[ nI ][ nJ + 1 ] + oPdf:SetFont( aFonts[ nI ][ 1 ], nJ - 1, oPdf:aReport[ FONTSIZE ] ) + oPdf:RJust("This is a test for " + aFonts[ nI ][ 1 ] + " " + ; + aStyle[ nJ ], nK++, oPdf:aReport[ REPORTWIDTH ], "R") + endif + next + oPdf:RJust(oPdf:Underline("Underline"), nK++, oPdf:aReport[ REPORTWIDTH ], "R") + oPdf:RJust(oPdf:Reverse("Test"), nK, oPdf:aReport[ REPORTWIDTH ], "R") + next + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Pictures", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "TIFF", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + // file, row, col, units, height, width + oPdf:Image( 'files\color.tif', 0, 0, "M" ) + oPdf:RJust( oPdf:Underline("TIFF"), nK++, oPdf:aReport[ REPORTWIDTH ], "R") + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "JPEG", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:Image( 'files\color.jpg', 0, 0, "M" ) // file, row, col, units, height, width + oPdf:RJust(oPdf:Underline("JPEG"), nK++, oPdf:aReport[ REPORTWIDTH ], "R") + + oPdf:OpenHeader('test.hea') + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Headers", 1, oPdf:aReport[ REPORTPAGE ], 0 ) + oPdf:BookAdd( "Picture Header Page 8", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + + oPdf:AtSay( chr(253) + chr(255) + chr(0) + chr(0) + 'Red Sample of header repeating on pages 8-10', 1, 20, "R" ) + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Picture Header Page 9", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + + oPdf:AtSay( chr(253) + chr(0) + chr(255) + chr(0) + 'Green Sample of header repeating on pages 8-10', 1, 20, "R" ) + + oPdf:NewPage( "LETTER", "P", 6 ) + oPdf:BookAdd( "Picture Header Page 10", 2, oPdf:aReport[ REPORTPAGE ], 0 ) + + oPdf:AtSay( chr(253) + chr(0) + chr(0) + chr(255) + 'Blue Sample of header repeating on pages 8-10', 1, 20, "R" ) + + oPdf:Close() + +#ifndef __XPP__ + oPdf:Execute( 'test.pdf' ) +#endif + + // oPdf:FilePrint() + +return nil + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ +// +// This function called only used in tstPdf.prg +// +static function cton( cString, nBase ) +local cTemp, nI, cChar := "", n := 0, nLen + + nLen := len( cString ) + cTemp := "" + for nI := nLen to 1 step -1 + cTemp += substr( cString, nI, 1 ) + next + cTemp = upper( cTemp ) + + for nI = 1 to nLen + cChar = substr( cTemp, nI, 1 ) + if .not. IsDigit( cChar ) + n = n + ((Asc( cChar ) - 65) + 10) * ( nBase ^ ( nI - 1 ) ) + else + n = n + (( nBase ^ ( nI - 1 )) * val( cChar )) + endif + next + +return n + +//ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\\ + + diff --git a/harbour/contrib/make_b32_all.bat b/harbour/contrib/make_b32_all.bat index 4b69a14fcb..40a8cbd9fa 100644 --- a/harbour/contrib/make_b32_all.bat +++ b/harbour/contrib/make_b32_all.bat @@ -42,7 +42,7 @@ rem ******************************************************* set _HB_DIRS=rddado hbbmcdx hbbtree gtwvg hbct hbgt hbmisc hbnf hbmsql for %%n in ( %_HB_DIRS% ) do %COMSPEC% /c %__BATWORKER__% %%n %1 %2 %3 %4 %5 %6 %7 %8 %9 -set _HB_DIRS=hbole hbziparch hbodbc hbtpathy hbtip hbw32 hbwhat32 xhb +set _HB_DIRS=hbole hbziparch hbodbc hbtpathy hbtip hbvpdf hbw32 hbwhat32 xhb for %%n in ( %_HB_DIRS% ) do %COMSPEC% /c %__BATWORKER__% %%n %1 %2 %3 %4 %5 %6 %7 %8 %9 set _HB_DIRS=hbclipsm hbw32ddr diff --git a/harbour/contrib/make_gcc_all.sh b/harbour/contrib/make_gcc_all.sh index 5449b18e81..22cb916e7e 100755 --- a/harbour/contrib/make_gcc_all.sh +++ b/harbour/contrib/make_gcc_all.sh @@ -38,7 +38,7 @@ fi #************************************************************** -_HB_DIRS="hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmsql hbnf hbtip hbtpathy xhb" +_HB_DIRS="hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmsql hbnf hbtip hbtpathy hbvpdf xhb" case "$HB_ARCHITECTURE" in w32|cyg|os2) diff --git a/harbour/contrib/make_vc_all.bat b/harbour/contrib/make_vc_all.bat index 5d07ebb597..40fe3283f3 100644 --- a/harbour/contrib/make_vc_all.bat +++ b/harbour/contrib/make_vc_all.bat @@ -42,7 +42,7 @@ rem ******************************************************* set _HB_DIRS=rddado hbbmcdx hbbtree gtwvg hbct hbgt hbmisc hbnf hbmsql for %%n in ( %_HB_DIRS% ) do %COMSPEC% /c %__BATWORKER__% %%n %1 %2 %3 %4 %5 %6 %7 %8 %9 -set _HB_DIRS=hbole hbziparch hbodbc hbtpathy hbtip hbw32 hbwhat32 xhb +set _HB_DIRS=hbole hbziparch hbodbc hbtpathy hbtip hbvpdf hbw32 hbwhat32 xhb for %%n in ( %_HB_DIRS% ) do %COMSPEC% /c %__BATWORKER__% %%n %1 %2 %3 %4 %5 %6 %7 %8 %9 set _HB_DIRS=hbclipsm hbw32ddr