diff options
Diffstat (limited to 'src/devices/grolbp')
-rw-r--r-- | src/devices/grolbp/charset.h | 89 | ||||
-rw-r--r-- | src/devices/grolbp/grolbp.1.man | 504 | ||||
-rw-r--r-- | src/devices/grolbp/grolbp.am | 36 | ||||
-rw-r--r-- | src/devices/grolbp/lbp.cpp | 738 | ||||
-rw-r--r-- | src/devices/grolbp/lbp.h | 544 |
5 files changed, 1911 insertions, 0 deletions
diff --git a/src/devices/grolbp/charset.h b/src/devices/grolbp/charset.h new file mode 100644 index 0000000..c4e43a0 --- /dev/null +++ b/src/devices/grolbp/charset.h @@ -0,0 +1,89 @@ +// -*- C++ -*- +/* Copyright (C) 2000-2020 Free Software Foundation, Inc. + Written by Francisco Andrés Verdú <pandres@dragonet.es> with many ideas + taken from the other groff drivers. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +// Definition of the WP54 character set + +unsigned char symset[] = { +0x57,0x50,0x35,0x34,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61, +0x72,0x64,0x65,0x2d,0x42,0x6f,0x6f,0x6b,0x00,0x41,0x76, +0x61,0x6e,0x74,0x47,0x61,0x72,0x64,0x65,0x2d,0x44,0x65, +0x6d,0x69,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61,0x72, +0x64,0x65,0x2d,0x42,0x6f,0x6f,0x6b,0x4f,0x62,0x6c,0x69, +0x71,0x75,0x65,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61, +0x72,0x64,0x65,0x2d,0x44,0x65,0x6d,0x69,0x4f,0x62,0x6c, +0x69,0x71,0x75,0x65,0x00,0x42,0x6f,0x6f,0x6b,0x6d,0x61, +0x6e,0x2d,0x4c,0x69,0x67,0x68,0x74,0x00,0x42,0x6f,0x6f, +0x6b,0x6d,0x61,0x6e,0x2d,0x44,0x65,0x6d,0x69,0x00,0x42, +0x6f,0x6f,0x6b,0x6d,0x61,0x6e,0x2d,0x4c,0x69,0x67,0x68, +0x74,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x42,0x6f,0x6f, +0x6b,0x6d,0x61,0x6e,0x2d,0x44,0x65,0x6d,0x69,0x49,0x74, +0x61,0x6c,0x69,0x63,0x00,0x43,0x65,0x6e,0x74,0x75,0x72, +0x79,0x53,0x63,0x68,0x6c,0x62,0x6b,0x2d,0x52,0x6f,0x6d, +0x61,0x6e,0x00,0x43,0x65,0x6e,0x74,0x75,0x72,0x79,0x53, +0x63,0x68,0x6c,0x62,0x6b,0x2d,0x42,0x6f,0x6c,0x64,0x00, +0x43,0x65,0x6e,0x74,0x75,0x72,0x79,0x53,0x63,0x68,0x6c, +0x62,0x6b,0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x43, +0x65,0x6e,0x74,0x75,0x72,0x79,0x53,0x63,0x68,0x6c,0x62, +0x6b,0x2d,0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c,0x69, +0x63,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x52,0x6f,0x6d, +0x61,0x6e,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x42,0x6f, +0x6c,0x64,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x49,0x74, +0x61,0x6c,0x69,0x63,0x00,0x44,0x75,0x74,0x63,0x68,0x2d, +0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c,0x69,0x63,0x00, +0x53,0x77,0x69,0x73,0x73,0x00,0x53,0x77,0x69,0x73,0x73, +0x2d,0x42,0x6f,0x6c,0x64,0x00,0x53,0x77,0x69,0x73,0x73, +0x2d,0x4f,0x62,0x6c,0x69,0x71,0x75,0x65,0x00,0x53,0x77, +0x69,0x73,0x73,0x2d,0x42,0x6f,0x6c,0x64,0x4f,0x62,0x6c, +0x69,0x71,0x75,0x65,0x00,0x53,0x77,0x69,0x73,0x73,0x2d, +0x4e,0x61,0x72,0x72,0x6f,0x77,0x00,0x53,0x77,0x69,0x73, +0x73,0x2d,0x4e,0x61,0x72,0x72,0x6f,0x77,0x2d,0x42,0x6f, +0x6c,0x64,0x00,0x53,0x77,0x69,0x73,0x73,0x2d,0x4e,0x61, +0x72,0x72,0x6f,0x77,0x2d,0x4f,0x62,0x6c,0x69,0x71,0x75, +0x65,0x00,0x53,0x77,0x69,0x73,0x73,0x2d,0x4e,0x61,0x72, +0x72,0x6f,0x77,0x2d,0x42,0x6f,0x6c,0x64,0x4f,0x62,0x6c, +0x69,0x71,0x75,0x65,0x00,0x5a,0x61,0x70,0x66,0x43,0x61, +0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x2d, +0x52,0x6f,0x6d,0x61,0x6e,0x00,0x5a,0x61,0x70,0x66,0x43, +0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63, +0x2d,0x42,0x6f,0x6c,0x64,0x00,0x5a,0x61,0x70,0x66,0x43, +0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63, +0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x5a,0x61,0x70, +0x66,0x43,0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68, +0x69,0x63,0x2d,0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c, +0x69,0x63,0x00,0x5a,0x61,0x70,0x66,0x43,0x68,0x61,0x6e, +0x63,0x65,0x72,0x79,0x2d,0x4d,0x65,0x64,0x69,0x75,0x6d, +0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x00,0x09,0x00,0x0A, +0x00,0x0B,0x00,0x0E,0x00,0x14,0x00,0x17,0x00,0x18,0x00, +0x1F,0x00,0x20,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x45,0x00, +0x47,0x00,0x48,0x00,0x80,0x00,0x82,0x00,0x83,0x00,0x84, +0x00,0x85,0x00,0x87,0x00,0x8B,0x00,0x8C,0x00,0x8D,0x00,0x8E, +0x00,0x8F,0x00,0x90,0x00,0x91,0x00,0x92,0x00,0x95,0x00,0x96, +0x00,0x97,0x00,0x98,0x00,0x99,0x00,0x9C,0x00,0x9E,0x00, +0x9F,0x00,0xA0,0x00,0xA1,0x00,0xA2,0x00,0xA3,0x00,0xCB,0x00, +0xCC,0x00,0xCD,0x00,0xCE,0x00,0xD1,0x00,0xD3,0x00,0xD4, +0x00,0xD5,0x00,0xD6,0x00,0xFA,0x00,0xFB,0x00,0xFC,0x00,0xFD, +0x00,0xCF,0x00,0x26,0x00,0x7E,0x03,0x05,0x00,0xA5,0x00, +0xA6,0x00,0xA8,0x00,0xAA,0x00,0xAD,0x00,0xAE,0x00,0xAF,0x00, +0xB0,0x00,0xB1,0x00,0xB2,0x00,0xB3,0x00,0xB5,0x00,0xB6,0x00, +0xB8,0x00,0xB9,0x00,0xBA,0x00,0xBB,0x00,0xBC,0x00,0xBE, +0x00,0xBF,0x00,0xC0,0x00,0xC1,0x00,0xC6,0x00,0xDC,0x00,0xEB, +0x00,0xEC,0x00,0xF2,0x00,0xF3,0x00,0x15,0x00,0x16,0x00, +0x86 +}; diff --git a/src/devices/grolbp/grolbp.1.man b/src/devices/grolbp/grolbp.1.man new file mode 100644 index 0000000..c8cda76 --- /dev/null +++ b/src/devices/grolbp/grolbp.1.man @@ -0,0 +1,504 @@ +'\" t +.TH grolbp @MAN1EXT@ "@MDATE@" "groff @VERSION@" +.SH Name +grolbp \- +.I groff +output driver for Canon CaPSL printers +. +. +.\" Modified from grolj4 man page by Francisco Andrés Verdú +.\" <pandres@dragonet.es> for the grolbp program. +. +. +.\" ==================================================================== +.\" Legal Terms +.\" ==================================================================== +.\" +.\" Copyright (C) 1994-2020 Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of +.\" this manual under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of +.\" a permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" manual into another language, under the above conditions for +.\" modified versions, except that this permission notice may be +.\" included in translations approved by the Free Software Foundation +.\" instead of in the original English. +. +. +.\" Save and disable compatibility mode (for, e.g., Solaris 10/11). +.do nr *groff_grolbp_1_man_C \n[.cp] +.cp 0 +. +.\" Define fallback for groff 1.23's MR macro if the system lacks it. +.nr do-fallback 0 +.if !\n(.f .nr do-fallback 1 \" mandoc +.if \n(.g .if !d MR .nr do-fallback 1 \" older groff +.if !\n(.g .nr do-fallback 1 \" non-groff *roff +.if \n[do-fallback] \{\ +. de MR +. ie \\n(.$=1 \ +. I \%\\$1 +. el \ +. IR \%\\$1 (\\$2)\\$3 +. . +.\} +.rr do-fallback +. +. +.\" ==================================================================== +.SH Synopsis +.\" ==================================================================== +. +.SY grolbp +.RB [ \-l ] +.RB [ \-c\~\c +.IR num-copies ] +.RB [ \-F\~\c +.IR font-directory ] +.RB [ \-o\~\c +.IR orientation ] +.RB [ \-p\~\c +.IR paper-format ] +.RB [ \-w\~\c +.IR width ] +.RI [ file\~ .\|.\|.] +. +.SY grolbp +[\c +.BI \-\-copies= num-copies\c +] [\c +.BI \-\-fontdir= font-directory\c +] [\c +.B \-\-landscape\c +] [\c +.BI \-\-linewidth= width\c +] [\c +.BI \-\-orientation= orientation\c +] [\c +.BI \-\-papersize= paper-format\c +] +.RI [ file\~ .\|.\|.] +.YS +. +. +.SY grolbp +.B \-h +. +.SY grolbp +.B \-\-help +.YS +. +. +.SY grolbp +.B \-v +. +.SY grolbp +.B \-\-version +.YS +. +. +.\" ==================================================================== +.SH Description +.\" ==================================================================== +. +This GNU +.I roff +output driver translates the output of +.MR @g@troff @MAN1EXT@ +into a CaPSL and VDM format suitable for Canon LBP-4 and LBP-8 printers. +. +Normally, +.I grolbp +is invoked by +.MR groff @MAN1EXT@ +when the latter is given the +.RB \[lq] \-T\~lbp \[rq] +option. +. +(In this installation, +.B @DEVICE@ +is the default output device.) +. +Use +.IR groff 's +.B \-P +option to pass any options shown above to +.IR grolbp . +. +If no +.I file +arguments are given, +or if +.I file +is \[lq]\-\[rq], +.I grolbp +reads the standard input stream. +. +Output is written to the standard output stream. +. +. +.\" ==================================================================== +.SS Typefaces +.\" ==================================================================== +. +The driver supports the Dutch, +Swiss, +and Swiss-Narrow scalable typefaces, +each in the regular, +bold, +italic, +and bold-italic styles. +. +Additionally, +the bitmapped, +monospaced Courier and Elite typefaces are available in regular, +bold, +and +italic styles; +Courier at 8 and 12 points, +Elite at 8 and 10 points. +. +The following chart summarizes the +.I groff +font names used to access them. +. +. +.P +.TS +tab(|) allbox center; +Cb Cb Cb Cb Cb +L L L L L +. +Typeface | Roman | Bold | Italic | Bold-Italic +Dutch | TR | TB | TI | TBI +Swiss | HR | HB | HI | HBI +Swiss Narrow | HNR | HNB | HNI | HNBI +Courier | CR | CB | CI | +Elite | ER | EB | EI | +.TE +. +. +.\" ==================================================================== +.SS "Paper format, orientation, and device description file" +.\" ==================================================================== +. +.I grolbp +supports paper formats +.RB \[lq] A4 \[rq], +.RB \[lq] letter \[rq], +.RB \[lq] legal \[rq], +and +.RB \[lq] executive \[rq]. +. +These are matched case-insensitively. +. +The +.BR \-p , +.B \-\-papersize +option overrides any setting in the device description file +.IR DESC . +. +If neither specifies a paper format, +A4 is assumed. +. +. +.P +In its +.I DESC +file, +.I grolbp +(case-insensitively) recognizes an +.B orientation +directive accepting one mandatory argument, +.B portrait +or +.BR landscape . +. +The first valid orientation directive encountered controls. +.\" XXX: This is inconsistent with other description file processing. +. +The +.BR \-l , +.BR \-o , +and +.B \-\-orientation +command-line options +override any setting in +.IR DESC . +. +If none of the foregoing specify the orientation, +portrait is assumed. +. +. +.\" ==================================================================== +.SS "Font description files" +.\" ==================================================================== +. +In addition to the font description file directives documented in +.MR groff_font @MAN5EXT@ , +.I grolbp +recognizes +.BR lbpname , +which maps the +.I groff +font name to the font name used internally by the printer. +. +Its syntax is as follows. +.RS +.EX +.RI lbpname\~ printer-font-name +.EE +.RE +. +. +.BR lbpname 's +argument is case-sensitive. +. +The printer's font names are encoded as follows. +. +. +.P +For bitmapped fonts, +.I printer-font_name +has the form +.RS +.EX +.RI N\[la] base-font-name \[ra]\[la] font-style \[ra] +.EE +.RE +.I base-font-name +is the font name as it appears in the printer's font listings without +the first letter, +up to +(but not including) +the font size. +. +.I font-style +can be one of the letters +.BR R , +.BR I , +or +.BR B , +.\" The bold-italic style apparently was not supported for bitmap fonts. +indicating the roman, +italic, +and bold styles, +respectively. +. +For instance, +if the printer's \[lq]font listing A\[rq] +shows \[lq]Nelite12I.ISO_USA\[rq], +the corresponding entry in the +.I groff +font description file is +.RS +.EX +lbpname NeliteI +.EE +.RE +. +You may need to modify +.I grolbp +to add support for new bitmapped fonts, +since the available font names and font sizes of bitmapped fonts +(as documented above) +are hard-coded into the program. +. +. +.P +For scalable fonts, +.I printer-font-name +is identical to the font name as it appears in the printer's \[lq]font +listing A\[rq]. +. +For instance, +to select the \[lq]Swiss\[rq] font in bold-italic style, +which appears in the font listing +as \%\[lq]Swiss\-BoldOblique\[rq], +.RS +.EX +lbpname Swiss\-BoldOblique +.EE +.RE +is the required directive, +and this is what we find in the +.I groff +font description file +.I HBI +for the +.B lbp +device. +. +. +.\" ==================================================================== +.SS "Drawing commands" +.\" ==================================================================== +. +For compatibility with +.MR grolj4 @MAN1EXT@ , +an additional drawing command is available. +. +. +.TP +.BI \[rs]D\[aq]R\~ "dh dv" \[aq] +Draw a rule +(solid black rectangle) +with one corner at the drawing position, +and the diagonally opposite corner at the drawing position +.RI +( dh , dv ). +.\" XXX , at which the drawing position will be afterward. ? +. +. +.\" ==================================================================== +.SH Options +.\" ==================================================================== +. +.B \-h +and +.B \-\-help +display a usage message, +while +.B \-v +and +.B \-\-version +show version information; +all exit afterward. +. +. +.TP +.BI \-c " num-copies" +.TQ +.BI \-\-copies= num-copies +Produce +.I num-copies +copies of each page. +. +. +.TP +.BI \-F " font-directory" +.TQ +.BI \-\-fontdir= font-directory +Prepend directory +.RI font-directory /dev name +to the search path for font and device description files; +.I name +is the name of the device, +usually +.BR lbp . +. +. +.TP +.B \-l +.TQ +.B \-\-landscape +Format the document in landscape orientation. +. +. +.TP +.BI \-o " orientation" +.TQ +.BI \-\-orientation= orientation +Format the document in the given +.IR orientation , +which must be +.RB \%\[lq] portrait \[rq] +or +.RB \%\[lq] landscape \[rq]. +. +. +.TP +.BI \-p " paper-format" +.TQ +.BI \-\-papersize= paper-format +Set the paper format to +.IR paper-format , +which must be a valid paper format as described above. +. +. +.TP +.BI \-w " width" +.TQ +.BI \-\-linewidth= width +Set the default line thickness to +.I width +thousandths of an em; +the default is +.B 40 +(0.04\~em). +. +. +.\" ==================================================================== +.SH Environment +.\" ==================================================================== +. +.TP +.I GROFF_FONT_PATH +lists directories in which to seek the selected output device's +directory of device and font description files. +. +See +.MR @g@troff @MAN1EXT@ +and +.MR groff_font @MAN5EXT@ . +. +. +.\" ==================================================================== +.SH Files +.\" ==================================================================== +. +.TP +.I @FONTDIR@/\:\%devlbp/\:DESC +describes the +.B lbp +output device. +. +. +.TP +.IR @FONTDIR@/\:\%devlbp/ F +describes the font known +.RI as\~ F +on device +.BR lbp . +. +. +.TP +.I @MACRODIR@/\:lbp\:.tmac +defines macros for use with the +.B lbp +output device. +. +It is automatically loaded by +.I troffrc +when the +.B lbp +output device is selected. +. +. +.\" ==================================================================== +.SH "See also" +.\" ==================================================================== +. +.MR groff @MAN1EXT@ , +.MR @g@troff @MAN1EXT@ , +.MR groff_out @MAN5EXT@ , +.MR groff_font @MAN5EXT@ , +.MR groff_char @MAN7EXT@ +. +. +.\" Restore compatibility mode (for, e.g., Solaris 10/11). +.cp \n[*groff_grolbp_1_man_C] +.do rr *groff_grolbp_1_man_C +. +. +.\" Local Variables: +.\" fill-column: 72 +.\" mode: nroff +.\" End: +.\" vim: set filetype=groff textwidth=72: diff --git a/src/devices/grolbp/grolbp.am b/src/devices/grolbp/grolbp.am new file mode 100644 index 0000000..3ee3a0a --- /dev/null +++ b/src/devices/grolbp/grolbp.am @@ -0,0 +1,36 @@ +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +bin_PROGRAMS += grolbp +grolbp_SOURCES = \ + src/devices/grolbp/lbp.cpp \ + src/devices/grolbp/lbp.h \ + src/devices/grolbp/charset.h + +grolbp_LDADD = $(LIBM) \ + libdriver.a \ + libgroff.a \ + lib/libgnu.a +man1_MANS += src/devices/grolbp/grolbp.1 +EXTRA_DIST += src/devices/grolbp/grolbp.1.man + + +# Local Variables: +# fill-column: 72 +# mode: makefile-automake +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/devices/grolbp/lbp.cpp b/src/devices/grolbp/lbp.cpp new file mode 100644 index 0000000..35cd54e --- /dev/null +++ b/src/devices/grolbp/lbp.cpp @@ -0,0 +1,738 @@ +/* Copyright (C) 1994-2020 Free Software Foundation, Inc. + Written by Francisco Andrés Verdú <pandres@dragonet.es> with many + ideas taken from the other groff drivers. + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* +TODO + + - Add X command to include bitmaps +*/ + +#include <assert.h> + +#include "driver.h" +#include "lbp.h" +#include "charset.h" +#include "paper.h" + +#include "nonposix.h" + +extern "C" const char *Version_string; + +static int user_papersize = -1; +static int orientation = -1; + +// custom paper format +static double user_paperlength = 0; +static double user_paperwidth = 0; + +static int ncopies = 1; + +#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em +static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR; + +static int set_papersize(const char *paperformat); + +class lbp_font : public font { +public: + ~lbp_font(); + void handle_unknown_font_command(const char *command, const char *arg, + const char *filename, int lineno); + static lbp_font *load_lbp_font(const char *); + char *lbpname; + char is_scalable; +private: + lbp_font(const char *); +}; + +class lbp_printer : public printer { +public: + lbp_printer(int, double, double); + ~lbp_printer(); + void set_char(glyph *, font *, const environment *, int, const char *name); + void draw(int code, int *p, int np, const environment *env); + void begin_page(int); + void end_page(int page_length); + font *make_font(const char *); + void end_of_line(); +private: + void set_line_thickness(int size,const environment *env); + void vdmstart(); + void vdmflush(); // the name vdmend was already used in lbp.h + void setfillmode(int mode); + void polygon( int hpos,int vpos,int np,int *p); + char *font_name(const lbp_font *f, const int siz); + + int fill_pattern; + int fill_mode; + int cur_hpos; + int cur_vpos; + lbp_font *cur_font; + int cur_size; + unsigned short cur_symbol_set; + int line_thickness; + int req_linethickness; // requested line thickness + // custom paper format + int papersize; + int paperlength; + int paperwidth; +}; + +lbp_font::lbp_font(const char *nm) +: font(nm) +{ +} + +lbp_font::~lbp_font() +{ +} + +lbp_font *lbp_font::load_lbp_font(const char *s) +{ + lbp_font *f = new lbp_font(s); + f->lbpname = NULL; + f->is_scalable = 1; // Default is that fonts are scalable + if (!f->load()) { + delete f; + return 0; + } + return f; +} + + +void lbp_font::handle_unknown_font_command(const char *command, + const char *arg, + const char *filename, int lineno) +{ + if (strcmp(command, "lbpname") == 0) { + if (arg == 0) + fatal_with_file_and_line(filename, lineno, + "'%1' command requires an argument", + command); + this->lbpname = new char[strlen(arg) + 1]; + strcpy(this->lbpname, arg); + // we recognize bitmapped fonts by the first character of its name + if (arg[0] == 'N') + this->is_scalable = 0; + // fprintf(stderr, "Loading font \"%s\" \n", arg); + } + // fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n", + // command, arg, filename, lineno); +} + +static void wp54charset() +{ + unsigned int i; + lbpputs("\033[714;100;29;0;32;120.}"); + for (i = 0; i < sizeof(symset); i++) + lbpputc(symset[i]); + lbpputs("\033[100;0 D"); + return; +} + +lbp_printer::lbp_printer(int ps, double pw, double pl) +: fill_pattern(1), + fill_mode(0), + cur_hpos(-1), + cur_font(0), + cur_size(0), + cur_symbol_set(0), + req_linethickness(-1) +{ + SET_BINARY(fileno(stdout)); + lbpinit(stdout); + lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h"); + wp54charset(); // Define the new symbol set + lbpputs("\033[7 I\033[?32h\033[?33h\033[11h"); + // Paper format handling + if (orientation < 0) + orientation = 0; // Default orientation is portrait + papersize = 14; // Default paper format is A4 + if (font::papersize) { + papersize = set_papersize(font::papersize); + paperlength = font::paperlength; + paperwidth = font::paperwidth; + } + if (ps >= 0) { + papersize = ps; + paperlength = int(pl * font::res + 0.5); + paperwidth = int(pw * font::res + 0.5); + } + if (papersize < 80) // standard paper + lbpprintf("\033[%dp", (papersize | orientation)); + else // Custom paper + lbpprintf("\033[%d;%d;%dp", (papersize | orientation), + paperlength, paperwidth); + // Number of copies + lbpprintf("\033[%dv\n", ncopies); + lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\"); + lbpmoveabs(0, 0); + lbpputs("\033[0t\033[2t"); + lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML + // Secondary symbol set IBMR1 + cur_symbol_set = 0; +} + +lbp_printer::~lbp_printer() +{ + lbpputs("\033P1y\033\\"); + lbpputs("\033c\033<"); +} + +inline void lbp_printer::set_line_thickness(int size,const environment *env) +{ + if (size == 0) + line_thickness = 1; + else { + if (size < 0) + // line_thickness = + // (env->size * (font::res/72)) * (linewidth_factor/1000) + // we ought to check for overflow + line_thickness = + env->size * linewidth_factor * font::res / 72000; + else // size > 0 + line_thickness = size; + } // else from if (size == 0) + if (line_thickness < 1) + line_thickness = 1; + if (vdminited()) + vdmlinewidth(line_thickness); + req_linethickness = size; // an size requested + /* fprintf(stderr, "thickness: %d == %d, size %d, %d \n", + size, line_thickness, env->size,req_linethickness); */ + return; +} // lbp_printer::set_line_thickness + +void lbp_printer::begin_page(int) +{ +} + +void lbp_printer::end_page(int) +{ + if (vdminited()) + vdmflush(); + lbpputc('\f'); + cur_hpos = -1; +} + +void lbp_printer::end_of_line() +{ + cur_hpos = -1; // force absolute motion +} + +char *lbp_printer::font_name(const lbp_font *f, const int siz) +{ + static char bfont_name[255]; // The resulting font name + char type, // Italic, Roman, Bold + ori, // Normal or Rotated + *nam; // The font name without other data. + int cpi; // The font size in characters per inch + // (bitmapped fonts are monospaced). + /* Bitmap font selection is ugly in this printer, so don't expect + this function to be elegant. */ + bfont_name[0] = 0x00; + if (orientation) // Landscape + ori = 'R'; + else // Portrait + ori = 'N'; + type = f->lbpname[strlen(f->lbpname) - 1]; + nam = new char[strlen(f->lbpname) - 2]; + strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2); + nam[strlen(f->lbpname) - 2] = 0x00; + // fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori); + /* Since these fonts are available only at certain sizes, + 10 and 17 cpi for courier, 12 and 17 cpi for elite, + we adjust the resulting size. */ + cpi = 17; + // Fortunately there are only two bitmapped fonts shipped with the printer. + if (!strcasecmp(nam, "courier")) { + // Courier font + if (siz >= 12) + cpi = 10; + else cpi = 17; + } + if (!strcasecmp(nam, "elite")) { + if (siz >= 10) + cpi = 12; + else cpi = 17; + } + // Now that we have all the data, let's generate the font name. + if ((type != 'B') && (type != 'I')) // Roman font + sprintf(bfont_name, "%c%s%d", ori, nam, cpi); + else + sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type); + return bfont_name; +} + +void lbp_printer::set_char(glyph *g, font *f, const environment *env, + int w, const char *) +{ + int code = f->get_code(g); + unsigned char ch = code & 0xff; + unsigned short symbol_set = code >> 8; + if (f != cur_font) { + lbp_font *psf = (lbp_font *)f; + // fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size); + if (psf->is_scalable) { + // Scalable font selection is different from bitmaped + lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname, + (int)((env->size * font::res) / 72)); + } + else + // bitmapped font + lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size)); + lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set + cur_font = psf; + cur_symbol_set = 0; + // Update the line thickness if needed + if ((req_linethickness < 0 ) && (env->size != cur_size)) + set_line_thickness(req_linethickness,env); + cur_size = env->size; + } + if (symbol_set != cur_symbol_set) { + if (cur_symbol_set == 3) + // if current symbol set is Symbol we must restore the font + lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname, + (int)((env->size * font::res) / 72)); + switch (symbol_set) { + case 0: + lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets + break; + case 1: + lbpputs("\033(d\033)' 1"); // Select wp54 symbol set + break; + case 2: + lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set + break; + case 3: + lbpprintf("\033PzSymbol.SYML\033\\\033[%d C", + (int)((env->size * font::res) / 72)); + lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font + break; + case 4: + lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set + break; + } + cur_symbol_set = symbol_set; + } + if (env->size != cur_size) { + if (!cur_font->is_scalable) + lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size)); + else + lbpprintf("\033[%d C", (int)((env->size * font::res) / 72)); + cur_size = env->size; + // Update the line thickness if needed + if (req_linethickness < 0 ) + set_line_thickness(req_linethickness,env); + } + if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) { + // lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos); + lbpmoveabs(env->hpos - 64, env->vpos - 64); + cur_vpos = env->vpos; + cur_hpos = env->hpos; + } + if ((ch & 0x7F) < 32) + lbpputs("\033[1.v"); + lbpputc(ch); + cur_hpos += w; +} + +void lbp_printer::vdmstart() +{ + FILE *f; + static int changed_origin = 0; + errno = 0; + f = tmpfile(); + // f = fopen("/tmp/gtmp","w+"); + if (f == NULL) + perror("Opening temporary file"); + vdminit(f); + if (!changed_origin) { // we should change the origin only one time + changed_origin = 1; + vdmorigin(-63, 0); + } + vdmlinewidth(line_thickness); +} + +void +lbp_printer::vdmflush() +{ + char buffer[1024]; + int bytes_read = 1; + vdmend(); + fflush(lbpoutput); + /* let's copy the vdm code to the output */ + rewind(vdmoutput); + do { + bytes_read = fread(buffer, 1, sizeof(buffer), vdmoutput); + bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput); + } while (bytes_read == sizeof(buffer)); + fclose(vdmoutput); // This will also delete the file, + // since it is created by tmpfile() + vdmoutput = NULL; +} + +inline void lbp_printer::setfillmode(int mode) +{ + if (mode != fill_mode) { + if (mode != 1) + vdmsetfillmode(mode, 1, 0); + else + // To get black, we must use white inverted. + vdmsetfillmode(mode, 1, 1); + + fill_mode = mode; + } +} + +inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p) +{ + int *points, i; + points = new int[np + 2]; + points[0] = hpos; + points[1] = vpos; + // fprintf(stderr, "Polygon (%d,%d) ", points[0], points[1]); + for (i = 0; i < np; i++) + points[i + 2] = p[i]; + // for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]); + // fprintf(stderr, "\n"); + vdmpolygon((np /2) + 1, points); +} + +void lbp_printer::draw(int code, int *p, int np, const environment *env) +{ + if ((req_linethickness < 0 ) && (env->size != cur_size)) + set_line_thickness(req_linethickness,env); + + switch (code) { + case 't': + if (np == 0) + line_thickness = 1; + else { // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) { + error("0 or 1 argument required for thickness"); + break; + } + set_line_thickness(p[0],env); + } + break; + case 'l': // Line + if (np != 2) { + error("2 arguments required for line"); + break; + } + if (!vdminited()) + vdmstart(); + vdmline(env->hpos, env->vpos, p[0], p[1]); +/* fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n", + env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0], + env->vpos -64 + p[1], env->size, line_thickness);*/ + break; + case 'R': // Rule + if (np != 2) { + error("2 arguments required for Rule"); + break; + } + if (vdminited()) { + setfillmode(fill_pattern); // Solid Rule + vdmrectangle(env->hpos, env->vpos, p[0], p[1]); + } + else { + lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]); + cur_vpos = p[1]; + cur_hpos = p[0]; + } + // fprintf(stderr, "\nrule: thickness %d == %d\n", + // env->size, line_thickness); + break; + case 'P': // Filled Polygon + if (!vdminited()) + vdmstart(); + setfillmode(fill_pattern); + polygon(env->hpos, env->vpos, np, p); + break; + case 'p': // Empty Polygon + if (!vdminited()) + vdmstart(); + setfillmode(0); + polygon(env->hpos, env->vpos, np, p); + break; + case 'C': // Filled Circle + if (!vdminited()) + vdmstart(); + // fprintf(stderr, "Circle (%d,%d) Fill %d\n", + // env->hpos, env->vpos, fill_pattern); + setfillmode(fill_pattern); + vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2); + break; + case 'c': // Empty Circle + if (!vdminited()) + vdmstart(); + setfillmode(0); + vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2); + break; + case 'E': // Filled Ellipse + if (!vdminited()) + vdmstart(); + setfillmode(fill_pattern); + vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0); + break; + case 'e': // Empty Ellipse + if (!vdminited()) + vdmstart(); + setfillmode(0); + vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0); + break; + case 'a': // Arc + if (!vdminited()) + vdmstart(); + setfillmode(0); + // VDM draws arcs clockwise and pic counterclockwise + // We must compensate for that, exchanging the starting and + // ending points + vdmvarc(env->hpos + p[0], env->vpos+p[1], + int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))), + p[2], p[3], + (-p[0]), (-p[1]), 1, 2); + break; + case '~': // Spline + if (!vdminited()) + vdmstart(); + setfillmode(0); + vdmspline(np/2, env->hpos, env->vpos, p); + break; + case 'f': + if (np != 1 && np != 2) { + error("1 argument required for fill"); + break; + } + // fprintf(stderr, "Fill %d\n", p[0]); + if ((p[0] == 1) || (p[0] >= 1000)) { // Black + fill_pattern = 1; + break; + } + if (p[0] == 0) { // White + fill_pattern = 0; + break; + } + if ((p[0] > 1) && (p[0] < 1000)) + { + if (p[0] >= 990) fill_pattern = -23; + else if (p[0] >= 700) fill_pattern = -28; + else if (p[0] >= 500) fill_pattern = -27; + else if (p[0] >= 400) fill_pattern = -26; + else if (p[0] >= 300) fill_pattern = -25; + else if (p[0] >= 200) fill_pattern = -22; + else if (p[0] >= 100) fill_pattern = -24; + else fill_pattern = -21; + } + break; + case 'F': + // not implemented yet + break; + default: + error("unrecognised drawing command '%1'", char(code)); + break; + } + return; +} + +font *lbp_printer::make_font(const char *nm) +{ + return lbp_font::load_lbp_font(nm); +} + +printer *make_printer() +{ + return new lbp_printer(user_papersize, user_paperwidth, user_paperlength); +} + +static struct { + const char *name; + int code; +} lbp_papersizes[] = + {{ "A4", 14 }, + { "letter", 30 }, + { "legal", 32 }, + { "executive", 40 }, + }; + +static int set_papersize(const char *paperformat) +{ + unsigned int i; + // First, test for a standard (i.e. supported directly by the printer) + // paper format. + for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++) + { + if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0) + return lbp_papersizes[i].code; + } + // Otherwise, we assume a custom paper format. + return 82; // XXX: magic number +} + +static void handle_unknown_desc_command(const char *command, const char *arg, + const char *filename, int lineno) +{ + // orientation command + if (strcasecmp(command, "orientation") == 0) { + // We give priority to command-line options + if (orientation > 0) + return; + if (arg == 0) + error_with_file_and_line(filename, lineno, + "'orientation' command requires an argument"); + else { + if (strcasecmp(arg, "portrait") == 0) + orientation = 0; + else { + if (strcasecmp(arg, "landscape") == 0) + orientation = 1; + else + error_with_file_and_line(filename, lineno, + "invalid argument to 'orientation' command"); + } + } + } +} + +static struct option long_options[] = { + { "orientation", required_argument, NULL, 'o' }, + { "version", no_argument, NULL, 'v' }, + { "copies", required_argument, NULL, 'c' }, + { "landscape", no_argument, NULL, 'l' }, + { "papersize", required_argument, NULL, 'p' }, + { "linewidth", required_argument, NULL, 'w' }, + { "fontdir", required_argument, NULL, 'F' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, 0, 0 } +}; + +static void usage(FILE *stream) +{ + fprintf(stream, +"usage: %s [-l] [-c num-copies] [-F font-directory] [-o orientation]" +" [-p paper-format] [-w width] [file ...]\n" +"usage: %s {-v | --version}\n" +"usage: %s {-h | --help}\n", + program_name, program_name, program_name); + if (stdout == stream) { + fputs( +"\n" +"Translate the output of troff(1) into a CaPSL and VDM format suitable" +"\n" +"for Canon LBP-4 and LBP-8 printers. See the grolbp(1) manual page.\n", + stream); + exit(EXIT_SUCCESS); + } +} + +int main(int argc, char **argv) +{ + if (program_name == NULL) + program_name = strsave(argv[0]); + font::set_unknown_desc_command_handler(handle_unknown_desc_command); + // command line parsing + int c; + int option_index = 0; + while ((c = getopt_long(argc, argv, "c:F:hI:lo:p:vw:", long_options, + &option_index)) + != EOF) { + switch (c) { + case 'F': + font::command_line_font_dir(optarg); + break; + case 'I': + // ignore include path arguments + break; + case 'p': + { + const char *s; + if (!font::scan_papersize(optarg, &s, + &user_paperlength, &user_paperwidth)) + error("ignoring invalid paper format '%1'", optarg); + else + user_papersize = set_papersize(s); + break; + } + case 'l': + orientation = 1; + break; + case 'v': + printf("GNU grolbp (groff) version %s\n", Version_string); + exit(EXIT_SUCCESS); + break; + case 'o': + if (strcasecmp(optarg, "portrait") == 0) + orientation = 0; + else { + if (strcasecmp(optarg, "landscape") == 0) + orientation = 1; + else + error("unknown orientation '%1'", optarg); + } + break; + case 'c': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if ((n <= 0) && (ptr == optarg)) + error("argument for -c must be a positive integer"); + else if (n <= 0 || n > 32767) + error("out of range argument for -c"); + else + ncopies = unsigned(n); + break; + } + case 'w': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if (n == 0 && ptr == optarg) + error("argument for -w must be a non-negative integer"); + else if (n < 0 || n > INT_MAX) + error("out of range argument for -w"); + else + linewidth_factor = int(n); + break; + } + case 'h': + usage(stdout); + break; + case '?': + usage(stderr); + exit(EXIT_FAILURE); + break; + default: + assert(0 == "unhandled getopt_long return value"); + } + } + if (optind >= argc) + do_file("-"); + while (optind < argc) + do_file(argv[optind++]); + if (lbpoutput) + lbpputs("\033c\033<"); + return 0; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: diff --git a/src/devices/grolbp/lbp.h b/src/devices/grolbp/lbp.h new file mode 100644 index 0000000..ee1c7b9 --- /dev/null +++ b/src/devices/grolbp/lbp.h @@ -0,0 +1,544 @@ +// -*- C -*- +/* Copyright (C) 1994-2020 Free Software Foundation, Inc. + Written by Francisco Andrés Verdú <pandres@dragonet.es> + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This file contains a set of utility functions to use canon CaPSL printers + * (lbp-4 and lbp-8 series printers) */ + +#ifndef LBP_H +#define LBP_H + +#include <stdio.h> +#include <stdarg.h> + +static FILE *lbpoutput = NULL; +static FILE *vdmoutput = NULL; + + +static inline void +lbpinit(FILE *outfile) +{ + lbpoutput = outfile; +} + + +static void +lbpprintf(const char *format, ... ) +{ /* Taken from cjet */ + va_list stuff; + + va_start(stuff, format); + vfprintf(lbpoutput, format, stuff); + va_end(stuff); +} + + +static inline void +lbpputs(const char *data) +{ + fputs(data,lbpoutput); +} + + +static inline void +lbpputc(unsigned char c) +{ + fputc(c,lbpoutput); +} + + +static inline void +lbpsavestatus(int idx ) +{ + fprintf(lbpoutput,"\033[%d%%y",idx); +} + + +static inline void +lbprestorestatus(int idx ) +{ + fprintf(lbpoutput,"\033[%d%cz",idx ,'%'); +} + + +static inline void +lbpsavepos(int idx) +{ + fprintf(lbpoutput,"\033[1;%d;0x",idx); +} + + +static inline void +lbprestorepos(int idx) +{ + fprintf(lbpoutput,"\033[0;%d;0x",idx); +} + + +static inline void +lbprestoreposx(int idx) +{ + fprintf(lbpoutput,"\033[0;%d;1x",idx); +} + + +static inline void +lbpmoverel(int despl, char direction) +{ + fprintf(lbpoutput,"\033[%d%c",despl,direction); +} + + +static inline void +lbplinerel(int width,int despl,char direction ) +{ + fprintf(lbpoutput,"\033[%d;0;9{\033[%d%c\033[9}",width,despl,direction); +} + + +static inline void +lbpmoveabs(int x, int y) +{ + fprintf(lbpoutput,"\033[%d;%df",y,x); +} + + +static inline void +lbplineto(int x,int y, int width ) +{ + fprintf(lbpoutput,"\033[%d;0;9{",width); + lbpmoveabs(x,y); + fprintf(lbpoutput,"\033[9}\n"); +} + + +static inline void +lbpruleabs(int x, int y, int hsize, int vsize) +{ + lbpmoveabs(x,y); + fprintf(lbpoutput,"\033[0;9;000s"); + lbpmoveabs(x+hsize,y+vsize); + fprintf(lbpoutput,"\033[9r"); +} + + +static void vdmprintf(const char *format, ... ); + + +static inline char * +vdmnum(int num,char *result) +{ + char b1,b2,b3; + char *p = result; + int nm; + + nm = abs(num); + /* First byte 1024 - 32768 */ + b1 = ((nm >> 10) & 0x3F); + if (b1) *p++ = b1 | 0x40; + + /* Second Byte 16 - 1024 */ + b2 = ((nm >> 4) & 0x3F); + if ( b1 || b2) *p++= b2 | 0x40; + + /* Third byte 0 - 15 */ + b3 = ((nm & 0x0F) | 32); + if (num >= 0) b3 |= 16; + *p++ = b3; + *p = 0x00; /* End of the resulting string */ + return result; +} + + +static inline void +vdmorigin(int newx, int newy) +{ + char nx[4],ny[4]; + + vdmprintf("}\"%s%s\x1e",vdmnum(newx,nx),vdmnum(newy,ny)); +} + + +static inline FILE * +vdminit(FILE *vdmfile) +{ + char scale[4],size[4],lineend[4]; + +/* vdmoutput = tmpfile();*/ + vdmoutput = vdmfile; + /* Initialize the VDM mode */ + vdmprintf("\033[0&}#GROLBP\x1e!0%s%s\x1e$\x1e}F%s\x1e",\ + vdmnum(-3,scale),vdmnum(1,size),vdmnum(1,lineend)); + return vdmoutput; + +} + + +static inline void +vdmend() +{ + vdmprintf("}p\x1e"); +} + + +static void +vdmprintf(const char *format, ... ) +{ /* Taken from cjet */ + va_list stuff; + + if (vdmoutput == NULL) vdminit(tmpfile()); + va_start(stuff, format); + vfprintf(vdmoutput, format, stuff); + va_end(stuff); +} + + +static inline void +vdmsetfillmode(int pattern,int perimeter, int inverted) +{ + char patt[4],perim[4], + rot[4], /* rotation */ + espejo[4], /* espejo */ + inv[4]; /* Inverted */ + + vdmprintf("I%s%s%s%s%s\x1e",vdmnum(pattern,patt),\ + vdmnum(perimeter,perim),vdmnum(0,rot), + vdmnum(0,espejo),vdmnum(inverted,inv)); +} + + +static inline void +vdmcircle(int centerx, int centery, int radius) +{ + char x[4],y[4],rad[4]; + + vdmprintf("5%s%s%s\x1e",vdmnum(centerx,x),vdmnum(centery,y),\ + vdmnum(radius,rad)); +} + + +static inline void +vdmaarc(int centerx, int centery, int radius,int startangle,int angle,int style,int arcopen) +{ + char x[4],y[4],rad[4],stx[4],sty[4],styl[4],op[4]; + + vdmprintf("}6%s%s%s%s%s%s%s\x1e",vdmnum(arcopen,op),\ + vdmnum(centerx,x),vdmnum(centery,y),\ + vdmnum(radius,rad),vdmnum(startangle,stx),vdmnum(angle,sty),\ + vdmnum(style,styl)); +} + + +static inline void +vdmvarc(int centerx, int centery,int radius, int startx, int starty, int endx, int endy,\ + int style,int arcopen) +{ + char x[4],y[4],rad[4],stx[4],sty[4],enx[4],eny[4],styl[4],op[4]; + + vdmprintf("}6%s%s%s%s%s%s%s%s%s\x1e",vdmnum(arcopen,op),\ + vdmnum(centerx,x),vdmnum(centery,y),\ + vdmnum(radius,rad),vdmnum(startx,stx),vdmnum(starty,sty),\ + vdmnum(endx,enx),vdmnum(endy,eny),vdmnum(style,styl)); +} + + +static inline void +vdmellipse(int centerx, int centery, int radiusx, int radiusy,int rotation) +{ + char x[4],y[4],radx[4],rady[4],rotat[4]; + + vdmprintf("}7%s%s%s%s%s\x1e\n",vdmnum(centerx,x),vdmnum(centery,y),\ + vdmnum(radiusx,radx),vdmnum(radiusy,rady),\ + vdmnum(rotation,rotat)); +} + + +static inline void +vdmsetlinetype(int lintype) +{ + char ltyp[4], expfact[4]; + + vdmprintf("E1%s%s\x1e",vdmnum(lintype,ltyp),vdmnum(1,expfact)); + +} + + +static inline void +vdmsetlinestyle(int lintype, int pattern,int unionstyle) +{ + char patt[4],ltip[4], + rot[4], /* rotation */ + espejo[4], /* espejo */ + in[4]; /* Inverted */ + + vdmprintf("}G%s%s%s%s%s\x1e",vdmnum(lintype,ltip),\ + vdmnum(pattern,patt),vdmnum(0,rot), + vdmnum(0,espejo),vdmnum(0,in)); + vdmprintf("}F%s",vdmnum(unionstyle,rot)); +} + + +static inline void +vdmlinewidth(int width) +{ + char wh[4]; + + vdmprintf("F1%s\x1e",vdmnum(width,wh)); +} + + +static inline void +vdmrectangle(int origx, int origy,int dstx, int dsty) +{ + char xcoord[4],ycoord[4],sdstx[4],sdsty[4]; + + vdmprintf("}:%s%s%s%s\x1e\n",vdmnum(origx,xcoord),vdmnum(dstx,sdstx),\ + vdmnum(origy,ycoord),vdmnum(dsty,sdsty)); +} + + +static inline void +vdmpolyline(int numpoints, int *points) +{ + int i,*p = points; + char xcoord[4],ycoord[4]; + + if (numpoints < 2) return; + vdmprintf("1%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord)); + p += 2; + for (i = 1; i < numpoints ; i++) { + vdmprintf("%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord)); + p += 2; + } /* for */ + vdmprintf("\x1e\n"); +} + + +static inline void +vdmpolygon(int numpoints, int *points) +{ + int i,*p = points; + char xcoord[4],ycoord[4]; + + if (numpoints < 2) return; + vdmprintf("2%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord)); + p += 2; + for (i = 1; i < numpoints ; i++) { + vdmprintf("%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord)); + p += 2; + } /* for */ + vdmprintf("\x1e\n"); + +} + + +/************************************************************************ + * Higher level auxiliary functions * + ************************************************************************/ +static inline int +vdminited() +{ + return (vdmoutput != NULL); +} + + +static inline void +vdmline(int startx, int starty, int sizex, int sizey) +{ + int points[4]; + + points[0] = startx; + points[1] = starty; + points[2] = sizex; + points[3] = sizey; + + vdmpolyline(2,points); + +} + + +/*#define THRESHOLD .05 */ /* inch */ +#define THRESHOLD 1 /* points (1/300 inch) */ +static inline void +splinerel(double px,double py,int flush) +{ + static int lx = 0 ,ly = 0; + static double pend = 0.0; + static int dy = 0, despx = 0, despy = 0, sigpend = 0; + int dxnew = 0, dynew = 0, sg; + char xcoord[4],ycoord[4]; + double npend ; + + if (flush == -1) {lx = (int)px; ly = (int)py; return;} + + if (flush == 0) { + dxnew = (int)px -lx; + dynew = (int)py -ly; + if ((dxnew == 0) && (dynew == 0)) return; + sg = (dxnew < 0)? -1 : 0; +/* fprintf(stderr,"s (%d,%d) (%d,%d)\n",dxnew,dynew,despx,despy);*/ + if (dynew == 0) { + despx = dxnew; + if ((sg == sigpend) && (dy == 0)){ + return; + } + dy = 0; + } + else { + dy = 1; + npend = (1.0*dxnew)/dynew; + if (( npend == pend) && (sigpend == sg)) + { despy = dynew; despx = dxnew; return; } + else + { sigpend = sg; + pend = npend; + } /* else (( npend == pend) && ... */ + } /* else (if (dynew == 0)) */ + } /* if (!flush ) */ + + /* if we've changed direction we must draw the line */ +/* fprintf(stderr," (%d) %.2f,%.2f\n",flush,(float)px,(float)py);*/ + if ((despx != 0) || (despy != 0)) vdmprintf("%s%s",vdmnum(despx,xcoord),\ + vdmnum(despy,ycoord)); + /*if ((despx != 0) || (despy != 0)) fprintf(stderr,"2 + *%d,%d\n",despx,despy);*/ + if (flush) { + dxnew = dy = despx = despy = 0; + return; + } /* if (flush) */ + dxnew -= despx; + dynew -= despy; + if ((dxnew != 0) || (dynew != 0)) vdmprintf("%s%s",vdmnum(dxnew,xcoord),\ + vdmnum(dynew,ycoord)); + +/* if ((dxnew != 0) || (dynew != 0)) fprintf(stderr,"3 + * %d,%d\n",dxnew,dynew);*/ + lx = (int)px; ly = (int)py; + dxnew = dy = despx = despy = 0; + +} + + +/********************************************************************** + * The following code to draw splines is adapted from the transfig package + */ +static void +quadratic_spline(double a_1, double b_1, double a_2, double b_2, \ + double a_3, double b_3, double a_4, double b_4) +{ + double x_1, y_1, x_4, y_4; + double x_mid, y_mid; + + x_1 = a_1; y_1 = b_1; + x_4 = a_4; y_4 = b_4; + x_mid = (a_2 + a_3)/2.0; + y_mid = (b_2 + b_3)/2.0; + if ((fabs(x_1 - x_mid) < THRESHOLD) + && (fabs(y_1 - y_mid) < THRESHOLD)) { + splinerel(x_mid, y_mid, 0); +/* fprintf(tfp, "PA%.4f,%.4f;\n", x_mid, y_mid);*/ + } + else { + quadratic_spline(x_1, y_1, ((x_1+a_2)/2.0), ((y_1+b_2)/2.0), + ((3.0*a_2+a_3)/4.0), ((3.0*b_2+b_3)/4.0), x_mid, y_mid); + } + + if ((fabs(x_mid - x_4) < THRESHOLD) + && (fabs(y_mid - y_4) < THRESHOLD)) { + splinerel(x_4, y_4, 0); +/* fprintf(tfp, "PA%.4f,%.4f;\n", x_4, y_4);*/ + } + else { + quadratic_spline(x_mid, y_mid, + ((a_2+3.0*a_3)/4.0), ((b_2+3.0*b_3)/4.0), + ((a_3+x_4)/2.0), ((b_3+y_4)/2.0), x_4, y_4); + } +} + + +#define XCOORD(i) numbers[(2*i)] +#define YCOORD(i) numbers[(2*i)+1] +static void +vdmspline(int numpoints, int o_x, int o_y, int *numbers) +{ + double cx_1, cy_1, cx_2, cy_2, cx_3, cy_3, cx_4, cy_4; + double x_1, y_1, x_2, y_2; + char xcoord[4],ycoord[4]; + int i; + + /*p = s->points; + x_1 = p->x/ppi;*/ + x_1 = o_x; + y_1 = o_y; +/* p = p->next; + x_2 = p->x/ppi; + y_2 = p->y/ppi;*/ + x_2 = o_x + XCOORD(0); + y_2 = o_y + YCOORD(0); + cx_1 = (x_1 + x_2)/2.0; + cy_1 = (y_1 + y_2)/2.0; + cx_2 = (x_1 + 3.0*x_2)/4.0; + cy_2 = (y_1 + 3.0*y_2)/4.0; + +/* fprintf(stderr,"Spline %d (%d,%d)\n",numpoints,(int)x_1,(int)y_1);*/ + vdmprintf("1%s%s",vdmnum((int)x_1,xcoord),vdmnum((int)y_1,ycoord)); + splinerel(x_1,y_1,-1); + splinerel(cx_1,cy_1,0); +/* fprintf(tfp, "PA%.4f,%.4f;PD%.4f,%.4f;\n", + x_1, y_1, cx_1, cy_1);*/ + + /*for (p = p->next; p != NULL; p = p->next) {*/ + for (i = 1; i < (numpoints); i++) { + x_1 = x_2; + y_1 = y_2; +/* x_2 = p->x/ppi; + y_2 = p->y/ppi;*/ + x_2 = x_1 + XCOORD(i); + y_2 = y_1 + YCOORD(i); + cx_3 = (3.0*x_1 + x_2)/4.0; + cy_3 = (3.0*y_1 + y_2)/4.0; + cx_4 = (x_1 + x_2)/2.0; + cy_4 = (y_1 + y_2)/2.0; + /* fprintf(stderr,"Point (%d,%d) - (%d,%d)\n",(int)x_1,(int)(y_1),(int)x_2,(int)y_2);*/ + quadratic_spline(cx_1, cy_1, cx_2, cy_2, cx_3, cy_3, cx_4, cy_4); + cx_1 = cx_4; + cy_1 = cy_4; + cx_2 = (x_1 + 3.0*x_2)/4.0; + cy_2 = (y_1 + 3.0*y_2)/4.0; + } + x_1 = x_2; + y_1 = y_2; +/* p = s->points->next; + x_2 = p->x/ppi; + y_2 = p->y/ppi;*/ + x_2 = o_x + XCOORD(0); + y_2 = o_y + YCOORD(0); + cx_3 = (3.0*x_1 + x_2)/4.0; + cy_3 = (3.0*y_1 + y_2)/4.0; + cx_4 = (x_1 + x_2)/2.0; + cy_4 = (y_1 + y_2)/2.0; + splinerel(x_1, y_1, 0); + splinerel(x_1, y_1, 1); + /*vdmprintf("%s%s",vdmnum((int)(x_1-lx),xcoord),\ + vdmnum((int)(y_1-ly),ycoord));*/ + vdmprintf("\x1e\n"); +/* fprintf(tfp, "PA%.4f,%.4f;PU;\n", x_1, y_1);*/ + + +} + + +#endif |