diff options
182 files changed, 32085 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..d8bf3cd --- /dev/null +++ b/ChangeLog @@ -0,0 +1,592 @@ +Fri May 13 15:18:27 1994 Karl Berry (karl@cs.umb.edu) + + * configure.in: Include kpathsea/common.ac. + +Sat Jul 31 11:38:21 1993 Karl Berry (karl@cs.umb.edu) + + * configure.in: Remove AC_PREFIX. + +Wed Jun 2 08:09:17 1993 Karl Berry (karl@cs.umb.edu) + + * configure.in: Call AC_PROG_CPP explicitly. Don't bother with + AC_GCC_TRADITIONAL. + +Sat May 22 11:22:57 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (dist): Run gzip -9. + +Thu May 20 16:59:38 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (default_tfm_path): Put . first. + +Tue May 18 14:02:05 1993 Karl Berry (karl@cs.umb.edu) + + * Makefile.in (install-*): mkdirchain on install dirs, and put + mkdirchain in the dist. + +Sun Apr 11 14:59:50 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (dist): Copy info files to the local info directory. + +Sat Apr 10 14:58:43 1993 Karl Berry (karl@cs.umb.edu) + + * configure.in: Do AC_XENIR_DIR after AC_DIR_HEADER. + +Thu Mar 25 16:01:51 1993 Karl Berry (karl@cs.umb.edu) + + * configure.in (AC_ISC_WLIBS): Remove. + * aclocal.m4: New version, see web2c ChangeLog. + +Tue Feb 23 16:52:13 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (dist): Copy info files to my local info directory. + +Sat Jan 9 15:22:51 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (configure, config.status): cd $(srcdir) first. + +Fri Jan 1 13:57:15 1993 Karl Berry (karl@cs.umb.edu) + + * configure.in: Changes for new Autoconf. + +Sun Dec 13 16:39:23 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (default_tfm_path): Use $(texdatadir). + +Thu Dec 10 10:34:30 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (GNUmakefile): Add $(srcdir) to dependency, and + use $(SHELL) instead of sh. + (config.status): Use $(SHELL). + +Sun Nov 29 17:17:46 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (emacslispdir): Doc fix. + +Wed Oct 28 15:09:29 1992 Karl Berry (karl@claude.cs.umb.edu) + + * Version 0.6. + + * GNUmakefile.in (install): Install data files with file as second + arg, not directory. + +Sun Oct 25 15:29:19 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (realclean): Depend on distclean. + + * GNUmakefile.in (installargs): Passed texinputdir as mfinputdir. + + * GNUmakefile.in (install): Correct to `emacs_datadir' in the mkdir. + +Thu Oct 15 08:35:21 1992 Karl Berry (karl@cs.umb.edu) + + * configure: Ran Autoconf 1.2. + +Mon Oct 5 10:24:15 1992 Karl Berry (karl@cs.umb.edu) + + * configure.in: Generate doc/Makefile. (arif@stat.fsu.edu) + + * GNUmakefile.in (install): Install common.cmi. (ab@meiko.co.uk) + +Sun Oct 4 11:22:45 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (examplefiles): Remove; just make links. + (dist): Don't copy them. + +Sun Sep 20 12:53:29 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile.in (config.status): use sh to run configure --no-create. + + * GNUmakefile.in (realclean): OK, don't remove configure. + +Mon Sep 14 17:50:54 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (realclean): separate from distclean. + (distclean): remove GNUmakefile. + (config.status): new target. + (GNUmakefile): depend on config.status. + +Sat Sep 12 14:53:31 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (dist): replace remaining occurrences of + `fontutils-$(version) with `$(top_distdir)'. + +Thu Sep 10 08:57:02 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (dist): changed where the COPYING* files are kept. + + * GNUmakefile.in (xincludedir, xlibdir): say that these are + options, not just directories. + + * GNUmakefile.in (realclean): remove configure. + +Tue Sep 8 16:42:04 1992 Karl Berry (karl@hayley) + + * configure.in: test for more Unix variants. + +Fri Sep 4 08:39:15 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (extraclean): new target. + +Thu Sep 3 08:54:12 1992 Karl Berry (karl@hayley) + + * Version 0.5. + + * GNUmakefile.in (distargs): pass $(version) down. + +Sat Aug 29 16:11:47 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (tex{data,input}dir): new variables. + (installargs): pass texinputdir. + +Thu Aug 27 08:56:47 1992 Karl Berry (karl@hayley) + + * configure: regenerated from Autoconf 1.1. + +Wed Aug 19 07:55:50 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (install): do make install in `doc', and install + the .enc and encoding.map files from `data'. + +Tue Aug 18 15:50:55 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (completedirs): remove `doc' (yay!). + +Sat Aug 15 13:32:38 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (mfdatadir, mfinputdir): new variables. + (installargs): pass mfinputdir. + +Mon Aug 3 16:00:58 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (emacs_datadir, emacslispdir): new variables. + (install): mkdir them. + (installargs): pass emacslispdir down. + +Fri Jul 31 17:02:22 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (dist): include our aclocal.m4. + + * GNUmakefile.in (LIBS): include $(extralibs) for the user to + define. + +Wed Jul 22 08:42:46 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (topfiles): add `NEWS'. + * NEWS: new file. + + * configure.in: changes for Autoconf 1.0. + +Thu Jul 2 15:26:14 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (makeargs): pass srcdir and CFLAGS. + (CCFLAGS): remove. + + * Run Autoconf 0.119. + +Mon Jun 29 08:58:37 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (paths.h): delete it before creating it. + Also, new target `GNUmakefile'. + (fu_datadir): new variable for the subdirectory in $(datadir) + which we create. + (install): mkdir all the directories we install into. + (CFLAGS): change to CCFLAGS, so the user can set CFLAGS on the + command line. + +Sat Jun 27 11:04:17 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (paths.h): depend on GNUmakefile.in and GNUmakefile. + +Sun Jun 21 12:43:32 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (app_defaults): change default and describe better. + +Thu Jun 11 09:07:01 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (.NOEXPORT): new target, since Autoconf doesn't add + it automatically any more. + +Sun Jun 7 08:09:17 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (examplefiles): new variable. + (dist): copy $(examplefiles) into doc/example. + +Thu Jun 4 08:24:46 1992 Karl Berry (karl@hayley) + + * configure.in (AC_HEADER_FILE): rename to AC_CONFIG_HEADER, for + Autoconf 0.115. + +Wed Jun 3 08:41:33 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (dist): add-version in top_distdir. + +Fri May 29 08:36:46 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (completedirs): add `doc' (temporarily). + +Thu May 21 15:00:30 1992 Karl Berry (karl@hayley) + + * GNUmakefile.in (programs): `imagetofont' => `imageto'. + +Mon May 18 12:01:42 1992 Karl Berry (karl@hayley) + + * configure.in: change top-level Makefile name to `GNUmakefile.in'. + * GNUmakefile.in: renamed from Makefile.in. + + * Makefile.in (dist): rewrite to `make dist' in subdirs. + + * Makefile.in (alldirs): move `doc' here. + (completedirs): from here. + + * Makefile.in (dist): copy testfont.tex into `data'. + +Sat May 16 10:09:34 1992 Karl Berry (karl@hayley) + + * configure.in: PROG_CPP must come before GCC_TRADITIONAL. + +Fri May 15 09:05:22 1992 Karl Berry (karl@hayley) + + * configure.in: add AC_GCC_TRADITIONAL and AC_PROG_CPP. + + * configure.in: AC_HEADER_MISSING is now AC_HEADER_CHECK. + + * Makefile.in (exec_prefix): new variable. + (bindir): use it. + +Thu May 14 06:41:19 1992 Karl Berry (karl@hayley) + + * Makefile.in (app_defaults_dir): -> app-defaults. + +Wed May 13 08:55:11 1992 Karl Berry (karl@hayley) + + * Makefile.in (VPATH): change for new Autoconf. + +Sat May 9 10:21:08 1992 Karl Berry (karl@hayley) + + * Makefile.in (dist): make dist in doc; copy COPYING*. + +Thu May 7 08:10:40 1992 Karl Berry (karl@hayley) + + * Makefile.in (dist): don't link include/*.in, we've already got it. + +Mon May 4 14:24:39 1992 Karl Berry (karl@hayley) + + * Makefile.in (gsrenderfont): remove this target. + (all): don't depend on it. + +Tue Apr 28 10:16:39 1992 Karl Berry (karl@hayley) + + * configure.in: Autoconf's prefix is now AC_, not M_. + +Thu Apr 23 07:32:29 1992 Karl Berry (karl@hayley) + + * configure.in: test $GCC instead of grepping for `gcc' in $CC. + + * Makefile.in (dist): distribute include/*.in. + + * Makefile.in (.NOEXPORT): remove this, as configure now puts it + in automatically. + +Wed Apr 22 12:58:49 1992 Karl Berry (karl@hayley) + + * Makefile.in (prefix): set to /usr/local; configure doesn't do + M_SUBST. + + * configure.in: M_MEMORY_H is now M_NEED_MEMORY_H. + +Sun Apr 19 10:41:07 1992 Karl Berry (karl@hayley) + + * Makefile.in (distclean): add this as a target. + +Sun Apr 12 14:08:35 1992 Karl Berry (karl@hayley) + + * Makefile.in (bzrtospecial): add *.el to the distributed list. + +Wed Apr 8 09:31:37 1992 Karl Berry (karl@hayley) + + * Makefile.in (all): depend on gsrenderfont. + (gsrenderfont/gsrenderfont): make it by substituting for the lib-path. + (gsrenderspecial): dist gsrf.in instead of gsrenderfont. + (versionfiles): likewise. + +Tue Apr 7 13:58:50 1992 Karl Berry (karl@hayley) + + * Makefile.in (dist): copy the .ad files into the distribution + directory, not the working dirs. + +Sun Mar 29 08:42:54 1992 Karl Berry (karl at hayley) + + * Makefile.in (programs, libraries, etc.): use $(MAKE), not `make'. + +Sat Mar 28 07:44:42 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Fri Mar 27 19:46:49 1992 Karl Berry (karl at hayley) + + * PROJECTS: move to doc. + * Makefile.in (topfiles): remove it. + +Thu Mar 26 19:54:28 1992 Karl Berry (karl at claude.cs.umb.edu) + + * Makefile.in (makeargs): pass xlibdir. + + * Makefile.in (installargs): missing quote. + (install): do `install' in subdirs. + +Thu Mar 26 06:37:55 1992 Karl Berry (karl at hayley) + + * Makefile.in (dist): remove include/paths.h. + +Wed Mar 25 07:20:10 1992 Karl Berry (karl at hayley) + + * Makefile.in (topfiles): remove PROBLEMS, add COPYING.LIB. + +Tue Mar 10 10:48:19 1992 Karl Berry (karl at hayley) + + * Makefile.in (programs): replace xbce and xlse with xbfe. + (dist): similarly. + +Sun Mar 8 12:48:52 1992 Karl Berry (karl at hayley) + + * configure.in: guess the value for `prefix'. + * Makefile.in (prefix): define it as a substitution. + + * Makefile.in (mostlyclean): new target. + (distclean): remove. + (clean): remove the config files here, not at realclean. + +Sat Mar 7 13:34:55 1992 Karl Berry (karl at fosse) + + * Makefile.in (xincludedir): new variable. + (CFLAGS): use it. + * configure.in: test for it. + +Sat Mar 7 09:59:10 1992 Karl Berry (karl at hayley) + + * configure.in: change config-auto.h to c-auto.h. + + * configure.in: substitute for LDFLAGS. + +Thu Mar 5 17:31:06 1992 Karl Berry (karl at claude.cs.umb.edu) + + * Makefile.in (makeargs): don't double the $'s. + +Thu Mar 5 07:12:13 1992 Karl Berry (karl at hayley) + + * Makefile.in (dist): add version numbers automatically; add in + special files in bzrto and gsrenderfont. + (bzrtospecial, gsrenderspecial): new variables. + +Wed Mar 4 11:24:12 1992 Karl Berry (karl at hayley) + + * gnuw: rename to `widgets'. + * Makefile.in (libraries): corresponding. + +Sun Mar 1 12:59:09 1992 Karl Berry (karl at hayley) + + * Makefile.in (libraries): add pbm. + pbm: new directory. + +Tue Feb 25 10:48:47 1992 Karl Berry (karl at hayley) + + * AUTHORS: new file. + Makefile.in (topfiles): dist it. + +Mon Feb 24 08:36:00 1992 Karl Berry (karl at hayley) + + * configure.in [isc]: include -shlib in LDFLAGS. + +Sun Feb 23 09:04:51 1992 Karl Berry (karl at hayley) + + * GNUmakefile (dist): update for various new directories and files. + +Tue Feb 11 09:56:23 1992 Karl Berry (karl at hayley) + + * configure.in: test for memcpy et al. only in <memory.h>. + + * configure.in: test for <limits.h> missing. + + * configure.in: test for extra window system libraries. + Makefile.in (wlibs): new variables. + (makeargs): pass it down to submakes. + + * configure.in: test M_ISC early, before any compiles. + + * Makefile.in (copt): remove it; use CC instead. + +Mon Feb 10 09:36:22 1992 Karl Berry (karl at hayley) + + * Makefile.in (copt): new variable. + +Sat Feb 8 14:48:28 1992 Karl Berry (karl at hayley) + + * Makefile.in (realclean): remove config.status and Makefile. + +Sun Feb 2 13:50:53 1992 Karl Berry (karl at hayley) + + * Makefile.in: rename paths.h-dist to paths.h.in. + +Sat Feb 1 14:57:12 1992 Karl Berry (karl at hayley) + + * Makefile.in (default_subdir_path): remove. + (default_tfm_path): change to new syntax for subdirs. + +Wed Jan 15 13:00:59 1992 Karl Berry (karl at hayley) + + * configure.in: do not test for getwd. + +Sun Jan 12 12:13:59 1992 Karl Berry (karl at hayley) + + * Makefile.in (default_lib_path): remove `.', as it is added + automatically now. + + * Makefile.in (.NOEXPORT): new target. + +Sat Jan 11 09:53:56 1992 Karl Berry (karl at hayley) + + * Makefile.in (CFLAGS): remove -I$(srcdir), and use + -I../$(srcdir)/include. + +Fri Jan 10 15:36:17 1992 Karl Berry (karl at hayley) + + * Makefile.in (default_tfm_path): set to null. + +Wed Jan 8 15:41:13 1992 Karl Berry (karl at hayley) + + * config: we don't need this directory any more. + * configure: or this script. + * fontutils.in: the input to autoconf, so it can make the + configure script. + + * GNUmakefile (programs): remove ospace and gsrenderfont, add + charspace. + + * rename `lib' as `data', and `kbase' as `lib'. Merge `getopt' + into `lib'. + * GNUmakefile (libraries): change to match. + +Tue Dec 24 16:41:51 1991 Kathy Hargreaves (kathy at hayley) + + * GNUmakefile (DEFAULT_LIB_PATH): define using $(shell pwd), not + the nonexistent $(PWD). + +Tue Oct 1 10:07:34 1991 Karl Berry (karl at hayley) + + * all files: change copyright notices to not use dashes. + +Tue Jul 30 13:16:38 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Fri Jul 26 10:33:26 1991 Karl Berry (karl at hayley) + + * PROJECTS: new file. + + * GNUmakefile (programs): `fit-outlines' is now `limn'; include + `gsrenderfont'. + +Wed Jul 24 15:17:33 1991 Karl Berry (karl at ra.cs.umb.edu) + + * configure: exit 0 at the end. + +Mon Jul 22 06:08:10 1991 Karl Berry (karl at hayley) + + * GNUmakefile (programs): add imagetofont. + +Fri Jul 19 08:31:06 1991 Karl Berry (karl at hayley) + + * GNUmakefile: add many variables to be overridden. + + * config: rename to configure. + * configfiles: rename to config. + +Wed Jun 12 05:42:44 1991 Karl Berry (karl at hayley) + + * GNUmakefile (tags): rename to `TAGS'. + (distclean): new target. + +Thu Jun 6 07:11:45 1991 Karl Berry (karl at hayley) + + * COPYING: change to version 2 of the GPL. + +Sun Mar 24 16:17:03 1991 Karl Berry (karl at hayley) + + * GNUmakefile (dist): new dependencies `depend' and `TAGS'. + +Mon Mar 11 08:19:59 1991 Karl Berry (karl at hayley) + + * GNUmakefile (dist): put bzrto/KKBuildChar.PS in the + distribution. + +Sun Mar 10 16:26:14 1991 Karl Berry (karl at hayley) + + * GNUmakefile (DEFAULT_TFM_PATH): change the default to `.'. + +Fri Mar 8 08:42:49 1991 Karl Berry (karl at hayley) + + * GNUmakefile (install): pass bindir as an arg to make. + + * GNUmakefile (dist): make an empty directory `bin'. (from + rich@rice.edu) + + * GNUmakefile (include/s.h): run ./config, not config, for the + sake of people who might have a system config earlier in their + path. (from ian@sq.com) + +Thu Mar 7 07:30:59 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Wed Mar 6 10:05:28 1991 Kathy Hargreaves (kathy at hayley) + + * config: use `sunosNNN' instead of `sunNNN'. + +Mon Mar 4 15:14:41 1991 Karl Berry (karl at hayley) + + * GNUmakefile (programs): fontconcat is gone. + +Fri Mar 1 09:53:28 1991 Karl Berry (karl at hayley) + + * GNUmakefile (completedirs, topfiles): new variables to help in + `make dist'. + +Mon Feb 25 09:20:37 1991 Karl Berry (karl at hayley) + + * GNUmakefile (programs): include `bzrto'. + + * GNUmakefile (DEFAULT_LIB_PATH): include `pwd`/lib. + +Sun Feb 17 09:54:28 1991 Karl Berry (karl at hayley) + + * GNUmakefile (realclean): remove include/{s,paths}.h. + +Sat Feb 16 17:21:39 1991 Karl Berry (karl at hayley) + + * GNUmakefile (all): new dependencies, on include/paths.h + and include/s.h. + * GNUmakefile (include/paths.h): new target. + +Sat Nov 17 11:28:25 1990 Karl Berry (karl at hayley) + + * GNUmakefile (programs): add fit-outlines. + +Thu Nov 1 08:51:29 1990 Karl Berry (karl at hayley) + + * INSTALL: DEFAULT_TFM_PATH has moved from kbase/filename.c to + kbase/font.c. + +Wed Oct 24 14:57:57 1990 Karl Berry (karl at aten) + + * Version 0.1. + +Sun Oct 21 16:23:20 1990 Karl Berry (karl at hayley) + + * GNUmakefile (libraries): add gnuw. + +Sun Sep 30 08:43:44 1990 Karl Berry (karl at hayley) + + * GNUmakefile (programs): add fontconcat. diff --git a/GNUmakefile.in b/GNUmakefile.in new file mode 100644 index 0000000..ed51c74 --- /dev/null +++ b/GNUmakefile.in @@ -0,0 +1,235 @@ +# Master GNU makefile for font utilities. +# +# Copyright (C) 1992, 93, 2004 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Version number of this release. +version = .6g + +# Installation prefixes. Since GNU programs and the TeX system may be +# installed in different places, we have different prefixes. +prefix = /usr/local +exec_prefix = $(prefix) +texmf_prefix = /usr/local + +# Installation directories. +bindir = $(exec_prefix)/bin +infodir = $(prefix)/info +datadir = $(prefix)/lib +fu_datadir = $(datadir)/fontutil +emacs_datadir = $(datadir)/emacs +# Emacs 18 and Emacs 19 both have different directories for this. +emacslispdir = $(emacs_datadir)/elisp # Where to install .el files. + +mfdatadir = $(texmf_prefix)/lib/mf +mfinputdir = $(mfdatadir)/macros +texdatadir = $(texmf_prefix)/lib/tex +texinputdir = $(texdatadir)/macros + +# Where the default resource files for X programs get installed. If you +# don't want to or can't write in the standard app-defaults directory, +# you can set this to any directory you like as long as you set the +# XAPPLRESDIR environment variable to the same directory. See the +# tutorial on resources in the X distribution +# (.../mit/doc/tutorial/resources.txt) for more information. +app_defaults = $(prefix)/lib/app-defaults + +# Default paths for you to override. You can either change these and +# run `make', or copy include/paths.h.in to include/paths.h and change +# them manually. These paths are overridden by various environment +# variables; see the documentation. The font paths here should probably +# match TeX's default paths. +default_lib_path = .:$(shell pwd)/data:$(fu_datadir) +default_tfm_path = .:$(texdatadir)/fonts// +default_pk_path = $(default_tfm_path) +default_gf_path = $(default_tfm_path) + +SHELL = /bin/sh +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Compiler option for #include <X11/...>, i.e., should start with `-I', +# or -DX_DISPLAY_MISSING if X is not supported. +xincludedir = @X_CFLAGS@ + +# Loader option for -lX..., i.e., should start with `-L'. +xlibdir = @X_LDFLAGS@ + +CC = @CC@ +CFLAGS = -g + +# Need DEFS to get -DHAVE_CONFIG_H. It's included in CPPFLAGS via +# data/defs.make. +DEFS = @DEFS@ + +LDFLAGS = $(xlibdir) $(CFLAGS) $(XLDFLAGS) +LIBS = @LIBS@ -lm $(extralibs) +wlibs = @wlibs@ + +RANLIB = @RANLIB@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# You shouldn't need to change anything below here. + +# If X is not supported, don't try to make the widget library or the +# bitmap editor. +# +ifeq "$(xincludedir)" "-DX_DISPLAY_MISSING" +widgets = +xbfe = +else +widgets = widgets +xbfe = xbfe +endif + +libraries = gf lib pbm pk tfm +programs = charspace fontconvert imageto +alldirs = $(libraries) $(programs) doc + +default: all + +.PHONY: all install libraries clean distclean extraclean realclean depend dist + +makeargs = $(MFLAGS) \ + SHELL="$(SHELL)" CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \ + LIBS="$(LIBS)" RANLIB="$(RANLIB)" srcdir=$(srcdir) \ + wlibs="$(wlibs)" xlibdir="$(xlibdir)" xincludedir="$(xincludedir)" \ + widgets="$(widgets)" + +all: libraries + for dir in $(programs); \ + do \ + (cd $${dir}; $(MAKE) $(makeargs) all); \ + done + +libraries: include/paths.h + for dir in $(libraries); \ + do \ + (cd $${dir}; $(MAKE) $(makeargs)); \ + done + +include/paths.h: include/paths.h.in GNUmakefile GNUmakefile.in + rm -f $@ + echo "/* Generated from paths.h.in (`date`). */" > $@ + sed -e "s,replace-with-lib-path,$(default_lib_path)," \ + -e "s,replace-with-tfm-path,$(default_tfm_path)," \ + -e "s,replace-with-pk-path,$(default_pk_path)," \ + -e "s,replace-with-gf-path,$(default_gf_path)," \ + $< >> $@ + + +installargs = bindir=$(bindir) \ + fu_datadir=$(fu_datadir) \ + emacslispdir=$(emacslispdir) \ + mfinputdir=$(mfinputdir) \ + texinputdir=$(texinputdir) \ + app_defaults=$(app_defaults) \ + INSTALL="$(INSTALL)" \ + INSTALL_DATA="$(INSTALL_DATA)" \ + INSTALL_PROGRAM="$(INSTALL_PROGRAM)" + +install: + PATH=.:$PATH mkdirchain $(bindir) $(infodir) \ + $(fu_datadir) $(emacslispdir) $(app_defaults) + for dir in $(programs) doc; do \ + (cd $${dir}; $(MAKE) $(installargs) install); \ + done + cd data; for f in *.enc *.map common.cmi; do \ + $(INSTALL_DATA) $$f $(fu_datadir); done + + +configure: configure.in + cd $(srcdir); autoconf + +config.status: configure + cd $(srcdir); $(SHELL) configure --no-create + +GNUmakefile: $(srcdir)/GNUmakefile.in config.status + $(SHELL) config.status + +include/c-auto.h.in: configure.in ../kpathsea/common.ac + autoheader + +# Prevent GNU make 3 from overflowing arg limit on system V. +.NOEXPORT: + +# Files in the top level directory to be distributed. +topfiles = AUTHORS ChangeLog NEWS README configure *.in + +# Directories whose complete contents (almost) are to be distributed. +completedirs = bin data include + +# Files which have version number or date templates. +versionfiles = gsrenderfont/gsrf.in */version.c + +top_distdir = fontutils-$(version) + +distargs = top_distdir=$(top_distdir) app_defaults=$(app_defaults) \ + version=$(version) srcdir=$(srcdir) + +dist:: # TAGS # depend + rm -rf $(top_distdir) + -mkdir $(top_distdir) +# Set up the top-level files. + ln $(topfiles) $(top_distdir) + cp -p $(HOME)/gnu/gnuorg/COPYING* $(top_distdir) + cp -p $(gnu)/lib/aclocal.m4 $(top_distdir) +# Set up the directories whose complete contents get distributed. + cd $(top_distdir); for dir in $(completedirs); do \ + (mkdir $$dir; ln ../$$dir/* $$dir); done + cp -p $(HOME)/bin/mkdirchain $(top_distdir)/bin + cp -p $(plain)/testfont.tex $(top_distdir)/data + cp -p $(ktex)/macros/printeps.tex $(top_distdir)/data + rm -f $(top_distdir)/include/c-auto.h $(top_distdir)/include/paths.h +# Set up the other subdirectories. + for dir in $(alldirs); do \ + (cd $$dir; $(MAKE) $(distargs) dir=$$dir dist) done +# Add version numbers. Have to do this after creating the +# $(versionfiles), naturally. + cd $(top_distdir); add-version $(version) $(versionfiles) + GZIP=-9 tar czf $(top_distdir). $(top_distdir) +# Put the new info files in the local directory. + cp -pf $(top_distdir)/doc/fontu.info* $(info) + rm -rf $(top_distdir) + +TAGS: + for dir in $(programs); \ + do \ + (cd $${dir}; $(MAKE) $@); \ + done + +depend: include/paths.h + for dir in $(alldirs); \ + do \ + (cd $${dir}; $(MAKE) $@); \ + done + +mostlyclean clean distclean extraclean realclean:: + for dir in $(alldirs); \ + do \ + (cd $${dir}; $(MAKE) $@); \ + done + +distclean:: + rm -f include/c-auto.h include/paths.h config.status GNUmakefile + +realclean:: distclean + +extraclean:: distclean + rm -f *~ *\#* @@ -0,0 +1,66 @@ +This file records user-visible changes. + +Version 0.7 + +* If the X window system is lacking, as much of the distribution as + possible is compiled anyway. +* Imageto looks for TFM widths in an existing TFM file before resorting + to the pixel widths. + +Version 0.6 (28 October 1992) + +* Imageto changes: + - Automatically removes all pieces of adjacent characters; the + `-clean-threshold' kludge is gone. + - `-info-filename' option renamed to `-ifi-filename'. + - Writes a complete GF font if the image file is incomplete. + - No longer crashes on a filename lacking an extension. + +* BZRto changes: + - No longer requires TFM files as input along with the BZR files. + - Doesn't guess that the CCC file is the same as the BZR file. + - Ligature/kern Metafont output doesn't crash on missing characters. + - Metafont output does better at not overflowing MF's memory. + +* GSrenderfont changes: + - Handles invisible characters, such as spaces. + - Reads Type 3 PostScript fonts, as well as Type 1. + - No longer requires an output encoding; default is same as input. + - Reads fonts that aren't known to Ghostscript by default. + +* Other program changes: + - Limn doesn't try to log uninitialized floating-point numbers. + - All the programs handle fontnames containing `.' better. + - Verbose output usually goes to standard output, instead of standard error. + - Minor installation and configuration fixes. + +* Documentation changes: + - The chapter on bug reporting has some further explanation of the + purpose of what we ask for, and clarifications. Please read before + submitting bug reports. + - The chapter on Imageto has been substantially rewritten. I hope the + difficulties people encountered using that program because of + deficiencies in the manual will be cleared up now. + +Version 0.5 (3 September 1992) + +* Manual written! + +* New program `BPLtoBZR' and new Emacs Lisp BZR editing mode bzredit.el. + +* BZRto provides for character construction (of, e.g., pre-accented + files) via CCC files. + Can also merge fonts, scaling them all to the same size. + +* Charspace reads CMI files instead of SBI files; pretty much the same + idea, but many changes to the syntax, etc. + +* Fontconvert can put a space character in its output. + Can do some things via character names, instead of only character codes. + +* Imageto uses character names instead of codes, and + can write EPS files. + +Version 0.4 (28 Mar 1992) + +First public release. @@ -0,0 +1,47 @@ +-- + fontutils needs a maintainer, see project at + http://savannah.gnu.org and/or email karl@gnu.org. + + The web page at http://www.gnu.org/software/fontutils/ describes + what's still potentially useful and what isn't from the last release. + + Everything here is out of date. +-- + +This directory contains the GNU font utilities. See `GNUmakefile.in' +for the version number. See `NEWS' for changes by release. + +See the Texinfo manual in doc/ for installation and usage information. +The file INSTALL contains a copy of the installation instructions, as +plain text. + +Send bug reports for the programs or documentation to +bug-gnu-utils@gnu.org. (See the `Bugs' section of the manual +for discussion of how to submit an effective bug report.) + +Suggestions for improvements (in either the programs or the manual), no +matter how small, are welcome. + +The default installation prefix (we'll call it `$prefix') is the parent +of the directory that contains the command `gcc'. Installing this +package will create a number of programs in $prefix/bin, and some files +in $prefix/lib/fontutil which support the programs. (These directories +will also be created, if they do not exist.) + +The GNU font utilities are free software. See the files COPYING* +for copying permissions. + +We need volunteers to help create fonts for the GNU project. You do not +need to be an expert type designer to help, but you do need to know +enough about TeX and/or PostScript to be able to install and test new +fonts. Example: if you know neither (1) the purpose of TeX utility +program `gftopk' nor (2) what the PostScript `scalefont' command does, +you probably need more experience before you can help. + +If you can volunteer, the first step is to compile the font utilities. +After that, contact me (karl@gnu.ai.mit.edu). I will get you a scanned +type specimen image. The manual explains how to use these utilities to +turn that into a font you can use in TeX or PostScript. + +Karl Berry karl@cs.umb.edu +Kathryn Hargreaves letters@cs.umb.edu diff --git a/charspace/ChangeLog b/charspace/ChangeLog new file mode 100644 index 0000000..d0cd360 --- /dev/null +++ b/charspace/ChangeLog @@ -0,0 +1,406 @@ +Thu Nov 23 09:06:06 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * main.c: replaced find_tfm_filename with kpse_find_tfm. + +Sat Aug 7 11:53:23 1993 Karl Berry (karl@cs.umb.edu) + + * cmi.y, *.h: c-ctype.h and types.h now in kpathsea. + +Fri Dec 11 14:59:42 1992 Karl Berry (karl@cs.umb.edu) + + * symtab.c (symval_as_string): `dtoa' is now `xdtoa'. + + * cmi.y: Change ctype references to use uppercase macros. + +Thu Dec 3 15:40:40 1992 Karl Berry (karl@cs.umb.edu) + + * main.c: Don't bother to include getopt.h, cmdline.h already does. + +Tue Oct 27 13:01:50 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Thu Sep 3 09:29:46 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Sun Aug 23 13:36:19 1992 Karl Berry (karl@hayley) + + * main.c (USAGE): put a newline before GETOPT_USAGE. + +Mon Aug 17 08:35:30 1992 Karl Berry (karl@hayley) + + * input-cmi.h: doc fix. + +Sun Aug 16 21:38:23 1992 Karl Berry (karl@hayley) + + * cmi.y (NOT_A_TOKEN): parenthesize the definition, for safety. + +Sun Jul 19 08:32:13 1992 Karl Berry (karl@hayley) + + * char.c (update_width): char-width now gives the lsb as a + percentage, not a hard number. + * cmi.y: doc fix. + +Tue Jul 14 16:41:54 1992 Karl Berry (karl@hayley) + + * output.c: doc fix. + + * cmi.y (char_width): new rule for the char-width cmd. + * realstrval.h (symval_tag_type): new value `symval_char_width'. + * char.c (update_via_name): handle this case. + (update_width, update_metrics): new routines. + (update_sidebearings): call update_metrics. + +Tue Jul 7 16:43:08 1992 Karl Berry (karl@hayley) + + * output.c (write_tfm): use same algorithm for TFM output names + as fontconvert/output-tfm.c + +Sun Jul 5 10:41:10 1992 Karl Berry (karl@hayley) + + * cmi.y (yylex): allow `+' to start a numeric constant. + +Fri Jul 3 17:46:36 1992 Karl Berry (karl@hayley) + + * main.c (read_encoding_info): default the encoding scheme, if the + user hasn't specified one. + +Sun Jun 14 07:19:12 1992 Karl Berry (karl@hayley) + + * output.c (make_gf_char): copied TFM width from `gf_char' instead + of `bitmap_char'. Argh. + + * output.c (write_tfm): check chars between `starting_char' and + `ending_char', *inclusive*. + + * cmi.y (yylex): `-' can start a numeric constant. + + * char.c (do_char): do the reporting of the charcodes (as we + process them) here. + * main.c (main): not here. + * char.h (do_char): void now, not boolean. + + * symtab.c (symval_as_string): new routine. + * symtab.h (symval_as_string): declare it. + * char.c (resolve_sidebearing): complain if the sb defn can't be + resolved. + + * main.c (main): the symbol table value of `designsize' should be + in pixels, not points. + * output.c (update_tfm_info_from_symtab, find_tfm_info, write_gf): + convert back to points. + * char.c (get_designsize_in_points): new routine. + (update_sidebearings): convert back here, too. + * char.h: declare it. + + * main.c (read_encoding_info): use an existing TFM file as a last + resort to guess the codingscheme. + + * output.c (find_tfm_info): guess the x-height; implies passing in + `chars' now, sigh. + (xheight_char): new global. + * output.h (xheight_char): declare it. + * main.c (read_command_line): new option `-xheight-char'. + (USAGE): document it. + + * symtab.c, output.c, main.c: remove all the logging junk; include + report.h instead of logreport.h. + + * output.c (find_tfm_info): call `tfm_set_fontsize'. + + * cmi.y (char): reversed sense of condition for preserving old kerns. + + * main.c (main): set `dpi_real' near the beginning. + +Sat Jun 13 09:33:37 1992 Karl Berry (karl@hayley) + + * symtab.c (symtab_char_node): call `init_char' on the new value. + + * cmi.y (yylex): keep track of line numbers. + (lineno): new static. + (yyerror): print the filename and line number. + + * output.c (update_tfm_info_from_symtab): don't call symtab_lookup + with a possibly NULL name. + + * cmi.y (token_number): if have a normal identifier, save its + name in yylval. + + * input-cmi.c (read_cmi_file): call `libfile_start'. + + * all files: misc. changes for compilation. + + * symtab.c (symtab_lookup, symtab_lookup_real): finally get around + to defining these. + + * char.c: update for new list fn names. + + * output.c: complete rewrite. + +Fri Jun 12 11:06:05 1992 Karl Berry (karl@hayley) + + * char.c (do_char): move here. + * main.c: from here. + * char.h: declare it. + +Thu Jun 11 11:06:47 1992 Karl Berry (karl@hayley) + + * char.h (char_type): new field `tfm_info'. + (CHAR_TFM_INFO): new macro to access it. + +Wed Jun 10 08:27:07 1992 Karl Berry (karl@hayley) + + * input-cmi.[ch]: new files extracted from main.c. + * GNUmakefile (c_and_h): add `input-cmi'. + * cmi.y: include input-cmi.h. + +Tue Jun 9 10:25:30 1992 Karl Berry (karl@hayley) + + * main.c (do_char): complete rewrite for new data structures. + * symtab.c (symtab_resolve, resolve_string): new routines to chase + names and do multiplications after the CMI stuff has all been read. + + * realstrval.h: new file to declare the common parts to the char + and symval structures. + + * GNUmakefile (c_and_h): add `kern'. + * kern.[ch]: new files. + * symtab.c: call `char_set_kern'. + +Mon Jun 8 09:09:46 1992 Karl Berry (karl@hayley) + + * cmi.c: rewrite as a Bison grammar, cmi.y. + * GNUmakefile (y): define to be `cmi'. + (c_and_h): remove `cmi'. + * main.c (read_cmi_file): move here, and call yyparse. + (main): define `designsize' in the symbol table. + +Sun Jun 7 19:35:15 1992 Karl Berry (karl@hayley) + + * GNUmakefile (c_and_h): delete `perctab'. + * perctab.[ch]: don't need these anymore. + * symtab.[ch]: generalize to include the percentages. + + * main.c (read_command_line): not a fatal error if -encoding was + not specified. + + * sbi.[ch]: change to cmi.[ch]. + * main.c: change `sbi' to `cmi' throughout. + * GNUmakefile (c_and_h): likewise. + +Fri Jun 5 09:19:16 1992 Karl Berry (karl@hayley) + + * main.c (main): `return 0' instead of `exit (0)'. (From Paul Eggert) + +Wed Jun 3 06:19:18 1992 Karl Berry (karl@hayley) + + * output.c (output_font): throw away the checksum from an existing + TFM. + + * output.c (write_files): report the output filenames. + + * symtab.c (new_symbol): call xstrdup on the key. + * perctab.c (new_perc_def): likewise. + + * sbi.c: report each line we parse. + +Tue Jun 2 12:04:29 1992 Karl Berry (karl@hayley) + + * char.h (alloc_char): declare this. + * char.c (alloc_char): new function. + + * sbi.c: rewrite to make each cmd a separate function. + +Mon Jun 1 08:54:43 1992 Karl Berry (karl@hayley) + + * sbi.h, main.h, sbi.c (give_warnings): rename to `warn_p'. + + * main.c (do_char): keep a local var instead of doing a bunch of + returns. + + * char.c (get_kern{_character,}_element: take an unsigned for + `index', instead of an int. + * char.h: change decls. + + * char.c (init_char): return a new character, instead of changing + an allocated one. + * char.h (init_char): change decl correspondingly. + * main.c (main): do not initialize the array at the beginning; + make it a static array of pointers instead. + * {sbi,output}.h: change decl of `chars'. + * output.c (find_widths, output_font): same. + * sbi.c (read_sbi_file): same. + + * main.c (read_sbi_file_list): use * instead of indexing to go + through the sbi file list. + + * main.c (main): open the log file in current directory. + + * sbi.c (WORD_MAX): remove, as it's unused. + + * main.h: remove unneeded externs. + + * main.h (DEBUG*): remove these macros. + * main.c (debug) [DEBUG]: remove. + * {perctab,sbi,symtab}.c: change DEBUG calls to LOG. + + * main.c (alphabet_sbi_name): remove, since there's no need for + an option anyway. Is there? + + * main.c (encoding_name): make static. + + * sbi.c (input_name): remove this global, as it's no longer used. + * sbi.h: remove decl. + * main.c (main): do not set it. + + * main.c ({start,end}ing_char): declare as `charcode_type', not `int'. + +Sat May 30 15:31:50 1992 Karl Berry (karl@hayley) + + * main.c (main): change call to `tfm_convert_pl'. + +Fri May 29 11:44:57 1992 Karl Berry (karl@hayley) + + * main.c (main): change return type to `int'. + +Wed May 6 09:19:20 1992 Karl Berry (karl@hayley) + + * main.c (read_sbi_file_list): don't loop through a null list. + + * main.c: doc fix. + +Thu Apr 30 09:29:34 1992 Karl Berry (karl@hayley) + + * char.c (init_char): initialize the lig/kern lists. + + * char.h: doc fixes. + + * main.c (unparsed_range): remove. + +Wed Apr 15 15:25:55 1992 Karl Berry (karl@hayley) + + * output.c: `make_output_filename' is now `extend_filename'. + +Sun Mar 29 19:10:12 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): remove empty else. + +Sat Mar 28 07:46:29 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Fri Mar 27 14:57:14 1992 Karl Berry (karl at hayley) + + * symbol_table.?: rename to symtab.?. + * perc_table.?: to perctab.?. + * GNUmakefile (c_and_h): as above. + +Wed Mar 25 08:31:49 1992 Karl Berry (karl at hayley) + + * perc_table.c (add_to_perc_def_table): use xstrdup, not strdup. + +Wed Mar 11 14:03:53 1992 Kathy Hargreaves (kathy at hayley) + + * char.c (get_char_info): make CODE charcode_type. + + * main.c (main): make `charcode' type `charcode_type'. + (do_char): ditto for CODE. + + * sbi.c (read_sbi_file): added `encoding_name' and `displacement'. + + * main.c [USAGE]: corrected -sbi-files option comment. + +Mon Mar 9 12:26:26 1992 Kathy Hargreaves (kathy at hayley) + + * sbi.h: changed comment. + +Sat Mar 7 13:06:11 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main): fatal if the output filename has a suffix. + +Sat Mar 7 09:32:20 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files): replace with `c_and_h', etc. + + * GNUmakefile (libraries): define correctly. + +Wed Mar 4 14:46:33 1992 Kathy Hargreaves (kathy at hayley) + + * output.c (write_files): construct output filenames using + make_output_filename. + +Wed Mar 4 11:54:05 1992 Karl Berry (karl at hayley) + + * input.c: rename to sbi.c. + * GNUmakefile (files): corresponding. + +Sun Feb 16 12:24:16 1992 Kathy Hargreaves (kathy at hayley) + + * output.c (find_widths): set freed tfm char kern list to NULL. + +Sat Feb 1 15:04:16 1992 Karl Berry (karl at hayley) + + * main.c (read_sbi_file_list): use basename, not depath. + +Fri Jan 31 17:04:20 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): declare `option_index' (for new + getopt). + +Wed Jan 22 13:12:21 1992 Kathy Hargreaves (kathy at hayley) + + * input.c (read_sbi_file): copy the string before doing the below. + + * input.c (read_sbi_file): in case char-percent, assign a string + to the displacement field of the character. + + * char.h (displacement_type): made the displacement field a string. + + * char.c (sym_string_to_value): changed sb_string_to_value to this + name. + (do_displacement): call sym_string_to_value on the character's + displacement. + + * input.c (read_sbi_file): added `char-percent' command. + + * char.h [CHAR_UNSET_VALUE]: added definition. + + * char.c (init_char): added routine to initialize the parts of a + character needed to calculate sidebearings. + + * main.c (do_char): now call do_displacement if the character's + displacement and left sidebearing percentage are set; otherwise + call do_sidebearings. + + * char.c (do_displacement): added routine to calculate + sidebearings using a displacement and a left sidebearing + percentage. + + * output.c (write_files): now give a warning and prepend an `x' + instead of an `o' to the filename if the output file is the same + one as the input file. + +Mon Jan 20 13:51:42 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (read_sbi_file_list): call `depath' on the current sbi name in + the list and on `font_name' when comparing them. + +Wed Jan 15 12:25:26 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (scan_string_list, read_sbi_files): added these so could + read a list of SBI files. + + * main.c: call add_perc_defs_to_symbol_table instead of + calculating percentages ``by hand.'' + + * input.c (read_sbi_file): added `define_perc' case. + + * perc_def_table.[ch]: added for percentage definitions. + + * input.c (read_sbi_file): don't fatal, only give warnings about + characters in SBI files which aren't in the encoding if a + boolean is sent in. (This gets around getting warnings for the + default alphabet SBI file.) diff --git a/charspace/GNUmakefile b/charspace/GNUmakefile new file mode 100644 index 0000000..1fbff67 --- /dev/null +++ b/charspace/GNUmakefile @@ -0,0 +1,30 @@ +# Makefile for character spacing program. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +program = charspace + +c_and_h = char input-cmi kern main output symtab +c_only = version +y = cmi + +libraries = $(bitmap_libs) tfm + +include ../data/defs.make +include ../data/defsprog.make + +include M.depend diff --git a/charspace/M.depend b/charspace/M.depend new file mode 100644 index 0000000..59bbc57 --- /dev/null +++ b/charspace/M.depend @@ -0,0 +1,105 @@ +cmi.o: .././include/config.h .././include/c-std.h \ + .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h .././include/libfile.h \ + .././include/varstring.h input-cmi.h main.h .././include/encoding.h \ + .././include/font.h .././include/bitmap.h .././include/bounding-box.h \ + .././include/tfm.h .././include/fix-num.h .././include/list.h \ + symtab.h char.h realstrval.h +char.o: char.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h .././include/list.h .././include/report.h \ + char.h .././include/font.h .././include/bitmap.h \ + .././include/bounding-box.h .././include/tfm.h .././include/fix-num.h \ + realstrval.h kern.h symtab.h main.h .././include/encoding.h +input-cmi.o: input-cmi.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h .././include/libfile.h input-cmi.h +kern.o: kern.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h kern.h symtab.h char.h .././include/font.h \ + .././include/bitmap.h .././include/bounding-box.h .././include/tfm.h \ + .././include/fix-num.h .././include/list.h realstrval.h +main.o: main.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h .././include/cmdline.h \ + .././include/filename.h .././include/getopt.h .././include/encoding.h \ + .././include/font.h .././include/bitmap.h .././include/bounding-box.h \ + .././include/tfm.h .././include/fix-num.h .././include/list.h \ + .././include/report.h char.h realstrval.h input-cmi.h main.h output.h \ + symtab.h cmi.h +output.o: output.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h .././include/encoding.h .././include/font.h \ + .././include/bitmap.h .././include/bounding-box.h .././include/tfm.h \ + .././include/fix-num.h .././include/list.h .././include/filename.h \ + .././include/gf.h .././include/libfile.h .././include/report.h char.h \ + realstrval.h main.h output.h symtab.h +symtab.o: symtab.c .././include/config.h $(kpathsea_srcdir)/config.h \ + .././include/c-auto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \ + $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h \ + $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + .././include/c-std.h .././include/c-unistd.h .././include/c-memstr.h \ + .././include/c-errno.h .././include/c-minmax.h \ + .././include/c-limits.h .././include/c-proto.h .././include/global.h \ + .././include/moretypes.h kern.h symtab.h char.h .././include/font.h \ + .././include/bitmap.h .././include/bounding-box.h .././include/tfm.h \ + .././include/fix-num.h .././include/list.h realstrval.h main.h \ + .././include/encoding.h +version.o: version.c diff --git a/charspace/README b/charspace/README new file mode 100644 index 0000000..2b8cac5 --- /dev/null +++ b/charspace/README @@ -0,0 +1,24 @@ +This program adds sidebearings to a bitmap font, and outputs a revised +bitmap font and a TFM file. It reads several auxiliary ``character +metric information'' (CMI) files to determine the side bearings. + +The ideas behind the CMI files are based on Harry Smith's (Linotype) +principles, as explicated by Walter Tracy in his book `Letters of +Credit'. (A book we highly recommend for those interested in type.) + +@book{Tracy:LC86, + author = "Walter Tracy", + title = "Letters of Credit", + publisher = "David R. Godine", + address = "Boston", + year = 1986, + price = "$27.50", + annote = "Two parts: the first + on general history and principles of type design, the + second a critical discussion of the work of Jan van + Krimpen, Frederic Goudy, Rudolf Koch, W.A. Dwiggins, + and Stanley Morison. Tracy was head of type design for + Linotype in Britain.", +} + +(This BibTeX entry is from the type.bib file on math.utah.edu:pub/tex/bib.) diff --git a/charspace/char.c b/charspace/char.c new file mode 100644 index 0000000..695eb40 --- /dev/null +++ b/charspace/char.c @@ -0,0 +1,382 @@ +/* char.c: functions to muck with `char_type's. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "list.h" +#include "report.h" + +#include "char.h" +#include "kern.h" +#include "main.h" +#include "symtab.h" + + +static boolean resolve_sidebearing (sidebearing_type *); +static void update_kerns (char_type *, tfm_char_type *); +static void update_metrics (real, real, char_info_type *, tfm_char_type *); +static void update_sidebearings (char_type *, char_info_type *, + tfm_char_type *); +static char_type *update_via_name (string, char_info_type *, tfm_char_type *); +static void update_width (char_type *, char_info_type *, tfm_char_type *); + +/* Initialize the parts of the character structure. */ + +char_type +init_char () +{ + char_type c; + + CHAR_BITMAP_INFO (c) = NULL; + CHAR_TFM_INFO (c) = NULL; + CHAR_LSB (c) = NULL; + CHAR_RSB (c) = NULL; + CHAR_KERNS (c) = list_init (); + + return c; +} + +/* Our goal here is to extract the information about the character CODE + from the symbol table, and fill in the information from the bitmap + and TFM fonts. We also read ligature information from the encoding + vector. C_PTR_ADDR is the address of a pointer to the `char_type' we + fill in (or will be). + + Thus far, we have information only in the symbol table, and thus + can be retrieved only by character name. But when it comes + time to output, we obviously have to do it by number. If we can find + `encoding_info's name for CODE in the symbol table, great -- we can + make *C_PTR_ADDR point at that character and fill it in. If not, + then we allocate some new space -- just because the character wasn't + mentioned in the CMI files shouldn't mean it doesn't get output. + (Only if we can't find bitmap information for a character do we not + output it.) + + We return true if CODE will be output, false if not. */ + +void +do_char (charcode_type code, char_type **c_ptr_addr) +{ + static unsigned char_count = 0; + string char_name; + tfm_char_type *tfm_char = NULL; + + /* Check that the character CODE exists in the input font. */ + char_info_type *bitmap_char = get_char (input_name, code); + + /* If no bitmap information, give up. Everything else we can fake. */ + if (bitmap_char == NULL) + return; + + REPORT1 ("[%d", CHARCODE (*bitmap_char)); + + /* Look for existing TFM information. */ + if (have_tfm) + tfm_char = tfm_get_char (code); + + /* If no prior TFM file, or if the character CODE wasn't there, + initialize `tfm_char' from the bitmap information. */ + if (tfm_char == NULL) + { + tfm_char = XTALLOC1 (tfm_char_type); + *tfm_char = tfm_new_char (); + + TFM_CHAR_EXISTS (*tfm_char) = true; + TFM_CHARCODE (*tfm_char) = code; + TFM_HEIGHT (*tfm_char) + = PIXELS_TO_POINTS (CHAR_HEIGHT (*bitmap_char), dpi_real); + TFM_DEPTH (*tfm_char) + = PIXELS_TO_POINTS (CHAR_DEPTH (*bitmap_char), dpi_real); + /* Leave the italic correction at zero, since we don't know how to + compute a reasonable value. And don't bother to compute the + width, since we do so below. */ + } + + /* We've initialized the TFM and bitmap information from previously + existing files. Next, get the character name from the global + `encoding_info', so we can get at info in the symbol table. */ + char_name = ENCODING_CHAR_NAME (encoding_info, code); + + if (char_name == NULL) + WARNING1 ("No character name for character %d", code); + else + *c_ptr_addr = update_via_name (char_name, bitmap_char, tfm_char); + + /* If we haven't allocated a `char_type' yet, do so. The fields which + get used for the CMI stuff -- the side bearings and kern list -- + don't need to be initialized. */ + if (*c_ptr_addr == NULL) + *c_ptr_addr = XTALLOC1 (char_type); + + /* Set the pointers in *C_PTR_ADDR to the new bitmap and TFM info. */ + CHAR_BITMAP_INFO (**c_ptr_addr) = bitmap_char; + CHAR_TFM_INFO (**c_ptr_addr) = tfm_char; + + REPORT1 ("]%c", ++char_count % 13 == 0 ? '\n' : ' '); + + return; +} + +/* Assume that CHAR_NAME exists in the encoding vector. If looking up + CHAR_NAME in the symbol table yields a character, return a pointer to + the `char_type' in the symbol table with updated side bearing + information. Otherwise we return NULL. In any case, update TFM_CHAR + with the ligatures from the global `encoding_info'. */ + +static char_type * +update_via_name (string char_name, char_info_type *bitmap_char, + tfm_char_type *tfm_char) +{ + list_type enc_ligs; + unsigned l; + char_type *c_ptr = NULL; + + /* We have a character name, so look for side bearing info. */ + symval_type *sv = symtab_lookup (char_name); + + if (sv == NULL) + WARNING1 ("%s: Undefined in CMI files", char_name); + + else if (SYMVAL_TAG (*sv) == symval_char) + { + /* We'll return `c_ptr', a pointer to the struct in the symbol table. */ + c_ptr = &SYMVAL_CHAR (*sv); + + update_sidebearings (c_ptr, bitmap_char, tfm_char); + update_kerns (c_ptr, tfm_char); + } + + else if (SYMVAL_TAG (*sv) == symval_char_width) + { + /* We'll return `c_ptr', a pointer to the struct in the symbol table. */ + c_ptr = &SYMVAL_CHAR (*sv); + + update_width (c_ptr, bitmap_char, tfm_char); + update_kerns (c_ptr, tfm_char); + } + + else + WARNING1 ("%s: Not defined as a character", char_name); + + /* Regardless of whether CHAR_NAME was in the symbol table, we can + also update the ligature list from `encoding_info'. */ + enc_ligs = ENCODING_CHAR_LIG (encoding_info, CHARCODE (*bitmap_char)); + for (l = 0; l < LIST_SIZE (enc_ligs); l++) + { + tfm_ligature_type *lig = LIST_ELT (enc_ligs, l); + tfm_set_ligature (&TFM_LIGATURE (*tfm_char), lig->character, + lig->ligature); + } + + return c_ptr; +} + +/* Update the set width and sidebearings for a character defined with + `char-width'. We take the RSB info in C_PTR to be the desired set + width and the LSB to be the percentage of whitespace to make the left + side bearing. We update BITMAP_CHAR and TFM_CHAR correspondingly. */ + +static void +update_width (char_type *c_ptr, char_info_type *bitmap_char, + tfm_char_type *tfm_char) +{ + real lsb_percent = 0.0; + charcode_type code = CHARCODE (*bitmap_char); + /* We might not have info for the character, though, so set up the + defaults as the existing metrics. */ + boolean changed_metrics = false; + real lsb = CHAR_MIN_COL (*bitmap_char); + real real_width = CHAR_SET_WIDTH (*bitmap_char); + + /* Find the lsb percent. */ + if (CHAR_LSB (*c_ptr) == NULL) + WARNING1 ("char %d: No left side bearing information", code); + else if (resolve_sidebearing (CHAR_LSB (*c_ptr))) + { + lsb_percent = SB_REAL (*CHAR_LSB (*c_ptr)); + if (lsb_percent <= 0.0) + WARNING2 ("char %d: lsb percent (%f) must be nonnegative", + code, lsb_percent); + } + + if (CHAR_RSB (*c_ptr) == NULL) + WARNING1 ("char %d: No set width information", CHARCODE (*bitmap_char)); + else if (resolve_sidebearing (CHAR_RSB (*c_ptr))) + { + real_width = SB_REAL (*CHAR_RSB (*c_ptr)); + changed_metrics = true; + } + + /* If we have a positive percent, figure out the new lsb. */ + if (lsb_percent > 0.0) + { + real whitespace = real_width - CHAR_BITMAP_WIDTH (*bitmap_char); + lsb = whitespace * lsb_percent; + changed_metrics = true; + } + + /* If necessary, update the widths. */ + if (changed_metrics) + update_metrics (real_width, lsb, bitmap_char, tfm_char); +} + + +/* Call `resolve_sidebearing' on the sidebearing info in C_PTR. If that + succeeds, update the various widths and side bearing info in + BITMAP_CHAR and TFM_CHAR. This is called for characters defined with + the `char' command. */ + +static void +update_sidebearings (char_type *c_ptr, char_info_type *bitmap_char, + tfm_char_type *tfm_char) +{ + /* We might not have side bearing info for it, so set up the defaults + as the existing side bearings. */ + boolean changed_sb = false; + real lsb = CHAR_MIN_COL (*bitmap_char); + real rsb = CHAR_SET_WIDTH (*bitmap_char) - CHAR_MAX_COL (*bitmap_char); + + /* Compute the side bearings. */ + if (CHAR_LSB (*c_ptr) == NULL) + WARNING1 ("char %d: No left side bearing information", + CHARCODE (*bitmap_char)); + else if (resolve_sidebearing (CHAR_LSB (*c_ptr))) + { + lsb = SB_REAL (*CHAR_LSB (*c_ptr)); + changed_sb = true; + } + + if (CHAR_RSB (*c_ptr) == NULL) + WARNING1 ("char %d: No right side bearing information", + CHARCODE (*bitmap_char)); + else if (resolve_sidebearing (CHAR_RSB (*c_ptr))) + { + rsb = SB_REAL (*CHAR_RSB (*c_ptr)); + changed_sb = true; + } + + /* If the side bearings changed, then update the widths. */ + if (changed_sb) + { + real real_width = lsb + CHAR_BITMAP_WIDTH (*bitmap_char) + rsb; + update_metrics (real_width, lsb, bitmap_char, tfm_char); + } +} + +/* Following routines are called by both `update_sidebearings' and + `update_width'. */ + +/* Try to make the definition of SB into a number, by looking up names + in the symbol table. */ + +static boolean +resolve_sidebearing (sidebearing_type *sb) +{ + boolean ok; + symval_type sv; + + /* This should have already been checked. */ + assert (sb != NULL); + + /* Make SB into a symval so we can resolve it. */ + SYMVAL_TAG (sv) = SB_TAG (*sb); + SYMVAL_REAL_STRING (sv) = SB_VALUE (*sb); + + ok = symval_resolve (&sv); + + if (ok) + { + SB_TAG (*sb) = symval_real; + SB_REAL (*sb) = SYMVAL_REAL (sv); + } + else + { + string desc = symval_as_string (sv); + WARNING1 ("Unresolvable sidebearing definition `%s'", desc); + free (desc); + } + + return ok; +} + + +/* Update the widths and side bearings in BITMAP_CHAR and TFM_CHAR + according to REAL_WIDTH and LSB. */ + +static void +update_metrics (real real_width, real lsb, char_info_type *bitmap_char, + tfm_char_type *tfm_char) +{ + int pixel_width = ROUND (real_width); + real point_width = PIXELS_TO_POINTS (real_width, dpi_real); + real ds = get_designsize_in_points (); + + TFM_WIDTH (*tfm_char) = point_width; + CHAR_TFM_WIDTH (*bitmap_char) = real_to_fix (point_width / ds); + CHAR_SET_WIDTH (*bitmap_char) = pixel_width; + CHAR_MIN_COL (*bitmap_char) = lsb; + CHAR_MAX_COL (*bitmap_char) = lsb + CHAR_BITMAP_WIDTH (*bitmap_char); +} + +/* Update the kern list in TFM_CHAR from any kerns in *C_PTR. */ + +static void +update_kerns (char_type *c_ptr, tfm_char_type *tfm_char) +{ + unsigned k; + list_type char_kerns = CHAR_KERNS (*c_ptr); + + for (k = 0; k < LIST_SIZE (char_kerns); k++) + { + char_kern_type *kern_elt = LIST_ELT (char_kerns, k); + + /* If the name of the kern character isn't in the global + `encoding_info', skip it. */ + int code = encoding_number (encoding_info, kern_elt->character); + + if (code != -1) + { + if (symval_resolve (&kern_elt->kern)) + { + real pixel_kern = SYMVAL_REAL (kern_elt->kern); + real points_kern = PIXELS_TO_POINTS (pixel_kern, dpi_real); + + tfm_set_kern (&TFM_KERN (*tfm_char), code, points_kern); + } + else + { + string desc = symval_as_string (kern_elt->kern); + WARNING2 ("%s: Unresolvable kern value `%s'", + kern_elt->character, desc); + free (desc); + } + } + } +} + +/* We need to do this several times, so... Have to use the global + `dpi-real'. */ + +real +get_designsize_in_points () +{ + real ds_pixels = symtab_lookup_real ("designsize"); + real ds_points = PIXELS_TO_POINTS (ds_pixels, dpi_real); + + return ds_points; +} diff --git a/charspace/char.h b/charspace/char.h new file mode 100644 index 0000000..541ca5f --- /dev/null +++ b/charspace/char.h @@ -0,0 +1,82 @@ +/* char.h: the definition of `char_type'. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef CHAR_H +#define CHAR_H + +#include "font.h" +#include "list.h" +#include "realstrval.h" + +/* We want these to mean the values in our own structure. */ +#undef CHAR_LSB +#undef CHAR_RSB + + +/* A side bearing can be defined almost like a symbol (no `char_type'). */ +typedef struct +{ + symval_tag_type tag; + real_string_val_type value; +} sidebearing_type; + +#define SB_TAG(sb) ((sb).tag) +#define SB_VALUE(sb) ((sb).value) +#define SB_REAL(sb) ((sb).value.real_val) +#define SB_STRING(sb) ((sb).value.string_val) + +/* The information about each character in which we're interested. */ +typedef struct +{ + char_info_type *char_info; + tfm_char_type *tfm_info; + sidebearing_type *lsb, *rsb; + list_type kerns; /* We use `char_kern_type' for the elements. */ +} char_type; + + +/* The information from the bitmap font. */ +#define CHAR_BITMAP_INFO(c) ((c).char_info) +#define CHAR_CHARCODE(c) CHARCODE (*CHAR_BITMAP_INFO (c)) + +/* The information from the TFM file. */ +#define CHAR_TFM_INFO(c) ((c).tfm_info) + +/* Information we've collected for the sidebearings. */ +#define CHAR_LSB(c) ((c).lsb) +#define CHAR_LSB_TAG(c) (CHAR_LSB (c)->tag) +#define CHAR_LSB_VALUE(c) (CHAR_LSB (c)->value) + +#define CHAR_RSB(c) ((c).rsb) +#define CHAR_RSB_TAG(c) (CHAR_RSB (c)->tag) +#define CHAR_RSB_VALUE(c) (CHAR_RSB (c)->value) + +#define CHAR_KERNS(c) ((c).kerns) + +/* Initialize the various fields. */ +extern char_type init_char (void); + +/* Get the font information for CODE, and update *C_PTR_ADDR from the + symbol table and encoding vector. */ +extern void do_char (charcode_type code, char_type **c_ptr_addr); + +/* Looks up `designsize' in the symbol table and converts the result + back to printer's points. */ +extern real get_designsize_in_points (void); + +#endif /* not CHAR_H */ diff --git a/charspace/cmi.h b/charspace/cmi.h new file mode 100644 index 0000000..c51cad3 --- /dev/null +++ b/charspace/cmi.h @@ -0,0 +1,18 @@ +typedef union +{ + real realval; + symval_type symval; + string strval; +} YYSTYPE; +#define TR_CHAR 258 +#define TR_CHAR_WIDTH 259 +#define TR_CODINGSCHEME 260 +#define TR_DEFINE 261 +#define TR_FONTDIMEN 262 +#define TR_KERN 263 +#define T_IDENTIFIER 264 +#define T_STRING 265 +#define T_REAL 266 + + +extern YYSTYPE yylval; diff --git a/charspace/cmi.y b/charspace/cmi.y new file mode 100644 index 0000000..22cbc7a --- /dev/null +++ b/charspace/cmi.y @@ -0,0 +1,339 @@ +%{ +/* cmi.y: parse a character metric information file, entering what we + find into the symbol table. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> +#include "libfile.h" +#include "varstring.h" + +#include "input-cmi.h" +#include "main.h" +#include "symtab.h" + + +static void yyerror (string); +static int yylex (void); +%} + +%union +{ + real realval; + symval_type symval; + string strval; +} + +%token TR_CHAR TR_CHAR_WIDTH TR_CODINGSCHEME TR_DEFINE TR_FONTDIMEN TR_KERN +%token <strval> T_IDENTIFIER T_STRING +%token <realval> T_REAL + +/* A <symval> is not a symbol, it's the value of a symbol. */ +%type <symval> expr + +%% +statements: + /* empty */ + | statements statement + ; + +statement: + char + | char_width + | codingscheme + | define + | fontdimen + | kern + ; + +/* The two expr's are the left and right side bearings. We have to + preserve any existing kerns. */ +char: + TR_CHAR T_IDENTIFIER expr ',' expr + { symval_type *old_sv = symtab_lookup ($2); + symval_type new_sv = symtab_char_node ($3, $5); + + if (old_sv != NULL && SYMVAL_TAG (*old_sv) == symval_char) + CHAR_KERNS (SYMVAL_CHAR (new_sv)) + = CHAR_KERNS (SYMVAL_CHAR (*old_sv)); + + symtab_define ($2, new_sv); + } + ; + +/* The two expr's here are the set width and the percentage of + (set width - bitmap width) to make the left side bearing. We cheat + and use the rsb to store the width expression in the interest of not + complicating the `char_type' structure even more. We use the symbol + tag to distinguish the different ways of defining characters. */ +char_width: + TR_CHAR_WIDTH T_IDENTIFIER expr ',' expr + { symval_type *old_sv = symtab_lookup ($2); + symval_type new_sv = symtab_char_node ($5, $3); + SYMVAL_TAG (new_sv) = symval_char_width; + + if (old_sv != NULL && SYMVAL_TAG (*old_sv) == symval_char) + CHAR_KERNS (SYMVAL_CHAR (new_sv)) + = CHAR_KERNS (SYMVAL_CHAR (*old_sv)); + + symtab_define ($2, new_sv); + } + ; + +codingscheme: + TR_CODINGSCHEME T_STRING + { symtab_define ("codingscheme", symtab_string_node ($2)); } + ; + +define: + TR_DEFINE T_IDENTIFIER expr + { symtab_define ($2, $3); } + ; + +fontdimen: + TR_FONTDIMEN T_IDENTIFIER expr + { if (tfm_fontdimen_number ($2) == 0) + WARNING1 ("%s: Not the name of a fontdimen", $2); + + symtab_define ($2, $3); + } + ; + +kern: + TR_KERN T_IDENTIFIER T_IDENTIFIER expr + { symtab_define_kern ($2, $3, $4); } + ; + +expr: + T_REAL + { $$ = symtab_real_node ($1); } + | T_IDENTIFIER + { $$ = symtab_string_node ($1); } + | T_REAL T_IDENTIFIER + { $$ = symtab_real_string_node ($1, $2); } + ; +%% + +/* Let's hope Bison will never use this value as a token code. */ +#define NOT_A_TOKEN (-1) + +/* Keep track of line numbers for error messages. */ +static unsigned lineno = 1; + +static int get_numeric_token (FILE *); +static int get_word_token (FILE *); +static int get_string_token (FILE *); +static int token_number (string); + + +/* Return the next token from `cmi_file'. */ + +static int +yylex (void) +{ + int t = NOT_A_TOKEN; + + do + { + int c = getc (cmi_file); + + /* Skip whitespace. */ + while (c != EOF && ISSPACE (c)) + { + if (c == '\n') lineno++; + c = getc (cmi_file); + } + + switch (c) + { + case EOF: + t = 0; + lineno = 1; /* For the next file. */ + break; + + /* Comments begin with % and go to the end of the line. */ + case '%': + while ((c = getc (cmi_file)) != '\n' && c != EOF) + ; + if (c == '\n') lineno++; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': case '-': case '+': + ungetc (c, cmi_file); + t = get_numeric_token (cmi_file); + break; + + case '"': + t = get_string_token (cmi_file); + break; + + case ',': + t = c; + break; + + default: + ungetc (c, cmi_file); + t = get_word_token (cmi_file); + break; + } + } + while (t == NOT_A_TOKEN); + + return t; +} + + +/* Assume we've opened the file with `libfile_start'. We've been + keeping track of the line numbers ourselves, though. */ + +static void +yyerror (string s) +{ + fprintf (stderr, "%s:%u: %s\n", libfilename (), lineno, s); +} + +/* Read a numeric decimal constant from the file F. Always return T_REAL + and set yylval.realval. */ + +static int +get_numeric_token (FILE *f) +{ + variable_string vs = vs_init (); + int c = getc (f); + + /* Look for a sign. */ + if (c == '+' || c == '-') + { + vs_append_char (&vs, c); + c = getc (f); + } + + /* Collect leading digits. */ + while (ISDIGIT (c)) + { + vs_append_char (&vs, c); + c = getc (f); + } + + /* If we're at a decimal point, keep going. */ + if (c == '.') + { + /* Collect more digits. Append first, so we grab the `.'. */ + do + { + vs_append_char (&vs, c); + c = getc (f); + } + while (ISDIGIT (c)); + + /* Don't bother to allow `e<exponent>' at the end. */ + } + + /* Add the terminating null and convert the string to a number. */ + vs_append_char (&vs, 0); + + yylval.realval = atof (VS_CHARS (vs)); + vs_free (&vs); + + return T_REAL; +} + +/* Read a string constant from the file F. We make no provision for + quoting " characters; the string just consists of everything from one + " to the next. We return T_STRING and set yylval.strval. */ + +static int +get_string_token (FILE *f) +{ + int c; + variable_string vs = vs_init (); + + while ((c = getc (f)) != EOF && c != '"') + vs_append_char (&vs, c); + + if (c == EOF) + FATAL ("CMI file ended in the midst of a string"); + + /* Add the terminating null. */ + vs_append_char (&vs, 0); + + yylval.strval = VS_CHARS (vs); + + return T_STRING; +} + +/* Return the Bison-defined value for the token equal to the + next (space-delimited) identifier in the file F. That is, if it's a + reserved word return the corresponding value TR_..., else return + T_IDENTIFIER. */ + +static int +get_word_token (FILE *f) +{ + int c, t; + variable_string word = vs_init (); + + while ((c = getc (f)) != EOF && !ISSPACE (c)) + vs_append_char (&word, c); + + if (c != EOF) + ungetc (c, f); + + /* Add the terminating null. */ + vs_append_char (&word, 0); + + t = token_number (VS_CHARS (word)); + + /* We don't need the characters in the identifier again. */ + vs_free (&word); + + return t; +} + + +/* Return the token code corresponding to the word STR. If STR is not + one of the reserved words, return T_IDENTIFIER. */ + +static int +token_number (string word) +{ + int t; + + if (STREQ (word, "char")) + t = TR_CHAR; + else if (STREQ (word, "char-width")) + t = TR_CHAR_WIDTH; + else if (STREQ (word, "codingscheme")) + t = TR_CODINGSCHEME; + else if (STREQ (word, "define")) + t = TR_DEFINE; + else if (STREQ (word, "fontdimen")) + t = TR_FONTDIMEN; + else if (STREQ (word, "kern")) + t = TR_KERN; + else + { + t = T_IDENTIFIER; + yylval.strval = xstrdup (word); + } + + return t; +} diff --git a/charspace/input-cmi.c b/charspace/input-cmi.c new file mode 100644 index 0000000..ffba878 --- /dev/null +++ b/charspace/input-cmi.c @@ -0,0 +1,60 @@ +/* input-cmi.c: routines to control the CMI parsing. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "libfile.h" + +#include "input-cmi.h" + + +/* Font-specific sidebearing and other information. (-cmi-files) + `cmi_file' is used as the input file in `cmi.y'. */ +FILE *cmi_file; +string *cmi_names = NULL; + +/* Call `read_cmi_file' on each CMI file in CMI_NAMES. DPI is + simply passed along. */ + +void +read_cmi_file_list (string *cmi_names, string dpi) +{ + if (cmi_names == NULL) + return; + + for ( ; *cmi_names != NULL; cmi_names++) + { + read_cmi_file (*cmi_names, dpi); + } +} + + +/* Read the CMI file `NAME.DPIcmi', unless NAME has a suffix, in which + case don't append the `.DPIcmi'. This uses the global `cmi_file' to + communicate with the Bison parser. */ + +void +read_cmi_file (string name, string dpi) +{ + extern int yyparse (); + + cmi_file = libfile_start (name, concat (dpi, "cmi")); + yyparse (); + + libfile_close (); +} diff --git a/charspace/input-cmi.h b/charspace/input-cmi.h new file mode 100644 index 0000000..469c6b0 --- /dev/null +++ b/charspace/input-cmi.h @@ -0,0 +1,37 @@ +/* input-cmi.h: declarations for top-level CMI reading. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef INPUT_CMI_H +#define INPUT_CMI_H + +#include <stdio.h> +#include <kpathsea/types.h> + + +/* See `input-cmi.c'. */ +extern FILE *cmi_file; +extern string *cmi_names; + + +/* Read the CMI file NAME. If NAME has no extension, supply `.DPIcmi'. */ +extern void read_cmi_file (string name, string dpi); + +/* Call `read_cmi_file' on each name in NAME_LIST. */ +extern void read_cmi_file_list (string *name_list, string dpi); + +#endif /* not INPUT_CMI_H */ diff --git a/charspace/kern.c b/charspace/kern.c new file mode 100644 index 0000000..80a2ea9 --- /dev/null +++ b/charspace/kern.c @@ -0,0 +1,52 @@ +/* kern.c: kerns in the CMI file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "kern.h" + + +/* This is taken from `tfm_set_kern', except RIGHT is a character name, + instead of a character code, and the value of the kern K is a + `symval_type' (since it is useful, as well as more consistent, to + define kerns like side bearings) instead of a real. */ + +void +char_set_kern (list_type *kern_list, string right, symval_type k) +{ + unsigned this_right; + char_kern_type *new_kern; + + assert (kern_list != NULL); + + for (this_right = 0; this_right < LIST_SIZE (*kern_list); this_right++) + { + char_kern_type *kern = LIST_ELT (*kern_list, this_right); + + if (STREQ (kern->character, right)) + { /* Already there, just replace the value. */ + kern->kern = k; + return; + } + } + + /* RIGHT wasn't in the existing list. Add it to the end. */ + new_kern = LIST_TAPPEND (kern_list, char_kern_type); + new_kern->character = right; + new_kern->kern = k; +} diff --git a/charspace/kern.h b/charspace/kern.h new file mode 100644 index 0000000..6df17ca --- /dev/null +++ b/charspace/kern.h @@ -0,0 +1,41 @@ +/* kern.h: handle kerns in the CMI file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef KERN_H +#define KERN_H + +#include "symtab.h" +#include <kpathsea/types.h> + +/* The kern list. This differs from `tfm_kern_type' in that it + uses character names instead of (integer) codes, and uses + `symval_type' for the value. Thus, the user can symbolically define + kerns in the same way as sidebearings. */ + +typedef struct +{ + string character; + symval_type kern; +} char_kern_type; + + +/* Make the kern for the character named RIGHT in the list of + `char_kern_type's KERN_LIST be K, replacing any kern already present. */ +extern void char_set_kern (list_type *kern_list, string right, symval_type k); + +#endif /* not KERN_H */ diff --git a/charspace/main.c b/charspace/main.c new file mode 100644 index 0000000..500c9a6 --- /dev/null +++ b/charspace/main.c @@ -0,0 +1,330 @@ +/* charspace -- find intercharacter spacing based on user information. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/tex-file.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/paths.h> + +#include "cmdline.h" +#include "encoding.h" +#include "font.h" +#include "report.h" + +#include "char.h" +#include "input-cmi.h" +#include "main.h" +#include "output.h" +#include "symtab.h" + +/* Must come after `symtab.h', since it uses `symval_type'. (It's + generated by Bison, so we can't fix it.) */ +#include "cmi.h" + + +/* The resolution of the font we will read, in pixels per inch. We + don't deal with nonsquare pixels. (-dpi) */ +string dpi = "300"; +real dpi_real; + +/* The name of the encoding file specified by the user, and the + structure we parse it into. (-encoding) */ +static string encoding_name = NULL; +encoding_info_type encoding_info; + +/* Whether or not there was a TFM file corresponding to `input_name'. + If true, `tfm_get_char' can be called -- otherwise not. */ +boolean have_tfm = false; + +/* The name of the bitmap font we input. */ +string input_name; + +/* Whether or not to output a GF file. (-no-gf) */ +boolean no_gf = false; + +/* Says which characters we should process. This is independent of the + ordering in the font file. (-range) */ +charcode_type starting_char = 0; +charcode_type ending_char = MAX_CHARCODE; + + +static string read_command_line (int, string[]); +static encoding_info_type read_encoding_info (string); +static string *scan_string_list (string); + +/* Charspace computes side bearing values to put in a font. It doesn't + do so automatically, unfortunately: auxiliary files have to specify + everything. The basic idea is due to Harry Carter as described in + Walter Tracy's book (see README for the citation): space a few of the + letters (O, H, o, n) by hand amongst themselves. Then a reasonable + value for most of the other side bearings can be determined + (independent of the typeface) as a percentage of those ``control + letters'' sidebearings. + + The basic strategy is to first read `common.cmi', which specifies the + font-independent side bearing apportionments. Then we read + font-specific CMI files to actually define the side bearing values, + specify kerns, and so on. + + This defines a whole bunch of things in the symbol table (see + `symtab.c'). We then resolve the side bearing information for all + the characters we will output, after all the definitions have been + read. + + Then we output the revised GF and TFM files. We read an existing TFM + file and an encoding file, as well as accepting various options, to + get lig/kern and other TFM information. */ + +int +main (int argc, string argv[]) +{ + /* This is static only because we want it to be initialized entirely + to NULL pointers, and it's too painful to write out 256 NULL's. */ + static char_type *chars[MAX_CHARCODE + 1]; + unsigned code; + bitmap_font_type font; + string font_rootname; + string tfm_name; + + /* Get the bitmap font we're reading. */ + input_name = read_command_line (argc, argv); + font = get_bitmap_font (input_name, atou (dpi)); + font_rootname = remove_suffix (basename (input_name)); + + /* Make sure the output name is ok. */ + if (output_name == NULL) + output_name = input_name; + + if (!no_gf && find_suffix (output_name) != NULL) + FATAL ("You can't specify a suffix and more than one output file"); + + tfm_name = kpse_find_tfm (input_name); + if (tfm_name != NULL) + { + if (!tfm_open_input_file (tfm_name)) + FATAL1 ("%s: Could not open TFM file", tfm_name); + else + have_tfm = true; + } + + /* Set the numeric counterpart of `dpi', for use in lots of places. */ + dpi_real = atof (dpi); + + /* If the user didn't specify CMI files to read, then use + `<input_name>.<dpi>cmi'. */ + if (cmi_names == NULL) + cmi_names = scan_string_list (input_name); + + /* Define the designsize, so the CMI files can refer to it. */ + { + real ds_points = BITMAP_FONT_DESIGN_SIZE (font); + real ds_pixels = POINTS_TO_REAL_PIXELS (ds_points, dpi_real); + symtab_define ("designsize", symtab_real_node (ds_pixels)); + } + + /* Read all the CMI information. */ + read_cmi_file ("common.cmi", ""); + read_cmi_file_list (cmi_names, dpi); + + /* Figure out the font encoding scheme. Must be done after reading + the CMI files, since they can specify the codingscheme. */ + encoding_info = read_encoding_info (encoding_name); + + /* The main loop: compute each character's information. */ + for (code = starting_char; code <= ending_char; code++) + { + do_char (code, &chars[code]); + } + + /* Output what we've so laboriously collected. */ + output_font (font, chars); + + close_font (input_name); + if (have_tfm) + tfm_close_input_file (); + + return 0; +} + +/* Return the font encoding. Use + 1) USER_NAME (if it's non-null); + 2) the value of `codingscheme' in the symbol table (if it's a string); + 3) the codingscheme from an existing TFM file (if we have one). + + Otherwise, give a fatal error. */ + +static encoding_info_type +read_encoding_info (string user_name) +{ + encoding_info_type ei; + + if (user_name != NULL) + ei = read_encoding_file (user_name); + else + { + string enc_name; + string codingscheme = NULL; + symval_type *sv = symtab_lookup ("codingscheme"); + + if (sv == NULL) + codingscheme = have_tfm ? tfm_get_coding_scheme () : DEFAULT_ENCODING; + + else if (SYMVAL_TAG (*sv) == symval_string) + codingscheme = SYMVAL_STRING (*sv); + + else + FATAL ("codingscheme: defined (in CMI file) as a non-string"); + + assert (codingscheme != NULL); + + enc_name = coding_scheme_to_filename (codingscheme); + ei = read_encoding_file (enc_name); + } + + return ei; +} + +/* Reading the options. */ + +/* This is defined in version.c. */ +extern string version_string; + +#define USAGE "Options: +<font_name> should be a filename, possibly with a resolution, e.g., + `cmr10' or `cmr10.300'.\n" \ + GETOPT_USAGE \ +"cmi-files <file1>,<file2>,...: read the CMI files + `<file1>.<dpi>cmi', `<file2>.<dpi>cmi', etc., after reading + `common.cmi'; default is `<font-name>.<dpi>cmi'. The <dpi>cmi is not + appended to any of the <file>s which already have a suffix. +dpi <unsigned>: use this resolution; default is 300. +encoding <filename>: read ligature and other encoding information + from <filename>.enc; there is no default. (A TFM file <font-name>.tfm + is also read, if it exists.) +fontdimens <fontdimen>:<real>,<fontdimen>:<real>,...: assign <value> + to each <fontdimen> given, when outputting a TFM file. A <fontdimen> + can be either one of the standard names (in either upper or + lowercase), or a number between 1 and 30. Each <real> is taken to be + in points (except in the case of the <fontdimen> `SLANT' (parameter + 1), which is a dimensionless number). +no-gf: don't output a GF file. +output-file <filename>: write the TFM file to `<filename>.tfm' and the + GF file to `<filename>.<dpi>gf'; <filename> shouldn't have a suffix; + default is <font-name>.tfm and <font-name>.<dpi>gf, or, if those would + overwrite the input, those preceded by `x'. +range <char1>-<char2>: only process characters between <char1> and + <char2>, inclusive. +verbose: print brief progress reports on stdout. +version: print the version number of this program. +xheight-char <charcode>: use the height of this character as the + default x-height (for the TFM output); default is 120 (ASCII `x'). +" + +static string +read_command_line (int argc, string argv[]) +{ + int g; /* `getopt' return code. */ + int option_index; + boolean explicit_dpi = false; + boolean printed_version = false; + struct option long_options[] + = { { "dpi", 1, 0, 0 }, + { "cmi-files", 1, 0, 0 }, + { "encoding", 1, 0, 0 }, + { "fontdimens", 1, 0, 0 }, + { "help", 0, 0, 0 }, + { "no-gf", 0, (int *) &no_gf, 1 }, + { "output-file", 1, 0, 0 }, + { "range", 1, 0, 0 }, + { "verbose", 0, (int *) &verbose, 1 }, + { "version", 0, (int *) &printed_version, 1 }, + { "xheight-char", 1, 0, 0 }, + { 0, 0, 0, 0 } }; + + while (true) + { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') + continue; /* Unknown option. */ + + assert (g == 0); /* We have no short option names. */ + + if (ARGUMENT_IS ("cmi-files")) + cmi_names = scan_string_list (optarg); + + else if (ARGUMENT_IS ("dpi")) + dpi = optarg; + + else if (ARGUMENT_IS ("encoding")) + encoding_name = optarg; + + else if (ARGUMENT_IS ("fontdimens")) + fontdimens = optarg; + + else if (ARGUMENT_IS ("help")) + { + fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]); + fprintf (stderr, USAGE); + exit (0); + } + + else if (ARGUMENT_IS ("output-file")) + output_name = optarg; + + else if (ARGUMENT_IS ("range")) + GET_RANGE (optarg, starting_char, ending_char); + + else if (ARGUMENT_IS ("version")) + printf ("%s.\n", version_string); + + else if (ARGUMENT_IS ("xheight-char")) + xheight_char = xparse_charcode (optarg); + + /* Else it was just a flag; getopt has already done the assignment. */ + } + + FINISH_COMMAND_LINE (); +} + + +/* Take a string L consisting of unsigned strings separated by commas + and return a vector of the strings, as pointers. + Append an element to the vector. */ + +static string * +scan_string_list (string l) +{ + string map; + unsigned length = 1; + string *vector = xmalloc (sizeof (string)); + + for (map = strtok (l, ","); map != NULL; map = strtok (NULL, ",")) + { + length++; + vector = xrealloc (vector, length * sizeof (string)); + vector[length - 2] = map; + } + + vector[length - 1] = NULL; + return vector; +} diff --git a/charspace/main.h b/charspace/main.h new file mode 100644 index 0000000..431f3e3 --- /dev/null +++ b/charspace/main.h @@ -0,0 +1,41 @@ +/* main.h: global variable declarations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef MAIN_H +#define MAIN_H + +#include <stdio.h> +#include <kpathsea/types.h> + +#include "encoding.h" + + +/* See main.c. */ +extern FILE *cmi_file; +extern string dpi; +extern real dpi_real; +extern encoding_info_type encoding_info; +extern boolean have_tfm; +extern string input_name; +extern boolean no_gf; +extern charcode_type starting_char, ending_char; + +/* This is defined in version.c. */ +extern string version_string; + +#endif /* not MAIN_H */ diff --git a/charspace/old-output.c b/charspace/old-output.c new file mode 100644 index 0000000..9d9f7a7 --- /dev/null +++ b/charspace/old-output.c @@ -0,0 +1,357 @@ +/* output.c: output + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "filename.h" +#include "libfile.h" +#include "report.h" + +#include "main.h" +#include "output.h" + + +/* The assignments to the TFM fontdimen values. (-fontdimens) */ +string fontdimens = NULL; + +/* The name of the output file specified by the user. (-output-file) */ +string output_name = NULL; + +/* The character code to use for the x-height. (-xheight-char) */ +charcode_type xheight_char = 120; /* `x' in ASCII. */ + + +static void finalize_kern_list (tfm_char_type *, char_type *[]); +static void finalize_lig_list (tfm_char_type *, char_type *[]); +static tfm_global_info_type find_tfm_info (char_type *[]); +static gf_char_type make_gf_char (char_info_type); +static void update_tfm_info_from_symtab (tfm_global_info_type *); +static void write_gf (bitmap_font_type, char_type *[]); +static void write_tfm (char_type *[]); +static boolean write_tfm_char (charcode_type, char_type *[]); + +/* Output a TFM and (optionally) GF file with the characters in CHARS. + Use the characters from BITMAP_FONT for the shapes. We use an + existing TFM file, the encoding file, and command line arguments to + determine the metric information. */ + +void +output_font (bitmap_font_type bitmap_font, char_type *chars[]) +{ + write_tfm (chars); + + if (!no_gf) + write_gf (bitmap_font, chars); +} + +/* Write a TFM file with CHARS. */ + +static void +write_tfm (char_type *chars[]) +{ + unsigned this_char; + unsigned char_count = 0; + string pl_output_name = extend_filename (output_name, "pl"); + tfm_global_info_type tfm_info = find_tfm_info (chars); + + /* If `have_tfm', we've already opened the input file. */ + string input_tfm_name = have_tfm ? tfm_input_filename () : NULL; + + /* We remove the suffix before making the PL name because if the user + said `-output-file=foo.bar', it's the TFM file which should be + named `foo.bar'; the PL file is still named `foo.pl'. */ + string output_root = remove_suffix (output_name); + string pl_name = extend_filename (output_root, "pl"); + string output_tfm_name = extend_filename (output_name, "tfm"); + + /* If we'd overwrite the input, change the name. */ + if (input_tfm_name != NULL && same_file_p (input_tfm_name, output_tfm_name)) + { + pl_name = make_prefix ("x", pl_name); + output_tfm_name = make_prefix ("x", output_tfm_name); + } + + /* Let's write the TFM file first, but to a PL file, which is easier. */ + if (!tfm_open_pl_output_file (pl_output_name)) + FATAL_PERROR (pl_output_name); + + REPORT1 ("\nWriting PL file `%s':\n", pl_output_name); + + /* Write the global information we just figured out. */ + tfm_put_global_info (tfm_info); + + /* Only look between `starting_char' and `ending_char', i.e., the + user's -range. */ + for (this_char = starting_char; this_char <= ending_char; this_char++) + { + if (write_tfm_char (this_char, chars)) + REPORT2 ("[%d]%c", this_char, ++char_count % 13 == 0 ? '\n' : ' '); + } + + if (char_count % 13 != 0) + REPORT ("\n"); + + tfm_convert_pl (output_tfm_name, verbose); + tfm_close_pl_output_file (); +} + + +/* Return the global TFM information structure: we read from an existing + TFM file, if the global `have_tfm' is true, then from the encoding + information in the global `encoding_info', then from the symbol + table, and finally from the command line (i.e., the global + `fontdimens). */ + +static tfm_global_info_type +find_tfm_info (char_type *chars[]) +{ + tfm_global_info_type tfm_info; + + if (have_tfm) + { + tfm_info = tfm_get_global_info (); + TFM_CHECKSUM (tfm_info) = 0; /* Can't use the old checksum. */ + } + else + { /* No TFM file to be found, so initialize the structure + with the defaults. */ + tfm_info = tfm_init_global_info (); + TFM_DESIGN_SIZE (tfm_info) = get_designsize_in_points (); + } + + /* `encoding_info' has been set at this point, one way or another; use + whatever codingscheme it says. */ + TFM_CODING_SCHEME (tfm_info) = ENCODING_SCHEME_NAME (encoding_info); + + /* The `fontsize' fontdimen is typically the same as the designsize. + (I can't imagine when it would be anything else, but it seems + prudent to let the user-specified values in the symbol table or + commandline override this.) */ + tfm_set_fontsize (&tfm_info); + + /* Use the bitmap height of `xheight_char', if it exists, for the + default x-height. If not, guess .5 of the designsize. */ + TFM_FONTDIMEN (tfm_info, TFM_XHEIGHT_PARAMETER) + = chars[xheight_char] != NULL + ? PIXELS_TO_POINTS ( + CHAR_HEIGHT (*CHAR_BITMAP_INFO (*chars[xheight_char])), dpi_real) + : .5 * TFM_DESIGN_SIZE (tfm_info); + + /* If any fontdimens were set in the CMI files, use them. */ + update_tfm_info_from_symtab (&tfm_info); + + /* Finally, update the fontdimens from the command line. */ + tfm_set_fontdimens (fontdimens, &tfm_info); + + return tfm_info; +} + + +/* It is not an error for the user to use a fontdimen name for something + else, so we do not complain if we cannot resolve such a name. */ + +static void +update_tfm_info_from_symtab (tfm_global_info_type *tfm_info) +{ + unsigned p; + + for (p = 1; p <= TFM_MAX_FONTDIMENS; p++) + { + string name = tfm_fontdimen_name (p); + symval_type *sv = name ? symtab_lookup (name) : NULL; + if (sv != NULL) + { + if (symval_resolve (sv)) + tfm_set_fontdimen (tfm_info, p, + PIXELS_TO_POINTS (SYMVAL_REAL (*sv), dpi_real)); + } + } +} + + +/* Return true if we have TFM info for CODE in CHARS. */ + +static boolean +have_tfm_char (charcode_type code, char_type *chars[]) +{ + boolean ok; + + /* If we have no `char_type' for CODE, have to give up. */ + if (chars[code] == NULL) + ok = false; + + /* If we have no TFM info in the `char_type', have to give up. */ + else if (CHAR_TFM_INFO (*chars[code]) == NULL) + ok = false; + +/* xx what about _EXISTS? */ + + else + ok = true; + + return ok; +} + + +/* Write the single character CODE from CHARS to the TFM file (assume + the latter is open), if we have all the information. Return true if + we wrote it, else false. */ + +static boolean +write_tfm_char (charcode_type code, char_type *chars[]) +{ + boolean ok; + + if (have_tfm_char (code, chars)) + { + tfm_char_type c = *CHAR_TFM_INFO (*chars[code]); + + /* The remaining thing to check is that the kerns and ligatures + refer only to (other) characters which will be output. */ + finalize_kern_list (&c, chars); + finalize_lig_list (&c, chars); + + /* Write the character. */ + tfm_put_char (c); + + ok = true; + } + else + ok = false; + + return ok; +} + + +/* Look through the kern list in C for kerns which refer to characters + in CHARS we won't be outputting. Remove such. */ + +static void +finalize_kern_list (tfm_char_type *c, char_type *chars[]) +{ + unsigned e; + list_type good_list = list_init (); + + for (e = 0; e < LIST_SIZE (TFM_KERN (*c)); e++) + { + tfm_kern_type *k = LIST_ELT (TFM_KERN (*c), e); + + if (have_tfm_char (k->character, chars)) + { + tfm_kern_type *new_kern = LIST_TAPPEND (&good_list, tfm_kern_type); + *new_kern = *k; + } + } + + /* Throw away the old list. */ + list_free (&TFM_KERN (*c)); + + /* Insert the good list. */ + TFM_KERN (*c) = good_list; +} + + +/* Routine for ligatures analogous to `finalize_kern_list'. */ + +static void +finalize_lig_list (tfm_char_type *c, char_type *chars[]) +{ + unsigned e; + list_type good_list = list_init (); + + for (e = 0; e < LIST_SIZE (TFM_LIGATURE (*c)); e++) + { + tfm_ligature_type *lig = LIST_ELT (TFM_LIGATURE (*c), e); + + if (have_tfm_char (lig->character, chars) + && have_tfm_char (lig->ligature, chars)) + { + tfm_ligature_type *new_lig + = LIST_TAPPEND (&good_list, tfm_ligature_type); + *new_lig = *lig; + } + } + + /* Throw away the old list. */ + list_free (&TFM_LIGATURE (*c)); + + /* Insert the good list. */ + TFM_LIGATURE (*c) = good_list; +} + +/* Write a GF file using BITMAP_FONT and CHARS. Don't overwrite an + existing file named `BITMAP_FONT_FILENAME (FONT)'. */ + +static void +write_gf (bitmap_font_type font, char_type *chars[]) +{ + unsigned this_char; + unsigned char_count = 0; + /* We depend upon `output_name' being set when we are called. */ + string gf_output_name = extend_filename (output_name, concat (dpi, "gf")); + + if (same_file_p (BITMAP_FONT_FILENAME (font), gf_output_name)) + gf_output_name = make_prefix ("x", gf_output_name); + + if (!gf_open_output_file (gf_output_name)) + FATAL_PERROR (gf_output_name); + + REPORT1 ("\nWriting GF file `%s':\n", gf_output_name); + + /* Write the first part of the file. */ + gf_put_preamble (concat4 ("charspace output ", now () + 4, " from ", + BITMAP_FONT_COMMENT (font))); + + for (this_char = starting_char; this_char <= ending_char; this_char++) + { + if (chars[this_char] != NULL + && CHAR_BITMAP_INFO (*chars[this_char]) != NULL) + { + gf_put_char (make_gf_char (*CHAR_BITMAP_INFO (*chars[this_char]))); + REPORT2 ("[%d]%c", this_char, ++char_count % 13 == 0 ? '\n' : ' '); + } + } + + if (char_count % 13 != 0) + REPORT ("\n"); + + /* Write the last part of the file. */ + gf_put_postamble (real_to_fix (get_designsize_in_points ()), + dpi_real, dpi_real); + + gf_close_output_file (); +} + + +/* Turn BITMAP_CHAR (the generic structure) into a `gf_char_type'. We + assume there are no real changes to be made in BITMAP_CHAR, i.e., + that we need only copy the relevant fields. */ + +static gf_char_type +make_gf_char (char_info_type bitmap_char) +{ + gf_char_type gf_char; + + GF_CHARCODE (gf_char) = CHARCODE (bitmap_char); + GF_BITMAP (gf_char) = CHAR_BITMAP (bitmap_char); + GF_CHAR_BB (gf_char) = CHAR_BB (bitmap_char); + GF_H_ESCAPEMENT (gf_char) = CHAR_SET_WIDTH (bitmap_char); + GF_TFM_WIDTH (gf_char) = CHAR_TFM_WIDTH (bitmap_char); + + return gf_char; +} diff --git a/charspace/output.c b/charspace/output.c new file mode 100644 index 0000000..82afe97 --- /dev/null +++ b/charspace/output.c @@ -0,0 +1,362 @@ +/* output.c: use the `char_type's' information to output a new font. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "encoding.h" +#include "filename.h" +#include "gf.h" +#include "libfile.h" +#include "report.h" +#include "tfm.h" + +#include "char.h" +#include "main.h" +#include "output.h" +#include "symtab.h" + + +/* The assignments to the TFM fontdimen values. (-fontdimens) */ +string fontdimens = NULL; + +/* The name of the output file specified by the user. (-output-file) */ +string output_name = NULL; + +/* The character code to use for the x-height. (-xheight-char) */ +charcode_type xheight_char = 120; /* `x' in ASCII. */ + + +static void finalize_kern_list (tfm_char_type *, char_type *[]); +static void finalize_lig_list (tfm_char_type *, char_type *[]); +static tfm_global_info_type find_tfm_info (char_type *[]); +static gf_char_type make_gf_char (char_info_type); +static void update_tfm_info_from_symtab (tfm_global_info_type *); +static void write_gf (bitmap_font_type, char_type *[]); +static void write_tfm (char_type *[]); +static boolean write_tfm_char (charcode_type, char_type *[]); + +/* Output a TFM and (optionally) GF file with the characters in CHARS. + Use the characters from BITMAP_FONT for the shapes. We use an + existing TFM file, the encoding file, and command line arguments to + determine the metric information. */ + +void +output_font (bitmap_font_type bitmap_font, char_type *chars[]) +{ + write_tfm (chars); + + if (!no_gf) + write_gf (bitmap_font, chars); +} + +/* Write a TFM file with CHARS. */ + +static void +write_tfm (char_type *chars[]) +{ + unsigned this_char; + unsigned char_count = 0; + string pl_output_name = extend_filename (output_name, "pl"); + tfm_global_info_type tfm_info = find_tfm_info (chars); + + /* If `have_tfm', we've already opened the input file. */ + string input_tfm_name = have_tfm ? tfm_input_filename () : NULL; + + /* We remove the suffix before making the PL name because if the user + said `-output-file=foo.bar', it's the TFM file which should be + named `foo.bar'; the PL file is still named `foo.pl'. */ + string output_root = remove_suffix (output_name); + string pl_name = extend_filename (output_root, "pl"); + string output_tfm_name = extend_filename (output_name, "tfm"); + + /* If we'd overwrite the input, change the name. */ + if (input_tfm_name != NULL && same_file_p (input_tfm_name, output_tfm_name)) + { + pl_name = make_prefix ("x", pl_name); + output_tfm_name = make_prefix ("x", output_tfm_name); + } + + /* Let's write the TFM file first, but to a PL file, which is easier. */ + if (!tfm_open_pl_output_file (pl_output_name)) + FATAL_PERROR (pl_output_name); + + REPORT1 ("\nWriting PL file `%s':\n", pl_output_name); + + /* Write the global information we just figured out. */ + tfm_put_global_info (tfm_info); + + /* Only look between `starting_char' and `ending_char', i.e., the + user's -range. */ + for (this_char = starting_char; this_char <= ending_char; this_char++) + { + if (write_tfm_char (this_char, chars)) + REPORT2 ("[%d]%c", this_char, ++char_count % 13 == 0 ? '\n' : ' '); + } + + if (char_count % 13 != 0) + REPORT ("\n"); + + tfm_convert_pl (output_tfm_name, verbose); + tfm_close_pl_output_file (); +} + + +/* Return the global TFM information structure: we read from an existing + TFM file, if the global `have_tfm' is true, then from the encoding + information in the global `encoding_info', then from the symbol + table, and finally from the command line (i.e., the global + `fontdimens). */ + +static tfm_global_info_type +find_tfm_info (char_type *chars[]) +{ + tfm_global_info_type tfm_info; + + if (have_tfm) + { + tfm_info = tfm_get_global_info (); + TFM_CHECKSUM (tfm_info) = 0; /* Can't use the old checksum. */ + } + else + { /* No TFM file to be found, so initialize the structure + with the defaults. */ + tfm_info = tfm_init_global_info (); + TFM_DESIGN_SIZE (tfm_info) = get_designsize_in_points (); + } + + /* `encoding_info' has been set at this point, one way or another; use + whatever codingscheme it says. */ + TFM_CODING_SCHEME (tfm_info) = ENCODING_SCHEME_NAME (encoding_info); + + /* The `fontsize' fontdimen is typically the same as the designsize. + (I can't imagine when it would be anything else, but it seems + prudent to let the user-specified values in the symbol table or + commandline override this.) */ + tfm_set_fontsize (&tfm_info); + + /* Use the bitmap height of `xheight_char', if it exists, for the + default x-height. If not, guess .5 of the designsize. */ + TFM_FONTDIMEN (tfm_info, TFM_XHEIGHT_PARAMETER) + = chars[xheight_char] != NULL + ? PIXELS_TO_POINTS ( + CHAR_HEIGHT (*CHAR_BITMAP_INFO (*chars[xheight_char])), dpi_real) + : .5 * TFM_DESIGN_SIZE (tfm_info); + + /* If any fontdimens were set in the CMI files, use them. */ + update_tfm_info_from_symtab (&tfm_info); + + /* Finally, update the fontdimens from the command line. */ + tfm_set_fontdimens (fontdimens, &tfm_info); + + return tfm_info; +} + + +/* It is not an error for the user to use a fontdimen name for something + else, so we do not complain if we cannot resolve such a name. */ + +static void +update_tfm_info_from_symtab (tfm_global_info_type *tfm_info) +{ + unsigned p; + + for (p = 1; p <= TFM_MAX_FONTDIMENS; p++) + { + string name = tfm_fontdimen_name (p); + symval_type *sv = name ? symtab_lookup (name) : NULL; + if (sv != NULL) + { + if (symval_resolve (sv)) + tfm_set_fontdimen (tfm_info, p, + PIXELS_TO_POINTS (SYMVAL_REAL (*sv), dpi_real)); + } + } +} + + +/* Return true if we have TFM info for CODE in CHARS. */ + +static boolean +have_tfm_char (charcode_type code, char_type *chars[]) +{ + boolean ok; + + /* If we have no `char_type' for CODE, have to give up. */ + if (chars[code] == NULL) + ok = false; + + /* If we have no TFM info in the `char_type', have to give up. */ + else if (CHAR_TFM_INFO (*chars[code]) == NULL) + ok = false; + +/* xx what about _EXISTS? */ + + else + ok = true; + + return ok; +} + + +/* Write the single character CODE from CHARS to the TFM file (assume + the latter is open), if we have all the information. Return true if + we wrote it, else false. */ + +static boolean +write_tfm_char (charcode_type code, char_type *chars[]) +{ + boolean ok; + + if (have_tfm_char (code, chars)) + { + tfm_char_type c = *CHAR_TFM_INFO (*chars[code]); + + /* The remaining thing to check is that the kerns and ligatures + refer only to (other) characters which will be output. */ + finalize_kern_list (&c, chars); + finalize_lig_list (&c, chars); + + /* Write the character. */ + tfm_put_char (c); + + ok = true; + } + else + ok = false; + + return ok; +} + + +/* Look through the kern list in C for kerns which refer to characters + in CHARS we won't be outputting. Remove such. */ + +static void +finalize_kern_list (tfm_char_type *c, char_type *chars[]) +{ + unsigned e; + list_type good_list = list_init (); + + for (e = 0; e < LIST_SIZE (TFM_KERN (*c)); e++) + { + tfm_kern_type *k = LIST_ELT (TFM_KERN (*c), e); + + if (have_tfm_char (k->character, chars)) + { + tfm_kern_type *new_kern = LIST_TAPPEND (&good_list, tfm_kern_type); + *new_kern = *k; + } + } + + /* Throw away the old list. */ + list_free (&TFM_KERN (*c)); + + /* Insert the good list. */ + TFM_KERN (*c) = good_list; +} + + +/* Routine for ligatures analogous to `finalize_kern_list'. */ + +static void +finalize_lig_list (tfm_char_type *c, char_type *chars[]) +{ + unsigned e; + list_type good_list = list_init (); + + for (e = 0; e < LIST_SIZE (TFM_LIGATURE (*c)); e++) + { + tfm_ligature_type *lig = LIST_ELT (TFM_LIGATURE (*c), e); + + if (have_tfm_char (lig->character, chars) + && have_tfm_char (lig->ligature, chars)) + { + tfm_ligature_type *new_lig + = LIST_TAPPEND (&good_list, tfm_ligature_type); + *new_lig = *lig; + } + } + + /* Throw away the old list. */ + list_free (&TFM_LIGATURE (*c)); + + /* Insert the good list. */ + TFM_LIGATURE (*c) = good_list; +} + +/* Write a GF file using BITMAP_FONT and CHARS. Don't overwrite an + existing file named `BITMAP_FONT_FILENAME (FONT)'. */ + +static void +write_gf (bitmap_font_type font, char_type *chars[]) +{ + unsigned this_char; + unsigned char_count = 0; + /* We depend upon `output_name' being set when we are called. */ + string gf_output_name = extend_filename (output_name, concat (dpi, "gf")); + + if (same_file_p (BITMAP_FONT_FILENAME (font), gf_output_name)) + gf_output_name = make_prefix ("x", gf_output_name); + + if (!gf_open_output_file (gf_output_name)) + FATAL_PERROR (gf_output_name); + + REPORT1 ("\nWriting GF file `%s':\n", gf_output_name); + + /* Write the first part of the file. */ + gf_put_preamble (concat4 ("charspace output ", now () + 4, " from ", + BITMAP_FONT_COMMENT (font))); + + for (this_char = starting_char; this_char <= ending_char; this_char++) + { + if (chars[this_char] != NULL + && CHAR_BITMAP_INFO (*chars[this_char]) != NULL) + { + gf_put_char (make_gf_char (*CHAR_BITMAP_INFO (*chars[this_char]))); + REPORT2 ("[%d]%c", this_char, ++char_count % 13 == 0 ? '\n' : ' '); + } + } + + if (char_count % 13 != 0) + REPORT ("\n"); + + /* Write the last part of the file. */ + gf_put_postamble (real_to_fix (get_designsize_in_points ()), + dpi_real, dpi_real); + + gf_close_output_file (); +} + + +/* Turn BITMAP_CHAR (the generic structure) into a `gf_char_type'. We + assume there are no real changes to be made in BITMAP_CHAR, i.e., + that we need only copy the relevant fields. */ + +static gf_char_type +make_gf_char (char_info_type bitmap_char) +{ + gf_char_type gf_char; + + GF_CHARCODE (gf_char) = CHARCODE (bitmap_char); + GF_BITMAP (gf_char) = CHAR_BITMAP (bitmap_char); + GF_CHAR_BB (gf_char) = CHAR_BB (bitmap_char); + GF_H_ESCAPEMENT (gf_char) = CHAR_SET_WIDTH (bitmap_char); + GF_TFM_WIDTH (gf_char) = CHAR_TFM_WIDTH (bitmap_char); + + return gf_char; +} diff --git a/charspace/output.h b/charspace/output.h new file mode 100644 index 0000000..f10c7dc --- /dev/null +++ b/charspace/output.h @@ -0,0 +1,36 @@ +/* output.h: declarations for outputting the newly spaced font. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUTPUT_H +#define OUTPUT_H + +#include "font.h" +#include "char.h" + + +/* See output.c. */ +extern string fontdimens; +extern string output_name; +extern charcode_type xheight_char; + +/* Output a TFM and (perhaps) GF file with the new spacings for the + characters CHARS. Use the font B for the character bitmaps. The + font is written to the current directory. */ +extern void output_font (bitmap_font_type b, char_type *chars[]); + +#endif /* not OUTPUT_H */ diff --git a/charspace/realstrval.h b/charspace/realstrval.h new file mode 100644 index 0000000..6a1b7f9 --- /dev/null +++ b/charspace/realstrval.h @@ -0,0 +1,46 @@ +/* realstrval.h: types common to `char.h' and `symtab.h'. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef REALSTRVAL_H +#define REALSTRVAL_H + +#include <kpathsea/types.h> + + +/* This structure is used both as part of `char_type' and as part of + `symval_type', so we must define it separately. + + We use `symval_tag_type' to remember which parts of the struct count, + although `symval_char' is irrelevant to a `real_string_val'. If both + the real and string parts are set, the value is taken to be the + product. */ + +typedef enum +{ + symval_real, symval_string, symval_real_string, symval_char, + symval_char_width +} symval_tag_type; + + +typedef struct +{ + real real_val; + string string_val; +} real_string_val_type; + +#endif /* not REALSTRVAL_H */ diff --git a/charspace/symtab.c b/charspace/symtab.c new file mode 100644 index 0000000..1004b5a --- /dev/null +++ b/charspace/symtab.c @@ -0,0 +1,322 @@ +/* symtab.c: create and update a symbol table. We use a simple linear + representation, since there will be a few hundred entries at + the very most. + + The numbers which get stored in the symbol table should all be in + pixels. That's what the rest of the program expects. (Unfortunately + there's no way to check this at the time of definition.) + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "kern.h" +#include "main.h" +#include "symtab.h" + + +/* Every identifier in the CMI files -- character names and fontdimen + names as well as `define'd quantities -- gets put into our symbol + table. We do not resolve any definitions until they are actually + needed, so that later definitions will replace earlier ones. */ +struct symbol +{ + string key; + symval_type value; + struct symbol *next; +}; + +/* These all work on pointers instead of structures, since that's what + we need to pass around in this file. */ +#define SYM_KEY(s) ((s)->key) +#define SYM_NEXT(s) ((s)->next) +#define SYM_VAL(s) ((s)->value) + +typedef struct symbol symbol_type; + + +/* We have only one symbol table. Here it is. */ +static symbol_type *symbol_table = NULL; + + +static symbol_type *symtab_find (string); +static boolean resolve_string (symval_type *, real); + +/* Routines to create symval nodes. */ + +symval_type +symtab_char_node (symval_type lsb, symval_type rsb) +{ + symval_type sv; + + SYMVAL_TAG (sv) = symval_char; + SYMVAL_CHAR (sv) = init_char (); + + CHAR_LSB (SYMVAL_CHAR (sv)) = XTALLOC1 (sidebearing_type); + CHAR_LSB_TAG (SYMVAL_CHAR (sv)) = SYMVAL_TAG (lsb); + CHAR_LSB_VALUE (SYMVAL_CHAR (sv)) = SYMVAL_REAL_STRING (lsb); + + CHAR_RSB (SYMVAL_CHAR (sv)) = XTALLOC1 (sidebearing_type); + CHAR_RSB_TAG (SYMVAL_CHAR (sv)) = SYMVAL_TAG (rsb); + CHAR_RSB_VALUE (SYMVAL_CHAR (sv)) = SYMVAL_REAL_STRING (rsb); + + return sv; +} + + +symval_type +symtab_real_node (real r) +{ + symval_type sv; + + SYMVAL_TAG (sv) = symval_real; + SYMVAL_REAL (sv) = r; + + return sv; +} + + +symval_type +symtab_real_string_node (real r, string s) +{ + symval_type sv; + + SYMVAL_TAG (sv) = symval_real_string; + SYMVAL_REAL (sv) = r; + SYMVAL_STRING (sv) = s; + + return sv; +} + + +symval_type +symtab_string_node (string s) +{ + symval_type sv; + + SYMVAL_TAG (sv) = symval_string; + SYMVAL_STRING (sv) = s; + + return sv; +} + +/* Define the identifier KEY to be the value V. We do no checking on V, + we just plop it in. Overwrite any previous definition of KEY. If + KEY was not previously defined, we malloc a new symbol. */ + +void +symtab_define (string key, symval_type v) +{ + symbol_type *s = symtab_find (key); + + if (s == NULL) + { + s = XTALLOC1 (symbol_type); + + /* Make a private copy of KEY so outside assignments or + deallocations don't affect the symbol table. */ + SYM_KEY (s) = xstrdup (key); + SYM_NEXT (s) = symbol_table; + symbol_table = s; + } + + /* Whether we just created it or not, put in the new value. */ + SYM_VAL (s) = v; +} + +/* Define a kern of K pixels between the characters named LEFT and + RIGHT. If no kern for that pair previously existed, we create it. + If the character LEFT was not previously in the symbol table, we add + it. But if LEFT was in the symbol table, we have to preserve any + kerns or side bearing information that have already been stored. */ + +void +symtab_define_kern (string left, string right, symval_type k) +{ + symval_type sv; + symbol_type *s = symtab_find (left); + + if (s == NULL || SYMVAL_TAG (SYM_VAL (s)) != symval_char) + { + list_type *kern_list_ptr; + char_kern_type *new_kern; + + SYMVAL_TAG (sv) = symval_char; + SYMVAL_CHAR (sv) = init_char (); + + kern_list_ptr = &CHAR_KERNS (SYMVAL_CHAR (sv)); + new_kern = LIST_TAPPEND (kern_list_ptr, char_kern_type); + new_kern->character = right; + new_kern->kern = k; + } + else + { + sv = SYM_VAL (s); + char_set_kern (&CHAR_KERNS (SYMVAL_CHAR (sv)), right, k); + } + + symtab_define (left, sv); +} + +/* Look up KEY in `symbol_table'. If found, return a pointer to the + corresponding symval, else NULL. */ + +symval_type * +symtab_lookup (string key) +{ + symbol_type *s = symtab_find (key); + symval_type *sv = s ? &SYM_VAL (s) : NULL; + + return sv; +} + + +/* Look up KEY in `symbol_table', resolve its definition to a real, and + return the result. If the value cannot be resolved, or if KEY isn't + defined, give a fatal error. */ + +real +symtab_lookup_real (string key) +{ + real r; + symval_type *sv = symtab_lookup (key); + + if (sv == NULL) + FATAL1 ("%s: Undefined symbol", key); + + if (symval_resolve (sv)) + r = SYMVAL_REAL (*sv); + else + FATAL1 ("%s: Cannot be resolved to a real", key); + + return r; +} + + +/* Look up KEY in `symbol_table'. If found, return the containing + symbol, otherwise NULL. */ + +static symbol_type * +symtab_find (string key) +{ + symbol_type *s; + + assert (key != NULL); + + for (s = symbol_table; s != NULL && !STREQ (SYM_KEY (s), key); + s = SYM_NEXT (s)) + ; + + return s; +} + +/* Resolve (to a real) the symbol value SV. Change SV if we succeed. + Return success. */ + +boolean +symval_resolve (symval_type *sv) +{ + boolean ok; + + if (sv == NULL) + return false; + + switch (SYMVAL_TAG (*sv)) + { + case symval_char: + ok = false; + break; + + case symval_real: + ok = true; + break; + + case symval_real_string: + ok = resolve_string (sv, SYMVAL_REAL (*sv)); + break; + + case symval_string: + ok = resolve_string (sv, 1.0); + break; + + default: + abort (); /* We have listed all the cases. */ + } + + return ok; +} + + +/* Assume SV is non-null, and that its SYMVAL_STRING field is + meaningful. Look up that string, resolve the result. If that + succeeds, multiply by FACTOR, change SV, and return success. */ + +static boolean +resolve_string (symval_type *sv, real factor) +{ + boolean ok = false; + + symval_type *sv_aux = symtab_lookup (SYMVAL_STRING (*sv)); + + if (symval_resolve (sv_aux)) + { + SYMVAL_TAG (*sv) = symval_real; + SYMVAL_REAL (*sv) = SYMVAL_REAL (*sv_aux) * factor; + ok = true; + } + + return ok; +} + +/* Return a description of SV as a string. */ + +string +symval_as_string (symval_type sv) +{ + string desc; + + switch (SYMVAL_TAG (sv)) + { + case symval_char: + { + string charcode = CHAR_BITMAP_INFO (SYMVAL_CHAR (sv)) != NULL + ? concat (" ", utoa (CHAR_CHARCODE (SYMVAL_CHAR (sv)))) + : ""; + desc = concat ("character", charcode); + if (*charcode != 0) + free (charcode); + } + break; + + case symval_real: + desc = xdtoa (SYMVAL_REAL (sv)); + break; + + case symval_real_string: + desc = concat (xdtoa (SYMVAL_REAL (sv)), SYMVAL_STRING (sv)); + break; + + case symval_string: + desc = xstrdup (SYMVAL_STRING (sv)); + break; + + default: + abort (); /* We have listed all the cases. */ + } + + return desc; +} diff --git a/charspace/symtab.h b/charspace/symtab.h new file mode 100644 index 0000000..e792ca8 --- /dev/null +++ b/charspace/symtab.h @@ -0,0 +1,78 @@ +/* symtab.h: declarations for our symbol table manipulations. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef SYMTAB_H +#define SYMTAB_H + +#include <kpathsea/types.h> +#include "char.h" +#include "realstrval.h" + + +/* What a single symbol looks like. */ + +typedef struct +{ + symval_tag_type tag; + + union + { + real_string_val_type real_string_val; + char_type char_val; + } value; +} symval_type; + +/* Accessor macros. */ +#define SYMVAL_TAG(s) ((s).tag) +#define SYMVAL_CHAR(s) ((s).value.char_val) +#define SYMVAL_REAL(s) ((s).value.real_string_val.real_val) +#define SYMVAL_REAL_STRING(s) ((s).value.real_string_val) +#define SYMVAL_STRING(s)((s).value.real_string_val.string_val) + + +/* Create new value nodes of the various types. */ +extern symval_type symtab_char_node (symval_type lsb, symval_type rsb); +extern symval_type symtab_real_node (real); +extern symval_type symtab_real_string_node (real, string); +extern symval_type symtab_string_node (string); + +/* Define the identifier KEY to be the value V. Overwrite any + previous definition of KEY. */ +extern void symtab_define (string key, symval_type v); + +/* Define a kern K between the characters named LEFT and RIGHT. */ +extern void symtab_define_kern (string left, string right, symval_type k); + + +/* Return the value of KEY, or NULL. */ +extern symval_type *symtab_lookup (string key); + +/* Resolve KEY to a real if possible and return the result. If it + cannot be resolved, give a fatal error. */ +extern real symtab_lookup_real (string key); + + +/* Resolve the definition of SV to a real, if possible. Return success. */ +extern boolean symval_resolve (symval_type *sv); + + +/* Return a string describing SV (e.g., for error messages). The string + is allocated with malloc. */ +extern string symval_as_string (symval_type sv); + +#endif /* not SYMTAB_H */ diff --git a/charspace/test.cmi b/charspace/test.cmi new file mode 100644 index 0000000..da98b7a --- /dev/null +++ b/charspace/test.cmi @@ -0,0 +1,11 @@ +char not in bitmap font + +char in bf but not in encoding + +char in bf & encoding, but not CMI + +char in bf, encoding, & cmi, but not a character + +char with only one SB defined? + +codingscheme non-string diff --git a/charspace/version.c b/charspace/version.c new file mode 100644 index 0000000..998c94c --- /dev/null +++ b/charspace/version.c @@ -0,0 +1 @@ +char *version_string = "charspace version REPLACE-WITH-VERSION"; diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..d53b6ac --- /dev/null +++ b/configure.in @@ -0,0 +1,20 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(limn/fit.c) + +dnl Write output here, instead of putting -D's on the command line. +AC_CONFIG_HEADER(include/c-auto.h) + +sinclude(../kpathsea/common.ac) + +# We must have gcc. +[if test -n "$GCC" +then : +else + echo "Warning: these programs are written in GNU C," + echo "so you need to have gcc." +fi] + +AC_FIND_XTRA + +# This will generate `Makefile'(s), `config.status', and our header file. +AC_OUTPUT(GNUmakefile doc/Makefile) diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 0000000..7e409bb --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,103 @@ +Mon Apr 8 08:32:57 1996 Kathy Hargreaves <letters@cs.umb.edu> + + * overview.texi: added direction to CCC arrow. + +Sat Mar 30 07:09:01 1996 Kathy Hargreaves <letters@cs.umb.edu> + + * overview.texi: added TFM output line from fontconvert to + imageto. Added directions to arrows for GF<->fontconvert and + CMI->fontconvert. + +Sat Dec 9 08:05:30 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * fontcvt.texi (Character manipulation options): filtering + eliminates small features, such as serifs (not features). + +Sun May 16 15:46:54 1993 Karl Berry (karl@cs.umb.edu) + + * fontu.texi: Change title to `GNU font utilities'. + +Wed Feb 17 06:31:03 1993 Karl Berry (karl@cs.umb.edu) + + * Makefile.in (INSTALL): Use tr instead of grep to remove the + Info control characters. + +Sun Feb 7 14:22:45 1993 Karl Berry (karl@cs.umb.edu) + + * Makefile.in (install): Give filename as second arg. + (info, dvi): New (synonym) targets. + +Sat Dec 5 17:15:31 1992 Karl Berry (karl@cs.umb.edu) + + * bpltobzr.texi: Comment syntax is now `; ... \n', a la Lisp. + +Thu Oct 29 06:39:04 1992 Karl Berry (karl@cs.umb.edu) + + * Makefile.in (distfiles): Add ChangeLog. + +Tue Oct 27 13:02:33 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + + * Makefile.in (dist): Need Makefile temporarily. + +Sun Oct 25 15:30:46 1992 Karl Berry (karl@cs.umb.edu) + + * Makefile.in (distclean): Depend on clean, and remove Makefile. + + * Makefile.in (.NOEXPORT): Add this. + + * Makefile.in (distfiles): Do Makefile.in, not Makefile. + +Sat Oct 24 05:18:03 1992 Karl Berry (karl@cs.umb.edu) + + * imageto.texi: Default encoding is none now, not ASCII. + * gsrenderf.texi: Likewise. + +Fri Oct 23 14:16:19 1992 Karl Berry (karl@cs.umb.edu) + + * fontcvt.texi: The -space option is gone. + * gsrenderf.texi: This doesn't use Fontconvert anymore. + +Tue Oct 20 14:49:21 1992 Karl Berry (karl@cs.umb.edu) + + * bzrto.texi: Document -ps-font-info option. + +Mon Oct 5 09:19:32 1992 Karl Berry (karl@cs.umb.edu) + + * Makefile.in: Renamed from Makefile (so $(prefix) gets configured.) + + * bugs.texi: Add more info about criteria and philosophy, + restructure into sections. + + * imageto.texi: Rewrite major portions. + +Sun Oct 4 11:18:43 1992 Karl Berry (karl@cs.umb.edu) + + * {imageto,overview}.texi: Remove doc on -clean-threshold. + +Mon Sep 21 11:03:32 1992 Karl Berry (karl@cs.umb.edu) + + * imageto.texi: document -ifi-file. + +Sun Sep 13 10:33:41 1992 Karl Berry (karl@hayley) + + * fontu.texi: the FSF should approve permissions, not me. + +Sat Sep 12 16:14:39 1992 Karl Berry (karl@hayley) + + * Makefile (dist): use $(MAKE). + +Tue Sep 8 17:41:02 1992 Karl Berry (karl@hayley) + + * Makefile (clean): remove dvi files etc. here. + (distclean): remove empty sorted index files here. + (dist): not here. + +Fri Sep 4 08:41:16 1992 Karl Berry (karl@hayley) + + * Makefile (extraclean): new target. + +Thu Sep 3 09:30:07 1992 Karl Berry (karl@hayley) + + * Version 0.5. diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..2acc2ce --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,99 @@ +# Makefile for the various bits of documentation. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# For `install'. +prefix = /usr/local +infodir = $(prefix)/info + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +MAKEINFO = makeinfo +MAKEINFO_FLAGS = --paragraph-indent=2 -I$(HOME)/gnu/gnuorg +# That -I is purely for my own benefit in doing `make dist'. It won't +# hurt anything for you (I hope). + +TEX = tex '\nonstopmode \input' +TEXINDEX = texindex + +SHELL = /bin/sh + +default: fontu.info + +all: INSTALL dvi + +dvi: fontu.dvi +fontu.dvi: fontu.cps + $(TEX) fontu.texi +fontu.cps: fontu.cp + $(TEXINDEX) fontu.?? +fontu.cp: *.texi + $(TEX) fontu.texi + +info: fontu.info +fontu.info: *.texi + $(MAKEINFO) $(MAKEINFO_FLAGS) ../$(srcdir)/doc/fontu.texi + +install: fontu.info + for i in fontu.info*; do $(INSTALL_DATA) $$i $(infodir)/$$i; done + +update: + emacs -batch -l update.el + +# We don't automatically generate dependencies. +depend: + +# Separate the installation instructions into a separate file, for the +# benefit of people who don't want to look at the info file. +INSTALL: fontu.info + sed -n '/Node: Installation/,/Good luck./p' fontu.info-1 \ + | tr -d '\037' > $@ + +# Prevent GNU make 3 from overflowing arg limit on system V. +.NOEXPORT: + +# `make dist' should only be called from the top-level Makefile, as it +# depends on $(version), $(top_distdir), and $(dir). +# +distdir = ../$(top_distdir)/$(dir) +distfiles = ChangeLog Makefile.in update.el *.texi + +dist:: + mkdir $(distdir) + ln Makefile $(distfiles) $(distdir) + cp -p $(plain)/texinfo.tex $(distdir) +# +# Have to add the version number and date before making the Info file. + (cd $(distdir); \ + add-version $(version) fontu.texi intro.texi; \ + add-date fontu.texi; \ + $(MAKE) INSTALL fontu.cps distclean) + mv $(distdir)/INSTALL ../$(top_distdir)/INSTALL + +clean mostlyclean: + rm -f fontu.?? *.dvi *.log *.toc + +distclean: clean + rm -f Makefile + for f in fontu.??s; do if test ! -s $$f; then rm -f $$f; fi; done + +extraclean: distclean + rm -f *~ \#* patch* *.orig *.rej *.bak *.ckp core a.out + +realclean: distclean + rm -f *.info* fontu.??? INSTALL diff --git a/doc/bpltobzr.texi b/doc/bpltobzr.texi new file mode 100644 index 0000000..157b5f4 --- /dev/null +++ b/doc/bpltobzr.texi @@ -0,0 +1,283 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node BPLtoBZR, XBfe, BZRto, Top +@chapter BPLtoBZR + +@pindex bpltobzr +@cindex converting BPL files to BZR +@cindex editing BZR fonts + +BPLtoBZR translates a human-readable (and -editable) text file in BPL +format (see below) to the binary BZR (Bezier) font format. + +Of the two, only BZR files can be changed into font formats which +typesetting programs can use. So after editing a BPL file, you need to +run this program. BZRedit likewise invokes it when necessary +(@pxref{BZRedit}). + +@menu +* BPL files:: Bezier property list file format. +* Invoking BPLtoBZR:: Command-line options. +@end menu + + +@node BPL files, Invoking BPLtoBZR, , BPLtoBZR +@section BPL files + +@cindex BPL files +@cindex Bezier property list files +@cindex plain text BZR files + +Bezier property list (BPL) files are free-format text files which +describe an outline font. They are a transliteration of the binary +BZR font format (@pxref{BZR files}). + +@cindex Lisp +@cindex BPL syntax +@cindex syntax, of BPL files +A BPL file is a sequence of entries of the form +@example +(@var{property-name} @var{value1} @var{value2} @dots{}) +@end example + +@cindex data types in BPL files +@cindex types of data in BPL files +@cindex BPL data types +@cindex realstr data type +The @var{property-name} is one of a small set of keywords understood by +BPLtoBZR. The @var{value}s vary depending on the property being +defined. BPL files have four types of values: unsigned integers, reals, +strings (enclosed in typewriter double-quote @samp{"} marks), and +@dfn{real strings} (@dfn{realstr} for short)---a real number in quotes. +@xref{Editing BPL files}, for an explanation of why realstrs are +necessary. + +@cindex comments in BPL files +@cindex BPL comments +@cmindex comment @r{BPL property} +A semicolon not inside a string constant begins a comment, which +continues until the end of the line. + +BPL files have three parts: a preamble, character definitions, and a +postamble. They must appear in that order. In many cases, the order in +which you give the properties within a part is also significant. + +@menu +* Preamble: BPL preamble. The beginning. +* Characters: BPL characters. The middle. +* Postamble: BPL postamble. The end. +@end menu + + +@node BPL preamble, BPL characters, , BPL files +@subsection BPL preamble + +@cindex BPL preamble +@cindex preamble in BPL files + +The @dfn{preamble} of a BPL file consists of the following three +properties: + +@enumerate + +@cmindex fontfile @r{BPL property} +@cindex BZR filename in BPL files +@item +@code{(fontfile @var{string})}. This merely documents the filename of +the BZR font from which BZRto made this BPL file. It is ignored. + +@cmindex fontcomment @r{BPL property} +@cindex maximum length of BPL comment +@cindex BPL comment, maximum length +@item +@code{(fontcomment @var{string})}. This is an arbitrary string written +as the ``comment'' in the BZR file. BZR-reading programs ignore this +comment. It typically identifies the source and time of +creation. If @var{string} is longer than 255 characters, it is +truncated (due to limitations of the BZR format). + +@cmindex designsize @r{BPL property} +@item +@code{(designsize @var{real})}. The design size of the font, in +printer's points. +@end enumerate + + +@node BPL characters, BPL postamble, BPL preamble, BPL files +@subsection BPL characters + +@cindex BPL characters +@cindex character definitions in BPL files + +A BPL file must have one or more @dfn{character definitions}. These +have the following form: + +@cmindex char @r{BPL property} +@example +(char @var{unsigned} + @var{width} + @var{bounding-box} + @var{outline1} + @var{outline2} + @dots{} +) +@end example + +The @var{unsigned} number directly after the @code{char} command +specifies the character code. If it is larger than 255 (the maximum +character code in BZR files, and all other font formats the font +utilities deal with) then BPLtoBZR issues a warning and uses its value +modulo 256. + +The other pieces are specified as properties: + +@itemize @bullet + +@cmindex width @r{BPL property} +@cindex set width in BPL files +@item +@code{(width @var{realstr})}. The set width of the character in +printer's points. + +@cmindex bb @r{BPL property} +@cindex character bounding box in BPL files +@cindex bounding box of characters in BPL files +@cindex side bearings in BPL files +@cindex left side bearing in BPL files +@cindex right side bearing in BPL files +@item +@code{(bb @var{llx} @var{lly} @var{urx} @var{ury})}. The bounding box +of the character in printer's points, defined by the lower-left @math{x} +coordinate and the upper-right @math{y} coordinate. Each value is a +realstr. The left side bearing is defined by @var{llx}, and the right +side bearing is defined by the difference between the set width and +@var{urx}. + +@end itemize + +Each @var{outline} specifies a geometrical outline, i.e., a closed +curve. For example, an @samp{o} would have two @var{outline}s. If the +character is entirely blank, the BPL file has no @var{outline}s at all. + +The outline property is somewhat more complex than the rest, so we +describe it below. + +@menu +* BPL outlines:: Representation of character outlines. +@end menu + + +@node BPL outlines, , , BPL characters +@subsubsection BPL outlines + +@cindex BPL outlines +@cindex outlines in BPL files +@cindex character shape in BPL files + +You specify an @dfn{outline} in a BPL file as a sequence of straight +lines and cubic splines, in any order: + +@cmindex outline @r{BPL property} +@example +(outline @var{start-x} @var{start-y} + @var{piece1} @var{piece2} @dots{} +) +@end example + +@var{start-x} and @var{start-y} are realstrs which specify the initial +position for drawing this outline. Each successive piece of the outline +is relative to a current point, and also updates the current point. + +At least one @var{piece} must be present. Each @var{piece} can be one of the +following two properties: + +@enumerate + +@cmindex line @r{BPL property} +@cindex straight lines in BPL files +@item +@code{line @math{x} @math{y}}. Draw a straight line from the current +point to @math{(x,y)}. Then set the current point to @math{(x,y)}. +@math{x} and @math{y} are realstrs. + +@cmindex spline @r{BPL property} +@cindex cubic splines in BPL files +@cindex Bezier splines in BPL files +@cindex curves in BPL files +@item +@code{spline @var{c1x} @var{c1y} @var{c2x} @var{c2y} @var{ex} @var{ey}}. +Draw the Bezier cubic using the current point as the starting point, +@math{(@var{c1x},@var{c1y})} and @math{(@var{c2x},@var{c2y})} as the control +points, and @math{(@var{ex},@var{ey})} as the endpoint. Then set the +current point to the endpoint. All coordinates are realstrs. + +@end enumerate + +If the last point the last piece of the @code{outline} is not the same +as the starting point, the result is undefined. + + +@node BPL postamble, , BPL characters, BPL files +@subsection BPL postamble + +@cindex BPL postamble +@cindex postamble, of BPL files + +The final piece of a BPL file is the @dfn{postamble}. It has two +components: + +@enumerate + +@cmindex fontbb @r{BPL property} +@cindex font bounding box in BPL files +@item +@code{(fontbb @var{llx} @var{lly} @var{urx} @var{ury})}. Defines the +bounding box for the entire font in the same way as the @code{bb} +property defines the bounding box for a character. @xref{BPL characters}. + +@cmindex nchars @r{BPL property} +@cindex character count in BPL files +@item +@code{(nchars @var{unsigned})}. The number of characters in the BPL +file. This is purely for informational purposes; BPLtoBZR ignores it. + +@end enumerate + + +@node Invoking BPLtoBZR, , BPL files, BPLtoBZR +@section Invoking BPLtoBZR + +@cindex invocation of BPLtoBZR +@cindex BPLtoBZR options +@cindex options for BPLtoBZR + +This section describes the options that BPLtoBZR accepts. +@xref{Command-line options}, for general option syntax. + +@table @samp + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -output-file +@item -output-file @var{filename} +Output to @var{filename} (if it has a suffix) or to +@file{@var{filename}.bzr} (if it doesn't). + +@opindex -range +@item -range @var{char1}-@var{char2} +Only output characters with codes between @var{char1} and @var{char2}, +inclusive. (@xref{Common options}, and @ref{Specifying character codes}.) + +@opindex -verbose +@item -verbose +Output progress reports. + +@opindex -version +@item -version +Print the version number of this program. + +@end table diff --git a/doc/bugs.texi b/doc/bugs.texi new file mode 100644 index 0000000..9fef45c --- /dev/null +++ b/doc/bugs.texi @@ -0,0 +1,247 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Bugs, File formats, Overview, Top +@chapter Bugs + +(This chapter is adapted from the analogous one in the GCC manual, +written by Richard Stallman.) + +@cindex bug reports, purpose of +Your bug reports are essential in making these programs reliable. + +@cindex service directory +Reporting a bug may help you by bringing a solution to your problem, or +it may not. (If it does not, look in the service directory, which is +part of the GNU CC and GNU Emacs distributions.) In any case, the +principal function of a bug report is to help the entire community by +making the next release work better. + +@cindex improvements, suggesting +Send bug reports for the GNU font utilities, or for their documentation, +to the address @code{bug-gnu-utils@@prep.ai.mit.edu}. We also welcome +suggestions for improvements, no matter how small. + +In order for a bug report to serve its purpose, you must include the +information that makes for fixing the bug, as described below. + +Thanks (in advance)! + +@menu +* Bug criteria:: Have you found a bug? +* Bug reporting:: How to effectively report a bug. +@end menu + + +@node Bug criteria, Bug reporting, , Bugs +@section Bug criteria + +@cindex criteria for bugs +@cindex bugs, criteria for + +If you are not sure whether you have found a bug, here are some +guidelines: + +@itemize @bullet + +@item +@cindex fatal signals +If a program gets a fatal signal, for any input whatsoever, that +is a bug. Reliable programs never crash. + +@item +@cindex invalid output fonts +@cindex bad output fonts +@cindex validity of fonts, checking +@cindex fatal errors and invalid output fonts +@pindex gftype@r{, checking validity font} +@pindex tftopl@r{, checking validity font} +If a program produces an invalid font, for any input whatsoever, that is +a bug---unless the program reported a fatal error that forced it to quit +prematurely. For example, if Metafont gives errors reading the output +of @code{bzrto -mf}, that is a bug. You can run the @TeX{} utility +programs GFtype and TFtoPL to check the validity of a GF or TFM file. + +@item +@cindex error messages, spurious +@cindex spurious error messages +If a program gives an error message for valid input, that is a bug. +Similarly, if a program gives a fatal error when it could continue +processing, that is a bug. It is sometimes hard to tell if these +conditions obtain; you must use your best judgement. + +@item +@cindex error messages, missing +If a program does not give an error message for invalid input, that is a bug. + +@end itemize + + +@node Bug reporting, , Bug criteria, Bugs +@section Bug reporting + +@cindex bugs, reporting +@cindex compilation bugs, reporting +@cindex installation bugs, reporting + +The purpose of a bug report is to enable someone to +fix the bug if it is not known. It isn't important what happens if the +bug is already known. Therefore, always write your bug reports on the +assumption that the bug is not known. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' or ``Should this be happening?'' This cannot help us fix a bug, +so it is basically useless. We can only respond by asking for the +details below, so we can investigate. You might as well expedite +matters by sending them to begin with. + +Try to make your bug report self-contained. If we ask you for more +information, it is best if you include all the original information in +your response, as well as the new information. We might have discarded +the previous message, or even if we haven't, it takes us time to search +for it. Similarly, if you've reported bugs before, it is still best to +send all the information; we can't possibly remember what environment +everyone uses! + +@menu +* Necessary information:: What you need to send. +* Unnecessary information:: What you don't need to send. +* Documentation bugs:: Report the bugs in the manual, too. +@end menu + + +@node Necessary information, Unnecessary information, , Bug reporting +@subsection Necessary information + +To enable us to fix a bug, please include all the information below. If +the bug was in compilation or installation, as opposed to in actually +running one of the programs, the last two items are irrelevant. But in +that case, please also make sure it is not a known problem before +reporting it. @xref{Problems}. + +You should include all of the following in your bug report: + +@itemize @bullet + +@item +The version number of the program. You can get this from the top-level +files @file{ChangeLog} or @file{GNUmakefile.in}, or from the +@samp{-version} option which all the programs have. + +@item +The type of machine you are using, and the operating system name +and version number. + +@item +A description of the bug. For example, ``The program gets a fatal +signal,'' or ``The baselines in the generated font are too high.'' + +@item +All the command-line arguments you gave the program. + +@item +The relevant input files. Since fonts and images are typically binary +files, be sure to use @file{uuencode} or @file{btoa} before mailing +them. Be sure to include the TFM file as well as the bitmap (GF or +PK) or BZR file, if the program needs both as input. + +Bugs typically apply to a single character in a font; you can find out +what character is being processed with the @samp{-verbose} option. It +should then be straightforward to cut that single character out of the +font with either the @samp{-range} option and/or the @samp{fontconvert} +program, to make a new (very small) font. It is easier for us to deal +with small files. + +But if you don't want to take the time to break up the font, please send +in the bug report anyway (with the entire font). We much prefer that to +you not reporting the bug at all! + +@end itemize + +In other words, we need enough information so that we can run the +offending program under the debugger, so we can find out what's +happening. Without all the command-line arguments, or the input file in +question, we cannot do this. Since you must have found the bug by +running the program with a particular set of options and on a particular +input file, you already have this information; all you need to do is +send it! + + +@node Unnecessary information, Documentation bugs, Necessary information, Bug reporting +@subsection Unnecessary information + +Here are some things that are not necessary to include in a bug report. + +@itemize @bullet + +@item +@cindex envelope of bugs +@cindex bugs, envelope of +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating which +changes to the input file or command-line options will make the bug go +away and which changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger with +breakpoints, not by pure deduction from a series of examples. You might +as well save your time for something else. + +@item +@cindex patches for bugs +@cindex bugs, sending patches for +@cindex sending patches for bugs +A patch for the bug. + +A patch for the bug is useful if it is a good one. But don't omit the +necessary information, such as the test case, on the assumption that a +patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand the patch at +all. Without an example, we won't be able to verify that the bug is +fixed. + +Also, if we can't understand what bug you are trying to fix, or why your +patch should be an improvement, we won't install it. A test case will +help us to understand. + +@xref{Sending Patches, , Sending Patches for GNU CC, gcc, GCC Manual}, +for more details on the best way to write changes. + +@item +@cindex bugs, sending backtraces for +@cindex backtraces, sending for bugs +Sometimes people send just a backtrace, but that is not useful by +itself. It is usually the values of local or global variables which +matter, sometimes very far away from the location where you noticed the +bug. We need to be able to run the debugger ourselves to investigate. + +@item +@cindex bugs, guesses about cause +@cindex guesses about bugs +A guess about what the bug is or what it depends on. + +Such guesses are not useful, and often wrong. It is impossible to guess +correctly without using the debugger to find the facts, so you might as +well save your imagination for other things! + +@end itemize + + +@node Documentation bugs, , Unnecessary information, Bug reporting +@subsection Documentation bugs + +@cindex manual bugs, reporting +@cindex documentation bugs, reporting + +It is just as important to report bugs in the documentation as in the +programs. If you want to do something using these programs, and reading +the manual doesn't tell you how, that is probably a bug. In fact, the +best way to report it is something like: ``I want to do @var{x}; I +looked in the manual in sections @var{a} and @var{b}, but they didn't +explain it.'' + +If your bug report makes it clear that you've actually made an attempt +to find the answers using the manual, we will be much more likely to +take action (since we won't have to search the manual ourselves). diff --git a/doc/bzredit.texi b/doc/bzredit.texi new file mode 100644 index 0000000..caa51b9 --- /dev/null +++ b/doc/bzredit.texi @@ -0,0 +1,238 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node BZRedit, GSrenderfont, XBfe, Top +@chapter BZRedit + +@pindex bzredit +@cindex editing BZR fonts +@cindex BZR fonts, editing +@cindex editing outlines +@cindex outline fonts, editing + +BZRedit allows hand-editing of outline fonts in the BZR font format +output by Limn (@pxref{Limn}). + +@cindex Emacs, prerequisite for BZRedit +@cindex Ghostscript, prerequisite for BZRedit +It is written in GNU Emacs Lisp, and thus works only inside GNU Emacs +(@pxref{Top, , , emacs, GNU Emacs Manual}). It uses Ghostscript to +display the character images, and thus you must have Ghostscript +installed to use it. @xref{Archives}, for information on how to obtain +GNU software. + +BZRedit provides only a simple form of editing: you change the textual +representation of the BZR font in an Emacs buffer; when you wish to see +the image corresponding to the particular character you have been +editing, you type an explicit command to tell Emacs to send the image in +PostScript form to a Ghostscript subprocess. + +BZRedit uses BPL format for the ``textual representation''. @xref{BPL +files}, for the precise details on what BPL files contain; however, you +will probably find them fairly self-explanatory. + +@cindex interactive outline editing +@cindex hints, editing +A more featureful editor would allow interactive manipulation of the +outlines, say via a mouse in an X window. It would also be useful to +allow adding or editing of hints (additional commands which improve +rasterization at low resolution and/or small sizes); right now, none of +the programs do anything at all about hints. + +@menu +* BZRedit usage:: Operating the editor. +@end menu + + +@node BZRedit usage, , , BZRedit +@section BZRedit usage + +@cindex BZRedit usage +@cindex usage of BZRedit + +The sections below detail using BZRedit. + +@menu +* BZRedit installation:: Additional installation is needed. +* BZR: Editing BZR files. Editing files in the binary format. +* BPL: Editing BPL files. Editing files in the textual format. +@end menu + + +@node BZRedit installation, Editing BZR files, , BZRedit usage +@subsection BZRedit installation + +@flindex bzredit.el +@flindex default.el +@flindex .emacs +BZRedit is contained in the file @file{bzrto/bzredit.el}. Installation +of the font utilities (@pxref{Installation}) copies this file into a +directory where Emacs can find it. But you still need to tell Emacs +what functions @file{bzredit.el} defines. To do this, put the following +definitions into either your own @file{.emacs} file (@pxref{Init File, , +The Init File: @file{.emacs}, elisp, GNU Emacs Lisp Manual}), if you are +the only person planning to use BZRedit, or into the system +initialization file @file{default.el} (@pxref{Start-up Summary, , +Summary: Sequence of Actions at Start Up, elisp, GNU Emacs Lisp +Manual}), for a public installation: + +@example +(autoload 'bpl-mode "bzredit" "Mode for editing BPL files." t) +(autoload 'bzredit "bzredit" "Set up to editing a BZR file." t) +@end example + +If you want the first function to be called automatically when you visit a +file with extension @file{.bpl}, you can add the +following code to (presumably) the same file: + +@example +(setq auto-mode-alist + (append auto-mode-alist (list '("\\.bpl\\'" . bpl-mode)))) +@end example + +@noindent If you do not do this, then to make the editing commands +(described in the following sections) available you must type @kbd{M-x +bpl-mode} after visiting a BPL file. + + +@node Editing BZR files, Editing BPL files, BZRedit installation, BZRedit usage +@subsection Editing BZR files + +@cindex editing BZR files +@cindex BZR files, editing +@findex bzredit + +To edit a BZR file, type @kbd{M-x bzredit} to Emacs. (See the previous +section for how to make this function known to Emacs.) This will ask +you for the filename of the BZR font. After typing the filename, type +@kbd{RET}. + +The @code{bzredit} function then calls BZRto with the @samp{-text} +option (@pxref{BZRto}) to produce a BPL file---the textual form of the +BZR font. Then it calls @code{bpl-mode} and makes the resulting buffer +visible (if it isn't already). + +The next section describes @code{bpl-mode}. + + +@node Editing BPL files, , Editing BZR files, BZRedit usage +@subsection Editing BPL files + +@cindex editing BPL files, +@cindex BPL files, editing +@findex bpl-mode + +To edit a BPL file in @code{bpl-mode}, the usual Emacs editing commands +work: cursor motion, deletion, and insertion all work just as with +normal text files. + +Here is an example of a piece of a BPL file. @xref{BPL files}, for a +full description of BPL files. + +@example +(char 0 ; hex 0x0 + (width "6.263") + (bb "0.241" "5.782" "-0.241" "6.745") + (outline "0.482" "6.745" + (line "1.445" "6.504") + (line "1.445" "0.241") + (line "0.482" "0.241") + (line "3.613" "0.000") + (spline "1.682" "1.264" "2.409" "4.436" "2.409" "6.504") + @dots{} + ) +) +@end example + +@noindent The most usual editing session is changing the numbers in the +@code{line} and @code{spline} commands, which are the coordinates that +determine the character outline. But you can do anything you want: +change a @code{line} to @code{spline} (and add the requisite other +coordinates) or vice versa, change the set width, etc. + +You must retain the quotation marks around the floating-point numbers, +however. (They are necessary because Emacs 18 does not recognize +floating-point constants.) If you inadvertently delete one, then when +you go to display the edited character (see below), you will get an +error from Emacs. + +When @code{bpl-mode} is first invoked, it starts up Ghostscript in a +subprocess. The section below describes the details of this. It is +Ghostscript which does the actual displaying. + +@code{bpl-mode} provides three additional commands (we show the default +bindings in parentheses): + +@enumerate + +@item +@findex bpl-quit +@cindex quitting @code{bpl-mode} +@cindex leaving @code{bpl-mode} +@kindex C-c q +@kindex C-c C-q +@code{bpl-quit} (@kbd{C-c q} and @kbd{C-c C-q}), which kills the +Ghostscript subprocess and then removes the BPL buffer from the screen. +@code{bpl-quit} does not convert the BPL file (back) to BZR form; that's +left for you to do by hand. + +@item +@findex bpl-erasepage +@findex erasepage +@kindex C-c e +@kindex C-c C-e +@code{bpl-erasepage} (@kbd{C-c e} and @kbd{C-c C-e}), which sends an +@code{erasepage} command to Ghostscript, thus erasing whatever is +currently displayed. + +@item +@findex bpl-show-char +@cindex showing edited characters +@cindex displaying edited characters +@kindex C-c c +@kindex C-c C-C +@code{bpl-show-char} (@kbd{C-c c} and @kbd{C-c C-c}), which sends to +Ghostscript a PostScript translation of the character that point is in. + +@end enumerate + +@findex bpl-mode-hook +@cindex hook, for @code{bpl-mode} +@code{bpl-mode} calls @code{bpl-mode-hook} as its last action. You can +define this to take additional actions if you like. + +@menu +* BZRedit and Ghostscript:: Customizing the use of Ghostscript. +@end menu + + +@node BZRedit and Ghostscript, , , Editing BPL files +@subsubsection BZRedit and Ghostscript + +@cindex BZRedit and Ghostscript +@cindex Ghostscript and BZRedit + +As mentioned above, BZRedit uses Ghostscript, the GNU PostScript +interpreter, to display the character images. @xref{Archives}, for how +to obtain Ghostscript. + +BZRedit assumes that Ghostscript's default output device is the correct +one to use---presumably a window on an X display. The actual default +depends on how Ghostscript was installed. + +The following variables control various attributes of the Ghostscript +output: + +@defvar bzr-gs-width +The width of the window, in pixels. Default is 300. +@end defvar + +@defvar bzr-gs-height +The height of the window, in pixels. Default is 300. +@end defvar + +@defvar bzr-gs-dpi +The resolution at which Ghostscript renders images, in pixels per inch. +Default is 300. +@end defvar diff --git a/doc/bzrto.texi b/doc/bzrto.texi new file mode 100644 index 0000000..5895ff6 --- /dev/null +++ b/doc/bzrto.texi @@ -0,0 +1,1008 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node BZRto, BPLtoBZR, Limn, Top +@chapter BZRto + +@pindex bzrto +@cindex outline conversion + +BZRto translates an outline font that's in our home-grown BZR outline +font format (described below) to some other form: Metafont, Type 1 +PostScript, Type 3 PostScript, or BPL. + +BPL format is simply a human-readable form of BZR files. @xref{BPL +files}. We discuss the other output forms below. + +Besides straight format conversion, BZRto can also: + +@itemize @bullet +@item +merge fonts, possibly of different sizes (see the @samp{-concat} option +in @ref{Invoking BZRto}); + +@item +slant fonts, so the oblique version of a font can be made without +respecifying the character shapes (see the @samp{-oblique-angle} +option); + +@item +create new characters by combining existing ones, via a fairly general +command language (@pxref{CCC files}). + +@end itemize + +@menu +* Metafont and BZRto:: Output as a Metafont program. +* Type 1 and BZRto:: Output as a Type 1 PostScript font. +* Type 3 and BZRto:: Output as a Type 3 PostScript font. +* CCC files:: Creating additional characters. +* Invoking BZRto:: Command-line options. +* BZR files:: The technical definition of BZR format. +@end menu + + +@node Metafont and BZRto, Type 1 and BZRto, , BZRto +@section Metafont and BZRto + +@cindex Metafont output from BZR files +@cindex converting from BZR to Metafont +@cindex BZR files, converting to Metafont + +@cindex Knuth, Donald E. +Metafont is a language for specifying graphic shapes, particularly +characters in a font of a type, as well as the name of the program which +interprets the language. It is commonly used to generate fonts for +@TeX{} and related software (@TeX{} and Metafont were developed +more-or-less simultaneously by Donald Knuth during the years +1977--1985). @xref{Archives}, for how to obtain the Metafont program. + +@opindex -metafont +BZRto generates a Metafont font @file{@var{foo}.mf} from the input file +@file{@var{foo}10.bzr} (the @samp{10} being the design size of the +input) if you specify the @samp{-metafont} option, as in: + +@example +bzrto -metafont @var{foo} +@end example + +Presuming Metafont has been installed properly at your site, you can +then make both a TFM and a GF file for @var{foo} at a size of 10@dmn{pt} +and rasterized for your most common output device with the command: + +@cindex GF file, generating with Metafont +@example +mf '\mode:=localfont; input @var{foo}' +@end example + +@noindent (The single quotes are not seen by Metafont; they just protect +the backslash and semicolon from interpretation by your shell.) + +@vindex localfont @r{Metafont mode} +@cindex Metafont mode +@cindex modes in Metafont +The assignment to @code{mode} tells Metafont the name of your output +device. @code{localfont} should be a synonym for some real output +device, defined when Metafont was installed. The GF file will be named +@file{@var{foo}.@var{dpi}gf}, where @var{dpi} is the resolution of the +@code{localfont} device. + +Given the TFM and GF file, you can now use the font in @TeX{}. + +@menu +* Metafont output at any size:: Making larger or smaller fonts. +* Proofing with Metafont:: Metafont can help with debugging fonts. +@end menu + + +@node Metafont output at any size, Proofing with Metafont, , Metafont and BZRto +@subsection Metafont output at any size + +@cindex Metafont output, at different sizes + +@vindex designsize @r{Metafont parameter} +@cindex point size, specifying to Metafont +We described above how to get Metafont output at a size of 10@dmn{pt}. +To generate a GF file for a font @var{foo} at a different size, assign +to @code{designsize} on the command line, as follows: + +@example +mf '\mode:=localfont; designsize:=@var{integer}; input @var{foo} +@end example + +@noindent +For example, if @code{localfont} corresponds to a 300@dmn{dpi} +device, and you specify @samp{designsize:=6}, this command creates +@file{@var{foo}.180gf}, i.e., a 40% reduction from +@file{@var{foo}.300gf}. + +@cindex magnification +@findex \magnification +In some cases, it may be more convenient to specify a magnification +factor than a new point size. (For example, this is the case if you are +enlarging or reducing an entire document by some constant factor, as +with @TeX{}'s @code{\magnification} command.) You can do this by +assigning to @code{mag}: + +@example +mf '\mode:=localfont; mag:=@var{real}; input @var{foo} +@end example + +@noindent +By default, @code{mag} is 1.0. You can also assign to both @code{mag} +and @code{designsize}. For example, if you set @code{designsize} to 5 +and @code{mag} to 4, the output will be a 20@dmn{pt} font. + +@cindex nonlinear scaling +@cindex scaling of Metafont fonts +@cindex anamorphic scaling +Although the Metafont language allows nonlinear scaling of fonts, so +that the 6@dmn{pt} font would not simply be a reduced version of the +10@dmn{pt} font, BZRto cannot take advantage of this sophistication. +The reason is that BZR files specify a single set of outlines, and the +nonlinear scaling cannot be deduced from that. Perhaps we will extend +the programs someday to handle interpolation between outlines of +different sizes. + + +@node Proofing with Metafont, , Metafont output at any size, Metafont and BZRto +@subsection Proofing with Metafont + +@cindex proofing fonts +@cindex fonts, proofing +@cindex debugging fonts +@cindex blowing up fonts + +@pindex gftodvi +While creating fonts, it is useful to enlarge the character shapes +enough to be able to make out small details. This blowing-up process is +called @dfn{proofing}. Metafont works together with GFtoDVI, another +program created as part of the @TeX{} project, to do this. + +@cindex gray proofs +@cindex smoke proofs +You can make two kinds of proofs with Metafont: @dfn{gray proofs} and +@dfn{smoke proofs}. Metafont calls the former @code{proof} mode, and +the latter @code{smoke} mode. @code{proof} mode is the default, so if +you do not assign to @code{mode} at all, you get gray proofs. To get +smoke proofs for a font @var{foo}, you run Metafont as follows: + +@example +mf '\mode:=smoke; input @var{foo}' +@end example + +@findex nodisplays +@noindent (See the preceding sections for general information on running +Metafont.) In @code{proof} or @code{smoke} mode, by default Metafont +will display the characters online as it runs (if you are on a terminal +capable of this, e.g., running under X). If you aren't interested in +seeing this online output, you can say @samp{nodisplays;} on the command +line. + +@vindex designsize @r{and proofing} +@cindex proof_size +In both kinds of proofs, the font is produced at a very high resolution, +typically thousands of pixels per inch, to minimize (or eliminate) +distortion due to rasterization difficulties. To be more precise, the +resolution is chosen so that the @code{designsize} of the font fills +@code{proof_size} inches; by default, @code{proof_size} is 7, which +works well enough for both letter-size and A4 paper. + +@vindex proof_resolution +In order to calculate this, Metafont must also know the resolution of +the final output device. This is called @code{proof_resolution}, and is +300 by default. + +@flindex bzrsetup.mf@r{, computing proof values} +You can change the values of @code{proof_size} and +@code{proof_resolution} on the command line; the actual calculation is +done in @file{bzrsetup.mf}. + +After running Metafont, you will have a GF file, e.g., +@file{@var{foo}.2602gf}. You can then make a DVI file you can preview +or print with: +@example +gftodvi @var{foo}.2602gf +@end example +@noindent This creates @file{@var{foo}.dvi}. In the DVI output from +GFtoDVI, each character in the font has its own page. Some additional +information is also present, as follows: + +@cindex gray fonts +@cindex control points of splines, seeing +@cindex endpoints of splines, seeings +In @code{proof} mode, the character shapes are printed in a ``gray'' +font, and the starting and ending points of each spline (or line) in the +character outline are shown. (Thus, you can see if Limn did a good job +choosing those points.) If you set @math{@code{proofing} > 2}, the +control points for each spline will also be shown. If a point would +otherwise overlap with others on the output, an equation is put off to +the right defining where it appears. + +@cindex Wall, The +In @code{smoke} mode, the character shapes are printed in black; if you +put the output on the wall and stand back, you can get an idea of how +the font is coming along. The character is also shown at its true size +off to the right (assuming you have made the font at the true-size +resolution, of course). + +@opindex -overflow-label-offset +@cindex losing proof information +@cindex proof information, losing +@cindex overflow equations, losing +You may find that the extra information to the right of the character +(``overflow equations'' in @code{proof} mode; the true-size character in +@code{smoke} mode) is being lost off the edge of the page. You can +change where GFtoDVI puts this with the @samp{-overflow-label-offset} +option to GFtoDVI. + +See the @cite{Metafontbook} and the GFtoDVI documentation for more +details. + + +@node Type 1 and BZRto, Type 3 and BZRto, Metafont and BZRto, BZRto +@section Type 1 PostScript fonts and BZRto + +@cindex Type 1 output from BZR files +@cindex PostScript Type 1 output from BZR files +@cindex converting from BZR to Type 1 +@cindex BZR files, converting to Type 1 + +The Type 1 font format, invented by Adobe Systems, Inc., is the most +common representation for PostScript fonts. Adobe first published its +specification in the book @cite{Adobe Type 1 Font Format} in 1990. It +defines a limited set of operations; general PostScript programs cannot +be represented as Type 1 fonts. It also defines hints---ways of +improving characters' appearances at low resolution and/or small +sizes---which cannot be represented in PostScript proper. + +@opindex -pstype1 +BZRto generates a Type 1 font @file{@var{foo}.gsf} from the input file +@file{@var{foo}10.bzr} (the @samp{10} being the design size of the +input) if you specify the @samp{-pstype1} option, as in: + +@example +bzrto -pstype1 @var{foo} +@end example + +The file @file{@var{foo}.gsf} consists only of plain text (it's not +really ``human-readable'', since Type 1 format requires encryption +of the character outlines). + +@cindex encryption of Type 1 fonts +@cindex Type 1 fonts, encryption of +@cindex unencrypted Type 1 fonts +Although Type 1 format also allows for encryption of the entire font, +this is not required, and BZRto does not do it. Some deficient +PostScript interpreters do not recognize unencrypted fonts; but +Ghostscript, the GNU quasi-PostScript interpreter, has no trouble. We +do not know of any utilities for encrypting an unencrypted Type 1 font, +but presumably such a program would not be hard to write. + + +@node Type 3 and BZRto, CCC files, Type 1 and BZRto, BZRto +@section Type 3 PostScript fonts and BZRto + +@cindex Type 3 output from BZR files +@cindex PostScript Type 3 output from BZR files +@cindex converting from BZR to Type 3 +@cindex BZR files, converting to Type 3 + +Type 3 PostScript fonts are not defined in a singular format, as are +Type 1 fonts (see the previous section). Rather, they are general +PostScript programs which happen to meet the PostScript language's +(liberal) requirements for being a font. They can therefore be used +with any PostScript interpreter. + +@opindex -pstype3 +BZRto generates a Type 3 font @file{@var{foo}.pf3} from an input BZR +file @file{@var{foo}.bzr} if you specify the @samp{-pstype3} option, as +in: + +@example +bzrto -pstype3 @var{foo} +@end example + +@cindex PF3 abbreviation +We do not know of any conventional extension for Type 3 fonts; we made +up @file{pf3} to stand for ``PostScript font Type 3''. + +@findex BuildChar @r{in Type 3 fonts} +The most important part of a Type 3 font is the @code{BuildChar} +routine, which does the actual rendering from the character program. +Unlike Type 1 fonts, whose @code{BuildChar} routine is built into the +PostScript interpreter, each Type 3 font supplies its own +@code{BuildChar} routine. + +@flindex bzrbuildch.PS +@findex run @r{PostScript command} +The Type 3 fonts output by BZRto use a @code{BuildChar} routine defined +in a separate file @file{bzrbuildch.PS} (distributed in the @file{bzr} +directory). They use the PostScript @code{run} command to read that +file; so if you want to download one to a printer (which naturally will +not have access to the file on your computer), you must replace the +@code{run} command with the contents of the file. For PostScript +interpreters which run on a host computer, such as Ghostscript, you have +to install @file{bzrbuildch.PS} in a directory where it will be found, +but you need not modify the fonts. + + +@node CCC files, Invoking BZRto, Type 3 and BZRto, BZRto +@section CCC files + +@cindex CCC files + +@cindex pre-accented characters +@cindex accented characters +@cindex piece accents +@cindex characters, accented +The CCC (composite character construction) language allows you to define +new characters in terms of existing ones. This is useful for building +such characters as pre-accented A's (from a piece accent and an `A'). + +A CCC file consists of a sequence of character definitions, each of +which looks like: + +@example +define @var{name} = @var{statements} end +@end example + +@noindent +where @var{name} is a character name, presumably from the encoding file +specified with the @samp{-encoding} option (@pxref{Invoking BZRto}). +@xref{Character names}, for the details of character names. + +We describe the possible @var{statements} below. + +You may also include comments starting with a @samp{%} character and +continuing to the end of the line. + +@menu +* setchar: CCC setchar. Statements for including a character. +* move: CCC move. Statements for moving to a new position. +@end menu + + +@node CCC setchar, CCC move, , CCC files +@subsection CCC @code{setchar} statements + +@cmindex setchar @r{CCC commands} +@cmindex setcharbb @r{CCC commands} +To use an existing character as part of a new character, you can use +either the @code{setchar} or @code{setcharbb} statement. They both take +a character name in parentheses as their argument, as in: + +@example +setchar ( @var{name} ) +setcharbb ( @var{name} ) +@end example + +@xref{Character names}, for the details of character names. + +@cindex side bearings in CCC files +The difference between the two commands lies in their treatment of the +existing character's sidebearings: the @code{setchar} command includes +them, and @code{setcharbb} does not. @code{setcharbb} also removes +any white space above and below the character shapes, as is usually +present in accent characters. + +This difference lets you construct characters without worrying about +interaction between their side bearings. For example, you could make an +`A' with an acute accent centered over the body of the `A' as follows: + +@vindex Aacute @r{character, constructing} +@example +define Aacute = + setchar (A) + hmove -.5 width (A) + vmove height (A) + setcharbb (acute) +end +@end example + +@noindent +(See the next section for a description of the @code{hmove} and +@code{vmove} commands.) Without the @code{setcharbb} command, this +definition would be complicated by the side bearings on the @code{acute} +character. + + +@node CCC move, , CCC setchar, CCC files +@subsection CCC @code{move} statements + +@cindex moves in CCC files + +To change the current position in a CCC file, you can use the +@code{hmove} or @code{vmove} command; as you might expect, the former +moves horizontally and the latter vertically. + +@cindex dimensions in CCC files +Both take a single argument: a @dfn{dimension}, which is an optional +real number followed by a unit of measure. The real number is a +multiplying factor. For example, one of the units is @code{pt} +(signifying printer's points, as usual), so the command @samp{hmove 3pt} +moves three points to the right (a pretty small distance). + +Here are the possible units of measure: + +@table @samp + +@item bbheight ( @var{name} ) +@vindex bbheight @r{CCC dimension} +The height exclusive of blank space above or below the shape of the +character @var{name} if it exists. + +@item bbwidth ( @var{name} ) +@vindex bbwidth @r{CCC dimension} +The width exclusive of side bearings of the character @var{name} if it +exists. + +@item capheight +@vindex capheight @r{CCC dimension} +The height of the capital letters, e.g., @samp{H}. See @samp{xheight} +for how this is determined. + +@item depth ( @var{name} ) +@vindex depth @r{CCC dimension} +The depth of the character @var{name}. + +@item designsize +@vindex designsize @r{CCC dimension} +The design size of the main input BZR font. + +@item em +@vindex em @r{CCC dimension} +The quad width of the font. This value is determined analogously to +@samp{xheight}, below. + +@item fontdepth +@vindex fontdepth @r{CCC dimension} +The maximum depth any character in the font descends below the baseline. +Again, this is determined analogously to @samp{xheight}. + +@item height ( @var{name} ) +@vindex height @r{CCC dimension} +The height of the character @var{name}. + +@item pt +@vindex pt @r{CCC dimension} +Printer's points; 72.27@dmn{pt} = 1@dmn{in}. Since dimensions specified +in points are absolute distances, they do not scale when the font size +changes. + +@item width ( @var{name} ) +@vindex width @r{CCC dimension} +The set width of the character @var{name}. + +@item xheight +@vindex xheight @r{CCC dimension} +The x-height of the main input font. If a TFM file corresponding to the +main BZR file exists and defines this, that value is used; otherwise, the +height of a suitable character (e.g., @samp{x}) is used if one exists; +otherwise, it's zero. BZRto treats the other font-related units of +measure in the same way. + +@end table + +If the character @var{name} does not exist, an error is given, and the +command ignored. + + +@node Invoking BZRto, BZR files, CCC files, BZRto +@section Invoking BZRto + +@cindex BZRto options +@cindex Invoking BZRto +@cindex options, for BZRto + +This section describes the options that BZRto accepts. +@xref{Command-line options}, for general option syntax. + +The root of the main input fontname is called @var{font-name} below. + +@table @samp + +@item -concat @var{bzr-name1}, @var{bzr-name2}, @dots{} +@opindex -concat +@cindex concatenating outline fonts +@cindex merging outline fonts +@cindex outline fonts, concatenating +@cindex font concatenation +Concatenate the main input file with the given @var{bzr-name}s; if a +character code exists in more than one of the BZR files, it's the first +occurrence that counts. The BZR files can have any design size; the +output is normalized to the size of the main input file. + +@item -ccc-file @var{filename} +@opindex -ccc-file +Read the CCC file @var{filename} (if @var{filename} has a suffix) or +@file{@var{filename}.ccc} (if it doesn't). Default is to use +@var{font-name} for @var{filename}, but if BZRto does not find +the file @file{@var{font-name}.ccc}, it does not complain. + +@item -encoding @var{filename} +@opindex -encoding +@cindex encoding of input fonts +Specify the encoding file for the input font, so character names in the +CCC files can be matched to character codes. If @var{filename} has no +suffix, use @file{@var{filename}.enc}, otherwise just @var{filename}. +The default is to guess the encoding from the @samp{codingscheme} string +in a TFM file corresponding to the main input file, if such exists. + +@item -help +@opindex -help +Print a usage message. @xref{Common options}. + +@item -metafont +@opindex -metafont +Translate the input to a Metafont program; write to +@file{@var{font-name}.mf}. @xref{Metafont and BZRto}. + +@item -mf +@opindex -mf +Synonym for @samp{-metafont}. + +@item -oblique-angle @var{angle-in-degrees} +@opindex -oblique-angle +@cindex slanted fonts, making +@cindex oblique fonts, making +Angle in degrees from the vertical by which to slant the shapes; default +is zero. + +@item -output-file @var{filename} +@opindex -output-file +Output to @var{filename} (if it has a suffix) or to +@file{@var{filename}.@var{font-format}} (if it doesn't), where +@var{font-format} is @file{mf}, @file{gsf}, etc. If you give more than +one of the output format options (i.e., @samp{metafont}, @samp{pstype1} and +@samp{pstype3}), @var{filename} cannot have a suffix. The default is +@var{font-name} with a trailing number removed, so that, for example, an +input filename of @file{cmr10} becomes @file{cmr}. + +@item -ps-font-info @var{name1}:@var{value1},@dots{} +@opindex -ps-font-info +@vindex FontInfo +Assign each @var{value} to the corresponding @var{name} when outputting +a PostScript font (either Type 1 or Type 3). Case is significant in +both the @var{name}s and @var{value}s. You can specify the following: + +@table @samp + +@item FontName:@var{string} +@vindex FontName @r{in PostScript fonts} +@vindex unknown @r{font name} +The full PostScript name of the font; e.g., @code{Times-BoldItalic}. +The default is @code{unknown}. + +@item FamilyName:@var{string} +@vindex FamilyName @r{in PostScript fonts} +The name of the typeface family to which this font belongs; e.g., +@code{Times}. The default is to use @code{FontName} up to the first +@samp{-}. + +@item Weight:@var{string} +@vindex Weight @r{in PostScript fonts} +The typographic weight of the font, e.g., @code{Bold}. If +@code{FontName} contains one of the strings @samp{Black}, @samp{Book}, +@samp{Bold}, @samp{Demi}, @samp{ExtraBold}, @samp{Light}, @samp{Heavy}, +@samp{Regular}, @samp{Semibold}, or @samp{Ultra}, that is the +weight. Otherwise, BZRto uses @samp{Medium}. + +@item ItalicAngle:@var{real} +@vindex ItalicAngle @r{in PostScript fonts} +The angle in degrees by which the font slopes to the right from the +vertical. Default is zero. Typical slanted or italic fonts have values +between 10--20. + +@item isFixedPitch:@code{true} @r{or} @code{false} +@vindex isFixedPitch @r{in PostScript fonts} +@cindex monospaced PostScript fonts +Whether or not this font is monospaced. If a TFM file corresponding to +the main BZR file exists, and specifies a zero interword stretch and +shrink, and a nonzero interword space, the default is @code{true}. +Otherwise, it's @code{false}. + +@item UnderlinePosition:@var{real} +@vindex UnderlinePosition @r{in PostScript fonts} +Distance from the baseline for positioning underlines, in units of the +character coordinate system. Default is @math{-100}. + +@item UnderlineThickness:@var{real} +@vindex UnderlineThickness @r{in PostScript fonts} +Thickness of underlines. Default is 50. + +@item UniqueID:@var{non-negative integer} +@vindex UniqueID @r{in PostScript fonts} +An integer in the range 0 to 16777215 (2^24 - 1) uniquely identifying +this font. The default is zero, meaning (for our purposes) not to +output any @code{UniqueID}. This avoids unlikely-but-possible conflicts +with existing fonts. + +@item version:@var{string} +@vindex version @r{in PostScript fonts} +Identification for the particular version of this font. If a TFM file +corresponding to the main BZR file exists, and specifies a version +number, that is the default; otherwise, there is none. + +@end table + +@noindent All values except @code{FontName} and @code{UniqueID} go in +the @code{FontInfo} dictionary. + +@item -pstype1 +@opindex -pstype1 +Translate the input to (unencrypted) PostScript Type 1 font format; +write to @file{@var{font-name}.gsf}. @xref{Type 1 and BZRto}. + +@item -pstype3 +@opindex -pstype3 +Translate the input to PostScript Type 3 font format; write to +@file{@var{font-name}.pf3}. @xref{Type 3 and BZRto}. + +@item -range @var{char1}-@var{char2} +@opindex -range +Only process characters between the character codes @var{char1} and +@var{char2}, inclusive. + +@item -text +@opindex -text +Translate the font to a BPL file, i.e., human-readable text; write to +standard output. @xref{BPL files}. + +@item -verbose +@opindex -verbose +Output progress reports to standard output, unless @samp{-text} is +specified, in which case output to standard error. + +@item -version +@opindex -version +Print the version number. + +@end table + + +@node BZR files, , Invoking BZRto, BZRto +@section BZR files + +@cindex BZR file format, definition of + +@flindex bzr @r{source directory} +This section describes the technical definition of the BZR file format. It +is intended for programmers who wish to write other programs which read +or write such files. The present distribution includes a subroutine +library which can be shared among programs (Limn, BPLtoBZR, and BZRto +all use it); new programs can and probably should use the existing +library as well. The source code is in the @file{bzr} directory. + +The BZR file format shares the philosophy of the @TeX{} project file +formats (DVI, GF, PK, etc.): machine-independence; compactness; and +easy interpretation. + +BZR files have three parts: a preamble, character definitions, and a +postamble. We describe each below, as well as some general +considerations. + +@menu +* Intro: BZR format introduction. General concepts and definitions. +* Preamble: BZR preamble. The beginning. +* Chars: BZR characters. The middle. +* Postamble: BZR postamble. The end. +@end menu + + +@node BZR format introduction, BZR preamble, , BZR files +@subsection BZR format introduction + +This section describes some general conventions of the BZR format. + +@cindex opcodes in BZR files +@flindex bzr_opcodes.h +@cindex notation, for BZR format +In the following sections, we use the notation @var{name}[@var{n}] to +mean that some constituent @var{name} of the BZR file takes up @var{n} +bytes. If @var{name} is all capital letters, it is an opcode, i.e., a +command byte, and therefore we give no [@var{n}] after @var{name}, since +all opcodes are a single byte. The numerical value of each opcode is +given in the source file @file{bzr/bzr_opcodes.h}. + +@cindex pointers in BZR files +Some values in BZR files are ``pointers''. These values give the +location of some other byte in the file. The first byte is numbered +0, the next byte numbered 1, and so on. + +@cmindex NO_OP @r{opcode in BZR files} +Besides commands which actually define the font, the BZR format has a +@code{NO_OP} command, which does nothing. Any number of @code{NO_OP}'s +can occur between the preamble and the character definitions, between +character definitions and commands within characters, between the +character definitions and the postamble, and after the postamble. But +they may not occur within the preamble, the postamble, or between a +command and its parameters. + +@cindex types in BZR format +@cindex designsize-scaled numbers in BZR files +Besides simple integers, BZR format uses a fixed-point representation of +real numbers called a @dfn{scaled}, which is three bytes: two bytes of +fraction and one byte of integer. We can get away with such a small +range because almost all numbers are scaled by the design size; i.e., in +a 10-point font, a designsize-scaled value of 1.0 would represent 10 +points (quite a large distance, relatively speaking). + +In fact, designsize-scaled numbers are typically less than 1.0, so the +BZR format provides for abbreviating such, thus making the font smaller, +as detailed in the following sections. + +@cindex two's complement in BZR files +@cindex negative numbers in BZR files +@cindex multibyte values in BZR files +@cindex BigEndian order in BZR files +@cindex portability of BZR files +Negative numbers are represented in 2's complement notation, and +multibyte values are stored in BigEndian order, regardless of the +conventions of the host computer. This makes a BZR font file +portable between different architectures. + + +@node BZR preamble, BZR characters, BZR format introduction, BZR files +@subsection BZR preamble + +@cindex BZR preamble +@cindex preamble in BZR files + +The preamble of a BZR file has two components, the font's design size +and a comment: @code{designsize}[3], @code{k}[1], +@code{comment}[@code{k}]. + +@xref{BZR format introduction}, for general information about BZR files +and for the definition of the types used here. + +@cindex designsize in BZR files +The @code{designsize} is a @code{scaled} number in printer's points. + +@cindex comment in BZR files +@cindex identification in BZR files +@cindex date of creation in BZR files +The @var{k}-byte long @code{comment} typically identifies the +source and creation date of the BZR file. + + +@node BZR characters, BZR postamble, BZR preamble, BZR files +@subsection BZR characters + +@cindex character definitions in BZR files + +@cmindex EOC @r{opcode in BZR files} +BZR characters consist of an identifying command, metric +information, shape information, and a terminating @code{EOC} command. + +We describe these parts below. + +@menu +* BOC: BZR character beginnings. Giving character metrics. +* Shape: BZR character shapes. Defining the outline(s). +@end menu + + +@node BZR character beginnings, BZR character shapes, , BZR characters +@subsubsection BZR character beginnings + +@cindex BZR character beginning +@cindex beginning of characters in BZR files + +BZR format provides two ways to start characters: an abbreviated one, +which saves space in common cases, and a longer form which (we hope) +will always suffice. + +The short form looks like this: + +@display +@code{BOC_ABBREV} @cmindex BOC_ABBREV +@code{charcode}[1] +@code{set-width}[2] +@code{llx}[2] @code{lly}[2] @code{urx}[2] @code{ury}[2] +@end display + +The long form: + +@display +@code{BOC} @cmindex BOC +@code{charcode}[1] +@code{set-width}[3] +@code{llx}[3] @code{lly}[3] @code{urx}[3] @code{ury}[3] +@end display + +Here is a description of these components: + +@itemize @bullet + +@item +The @code{BOC} or @code{BOC_ABBREV} opcode byte introduces the character. + +@cindex character code in BZR files +@item +@code{charcode} defines the character code in question. + +@cindex set width in BZR files +@item +@code{set-width} defines the set width of the character, given as a +design-size scaled, in printer's points. + +@item +@code{llx} @dots{} @code{ury} (which stand for ``lower left @math{x}'', +``lower left @math{y}'', ``upper right @math{x}'', and ``upper right +@math{y}'') define the bounding box for this character. The values are +designsize-scaled, in printer's points. The bounding box is not +guaranteed to be the tightest possible, because it is difficult to +compute the exact path of any splines in the character shape (@pxref{BZR +character shapes}). + +@end itemize + +As with other formats, the left side bearing is defined by @code{llx}, +and the right side bearing by @code{set-width} @minus{} @code{urx}. + +@xref{BZR format introduction}, for general information about BZR files +and for the definition of the types used here. + + +@node BZR character shapes, , BZR character beginnings, BZR characters +@subsubsection BZR character shapes + +@cindex BZR character shapes +@cindex character shapes in BZR files +@cindex shapes of characters in BZR files +@cindex outlines of characters in BZR files + +In the BZR format, a character shape is defined as a sequence of +(non-contiguous) closed paths, i.e., outlines. Each path can contain +straight lines and Bezier cubic splines. As a BZR-reading program +interprets the character definition, it keeps track of a ``current +point'', which is initially undefined. + +@cmindex PATH @r{opcode in BZR files} +@cindex path command in BZR files +Each path---and therefore also the character shape itself---starts with a +path command: @code{PATH}, @code{x}[3], @code{y}[3]. This +finishes off any previous outline and starts a new one, setting the +current point to @code{(x,y)}. @code{x} and @code{y} are +designsize-scaled values in printer's points. + +After a path command has started an outline, a sequence of zero or more +line and/or spline commands, intermixed in any order, follows. (A path +command followed by another path command is allowed, but does nothing +useful.) + +@cindex outside curves +@cindex inside curves +@cindex counterclockwise drawing of curves +@cindex clockwise drawing of curves +Although the BZR format itself does not require it, for the font to work +properly when translated to some other formats, the ``outside curves'' +must be drawn counterclockwise, and the inside ones clockwise. + +The BZR format defines both abbreviated and long versions of both straight +line and spline commands, as follows. + +@cindex straight lines in BZR files +The abbreviated line command is: + +@display +@code{LINE_ABBREV} @cmindex LINE_ABBREV @r{opcode in BZR files} +@code{ex}[2] +@code{ey}[2] +@end display + +@noindent which defines a straight line from the current point to +@code{(ex,ey)}. @code{ex} and @code{ey} are designsize-scaled numbers +in points. After drawing the line, the current point is set to +@code{(ex,ey)}. + +@cmindex LINE @r{opcode in BZR files} +The long form of the line command differs only in starting with a +@code{LINE} opcode, and the coordinate parameters being three bytes long, +instead of two. + +@cindex splines in BZR files +The spline commands are analogous. Here is the abbreviated form: + +@display +@code{SPLINE_ABBREV} @cmindex SPLINE_ABBREV @r{opcode in BZR files} +@code{c1x}[2] @code{c1y}[2] +@code{c2x}[2] @code{c2y}[2] +@code{ex}[2] @code{ey}[2] +@end display + +@noindent This defines a Bezier spline with initial point the +current point, control points @code{(c1x,c1y)} and @code{(c2x,c2y)}, and +ending point @code{(ex,ey)}. The current point is then set to +@code{(ex,ey)}. As with the line commands, the coordinate parameters +are designsize-scaled in units of points. + +@cmindex SPLINE @r{opcode in BZR files} +Also as with the line commands, the long form of the spline command +differs only in starting with a @code{SPLINE} opcode and the other +parameters being three bytes long instead of two. + + +@node BZR postamble, , BZR characters, BZR files +@subsection BZR postamble + +@cindex BZR postamble +@cindex postamble in BZR files + +The postamble of a BZR file consists of the following. @xref{BZR format +introduction}, for general information about BZR files and for the +definition of the types used here. + +@display +@code{POST} @cmindex POST @r{opcode in BZR files} +@code{llx}[3] @code{lly}[3] @code{urx}[3] @code{ury}[3] +character locators (see below) +@code{POST_POST} @cmindex POST_POST @r{opcode in BZR files} +@code{nchars}[1] +@code{post-ptr}[4] +@code{id}[1] +1 to any number of @code{NO_OP}'s +@end display +@cmindex NO_OP @r{opcode in BZR files} + +Here is a description of these components: + +@itemize @bullet + +@cindex font bounding box in BZR files +@cindex bounding box of font in BZR files +@item +@code{llx} @dots{} @code{ury} are all designsize-scaled +numbers. They define the bounding box for the entire font, which is +simply the smallest box that encloses all the characters. @xref{BZR +character beginnings}. + +@cindex character locators in BZR files +@item +A character locators provides a pointer to the first byte of the +corresponding character description, i.e., its @code{BOC}. There are +two forms of character locators: one abbreviates the common case of the +pointer being less than 65536; the other allows for a full four-byte +pointer value. + +@cmindex CHAR_LOC_ABBREV @r{opcode in BZR files} +More precisely, an abbreviated character locator consists of: + +@example +CHAR_LOC_ABBREV charcode@r{[1]} pointer@r{[2]} +@end example + +@cmindex CHAR_LOC @r{opcode in BZR files} +@noindent and a long character locator consists of: + +@display +@code{CHAR_LOC} @code{charcode}[1] @code{pointer}[4] +@end display + +@cindex number of characters in BZR files +@cindex character count in BZR files +@item +@code{nchars} is the number of characters defined in the BZR file. + +@cindex postamble pointer in BZR files +@item +@code{post-ptr} points to the @code{POST} byte. + +@cindex identification of BZR format +@cindex BZR format, identification +@item +@code{id} identifies the version of BZR format; this is currently 75. + +@end itemize + +@cindex BZR files, algorithm for reading +This way of ending BZR files makes it straightforward to process a BZR +file from end to beginning, even though it must of course be written +beginning to end. The BZR-reading program can position itself at the +end of the file, skip over the @code{NO_OP} bytes at the end to the +@code{id} byte, and then read the pointer to the postamble proper, which +provides enough information to read each character individually. This +eliminates the need to read the entire (potentially large) BZR file into +memory before doing any processing. diff --git a/doc/charspace.texi b/doc/charspace.texi new file mode 100644 index 0000000..fe85de9 --- /dev/null +++ b/doc/charspace.texi @@ -0,0 +1,852 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Charspace, Limn, Fontconvert, Top +@chapter Charspace + +@pindex charspace +@cindex side bearings, adding +@cindex spacing, character +@cindex character spacing + +Charspace lets you add @dfn{side bearings} (the blank spaces on either +side of a character) to a bitmap font. This is necessary because +scanned images typically do not include side bearing information, and +therefore Imageto (@pxref{Imageto}) cannot determine it. + +The input is a bitmap (GF or PK) font, together with one or more CMI +files (@pxref{CMI files}), which specify character metric information. If a +corresponding TFM file exists, it is read to get default values for the +character dimensions (Charspace promptly overwrites the widths). The +output is a TFM file and (typically) a revised GF file with the new +width information. + +@cindex Smith, Harry +@cindex Tracy, Walter +@cindex Letters of Credit +The basic idea for Charspace came from Harry Smith, via Walter Tracy's +book @cite{Letters of Credit}. See @file{charspace/README} for the full +citation. + +@menu +* Charspace usage:: Details on improving the character metrics. +* CMI files:: You specify the metrics in a separate file. +* Invoking Charspace:: Command-line options. +@end menu + + +@node Charspace usage, CMI files, , Charspace +@section Charspace usage + +@cindex Charspace usage +@cindex usage of Charspace + +Charspace makes no attempt to be intelligent about the side bearings it +computes; it just follows the instructions in the CMI files. + +The CMI files must be created by human hands, since the information they +contain usually cannot be determined automatically. See the next +section for the details on what CMI files contain. + +@flindex common.cmi +We supply one CMI file, @file{common.cmi} (distributed in the +@file{data} directory), which defines more-or-less typeface-independent +definitions for most common characters. Charspace reads +@file{common.cmi} before any of the CMI files you supply, so your +definitions override its. + +@file{common.cmi} can be used for all typefaces because its definitions +are entirely symbolic; therefore, your CMI file must define actual +values for the identifiers it uses. For example, @file{common.cmi} +defines the right side bearing of @samp{K} to be @code{uc-min-sb}; you +yourself must define @code{uc-min-sb}. + +You must also define side bearings for characters not in +@file{common.cmi}. And you can redefine side bearings that @emph{are} +in @file{common.cmi}, if you find its definitions unsuitable. + +Once you have prepared a CMI file, you can run Charspace, e.g.: +@example +charspace -verbose -encoding=@var{enc-file} @var{fontname}.@var{dpi} \ + -output-file=@var{out-fontname} +@end example + +@noindent where @var{enc-file} specifies the encoding, +@var{fontname} the input font, @var{dpi} the resolution, and +@var{out-fontname} the name of the output font. + +@flindex testfont.tex +With these options, Charspace will write files +@file{@var{out-fontname}.tfm} and @file{@var{out-fontname}.@var{dpi}gf}. +You can then run @TeX{} on @file{testfont.tex}, telling @TeX{} to use +the font @var{out-fontname}. This produces a DVI file which you can +print or preview as you usually do with @TeX{} documents. + +This will probably reveal problems in your CMI file, e.g., the spacing +for some characters or character combinations will be poor. So you need +to iterate. + +However, if you are planning to eventually run your bitmap font through +Limn (@pxref{Limn}) and BZRto (@pxref{BZRto}) to make an outline font, +there's little point in excessively fine-tuning the spacing of the +original bitmap font. The reason is that the generated outline font +will inevitably rasterize differently than the original bitmaps, and the +change in character shapes will almost certainly affect the spacing. + + +@node CMI files, Invoking Charspace, Charspace usage, Charspace +@section CMI files + +@cindex CMI files +@cindex character metric information files +@cindex side bearing information files +@cindex side bearings, definition of + +@dfn{Character metric information} (CMI) files are free-format text +files which (primarily) describe the side bearings for characters in a +font. @dfn{Side bearings} are the blank spaces to the left and right of +a character which makeprinted type easier to read, as well as more pleasing +visually. + +In addition to side bearing definitions, CMI files can also contain +kerns, which insert or remove space between particular letter +pairs, and font dimensions, global information about the font +stored in the TFM file (@pxref{TFM fontdimens}). + +If your font is named @file{@var{foo}.300gf} (or @file{@dots{} pk}), it +is customary to name the corresponding CMI file @file{@var{foo}.300cmi}. +That is what Charspace looks for by default. If you name it something +else, you must use the @samp{-cmi-files} option to tell Charspace its +name. It is reasonable to use the resolution as part of the CMI +filename, since the values written in it are (for the most part) in +pixels. + +@xref{Common file syntax}, for a precise description of syntax elements +common to all data files processed by these programs, including +comments. + +@flindex ggmr.1200cmi +@cindex CMI example +See the file @file{data/ggmr.1200cmi} in the distribution for an example. + +In the following sections, we describe the individual commands, the +tokens that comprise them, and the way Charspace processes them. + +@menu +* CMI tokens:: The building blocks of CMI files. +* char command:: Defining a character's side bearings. +* char-width command:: Defining side bearings via the set width. +* define command:: Introducing a new identifier. +* kern command:: Defining a kerning pair. +* codingscheme command:: Specifying the font encoding. +* fontdimen command:: Defining additional font parameters. +* CMI processing:: How Charspace reads CMI files. +@end menu + + +@node CMI tokens, char command, , CMI files +@subsection CMI tokens + +@cindex tokens in CMI files +@cindex CMI file tokens +Tokens in a CMI file are one of the following. + +@enumerate + +@cindex real constants +@cindex floating-point constants +@cindex numbers +@item +A numeric constant consists of (in order) an optional sign, zero or more +digits, an optional decimal point, and zero or more digits---but at +least one digit must be present. For example, @samp{+0}, @samp{-0}, +@samp{0}, @samp{.0}, and @samp{-0.0} are all valid ways to write the +number zero. + +@cindex string constants +@item +A string constant consists of all characters between two double-quote +characters @samp{"}. We made no provision for quoting @samp{"}, because +our particular uses for string constants never need quote characters. + +@cindex comma token +@item +A comma is a self-terminating token. It serves merely to separate two +expressions. + +@cindex identifiers +@cindex names +@findex isspace +@item +An identifier is any number of characters starting with a non-whitespace +character (whitespace being defined by the C facility @code{isspace}) +not listed above, and terminated by a whitespace character. + +@cindex character names +In some contexts, an identifier is taken as a @dfn{character name}---a name +from the encoding file Charspace is using, either the default or one you +specified with @samp{-encoding} (@pxref{Invoking Charspace}). +@xref{Encoding files}, for the definition of encoding files. + +In all other cases, identifiers are internal to Charspace. The particular +commands describe the semantics which apply to them. + +@cindex reserved words +@cindex keywords +Some identifiers are @dfn{reserved}, i.e., they cannot be used in any +context except as described in the following sections. Reserved words +are always shown in typewriter type. + +@end enumerate + +@cindex expressions @r{in CMI files} +An expression in a CMI file is one of: a number, an identifier, or a +number followed by an identifier. This last, as in @samp{.75 foo}, +denotes multiplication. + + +@node char command, char-width command, CMI tokens, CMI files +@subsection @code{char} command + +@cmindex char @r{CMI command} +@cindex side bearings, defining in CMI files + +The @code{char} command specifies both side bearings for a single +character. It has the form: + +@example +char @var{charname} @var{expr1} , @var{expr2} +@end example + +@noindent where: + +@table @var + +@item charname +is a character name from the font encoding. @xref{Invoking Charspace}, +for how to specify the encoding file. + +@cindex left side bearing in @code{char} command +@cindex right side bearing in @code{char} command +@cindex side bearings in @code{char} command +@itemx expr1 +@item expr2 +specify the left and right side bearings, in pixels, respectively: the +character widths in the output TFM and GF files are @math{@var{expr1} + +@var{expr2} + @code{width} (@var{charname})}. If these +expressions contain identifiers, the values of those identifiers are not +resolved until after Charspace has read all the CMI files. + +@end table + +Giving the side bearings symbolically is useful when the character +definition is intended to be used for more than one typeface. For +example, @file{common.cmi} (@pxref{Charspace usage}) contains: + +@example +char K H-sb , uc-min-sb +char L H-sb , uc-min-sb +@end example + +Then the CMI file you write for a particular font can define @code{H-sb} +and @code{uc-min-sb}, and not have to redefine the side bearings for +@code{K} and @code{L}. + + +@node char-width command, define command, char command, CMI files +@subsection @code{char-width} command + +@cmindex char-width @r{CMI command} +@cindex side bearings, defining in CMI files + +The @code{char-width} command specifies the set width and left side +bearing as a percentage of the total remaining space for a single +character. It has the form: + +@example +char-width @var{charname} @var{width-expr} , @var{lsb-%-expr} +@end example + +@noindent where: + +@table @var + +@item charname +is a character name from the font encoding. @xref{Invoking Charspace}, +for how to specify the encoding file. + +@cindex width in @code{char-width} command +@cindex character width in @code{char-width} command +@cindex set width in @code{char-width} command +@item width-expr +specifies the set width of the character in pixels. The @dfn{set width} +is the sum of the bitmap width, left side bearing, and right side +bearing. + +@cindex left side bearing in @code{char-width} command +@item lsb-%-expr +specifies the left side bearing as a percentage of @var{width-expr} +minus the bitmap width of the character. Expressing the lsb as a +percentage means that you need not think about the width of the +character image: if you want to center a character, for example, +@samp{.5} for @var{lsb-%-expr} will always work. + +@end table + +The @code{char-width} command is useful when you want a character to +have a particular set width, since it's much simpler to specify that +width and the left side bearing (and let the program compute the right +side bearing) than to somehow estimate the bitmap width and then choose +the side bearings to add up to the desired set width. + +@cindex widths of numerals +@cindex numeral widths +@vindex numeral-width @r{variable in @file{common.cmi}} +@flindex common.cmi@r{, numerals in} +For example, in most fonts, the numerals all have the same width, to +ease typesetting of columns of them in tables. Thus, @file{common.cmi} +defines @code{eight} (the name for the numeral @samp{8}) as follows: + +@example +char-width eight numeral-width , eight-lsb-percent +@end example + +@noindent Since the numeral width is traditionally one-half the em width of +the font, @file{common.cmi} defines @code{numeral-width} as +@code{enspace}, which in turn is defined to be half the @code{quad} +fontdimen. + +@code{eight-lsb-percent} is defined to be @samp{.5}, thus centering the +@samp{8}. + +The other numerals are also defined to have width @code{numeral-width}, +but the @code{lsb-percent}s vary according to the character shapes. + + +@node define command, kern command, char-width command, CMI files +@subsection @code{define} command + +@cmindex define @r{CMI command} +@cindex identifier, defining in CMI files + +The @code{define} command defines an identifier as a number. This is +useful to give a symbolic name to a constant used in more than one +character or fontdimen definition, for ease of change. +It has the form: + +@example +define @var{id} @var{expr} +@end example + +The identifier @var{id} is defined to be the expression @var{expr}. Any +previous definition of @var{id} is replaced. The @var{id} can be used +prior to the @code{define} command; Charspace doesn't try to resolve any +definitions in the CMI files until after all files have been read. + + +@node kern command, codingscheme command, define command, CMI files +@subsection @code{kern} command + +@cmindex kern @r{CMI command} +@cindex kerns, defining in CMI files + +The @code{kern} command defines a space to insert or remove between two +particular characters. The kerning information is written only to the +TFM file. It has the form: + +@example +kern @var{name1} @var{name2} @var{expr} +@end example + +@noindent where @var{name1} and @var{name2} are character names, as in +the @code{char} command (@pxref{char command}), and @var{expr} is the +amount of the kern in pixels. + +For example: + +@example +kern F dot -7.5 +@end example + +@noindent would put an entry in the TFM file's kerning table such that +when @TeX{} typesets a @samp{F} followed by a @samp{.}, it inserts +an additional space equivalent to @math{-7.5} pixels in the resolution of +Charspace's input font, i.e., it moves the two characters closer together. + + +@node codingscheme command, fontdimen command, kern command, CMI files +@subsection @code{codingscheme} command + +@cmindex codingscheme @r{CMI command} +@cindex encoding scheme, specifying +@cindex font encoding, specifying + +The @code{codingscheme} command defines the encoding scheme to be used +for the output files. (@xref{Encoding files}, for a full description of +font encodings.) It has the form: + +@example +codingscheme @var{string-constant} +@end example + +@flindex encoding.map +@noindent where @var{string-constant} is a coding scheme string; for +example, @samp{"GNU Latin text"}. This string is looked up in the data +file @file{encoding.map} to find the name of the corresponding encoding +file (@pxref{Coding scheme map file}). + + +@node fontdimen command, CMI processing, codingscheme command, CMI files +@subsection @code{fontdimen} command + +@cmindex fontdimen @r{CMI command} +@cindex fontdimens in CMI files + +The @code{fontdimen} command defines a font parameter to be put in the +TFM file. It has the form: + +@example +fontdimen @var{fontdimen-name} @var{expr} +@end example + +@noindent where @var{fontdimen-name} is any of the fontdimen names +listed in the section below, and @var{expr} gives the new value of the +fontdimen, in pixels. + +For example, @file{common.cmi} (@pxref{Charspace usage}) makes the +following definitions: + +@example +fontdimen quad designsize +fontdimen space .333 quad +@end example + +@noindent This defines the fontdimen @code{quad}, which determines the +width of the @code{em} dimension in @TeX{}, to be the same as the design +size of the font. (This is traditionally the case, although it is not a +hard-and-fast rule.) Then it defines the fontdimen @code{space}, which +is the normal interword space in @TeX{}, to be one-third of the quad. + +Because of the way that Charspace processes the CMI files +(@pxref{CMI processing}), if you redefine the @code{quad} fontdimen in +another CMI file, the value of @code{space} will change correspondingly. + +The section below lists all the TFM fontdimen names Charspace +recognizes, and their meaning to @TeX{}. + +@menu +* TFM fontdimens:: All the valid fontdimens. +@end menu + + +@node TFM fontdimens, , , fontdimen command +@subsubsection TFM fontdimens + +@cindex fontdimens in TFM files +@cindex TFM fontdimens +@cindex global font parameters +@cindex parameters, global in TFM files + +This section lists all the TFM fontdimens recognized by these programs: +all those recognized by @TeX{}, plus a few others we thought would prove +useful when writing @TeX{} macros. + +A @dfn{fontdimen} is an arbitrary number, in all cases but one +(@code{slant}, see below) measured in printer's points, which is +associated with a particular font. Their values are stored in the TFM +file for the font. We also refer, context permitting, to fontdimens as +``font parameters'', or simply ``parameters''. + +Fontdimens affect many aspects of @TeX{}'s behavior: the interword +spacing, accent placement, and math formula construction. The math +fontdimens in particular are fairly obscure; if you don't have a firm +grasp on how @TeX{} constructs math formulas, the explanations below +will probably be meaningless to you, and---unless you're making a font +for math typesetting---can be ignored. + +@flindex common.cmi +The @file{common.cmi} file which Charspace reads sets reasonable +defaults for the fontdimens relevant to normal text typesetting. + +@cindex fontdimens, scaled fonts and +When @TeX{} (or other programs) scale a font, its fontdimen values are +scaled proportionally to the design size. For example, suppose the +designsize of some font @var{f} is 10@dmn{pt}, and some fontdimen in +@var{f} has the value 7.5@dmn{pt}. Then if the font is used scaled to +20@dmn{pt}, the fontdimen's value is scaled to 15@dmn{pt}. + +@pindex pltotf +You can get the table of fontdimen values in a particular TFM file by +running the standard @TeX{} utility program PLtoTF and inspecting its +(human-readable text) output. + +In our programs and in PLtoTF, fontdimens are typically shown by their +names. But each also has a number, starting at 1. You can use either +the number or the name on the command line (in the argument to the +@samp{-fontdimens} option). The numbers are given in parentheses after +the name in the table below. + +@cindex math symbol fonts +@cindex math extension fonts +@cindex extension, math fonts +@cindex math families in @TeX{} +In a few cases (fontdimens 8--13), the same number fontdimen has two +different names, and two different meanings. This does not cause +problems in practice, because these fontdimens are used only in the +@TeX{} math symbol and math extension fonts, which @TeX{} can +distinguish via its ``math families'' (see @cite{The @TeX{}book} for +the details). + +@c The variable index doesn't seem quite right for the fontdimen names, +@c but I can't think of anything better, and it doesn't make any +@c practical difference, since we conglomerate all the indices into one anyway. +@table @code + +@vindex slant @r{fontdimen} +@cindex font slant +@item slant @r{(1)} +Unlike all other fontdimens, the @code{slant} parameter is not scaled +with the font when it is loaded. It defines the ``slant per pt'' of the +font; for example, a @code{slant} of 0.2 means a 1@dmn{pt}-high +character stem would end 0.2@dmn{pt} to the right of where it began. +This value is typical for slanted or italic fonts; for normal upright +fonts, @code{slant} is zero, naturally. @TeX{} uses this to position +accents. + +@vindex space @r{fontdimen} +@cindex font spacing +@cindex interword space +@item space @r{(2)} +The @code{space} parameter defines the normal interword space of the +font. This is typically about one-third of the design size, but it +varies according to the type design: a narrow, spiky typeface will +have a small interword space relative to a wide, regular one. +Exception: in math fonts, the interword space is zero. + +@vindex stretch @r{fontdimen} +@item stretch @r{(3)} +The @code{stretch} parameter defines the interword stretch of the font. +This is typically about one-half of the @code{space} parameter. @TeX{} +is reluctant to increase interword spacing beyond the width +@math{@code{space} + @code{stretch}}. In monospaced fonts, the stretch +is typically zero. + +@vindex shrink @r{fontdimen} +@item shrink @r{(4)} +The @code{shrink} parameter defines the interword shrink of the font. +This is typically about one-third of the @code{space} parameter. @TeX{} +does not decrease interword spacing beyond the width @math{@code{space} +- @code{shrink}}. In monospaced fonts, the shrink is typically zero. + +@vindex xheight @r{fontdimen} +@item xheight @r{(5)} +The @code{xheight} parameter defines the x-height of the font, i.e., the +main body size. The height of the lowercase `x' is often used for this, +since neither the top nor the bottom of `x' are curves. There is no +hard-and-fast rule in @TeX{} that the x-height must equal the height of +`x', however. + +@vindex ex @r{@TeX{} dimension} +This fontdimen defines the value of the @code{ex} dimension in @TeX{}. +@TeX{} also uses this to position: it assumes the accents in the font +are properly positioned over a character that is exactly 1@dmn{ex} high. + +@vindex quad @r{fontdimen} +@vindex em @r{@TeX{} dimension} +@item quad @r{(6)} +The @code{quad} fontdimen defines the value of the @code{em} dimension +in @TeX{}. This is often the same as the design size of the font, but +as usual, that's not an absolute requirement. + +Typesetters often use @code{em}s and @code{ex}s instead of hardwiring +dimensions in terms of (say) points; that way, experimenting with +different fonts for a particular job does not require changing the +dimensions. + +@vindex extraspace @r{fontdimen} +@cindex sentence-ending space +@findex \spacefactor +@item extraspace @r{(7)} +The @code{extraspace} fontdimen defines the space @TeX{} puts at the end +of sentence. (Technically, when the @code{\spacefactor} is 20000 or +more.) This is typically about one-sixth of the normal interword space. + +@vindex num1 @r{fontdimen} +@item num1 @r{(8)} + +@vindex num2 @r{fontdimen} +@item num2 @r{(9)} + +@vindex num3 @r{fontdimen} +@item num3 @r{(10)} + +@vindex denom1 @r{fontdimen} +@item denom1 @r{(11)} + +@vindex denom2 @r{fontdimen} +@item denom2 @r{(12)} + +@vindex sup1 @r{fontdimen} +@item sup1 @r{(13)} + +@vindex sup2 @r{fontdimen} +@item sup2 @r{(14)} + +@vindex sup3 @r{fontdimen} +@item sup3 @r{(15)} + +@vindex sub1 @r{fontdimen} +@item sub1 @r{(16)} + +@vindex sub2 @r{fontdimen} +@item sub2 @r{(17)} + +@vindex supdrop @r{fontdimen} +@item supdrop @r{(18)} + +@vindex subdrop @r{fontdimen} +@item subdrop @r{(19)} + +@vindex delim1 @r{fontdimen} +@item delim1 @r{(20)} + +@vindex delim2 @r{fontdimen} +@item delim2 @r{(21)} + +@vindex axisheight @r{fontdimen} +@item axisheight @r{(22)} + +@vindex defaultrulethickness @r{fontdimen} +@item defaultrulethickness @r{(8)} + +@vindex bigopspacing1 @r{fontdimen} +@item bigopspacing1 @r{(9)} + +@vindex bigopspacing2 @r{fontdimen} +@item bigopspacing2 @r{(10)} + +@vindex bigopspacing3 @r{fontdimen} +@item bigopspacing3 @r{(11)} + +@vindex bigopspacing4 @r{fontdimen} +@item bigopspacing4 @r{(12)} + +@vindex bigopspacing5 @r{fontdimen} +@item bigopspacing5 @r{(13)} + +(Sorry, we haven't written a description of the math fontdimens yet.) + +@vindex leadingheight @r{fontdimen} +@cindex leading +@cindex interline space +@cindex space, between lines +@cindex strut height +@findex \strutbox +@item leadingheight @r{(23)} +The @code{leadingheight} parameter defines the height component of the +recommended leading for this font. @dfn{Leading} is the +baseline-to-baseline distance when setting lines of type. + +@TeX{} does not automatically use this fontdimen, and the standard +@TeX{} fonts do not define it, but you may wish to include it in new +fonts for the benefit of future @TeX{} macros. This fontdimen is a GNU +extension. + +@vindex leadingdepth @r{fontdimen} +@item leadingdepth @r{(24)} +The @code{leadingdepth} parameters defines the depth of the recommended +leading for this font. See @code{leadingheight} directly above. This +fontdimen is a GNU extension. + +@vindex fontsize @r{fontdimen} +@item fontsize @r{(25)} +The @code{fontsize} parameter is the design size of the font. This is +needed for @TeX{} macros to find the font's design size. This fontdimen +is a GNU extension. + +@vindex version @r{fontdimen} +@cindex character dimensions, changing +@cindex ligkern table, changing +@cindex compatibility of fonts +@item version @r{(26)} +The @code{version} parameter identifies a particular version of the TFM +file. Whenever the character dimensions, kerns, or ligature table for a +font changes, it is good to increment the version number. It is also good +to keep such changes to a minimum, since they can change the line breaks +and page breaks in documents typeset with previous versions. This +fontdimen is a GNU extension. +@end table + + +@node CMI processing, , fontdimen command, CMI files +@subsection CMI processing + +@cindex CMI files, processing + +Here are some further details on how Charspace processes the CMI files: + +@itemize @bullet + +@cindex namespace in CMI files +@cindex redefining identifiers in CMI files +@cindex identifiers, redefining in CMI files +@item +Charspace uses a single @dfn{namespace}; i.e., each defined identifier, +whether it be a character name, an internal identifier, a fontdimen +name, or whatever, is stored in the same table. Furthermore, Charspace +does not complain, or even warn, about redefinition of identifiers: as +we build up CMI files to be shared among different fonts, we felt such +redefinition would be common. + +@cindex use-before-definition in CMI files +@cindex definition-before-use in CMI files +@item +Charspace does not insist that identifiers be used before they are +defined. For example, the following sequence: + +@example +define foo bar +define bar 1.0 +char A foo , bar +@end example + +@noindent is valid, and defines both side bearings of @samp{A} to be +1.0. (See the preceding sections for the definition of the various +commands allowed in CMI files.) + +@cindex resolution of definitions +@item +Charspace only tries to resolve the definitions of those identifiers +which are actually used to produce the output files (i.e., those in a +sidebearing definition, a kern value, or a fontdimen value). Thus, +something like + +@example +define foo bar +@end example + +@noindent will elicit no complaint, if @samp{foo} is not needed to make +the output files. + +@item +Charspace reads the contents of all the CMI files before attempting to +resolve any definitions. Thus, it is the last definition which counts. +For example: + +@example +define bar 100 +define foo 2 bar +define bar 1 +char A foo , foo +@end example + +@noindent defines both side bearings of @samp{A} to be 2, not 200. + +@vindex designsize @r{predefined for CMI files} +@item +Charspace predefines one identifier, @code{designsize}, to be the +design size of the input font (in pixels). It can be redefined like any +other identifier. + +@end itemize + +@flindex char.c +@flindex cmi.y +If you can read programs in the C language, you may find it instructive +to examine the implementation of CMI file processing in the source files +@file{charspace/char.c} and @file{charspace/cmi.y}. The source provides +the full details of CMI processing. + + +@node Invoking Charspace, , CMI files, Charspace +@section Invoking Charspace + +@cindex Charspace options +@cindex invocation of Charspace +@cindex options for Charspace + +This section describes the options that Charspace accepts. +@xref{Command-line options}, for general option syntax. + +The root of the main input fontname is called @var{font-name} below. + +@table @samp + +@opindex -cmi-files +@item -cmi-files @var{file1},@var{file2},@dots{} +read the CMI files @file{@var{file1}.@var{dpi}cmi}, +@file{@var{file2}.@var{dpi}cmi}, etc., where @var{dpi} is the resolution +of the main input font. Default is to read +@file{@var{font-name}.@var{dpi}cmi}. The @file{.@var{dpi}cmi} is not +appended to any of the @var{file}s which already have a suffix. + +@flindex common.cmi +@file{common.cmi} is read before any of these files. + +@opindex -dpi +@item -dpi @var{unsigned} +The resolution, in pixels per inch. @xref{Common options}. + +@opindex -encoding +@item -encoding @var{enc-file} +The encoding file to read for the mapping between character codes in the +input font and character names. @xref{Encoding files}. If +@var{enc-file} has no suffix, @samp{.enc} is appended. The default is +to read the encoding file specified via the @code{codingscheme} command +(@pxref{codingscheme command}). + +If a TFM file @file{@var{font-name}.tfm} exists, it is also read for +default ligature, headerbyte, and fontdimen information. Definitions in +the CMI files override those in such a TFM file. + +@opindex -fontdimens +@item -fontdimens @var{fd1}:@var{value1},@var{fd2}:@var{value2},@dots{} +@xref{TFM fontdimens}. + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -no-gf +@item -no-gf +Don't output a revised GF file. This is primarily useful while +debugging the TFM output, since without a bitmap font to match the TFM +output, you can't actually print anything reliably. + +@opindex -output-file +@cindex output file, naming +@item -output-file @var{filename} +If @var{filename} does not have a suffix, write the output to +@file{@var{filename}.tfm} and (if @samp{-no-gf} was not specified) +@file{@var{filename}.@var{dpi}gf}. If this would overwrite an input +file, prepend an @samp{x} to the output name. + +If @var{filename} has a suffix, and @samp{-no-gf} was not specified, +Charspace complains and gives up, since it can't output two files with +the same name. + +By default, use the name of the main input font for @var{filename}. + +@opindex -range +@item -range @var{char1}-@var{char2} +Only output characters with codes between @var{char1} and @var{char2}, +inclusive. (@xref{Common options}, and @ref{Specifying character codes}.) + +@opindex -verbose +@item -verbose +Output progress reports. + +@opindex -version +@item -version +Print the version number. + +@opindex -xheight-char +@item -xheight-char @var{code} +Use the TFM height of @var{code} for the @code{xheight} fontdimen +(@pxref{TFM fontdimens}); default is 120 (ASCII @samp{x}). (It is +reasonable to use 120 instead of whatever @samp{x} is in the underlying +character set because most font encoding schemes are based on ASCII +regardless of the host computer's character set.) + +@end table diff --git a/doc/enhance.texi b/doc/enhance.texi new file mode 100644 index 0000000..8846a34 --- /dev/null +++ b/doc/enhance.texi @@ -0,0 +1,360 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Enhancements, Copying, GSrenderfont, Top +@chapter Enhancements + +@cindex enhancements, future +@cindex improvements, possible future +@cindex future enhancements +@cindex projects + +@cindex volunteering +@cindex contribution, making your own +Like all software, the font utilities can all be (probably endlessly) +improved. Following are some possible projects. + +If you would like to contribute, send mail to +@samp{bug-gnu-utils@@prep.ai.mit.edu} first, so we can coordinate the +work. + +@menu +* Additional fonts:: GNU needs more fonts. +* Program features:: These programs can be improved. +* Portability:: Assumptions about the programming environment. +* Implementation:: Conventions we used in the sources. +@end menu + + +@node Additional fonts, Program features, , Enhancements +@section Additional fonts + +The original purpose of these programs was to create fonts for +Ghostscript, the GNU PostScript-compatible interpreter written by Peter +Deutsch. Adobe and many other vendors sell fonts which Ghostscript can +use, but they place many restrictions on the use of those fonts. These +restrictions certainly include modification and copying; in some cases, +they even include using the font on more than one printer or display! +These restrictions are contrary to the aims of the GNU project. + +Obviously we cannot compete in volume with Adobe, Bitstream, or other +vendors, all of whom probably have dozens if not hundreds of people +working on nothing but font production, and additional people hired as +programmers in support. The present authors (both working half-time) +are the entire FSF ``font production'' department, both for design and +for programming. + +Fortunately, we do not need to compete in volume (certainly we haven't +needed the thousands of Adobe fonts in our practice as typographers). +Our aim is to produce the basic typefaces for typography: Garamond, +Bodoni, Gill Sans, Univers, Baskerville, and perhaps a few others. If +someone wants some other typeface, they could use our programs to make +it, and, we hope, contribute it back to GNU for others to use. + +We do need volunteers to help create fonts for the GNU project. You do +not need to be an expert type designer to help, but you do need to know +enough about @TeX{} and/or PostScript to be able to install and test new +fonts. Example: if you know neither (1) the purpose of TeX utility +program @code{gftopk} nor (2) what the PostScript @code{scalefont} +command does, you probably need more experience before you can help. + +If you can volunteer, the first step is to compile the font utilities +(@pxref{Installation}). After that, contact us at +@samp{karl@@gnu.ai.mit.edu}. I will get you a scanned type specimen +image. @xref{Creating fonts}, for how to use these utilities to turn +that into a font you can use in @TeX{} or PostScript. + + +@node Program features, Portability, Additional fonts, Enhancements +@section Program features + +@cindex features, lacking + +Here are some possible projects: + +@table @asis + +@item BZRedit +@itemize @bullet +@item +Rewrite as a C program along the lines of XBfe (in fact, seeing the +bitmap and the generated splines simultaneously would be useful). +@item +@cindex hints +Add support for hints. +@end itemize + +@item BZRto +@itemize @bullet +@item +@cindex TrueType +Output more font formats, e.g., TrueType. +@item +Output hints for Metafont and Type 1 fonts. +@item +@vindex FontInfo +Make better guesses for the @code{FontInfo} information. +@item +@cindex obliquing +Handle obliquing fonts by changing the transform matrix in the output, +instead of changing the numbers in the splines. +@item +@cindex nonlinear scaling +@cindex scaling, nonlinear +@cindex anamorphic scaling +@cindex optical scaling +Do nonlinear scaling. +@item +@cindex italic corrections +Handle italic corrections in the Metafont output somehow. Probably have +to do the same in Charspace. +@end itemize + +@item Fontconvert +@itemize @bullet +@item +@cindex virtual fonts +Output virtual fonts as an option, instead of another bitmap font. +@item +@cindex encodings, translating between +Allow specifying entire input encodings and output encodings (the +same @file{.enc} files that the other programs read). +@end itemize + +@item GF library +@itemize @bullet +@item +Support multiple simultaneous open fonts, like the PK library does now. +@cindex checksum +@item +Output a checksum. +@end itemize + +@item GSrenderfont +@itemize @bullet +@item +@cindex size of characters, maximum +@cindex limit on character size +Allow for characters larger than 1 inch square in the original font. +@item +@cindex slanted fonts +@cindex extended fonts +@cindex small caps +Implement slanting, extending, and small caps, a la Dvips. +@end itemize + +@item Imageto +@itemize @bullet +@item +@cindex Tiff +Recognize more image formats, e.g., Tiff. +@item +@cindex splitting characters +@cindex characters, splitting +Perhaps the @samp{-column-split} option in Fontconvert should be +removed, and the equivalent information specified in the IFI file. +@end itemize + +@item IMGrotate +@itemize @bullet +@item +Perhaps combine with Imageto. +@item +@pindex pnmrotate +@cindex rotation algorithm +Implement a good rotation algorithm, perhaps as described in: ``A Fast +Algorithm for General Raster Rotation'', by Alan Paeth, @cite{Graphics +Interface '86}, pages 77--81. (We'd be interested in hearing of +optimized alternatives for the case of 90 degree rotation only). The +program @code{pnmrotate}, which mentions that article, in the PBMplus +distribution could perhaps be adapted. +@end itemize + +@item @code{lib} +@itemize @bullet +@item +Extend the encoding files to allow defining math attributes, probably by +rewriting the parsing routines as a Bison grammar. +@item +@findex string_to_bitmap +@flindex font.c +@cindex typesetting kerns and ligatures +@cindex kerns, typesetting +@cindex ligatures, typesetting +Write a variant of @code{string_to_bitmap} (in @file{font.c}) which +understands kerns and ligatures. +@item +@cindex BDF format +Add support for BDF or other bitmap formats. Unrelated utility programs +now exist for handling the X11 BDF format (specifically, Bdf2gf and +GFto), but it might be useful to integrate BDF support. +@end itemize + +@item Limn +Handle the standard X toolkit options. + +@item PK library +Implement output of PK files. + +@item TFM library +@itemize @bullet +@item +Support multiple simultaneous open fonts, like PK does now. +@cindex ligatures in TFM files +@item +Support ligatures in their full generality. +@item +Output a checksum. +@end itemize + +@item XBfe +@itemize @bullet +@item +Allow showing more than one character at a time. +@cindex guidelines +@item +Adjusting (or at least seeing) the baseline, cap height, x-height, or +arbitrary guidelines. +@item +Handle multiple fonts. +@item +Notice if the window it's given is too small, and give up. +@item +@cindex window size for XBfe +Ask the window manager for a window big enough for the largest character +in the font, not the first character. +@end itemize + +@end table + +In addition, one general enhancement would be to allow more than 256 +characters per font. The bitmap formats allow this already, and the TFM +format has some support for it. + +Two other smaller general improvements: combine multiple @samp{-range} +options; allow for omitting ranges. + + +@node Portability, Implementation, Program features, Enhancements +@section Portability + +@cindex portability of sources +@cindex GNU C extensions + +We didn't worry about making the programs work with any C compiler; +instead, we used GNU C extensions where they were useful. Likewise for +GNU make. + +@cindex GNU evangelism +We allowed ourselves this luxury because these programs are not +historical utilities which people would expect to find on any Unix +system. Rather, they are application programs. Perhaps having them +work only with other GNU programs will encourage people to switch to +GNU programs, or at least become aware of them. + +It probably would not be too hard to change the programs to work with +other ANSI C compilers. Changing them to work with old C compilers +would be more painful. Thus far, the dependency on GCC hasn't proved a +serious problem, because GCC runs on so many machines. + +@cindex GNU make, dependency on +It would be dull but straightforward to write Makefiles for the +programs which didn't use any of GNU make's special features. As with +GCC, though, GNU make is so widely available that we haven't felt it +necessary to do so. + +@cindex path searching, implementation of +The one exception is to this are the dozen or so files in the @file{lib} +and @file{include} directories which implement the path searching +algorithm. Because these files are shared with the @TeX{}, Dvips, and +XDvi distributions, they are written to work with old C compilers. + +@xref{Archives}, for information on how to obtain GCC and the other +programs mentioned. @xref{Portability, , Portability as it applies to +GNU, standards, GNU Coding Standards}, for more discussion of the +portability of GNU programs in general. + + +@node Implementation, , Portability, Enhancements +@section Implementation + +@cindex implementation +@cindex coding standards +@cindex programming conventions + +@c Texinfo has no good way of referring to a whole manual. Argh. +This section describes some of the conventions we used in the +organization of the source code. @xref{Top, , , standards, GNU Coding +Standards}, for the general GNU conventions. + +In our sources, @file{.c} files include @file{config.h} first, which in +turn includes @file{global.h}, which includes @file{types.h} and other +header files which define ubiquitous identifiers. + +@cindex header files +@file{.h} files, on the other hand, do not include @file{config.h}. +They only include whatever headers are needed to define what they +themselves use---typically including but not limited to @file{types.h}. + +All @file{.h} files are protected with @code{#ifndef @var{unique-symbol}}. + +The upshot of these conventions is that headers can be included in any +order, as many times as necessary. In a @file{.c} file, only those +headers which define symbols needed in the C source need be included, +without worrying that some headers depend on others. (ANSI C defines its +headers to follow these same rules.) + +@ignore +@c Skip this, who cares? Anyway, we aren't perfectly consistent. +Since the headers can be included in any order, we arbitrarily chose to +have three groups of @code{#include}s: @file{config.h}; system or +library headers, such as @file{<sys/stat.h>} or @file{line.h}; and +program-specific headers. +@end ignore + +Virtually all @file{.c} files---the only exceptions are (sometimes) +@file{main.c} and some library files---have a corresponding @file{.h} +file, which defines all the public symbols (e.g., non-@code{static} +routines and types). in the @file{.h} file are intended to explain the +external interface; comments in the @file{.c} file assume you already +know what's in the @file{.h} file, to avoid having the same information +in two places, and try to explain only implementation details. + +@opindex -Wmissing-prototypes +@cindex missing prototypes +@cindex prototypes, missing +Therefore, a @file{.c} file should always include its corresponding +@file{.h} file, to ensure consistency between the definitions and the +declarations. GCC 2's @samp{-Wmissing-prototypes} option can be used to +check this. + +@cindex main program +@flindex main.c +The main program is always in a file named @file{main.c}. Typically it +loops through all the characters in the input font, doing something with +them. Parsing arguments is also done in @file{main.c}, in a function +named @code{read_command_line}, using @code{getopt}. @xref{Command-line +options}, for more information on option parsing. + +@pindex configure@r{, creation of} +@flindex include/c-auto.h@r{, creation of} +The @file{configure} script used to determine system dependencies is +generated by GNU Autoconf from @file{configure.in}. When +@file{configure} runs, it creates @file{include/c-auto.h} from +@file{include/c-auto.h.in} to record what it discovers. @file{config.h} +includes this file. + +@cindex structure types +We access members of most structure types via macros instead of with +@code{.} or @code{->} directly. We pass and return whole structures +without hesitation; this has not resulted in any noticeable performance +loss. When we use pointers to structures, it's almost always because we +need a distinguishable value (i.e., @code{NULL}). +@vindex NULL + +@cindex functions, declaring @code{const} +When a function has no side effects (e.g., assignments to global +variables), and does not examine any values except its arguments (e.g. +if a pointer is passed, it does not examine the data pointed to), +we declare it @code{const}. (This is a GNU C extension.) diff --git a/doc/filefmts.texi b/doc/filefmts.texi new file mode 100644 index 0000000..56eb7e8 --- /dev/null +++ b/doc/filefmts.texi @@ -0,0 +1,442 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node File formats, Imageto, Bugs, Top +@chapter File formats + +@cindex file formats +@cindex auxiliary files +@cindex data files + +These programs use various data files to specify font encodings, +auxliary information for a font, and other things. Some of these data +files are distributed in the directory @file{data}; others must be +constructed on a font-by-font basis. + +@vindex FONTUTIL_LIB @r{environment variable} +@cindex data file searching +If the environment variable @code{FONTUTIL_LIB} is set, data files are +looked up along the path it specifies, using the same algorithm as is +used for font searching (@pxref{Font searching}). Otherwise, the +default path is set in the top-level Makefile. + +The following sections (in other chapters of the manual) also describe +file formats: + +@itemize @bullet + +@item +@ref{BZR files}. + +@item +@ref{CCC files}. + +@item +@ref{CMI files}. + +@item +@ref{IFI files}. + +@end itemize + +@menu +* File format abbreviations:: The alphabet soup of font formats. +* Common file syntax:: Some elements of auxiliary files are constant. +* Encoding files:: The character code-to-shape mapping. +* Coding scheme map file:: The coding scheme string-to-filename mapping. +@end menu + + +@node File format abbreviations, Common file syntax, , File formats +@section File format abbreviations + +@cindex abbreviations, of file formats +@cindex file format abbreviations +@cindex meaning, of file format abbreviations + +For the sake of brevity, we do not spell out every abbreviation +(typically of file format names) in the manual every time we use it. +This section collects and defines all the common abbreviations we use. + +@table @asis + +@cindex BPL abbrevation +@item BPL +The `Bezier property list' format output by BZRto and read by BPLtoBZR. +This is a transliteration of the binary BZR format into human-readable +(and -editable) text. @xref{BPL files}. + +@cindex BZR abbrevation +@item BZR +The `Bezier' outline format output by Limn and read by BZRto. We +invented this format ourselves. @xref{BZR files}. + +@cindex CCC abbreviation +@item CCC +The `cookie-cutter character' (er, `composite character construction') +files read by BZRto to add pre-accented and other such characters to a +font. @xref{CCC files}. + +@cindex CMI abbreviation +@item CMI +The `character metric information' files read by Charspace to add side +bearings to a font. @xref{CMI files}. + +@cindex GF abbreviation +@item GF +The `generic font' bitmap format output by Metafont (and by most of +these programs). See the sources for Metafont or one of the other +@TeX{} font utility programs (GFtoPK, etc.) for the definition. + +@cindex DVI abbreviation +@item DVI +The `device independent' format output by @TeX{}, GFtoDVI, etc. Many +``DVI driver'' programs have been written to translate DVI format to +something that can actually be printed or previewed. See sources for +@TeX{} or DVItype for the definition. + +@cindex EPS abbreviation +@cindex advertising +@item EPS +The `Encapsulated PostScript' format output by many programs, including +Imageto (@pxref{Viewing an image}) and Fontconvert (@pxref{Fontconvert +output options}). An EPS file differs from a plain PostScript file in +that it contains information about the PostScript image it produces: its +bounding box, for example. (This information is contained in comments, +since PostScript has no good way to express such information directly.) + +@cindex IFI abbreviation +@item IFI +The `image font information' files read by Imageto when making a font +from an image. @xref{IFI files}. + +@cindex GSF abbrevation +@pindex bdftops +@cindex Ghostscript font format +@item GSF +The `Ghostscript font' format output by BZRto and the @file{bdftops} +program in the Ghostscript distribution. This is nothing more than the +Adobe Type 1 font format, unencrypted. The Adobe Type 1 format is +defined in a book published by Adobe. (Many PostScript interpreters +cannot read unencrypted Type 1 fonts, despite the fact that the +definition says encryption is not required. Ghostscript can read both +encrypted and unencrypted Type 1 fonts.) + +@cindex IMG abbreviation +@cindex GEM +@cindex DOS image format +@item IMG +The `image' format used by some GEM (a window system sometimes used +under DOS) programs; specifically, by the program which drives our +scanner. + +@cindex MF abbreviation +@cindex Knuth, Donald E. +@item MF +The `Meta-Font' programming language for designing typefaces invented by +Donald Knuth. His @cite{Metafontbook} is the only manual written to +date (that we know of). + +@cindex PBM abbreviation +@cindex Poskanzer, Jef +@item PBM +The `portable bitmap' format used by the PBMplus programs, +Ghostscript, Imageto, etc. It was invented by Jef Poskanzer (we +believe), the author of PBMplus. + +@cindex PFA abbreviation +@item PFA +The `printer font ASCII' format in which Type 1 PostScript fonts are +sometimes distributed. This format uses the ASCII hexadecimal +characters @samp{0} to @samp{9} and @samp{a} to @samp{f} (and/or +@samp{A} to @samp{F}) to represent an @code{eexec}-encrypted Type 1 +font. + +@cindex PFB abbreviation +@item PFB +The `printer font binary' format in which Type 1 PostScript fonts are +sometimes distributed. This format is most commonly used on DOS +systems. (Personally, we find the existence of this format truly +despicable, as one of the major advantages of PostScript is its being +defined entirely in terms of plain text files (in Level 1 PostScript, +anyway). Having an unportable binary font format completely defeats +this.) + +@cindex PK abbreviation +@cindex Rokicki, Tom +@pindex gftopk +@item PK +The `packed font' bitmap format output by GFtoPK. PK format has (for +all practical purposes) the same information as GF format, and does a +better job of packing: typically a font in PK format will be one-half to +two-thirds of the size of the same font in GF format. It was invented +by Tom Rokicki as part of the @TeX{} project. See the GFtoPK source for +the definition. + +@cindex PL abbreviation +@cindex property list format +@cindex editing TFM files +@pindex tftopl +@item PL +The `property list' format output by TFtoPL. This is a transliteration +of the binary TFM format into human-readable (and -editable) text. Some +of these programs output a PL file and call PLtoTF to make a TFM from +it. (For technical reasons it is easier to do this than to output a TFM +file directly.) See the PLtoTF source for the details. + +@cindex TFM abbreviation +@cindex @TeX{} font metric format +@cindex font metrics +@pindex pltotf +@item TFM +The `@TeX{} font metric' format output by Metafont, PLtoTF, and other +programs, and read by @TeX{}. TFM files include only character +dimension information (widths, heights, depths, and italic corrections), +kerns, ligatures, and font parameters; in particular, there is no +information about the character shapes. See the @TeX{} or Metafont +source for the definition. + +@end table + + +@node Common file syntax, Encoding files, File format abbreviations, File formats +@section Common file syntax + +@cindex syntax, common data file +@cindex common data file syntax +@cindex file syntax, common +@cindex data file syntax, common + +Data files read by these programs are text files that share certain +syntax elements: + +@itemize @bullet + +@cindex comments in data files +@cindex data files, comments in +@item +Comments begin with a @samp{%} character and continue to the end of the +line. The content of comments is entirely ignored. + +@cindex blank lines in data files +@cindex data files, blank lines in +@cindex whitespace characters in data files +@cindex data files, whitespace characters in +@findex isspace +@item +Blank lines are allowed, and ignored. Whitespace characters (as +defined by the C facility @code{isspace}) are ignored at the beginning of +a line. + +@cindex null byte in data files +@cindex ASCII NUL in data files +@cindex data files, valid characters in +@item +Any character except ASCII NUL---character zero---is acceptable in data +files. (We would allow NULs, too, at the expense of complicating the +code, if we knew of any useful purpose for them.) + +@end itemize + +@cindex line length in data files +A line can be as long as you want. + + +@node Encoding files, Coding scheme map file, Common file syntax, File formats +@section Encoding files + +@cindex encoding files +@cindex font encoding, files for +@cindex character mapping +@cindex mapping, of characters + +The @dfn{encoding} of a font specifies the mapping from character codes +(an integer, typically between zero and 255) to the characters +themselves; e.g., does a character with code 92 wind up printing as a +backslash (as it does under the ASCII encoding) or as a double left +quote (as it does under the most common @TeX{} font encoding)? Put +another way, the encoding is the arrangement of the characters in the +font. + +It is sad but true that no single encoding has been widely adopted, even +for basic text fonts. (Text fonts and, say, math fonts or symbol fonts +will clearly have different encodings.) Every typesetting program +and/or font source seems to come up with a new encoding; GNU is no +exception (see below). Therefore, when you decide on the encoding for +the fonts you create, you should choose whatever is most convenient for +the typesetting programs you intend to run it with. (Decent typesetting +systems would make it trivial to set font encodings; unfortunately, +almost nothing is decent in that regard!) + +@flindex .enc @r{suffix} +The @dfn{encoding file} format we invented is a font-format-independent +representation of an encoding. Encoding files are ``data files'' which +have the basic syntax elements described above (@pxref{Common file +syntax}). They are usually named with the extension @code{.enc}. + +The first nonblank non-comment line in an encoding file is a string to +put into TFM files as the ``coding scheme'' to describe the encoding; +some common coding schemes are @samp{TeX text}, @samp{TeX math symbol}, +@samp{Adobe standard}. Case is irrelevant; that is, any programs which +use the coding scheme should pay no attention to its case. + +Thereafter, each nonblank non-comment line defines the character for the +corresponding code: the first such line defines the character with code +zero, the next with code one, and so on. + +Each character consists of a name, optionally followed by ligature +information. (All fonts using the same encoding should have the same +ligatures, it seems to us.) + +@menu +* Character names:: How to write character names. +* Ligature definitions:: How to define ligatures. +* GNU encodings:: Why we invented new encodings for GNU. +@end menu + + +@node Character names, Ligature definitions, , Encoding files +@subsection Character names + +@cindex character names +@cindex names of characters + +The @dfn{character name} in an encoding file is an arbitrary sequence of +nonblank characters (except it can't include a @code{%}, since that +starts a comment). Conventionally, it consists of only lowercase +letters, except where an uppercase letter is actually involved. (For +example, @code{eacute} is a lowercase @code{e} with an acute accent; +@code{Eacute} is an uppercase @code{E} with an acute accent. + +@vindex .notdef +@cindex blank positions in fonts +@cindex undefined characters in fonts +@cindex fonts, undefined characters in +If a character code has no equivalent character in the font, i.e., the +font table has a ``blank spot'', you should use the name @code{.notdef} +for that code. This is the only name you can usefully give more than +once. If any other name is used more than once, the results are +undefined. + +To avoid unnecessary proliferation of character names, you should use +names from existing @file{.enc} files where possible. All the +@file{.enc} files we have created are distributed in the @file{data} +directory. + + +@node Ligature definitions, GNU encodings, Character names, Encoding files +@subsection Ligature definitions + +@cindex ligature definitions +@cindex defining ligatures +@cindex encoding, ligatures in + +The ligature information for a character in an encoding file is +optional. More than one ligature specification may be given. Each +specification looks like: + +@example +lig @var{second-char} =: @var{lig-char} +@end example + +This means that a ligature character @var{lig-char} should be present in +the font for the current character (the one being defined on this line +of the encoding file) followed by @var{second-char}. You give +@var{second-char} and @var{lig-char} as character codes +(@pxref{Specifying character codes}). For example, in most text +encodings (which involve Latin characters), some variation on the +following line will be present: + +@example +f lig f =: 013 lig i =: 014 lig l =: 015 +@end example + +This will produce a ligature in the font such that when a typesetting +program sees the two character sequence @samp{ff} in the input, it +replaces those two characters in the output with the single character at +position octal 13 (presumably the `fi' ligature) of the font; when it +sees @samp{fi}, the character at position octal 14 is output; when +it sees @samp{fl}, the character at position octal 15 is output. + +@cindex ligatures in Metafont 2 +Metafont version 2 allows a more general ligature scheme; if there is a +demand for it, it wouldn't be hard to add. + + +@node GNU encodings, , Ligature definitions, Encoding files +@subsection GNU encodings + +@cindex encodings, GNU +@cindex GNU encodings + +@cindex Cork encoding +@cindex PostScript encodings +@cindex Adobe encodings +@cindex @TeX{} encodings +When we started making fonts for the GNU project, we had to decide on +some font encoding. We hoped to use an existing one, but none that we +found seemed suitable: the @TeX{} font encodings, including the ``Cork +encoding'' described in TUGboat 11#4, lacked many standard PostScript +characters; conversely, the standard PostScript encodings lacked useful +@TeX{} characters. Since we knew that Ghostscript and @TeX{} would be +the two main applications using the fonts, we thought it unacceptable to +favor one at the expense of the other. + +@flindex gnulatin.enc +Therefore, we invented two new encodings. The first one, ``GNU Latin +text'' (distributed in @file{data/gnulatin.enc}), is based on ISO Latin +1, and is close to a superset of both the basic @TeX{} text encoding and +the Adobe standard text encoding. We felt it was best to use ISO Latin +1 as the foundation, since some existing systems actually use ISO Latin +1 instead of ASCII. We also left the first eight positions open, so +particular fonts could add more ligatures or other unusual characters. + +@cindex expert encoding +The second, ``GNU Latin text complement'' (distributed in +@file{data/gnulcomp.enc}), includes the remaining pre-accented +characters from the Cork encoding, the PostScript expert encoding, swash +characters, small caps, etc. + +@c todo discuss encodings in more detail, show tables, etc. + + +@node Coding scheme map file, , Encoding files, File formats +@section Coding scheme map file + +@cindex coding scheme mapping +@cindex finding encodings + +When a program reads a TFM file, it's given an arbitrary string (at +best) for the coding scheme. To be useful, it needs to find the +corresponding encoding file. We couldn't think of any way to name our +@file{.enc} files that would allow the filename to be guessed +automatically. Therefore, we invented another data file which maps the +TFM coding scheme strings to our @file{.enc} filenames. + +@flindex encoding.map +This file is distributed as @file{data/encoding.map}. @xref{Common file +syntax}, for a description of the common syntax elements. + +Each nonblank non-comment line in @file{encoding.map} has two entries: +the first word (contiguous nonblank characters) is the @file{.enc} +filename; the rest of the line, after ignoring whitespace, is the string +in the TFM file. This should be the same string that appears on the +first line of the @file{.enc} file (@pxref{Encoding files}). + +Programs should ignore case when using the coding scheme string. + +Here is the coding scheme map file we distribute: + +@example +adobestd Adobe standard +ascii ASCII +dvips dvips +dvips TeX text + adobestandardencoding +gnulatin GNU Latin text +gnulcomp GNU Latin text complement +psymbol PostScript Symbol +texlatin Extended TeX Latin +textext TeX text +zdingbat Zapf Dingbats +@end example diff --git a/doc/fontcvt.texi b/doc/fontcvt.texi new file mode 100644 index 0000000..5341df7 --- /dev/null +++ b/doc/fontcvt.texi @@ -0,0 +1,398 @@ +@c Copyright (C) 1992, 93 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Fontconvert, Charspace, IMGrotate, Top +@chapter Fontconvert + +@pindex fontconvert +@cindex manipulation, of bitmap fonts +@cindex bitmap font manipulation + +Fontconvert performs manipulations on bitmap fonts: conversion to other +formats, merging multiple fonts, adjusting individual characters, moving +characters around within a font, @dots{} + +The input is either a GF or a PK bitmap font, and in some +circumstances, a TFM file. (@xref{File format abbreviations}.) The +output varies according to the options specified. + +@menu +* Invoking Fontconvert:: Command-line options. +@end menu + + +@node Invoking Fontconvert, , , Fontconvert +@section Invoking Fontconvert + +@cindex Fontconvert options +@cindex invocation of Fontconvert +@cindex options for Fontconvert + +In the following sections we describe all the options Fontconvert +accepts, grouped according to general function. + +@menu +* Fontconvert output options:: Specifying the output format(s). +* Character selection options:: What characters to operate on. +* Character manipulation options:: Changing characters' appearance. +* Fontwide information options:: Changing global information in a font. +* Miscellaneous options:: Other options. +@end menu + + +@node Fontconvert output options, Character selection options, , Invoking Fontconvert +@subsection Fontconvert output options + +@cindex Fontconvert output formats +@cindex output formats +@cindex formats, Fontconvert output + +The following table describes the options which affect the output +file(s) Fontconvert writes. You can specify as many as you like. If +you don't specify any, the default is to write nothing at all. + +In the following, @var{font-name} stands for the root part of the main +input file (@pxref{Main input file}). The output filenames here are the +defaults; you can override them with the @samp{-output-file} option +(@pxref{Miscellaneous options}). + +@table @samp + +@opindex -epsf +@cindex EPS +@cindex Encapsulated PostScript +@item -epsf +Output each character in the font as an Encapsulated PostScript (EPS) +file named @file{@var{font-name}-@var{code}.eps}, where @var{code} is +the character code (in decimal). This may be useful if the input +``font'' is actually a collection of images. + +@opindex -gf +@cindex GF output +@flindex x @r{prefix} +@item -gf +Output a GF font @file{@var{font-name}.@var{dpi}gf}, where @var{dpi} is +the resolution of the input font in dots per inch. If this would +overwrite the input file (presumably because it, too, is a GF font), +then prepend @samp{x} to the output name. + +This is mainly useful in conjunction with options that change the +characters in the input font in some way. + +@opindex -text +@cindex text output +@cindex bitmaps, viewing +@cindex GFtype +@cindex PKtype +@item -text +Write the output in a human-readable plain text form to standard output. +The bitmap for each character is shown using @samp{*} and @samp{ }. +This is an easy way to see what output is being generated, without going +to the trouble of running @TeX{} and a DVI driver. (The standard @TeX{} +programs GFtype and PKtype, which serve a similar purpose, do not always +write the entire bitmap.) + +@opindex -tfm +@cindex TFM output +@item -tfm +Write a TFM file to @file{@var{font-name}.tfm}. If a TFM file +@file{@var{font-name}.tfm} can be found, it is read, and an @samp{x} is +prepended to the output name. + +If an existing TFM file is found, then Fontconvert uses it (by default) +for the TFM header information, and for the ligature and kern +information. Unless the @samp{-baseline-adjust}, @samp{-column-split}, +filtering, or randomizing options were specified, Fontconvert also uses +it for the character dimensions. (Those options radically change the +appearance and size of the characters, so using the dimensions of the +originals would be inappropriate.) + +@xref{Fontwide information options}, for how to specify the global TFM +information yourself, overriding the default. + +@end table + + +@node Character selection options, Character manipulation options, Fontconvert output options, Invoking Fontconvert +@subsection Character selection options + +@cindex character selection +@cindex selection, of characters + +The following table describes the options which affect the set of +characters Fontconvert writes. + +@table @samp + +@opindex -concat +@cindex concatenation of bitmap fonts +@cindex bitmap fonts, concatenating +@cindex font concatenation +@item -concat @var{font1},@var{font2},@dots{} +After processing the main input file (@pxref{Main input file}), process +the additional fonts @var{font1}, @var{font2}, etc. Multiple +@samp{-concat} options do combine, e.g., @samp{-concat @var{font1} +-concat @var{font2}} is the same as @samp{-concat +@var{font1},@var{font2}}. + +@cindex duplicated characters +@cindex repeated characters +@cindex characters, duplicated +@cindex characters, repeated +If a character appears in more than one font, its first appearance is +the one that counts. Fontconvert issues a warning about such repeated +characters. + +The design size, resolution, and other global information in the output +font is always taken from the main input font, not from the concatenated +fonts. + +@opindex -column-split +@cindex splitting characters +@cindex characters, splitting +@cindex muddy images +@item -column-split @var{charspec}@@@var{col_1},@dots{},@var{col_n} +Split the input character at position @var{charspec} before each of the +@var{N} @var{column}s, thus producing @var{n} new characters. + +The new characters have codes @var{charspec}, @math{@var{charspec}+1}, +@dots{}, @math{@var{charspec}+@var{n}}. (These character codes are +subject to the remapping specified by @samp{-remap}; see below. Any +previous characters at those codes are overwritten.) + +The bitmaps of the new characters are slices from the original +character: 0 to column @math{@var{col_1}-1}, @dots{}, @var{col_n} to the +bitmap width. You specify the column numbers in bitmap coordinates, +i.e., the first column is numbered zero. + +To split more than one character, simply specify @samp{-column-split} +for each. + +This option is useful when two different characters in a scanned image +of a font were printed so closely together that their images overlap. +In this case, Imageto cannot break the characters apart, because they +are a single bounding box. But you can split them with this option; you +have to use your best judgement for the exact column at which to split. +(Probably judicious hand-editing with XBfe (@pxref{XBfe}) will be +necessary after you do this.) + +@opindex -range +@item -range @var{char1}-@var{char2} +Only output characters with codes between @var{char1} and @var{char2}, +inclusive. (@xref{Common options}, and @ref{Specifying character codes}.) + +@opindex -omit +@cindex omitting characters +@cindex characters, omitting +@cindex deleting characters +@cindex characters, deleting +@item -omit @var{charspec1},@var{charspec2},@dots{} +Omit the characters with the specified codes (before remapping) from the +output. Multiple @samp{-omit} options combine. + +@opindex -remap +@cindex remapping characters +@cindex characters, remapping +@cindex translating characters +@cindex characters, translating +@item -remap @var{src1}:@var{dest1},@var{src2}:@var{dest2},@dots{} +For each pair of character specifications @var{src}/@var{dest}, change +the character with code @var{src} in the input font to have code +@var{dest} in the output. + +@end table + + +@node Character manipulation options, Fontwide information options, Character selection options, Invoking Fontconvert +@subsection Character manipulation options + +The following options affect individual characters. + +When any of them are specified, the dimensions of the output character +are likely to be quite different than those of the input characters; +therefore, Fontconvert does not copy the TFM information (when writing a +TFM file) from an existing TFM file. + +@table @samp + +@opindex -baseline-adjust +@cindex baseline adjustment +@cindex adjustment, to baseline +@item -baseline-adjust @var{code1}:@var{delta1},@var{code2}:@var{delta2},@dots{} +Adjust the baseline of the output (i.e., after remapping) character +@var{code} by the corresponding @var{delta}. A negative @var{delta} +moves the baseline down, a positive one up. Multiple +@samp{-baseline-adjust} options combine. + +@opindex -filter-passes +@opindex -filter-size +@opindex -filter-threshold +@cindex smoothing bitmaps +@cindex filtering bitmaps +@cindex bitmaps, filtering +@cindex averaging filter +@item -filter-passes @var{passes} +@itemx -filter-size @var{half-cell-size} +@itemx -filter-threshold @var{intensity} +Run each character through an ``averaging filter'' @var{passes} times. +This tends to smooth rough edges on characters or irregular curves. By +the same token, it tends to shrink or eliminate small features, such as +serifs. Experimentation is necessary to determine the best values for +any particular font. + +For the pixel at coordinate @math{(x,y)}, Fontconvert looks at its +neighbors in rows @math{y} @minus{} @var{half-cell-size}, @dots{}, +@math{y-1}, @math{y+1}, @dots{}, @math{y} + @var{half-cell-size}, and +similarly for the columns. + +Fontconvert computes the average intensity of this square; if the result +is greater than @var{intensity}, it outputs a black pixel at +@math{(x,y)}; a white one, otherwise. + +This process is repeated for every pixel in every character, and every +character is filtered @var{passes} times. + +The default is to do no filtering, i.e., @var{passes} is zero. The +default for @var{half-cell-size} is one; the default for @var{intensity} +is @math{.5}. + +@opindex -random +@opindex -random-threshold +@cindex randomizing bitmaps +@cindex bitmaps, randomizing +@cindex distorting characters +@item -random @var{distance} +@itemx -random-threshold @var{probability} +In every character, randomly move each black pixel. We implemented this +as part of our research (to see how much characters could be distorted +before they became noticeably harder to read---the answer is a lot), but +left it in the program for its amusement value. + +For each black pixel, a first random number between zero and one is +compared to @var{probability}. If it is greater, nothing happens. +Otherwise, a second random number is chosen, this one between +@math{-@var{distance}} and @var{distance}. The pixel is ``moved'' that +far horizontally. Then repeat for the vertical axis. + +The default is to do no randomization, i.e., @var{distance} is zero. +The default for @var{probability} is @math{.2}. + +@end table + + +@node Fontwide information options, Miscellaneous options, Character manipulation options, Invoking Fontconvert +@subsection Fontwide information options + +These options provide a way for you to set the global information in TFM +and GF files. They override the default values (which are taken from +the input bitmap or TFM files). + +@table @samp + +@opindex -designsize +@cindex designsize +@cindex font size +@item -designsize @var{real} +Set the design size in both the TFM and GF output files to @var{real}. +You give @var{real} in printer's points. + +You might want to use this after seeing the Metafont or PostScript fonts +output by BZRto, and deciding they look too small. For example, the +original Garamond type specimen we scanned was (nominally) printed in +30@dmn{pt}. But when scaled down to 10@dmn{pt} via Metafont, the +characters looked too small. So we ran Fontconvert with +@samp{-designsize=26} on the bitmap font made from the original image, +and then reran Limn, BZRto, and Metafont to see the result. (We settled +on 26 after several trials.) @xref{Creating fonts}, for a description +of all the steps in creating fonts from scanned images. + +@opindex -fontdimens +@item -fontdimens @var{fd1}:@var{value1},@var{fd2}:@var{value2},@dots{} +@xref{TFM fontdimens}. + +@opindex -tfm-header +@cindex TFM header bytes +@cindex header bytes in TFM +@item -tfm-header @var{name1}:@var{value1},@var{name2}:@var{value2},@dots{} +Assign each @var{value} to the corresponding @var{name} in the header +information written to the TFM file. The standard @TeX{} names are +recognized: + +@table @samp + +@cindex checksum, specifying in TFM header +@item checksum +The corresponding @var{value} should be an unsigned integer, which should +uniquely identify this TFM file. A checksum of zero disables testing. +The default is zero. + +@cindex design size, specifying in TFM header +@item designsize +The corresponding @var{value} should be a real number between 1 and 2048 +(this limit is in the TFM file format). This overrides (for the TFM +output only) the @samp{-designsize} option, if both are specified. The +default is the design size of the input. + +@cindex codingscheme, specifying in TFM header +@item codingscheme +The corresponding @var{value} should be a string of length less than 40, +containing no parentheses or commas. Again, these restrictions are due +to the TFM file format. This coding scheme declares the font's +encoding vector. @xref{Coding scheme map file}. + +@end table + +@end table + + +@node Miscellaneous options, , Fontwide information options, Invoking Fontconvert +@subsection Miscellaneous options + +These options are the generic ones accepted by most (in some cases, all) +programs. @xref{Common options}. + +@table @samp + +@opindex -dpi +@item -dpi @var{unsigned} +The resolution of the main input font, in pixels per inch. + +@opindex -encoding +@cindex encoding of input fonts +@item -encoding @var{enc-file} +The encoding file to read for the mapping between character names and +character codes. @xref{Encoding files}. If @var{enc-file} has no +suffix, @samp{.enc} is appended. There is no default. Without an +encoding file, the options listed in @ref{Character selection options} +which take character specs will just complain if you supply character +names, instead of character codes. + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@item -output-file @var{filename} +@opindex -output-file +@cindex output file, naming +If @var{filename} has a suffix and if only one output file is to be +written, write to @var{filename}. If @var{filename} has a suffix and +you've specified options which imply more than one output file, +Fontconvert complains and gives up. + +If @var{filename} does not have a suffix, extend @var{filename} with +whatever is appropriate for the output format(s). In the case of GF and +TFM output, if this would overwrite the input, prepend an @samp{x} to +the output name. + +By default, use the name of the main input font for @var{filename}. + +@item -verbose +@opindex -verbose +Output progress reports. + +@item -version +@opindex -version +Print the version number. + +@end table diff --git a/doc/fontu.texi b/doc/fontu.texi new file mode 100644 index 0000000..a4deb01 --- /dev/null +++ b/doc/fontu.texi @@ -0,0 +1,395 @@ +\input texinfo +@c %**start of header +@setfilename fontu.info +@settitle GNU font utilities +@c %**end of header + +@c Define new indices for commands in auxiliary files, filenames, and options. +@defcodeindex cm +@defcodeindex fl +@defcodeindex op + +@c Put everything in one index (arbitrarily chosen to be the concept index). +@syncodeindex cm cp +@syncodeindex fl cp +@syncodeindex fn cp +@syncodeindex ky cp +@syncodeindex op cp +@syncodeindex pg cp +@syncodeindex vr cp + +@c Here is what we use in the Info `dir' file: +@c * Fontutils: (fontu). Programs for font manipulation. + + +@ifinfo +This file documents the GNU font utilities. + +Copyright (C) 1992, 93 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. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Freedom'' and ``GNU General Public License'' are +included exactly as in the original, and 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 the sections entitled ``Freedom'' and ``GNU General Public +License'' may be included in a translation approved by the Free Software +Foundation instead of in the original English. +@end ifinfo + + +@titlepage + +@title GNU font utilities +@subtitle for version REPLACE-WITH-VERSION +@subtitle REPLACE-WITH-MONTH-YEAR +@author Karl Berry +@author with Kathryn A. Hargreaves + +@page + +@vskip 0pt plus 1filll +Copyright @copyright{} 1992 Free Software Foundation. + +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 also that the +sections entitled ``Regain your programming freedom'' and ``GNU General +Public License'' are included exactly as in the original, and 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 the sections entitled ``Regain your programming freedom'' +and ``GNU General Public License'' may be included in a translation +approved by the Free Software Foundation instead of in the original English. + +@end titlepage + + +@ifinfo +@node Top, Introduction, (dir), (dir) +@top GNU font utilities + +This manual documents how to install and run the GNU font utilities. It +corresponds to version REPLACE-WITH-VERSION (released in +REPLACE-WITH-MONTH-YEAR). + +The introduction briefly describes the purpose and philosophy of the +font utilities. The overview gives details on their general usage, +especially how they interact, and describes various things which are +common to all or most of the programs. + +The first part of this master menu lists the major nodes in this Info +document, including the index. The rest of the menu lists all the +lower level nodes in the document. + +@menu +* Introduction:: A brief introduction. +* Installation:: How to compile and install the font utilities. +* Overview:: Commonalities to the programs, + a roadmap to how they fit together, + and examples of usage. +* Bugs:: How, why, and where to report bugs. +* File formats:: These programs read and write many files. +* Imageto:: Extracting a font from a scanned image. +* IMGrotate:: Rotating an image. +* Fontconvert:: Manipulation of bitmap fonts. +* Charspace:: Adding character metrics to a font. +* Limn:: Making outlines from bitmaps. +* BZRto:: Converting generic outlines to other formats. +* BPLtoBZR:: Converting plain text to binary BZR fonts. +* XBfe:: Hand editor for bitmap fonts under X11. +* BZRedit:: Hand editor for outline fonts under Emacs. +* GSrenderfont:: Rasterize PostScript fonts. +* Enhancements:: Future projects. +* Copying:: Conditions for copying and sharing. +* Freedom:: Regain your programming freedom. +* Index:: General index. + + --- The Detailed Node Listing --- + +Installation + +* Prereqs:: What's needed before installation. +* Problems:: Known trouble. + +Prerequisites + +* Archives:: Where to find programs. + +Overview + +* Picture:: A pictorial overview. +* Creating fonts:: How to use the programs together. +* Command-line options:: Many aspects of the command line are + common to all programs. +* Font searching:: How fonts and other files are looked for. +* Font naming:: How to name fonts. + +Creating fonts + +* Font creation example:: A real-life example. + +Command-line options + +* Main input file:: Each program operates on a ``main'' font. +* Options: Common options. Some options are accepted by all programs. +* Specifying character codes:: Ways of specifying single characters. +* Values: Common option values. Some options need more information. + +Specifying character codes + +* Named character codes:: Character names are looked up in the encoding. +* Numeric character codes:: Decimal, octal, hex, or ASCII. + +Bugs + +* Bug criteria:: Have you found a bug? +* Bug reporting:: How to effectively report a bug. + +Bug reporting + +* Necessary information:: What you need to send. +* Unnecessary information:: What you don't need to send. +* Documentation bugs:: Report the bugs in the manual, too. + +File formats + +* File format abbreviations:: The alphabet soup of font formats. +* Common file syntax:: Some elements of auxiliary files are constant. +* Encoding files:: The character code-to-shape mapping. +* Coding scheme map file:: The coding scheme string-to-filename mapping. + +Encoding files + +* Character names:: How to write character names. +* Ligature definitions:: How to define ligatures. +* GNU encodings:: Why we invented new encodings for GNU. + +Imageto + +* Imageto usage:: Process for extracting fonts from an image. +* IFI files:: IFI files supply extra information. +* Invoking Imageto:: Command-line options. + +Imageto usage + +* Viewing an image:: Seeing what's in an image. +* Image to font conversion:: Extracting a font. +* Dirty images:: Handling scanning artifacts or other noise. + +IMGrotate + +* IMGrotate usage:: Doing the image rotation. +* Invoking IMGrotate:: Command-line options. + +IMGrotate usage + +* Clockwise rotation:: Rotating clockwise. +* Flip rotation:: FLipping end-for-end. + +Fontconvert + +* Invoking Fontconvert:: Command-line options. + +Invoking Fontconvert + +* Fontconvert output options:: Specifying the output format(s). +* Character selection options:: What characters to operate on. +* Character manipulation options:: Changing characters' appearance. +* Fontwide information options:: Changing global information in a font. +* Miscellaneous options:: Other options. + +Charspace + +* Charspace usage:: Details on improving the character metrics. +* CMI files:: You specify the metrics in a separate file. +* Invoking Charspace:: Command-line options. + +CMI files + +* CMI tokens:: The building blocks of CMI files. +* char command:: Defining a character's side bearings. +* char-width command:: Defining side bearings via the set width. +* define command:: Introducing a new identifier. +* kern command:: Defining a kerning pair. +* codingscheme command:: Specifying the font encoding. +* fontdimen command:: Defining additional font parameters. +* CMI processing:: How Charspace reads CMI files. + +@code{fontdimen} command + +* TFM fontdimens:: All the valid fontdimens. + +Limn + +* Limn algorithm:: How Limn fits outlines to bitmaps. +* Invoking Limn:: Command-line options. + +Limn algorithm + +* Finding pixel outlines:: Extracting the edges from the bitmap. +* Finding corners:: Finding subsections of each outline. +* Removing knees:: Removing extraneous points. +* Filtering curves:: Smoothing the outlines. +* Fitting the bitmap curve:: Doing the fitting. +* Changing splines to lines:: Use straight lines where possible. +* Changing lines to splines:: Sometimes it isn't possible. +* Aligning endpoints:: If points are close enough, line them out. +* Displaying fitting online:: Seeing the results as Limn runs. + +Fitting the bitmap curve + +* Initializing t:: Initializing the parameter values. +* Finding tangents:: Computing the direction of the curve at + the endpoints. +* Finding the spline:: Where are the control points? +* Reparameterization:: Changing the parameter values. +* Subdivision:: Splitting the curve into pieces. + +BZRto + +* Metafont and BZRto:: Output as a Metafont program. +* Type 1 and BZRto:: Output as a Type 1 PostScript font. +* Type 3 and BZRto:: Output as a Type 3 PostScript font. +* CCC files:: Creating additional characters. +* Invoking BZRto:: Command-line options. +* BZR files:: The technical definition of BZR format. + +Metafont and BZRto + +* Metafont output at any size:: Making larger or smaller fonts. +* Proofing with Metafont:: Metafont can help with debugging fonts. + +CCC files + +* setchar: CCC setchar. Statements for including a character. +* move: CCC move. Statements for moving to a new position. + +BZR files + +* Intro: BZR format introduction. General concepts and definitions. +* Preamble: BZR preamble. The beginning. +* Chars: BZR characters. The middle. +* Postamble: BZR postamble. The end. + +BZR characters + +* BOC: BZR character beginnings. Giving character metrics. +* Shape: BZR character shapes. Defining the outline(s). + +BPLtoBZR + +* BPL files:: Bezier property list file format. +* Invoking BPLtoBZR:: Command-line options. + +BPL files + +* Preamble: BPL preamble. The beginning. +* Characters: BPL characters. The middle. +* Postamble: BPL postamble. The end. + +BPL characters + +* BPL outlines:: Representation of character outlines. + +XBfe + +* XBfe usage:: How to edit fonts. +* Invoking XBfe:: Command-line options. + +XBfe usage + +* Controlling XBfe :: Controlling XBfe +* Shape: XBfe shape editing. Changing the pixels. +* Metrics: XBfe metrics editing. Changing the side bearings. + +XBfe shape editing + +* Selections:: Marking pixel regions for later operations. +* Enlarging the bitmap:: Give yourself more room at the edges. + +BZRedit + +* BZRedit usage:: Operating the editor. + +BZRedit usage + +* BZRedit installation:: Additional installation is needed. +* BZR: Editing BZR files. Editing files in the binary format. +* BPL: Editing BPL files. Editing files in the textual format. + +Editing BPL files + +* BZRedit and Ghostscript:: Customizing the use of Ghostscript. + +GSrenderfont + +* GSrenderfont usage:: Making bitmap fonts from PostScript. +* Invoking GSrenderfont:: Command-line options. + +GSrenderfont usage + +* Names: GSrenderfont font names. Supplying PostScript names and filenames. +* Size: GSrenderfont output size. Specifying the size and resolution. +* Encoding: GSrenderfont encoding. Specifying the output encoding. + +Enhancements + +* Additional fonts:: GNU needs more fonts. +* Program features:: These programs can be improved. +* Portability:: Assumptions about the programming environment. +* Implementation:: Conventions we used in the sources. + +Regain your programming freedom + +* Software patents:: Algorithm monopolies. +* User interface copyright:: Forbidding upward-compatibility. +* What to do?:: What to do? +@end menu +@end ifinfo + +@include intro.texi +@include install.texi +@include overview.texi +@include bugs.texi +@include filefmts.texi +@include imageto.texi +@include imgrotate.texi +@include fontcvt.texi +@include charspace.texi +@include limn.texi +@include bzrto.texi +@include bpltobzr.texi +@include xbfe.texi +@include bzredit.texi +@include gsrenderf.texi +@include enhance.texi +@include copying.texi +@include freedom.texi +@include index.texi + +@summarycontents +@contents + +@bye diff --git a/doc/freedom.texi b/doc/freedom.texi new file mode 100644 index 0000000..c8a09b7 --- /dev/null +++ b/doc/freedom.texi @@ -0,0 +1,268 @@ +@c Copyright (C) 1992 Karl Berry. +@c For copying conditions, see the file copying.texi. + +@node Freedom, Index, Copying, Top +@appendix Regain your programming freedom + +@cindex freedom, programming +Until a few years ago, programmers in the United States could write any +program they wished. This freedom has now been taken away by two +developments: software patents, which grant the patent holder an +absolute monopoly on some programming technique, and user interface +copyright, which forbid compatible implementations of an existing user +interface. + +In Europe, especially through the GATT treaty, things are rapidly +approaching the same pass. + +@menu +* Software patents:: Algorithm monopolies. +* User interface copyright:: Forbidding upward-compatibility. +* What to do?:: What to do? +@end menu + + +@node Software patents, User interface copyright, , Freedom +@section Software patents + +@cindex patents, software +@cindex software patents + +The U.S. Patent and Trademark Office has granted numerous software +patents on software techniques. Patents are an absolute +monopoly---independent reinvention is precluded. This monopoly lasts +for seventeen years, i.e., forever (with respect to computer science). + +One patent relevant to @TeX{} is patent 4,956,809, issued to the Mark +Williams company on September 11, 1990, applied for in 1982, which +covers (among other things) +@quotation +representing in a standardized order +consisting of a standard binary structure file stored on auxiliary +memory or transported on a communications means, said standardized +order being different from a different order used on at least one +of the different computers; + +Converting in each of the different computers binary data read from an +auxiliary data storage or communications means from the standardized +order to the natural order of the respective host computer after said +binary data are read from said auxiliary data storage or +communications means and before said binary data are used by the +respective host computer; and + +Converting in each of the different computers binary data written into +auxiliary data storage or communications means from the natural order +of the respective host computer to the standardized order prior to +said writing. +@end quotation + +@noindent @dots{} in other words, storing data on disk in +a machine-independent order, as the DVI, TFM, GF, and PK file formats +specify. Even though @TeX{} is ``prior art'' in this respect, the +patent was granted (the patent examiners not being computer scientists, +even less computer typographers). Since there is a strong presumption +in the courts of a patent's validity once it has been granted, there is +a good chance that users or implementors of @TeX{} could be successfully +sued on the issue. + +As another example, the X window system, which was intended to be able +to be used freely by everyone, is now being threatened by two patents: +4,197,590 on the use of exclusive-or to redraw cursors, held by Cadtrak, +a litigation company (this has been upheld twice in court); and +4,555,775, held by AT&T, on the use of backing store to redraw windows +quickly. + +Here is one excerpt from a recent mailing by the League for Programming +Freedom (@pxref{What to do?}) which I feel sums up the situation rather +well. It comes from an article in @cite{Think} magazine, issue #5, +1990. The comments after the quote were written by Richard Stallman. + +@quotation + ``You get value from patents in two ways,'' says Roger Smith, IBM + Assistant General Counsel, intellectual property law. ``Through fees, + and through licensing negotiations that give IBM access to other + patents. + + ``The IBM patent portfolio gains us the freedom to do what we need to + do through cross-licensing---it gives us access to the inventions of + others that are the key to rapid innovation. Access is far more + valuable to IBM than the fees it receives from its 9,000 active + patents. There's no direct calculation of this value, but it's many + times larger than the fee income, perhaps an order of magnitude + larger.'' +@end quotation + +This information should dispel the belief that the patent system will +``protect'' a small software developer from competition from IBM. IBM +can always find patents in its collection which the small developer is +infringing, and thus obtain a cross-license. + +However, the patent system does cause trouble for the smaller +companies which, like IBM, need access to patented techniques in order +to do useful work in software. Unlike IBM, the smaller companies do +not have 9,000 patents and cannot usually get a cross-license. No +matter how hard they try, they cannot have enough patents to do this. + +Only the elimination of patents from the software field can enable +most software developers to continue with their work. + +The value IBM gets from cross-licensing is a measure of the amount of +harm that the patent system would do to IBM if IBM could not avoid it. +IBM's estimate is that the trouble could easily be ten times the good +one can expect from one's own patents---even for a company with 9,000 +of them. + + +@node User interface copyright, What to do?, Software patents, Freedom +@section User interface copyright + +@cindex rms +@cindex user interface copyright +@cindex interface copyright +(This section is copied from the GCC manual, by Richard Stallman.) + +@quotation +@i{This section is a political message from the League for Programming +Freedom to the users of the GNU font utilities. It is included here as +an expression of support for the League on my part.} +@end quotation + +Apple, Lotus and Xerox are trying to create a new form of +legal monopoly: a copyright on a class of user interfaces. These +monopolies would cause serious problems for users and developers of +computer software and systems. + +Until a few years ago, the law seemed clear: no one could restrict +others from using a user interface; programmers were free to implement +any interface they chose. Imitating interfaces, sometimes with changes, +was standard practice in the computer field. The interfaces we know +evolved gradually in this way; for example, the Macintosh user interface +drew ideas from the Xerox interface, which in turn drew on work done at +Stanford and SRI. 1-2-3 imitated VisiCalc, and dBase imitated a +database program from JPL. + +Most computer companies, and nearly all computer users, were happy with +this state of affairs. The companies that are suing say it does not +offer ``enough incentive'' to develop their products, but they must have +considered it ``enough'' when they made their decision to do so. It +seems they are not satisfied with the opportunity to continue to compete +in the marketplace---not even with a head start. + +If Xerox, Lotus, and Apple are permitted to make law through +the courts, the precedent will hobble the software industry: + +@itemize @bullet +@item +Gratuitous incompatibilities will burden users. Imagine if each +car manufacturer had to arrange the pedals in a different order. + +@item +Software will become and remain more expensive. Users will be +``locked in'' to proprietary interfaces, for which there is no real +competition. + +@item +Large companies have an unfair advantage wherever lawsuits become +commonplace. Since they can easily afford to sue, they can intimidate +small companies with threats even when they don't really have a case. + +@item +User interface improvements will come slower, since incremental +evolution through creative imitation will no longer be permitted. + +@item +Even Apple, etc., will find it harder to make improvements if +they can no longer adapt the good ideas that others introduce, for +fear of weakening their own legal positions. Some users suggest that +this stagnation may already have started. + +@item +If you use GNU software, you might find it of some concern that user +interface copyright will make it hard for the Free Software Foundation +to develop programs compatible with the interfaces that you already +know. +@end itemize + + +@node What to do?, , User interface copyright, Freedom +@section What to do? + +(This section is copied from the GCC manual, by Richard Stallman.) + +To protect our freedom from lawsuits like these, a group of programmers +and users have formed a new grass-roots political organization, the +League for Programming Freedom. + +The purpose of the League is to oppose new monopolistic practices such +as user-interface copyright and software patents; it calls for a return +to the legal policies of the recent past, in which these practices were +not allowed. The League is not concerned with free software as an +issue, and not affiliated with the Free Software Foundation. + +The League's membership rolls include John McCarthy, inventor of Lisp, +Marvin Minsky, founder of the Artificial Intelligence lab, Guy L. +Steele, Jr., author of well-known books on Lisp and C, as well as +Richard Stallman, the developer of GNU CC. Please join and add your +name to the list. Membership dues in the League are $42 per year for +programmers, managers and professionals; $10.50 for students; $21 for +others. + +The League needs both activist members and members who only pay their +dues. + +To join, or for more information, phone (617) 492-0023 or write to: + +@display +League for Programming Freedom +1 Kendall Square #143 +P.O. Box 9171 +Cambridge, MA 02139 +@end display + +You can also send electronic mail to @code{league@@prep.ai.mit.edu}. + +Here are some suggestions from the League for things you can do to +protect your freedom to write programs: + +@itemize @bullet +@item +Don't buy from Xerox, Lotus or Apple. Buy from their competitors or +from the defendants they are suing. + +@item +Don't develop software to work with the systems made by these companies. + +@item +Port your existing software to competing systems, so that you encourage +users to switch. + +@item +Write letters to company presidents to let them know their conduct +is unacceptable. + +@item +Tell your friends and colleagues about this issue and how it threatens +to ruin the computer industry. + +@item +Above all, don't work for the look-and-feel plaintiffs, and don't +accept contracts from them. + +@item +Write to Congress to explain the importance of this issue. + +@display +House Subcommittee on Intellectual Property +2137 Rayburn Bldg +Washington, DC 20515 + +Senate Subcommittee on Patents, Trademarks and Copyrights +United States Senate +Washington, DC 20510 +@end display + +(These committees have received lots of mail already; let's give them +even more.) +@end itemize + +Express your opinion! You can make a difference. diff --git a/doc/gsrenderf.texi b/doc/gsrenderf.texi new file mode 100644 index 0000000..a7896cd --- /dev/null +++ b/doc/gsrenderf.texi @@ -0,0 +1,246 @@ +@c Copyright (C) 1992, 93 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node GSrenderfont, Enhancements, BZRedit, Top +@chapter GSrenderfont + +@pindex gsrenderfont +@cindex converting PostScript fonts to bitmaps +@cindex bitmap fonts, making from PostScript +@cindex PostScript fonts, converting to bitmaps +@cindex previewing @TeX{} documents with PostScript fonts +@cindex DVI files with PostScript fonts, previewing +@cindex @TeX{} documents with PostScript fonts, previewing +@cindex Ghostscript, prerequisite for GSrenderfont + +GSrenderfont uses Ghostscript to rasterize a PostScript outline font at +a particular point size and resolution. The final result is a bitmap +font in PK form, which can be used by any DVI-processing program, unlike +the original PostScript font. In particular, you can then use your +favorite previewer with @TeX{} documents which use PostScript fonts. + +@pindex ghostview +An alternative to using such PK fonts is to use a DVI-to-PostScript +translator and then use Ghostscript or Ghostview directly on the result. +The PostScript file consumes quite a bit of disk space, however; also, +the extra step after running @TeX{} can be quite inconvenient. + +@pindex ps2pk +An alternative to using GSrenderfont is the standalone C program +@code{ps2pk}. It does the same job: rasterizing PostScript fonts. It +is available by ftp from @samp{ftp.urc.tue.nl}. + +@flindex gsrenderfont/main.c +@cindex GSrenderfont, prerequisites for +@pindex awk +@pindex gawk +@pindex bbcount +@pindex gftopk +@pindex tail +@pindex wc +@cindex Imageto, used by GSrenderfont +Besides Ghostscript, GSrenderfont uses @code{gawk} (GNU Awk), the +standard Unix utilities @code{tail} and @code{wc}, the standard @TeX{} +utility @code{gftopk}, another programs from this distribution +(Imageto), and one small program written expressly for it, +@code{bbcount}. Since this last is of doubtful value for anything but +GSrenderfont, it is not documented here. See @file{gsrenderfont/main.c} +if you are interested in what it does. + +GSrenderfont has nothing in particular to do with the main task of +creating typefaces, but it seemed a small enough job (given the other +programs' existence) and widely enough asked for to be worthwhile. + +@menu +* GSrenderfont usage:: Making bitmap fonts from PostScript. +* Invoking GSrenderfont:: Command-line options. +@end menu + + +@node GSrenderfont usage, Invoking GSrenderfont, , GSrenderfont +@section GSrenderfont usage + +@cindex GSrenderfont usage +@cindex usage of GSrenderfont + +GSrenderfont needs several bits of information to do its job, as +described in the sections below. + +@menu +* Names: GSrenderfont font names. Supplying PostScript names and filenames. +* Size: GSrenderfont output size. Specifying the size and resolution. +* Encoding: GSrenderfont encoding. Specifying the output encoding. +@end menu + + +@node GSrenderfont font names, GSrenderfont output size, , GSrenderfont usage +@subsection GSrenderfont font names + +@cindex font names in GSrenderfont +@cindex GSrenderfont font names +@cindex names of fonts in GSrenderfont + +@cindex PostScript font names, as filenames +GSrenderfont needs two names to do its job: the PostScript font name +(e.g., @samp{Times-Roman}), and the output filename (e.g., @file{ptmr}). +(The PostScript font name cannot also be used as the filename because of +its length. At best, the result would be unwieldy, and at worst, +invalid because of operating system restrictions.) If the font is not +known to Ghostscript (i.e., in its @file{Fontmap} +@flindex Fontmap +file), then an input filename is also needed. + +@opindex -font +@opindex -output-file +You can explicitly specify the first with the @samp{-font} option, the +second with the @samp{-output-file} option, and the third with a +non-option argument. If you specify them all, as in + +@example +gsrenderfont -font=Myfont -out=test myfont.ps +@end example + +@noindent then GSrenderfont simply uses what you've given. + +@opindex -map +@flindex psfonts.map +@flindex /usr/local/lib/tex/dvips/psfonts.map +@cindex mapping file for PostScript fonts +@cindex PostScript fonts, mapping file for +But if you specify only the font name or the input filename, +GSrenderfont tries to guess the other using a @dfn{mapping file}. On +each line of this file the first (whitespace-delimited) @dfn{word} is +the filename (possibly preceded by an @samp{r}; @pxref{Top, , +Introduction, fontname, Filenames for fonts}, for why), the second word +is the PostScript font name, and any remaining stuff is ignored. Unlike +the other data files, GSrenderfont does not use path searching to find +this file; it just uses the default: + +@example +/usr/local/lib/tex/dvips/psfonts.map +@end example + +@noindent +unless you specify a different file with the @samp{-map} option. The +reason for this is that @file{psfonts.map} should contain all the +PostScript fonts in use at your site. + +GSrenderfont complains and gives up if you specify neither the +PostScript font name nor the input filename. It also gives up if it +can't determine the filename from the PostScript name or vice versa. + +The default for the output filename is the input filename. + + +@node GSrenderfont output size, GSrenderfont encoding, GSrenderfont font names, GSrenderfont usage +@subsection GSrenderfont output size + +@cindex point size of GSrenderfont output +@cindex resolution of GSrenderfont output +@cindex GSrenderfont output, resolution of + +@opindex -point-size +@opindex -dpi +For convenience, GSrenderfont allows you to independently specify the +point size and the resolution of the output font: the @samp{-point-size} +option, as an integer in points, and the latter with +@samp{-dpi} in pixels per inch. The defaults are 10@dmn{pt} and +300@dmn{dpi}. + +@cindex PostScript font size, default +@cindex default PostScript font size +Because PostScript fonts are (in practice) linearly scaled, however, +GSrenderfont does not put the point size in the output filename. +Instead, it simply computes the final resolution as the @samp{dpi} +multiplied by the @samp{point-size} divided by 10. This assumes that +the default size of the fonts as used in @TeX{} is 10@dmn{pt}, which is +true for the PostScript fonts distributed with Dvips. + +For example, supposing the output filename is @file{ptmr}, and you +specify @samp{-point-size=12}, the bitmap font will be named +@file{ptmr.360pk}. + + +@node GSrenderfont encoding, , GSrenderfont output size, GSrenderfont usage +@subsection GSrenderfont encoding + +@cindex GSrenderfont output encoding +@cindex encoding, with GSrenderfont +@cindex font encoding, with GSrenderfont + +You specify the encoding for the new bitmap font with the +@samp{-encoding} option; the default is to use the encoding of the input +font. GSrenderfont reads the same encoding files as the other programs. +@xref{Encoding files}. + +As with all other data files in the other programs, GSrenderfont +searches for the encoding file using the path specified by the +environment variable @code{FONTUTIL_LIB} if it is set; otherwise it uses +the default path set during compilation. @xref{Font searching}, for the +details of the path searching algorithm. + + +@node Invoking GSrenderfont, , GSrenderfont usage, GSrenderfont +@section Invoking GSrenderfont + +@cindex GSrenderfont options +@cindex invocation of GSrenderfont +@cindex options for GSrenderfont + +This section describes the options that GSrenderfont accepts. +@xref{Command-line options}, for general option syntax. + +You must specify either @samp{-font} or a single non-option +argument, so GSrenderfont knows what font to work on. See the previous +section for more details. + +@table @samp + +@opindex -dpi +@item -dpi @var{unsigned} +Render the output at a resolution of @var{unsigned} pixels per inch; +default is 300. + +@opindex -encoding +@cindex data file searching +@item -encoding @var{scheme} +Read @file{@var{scheme}.enc} to define the encoding of the output font; +default is @file{dvips}. + +@opindex -font +@item -font @var{FontName} +Render the PostScript font @var{FontName} (e.g., @samp{Times-Roman}). + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -map +@flindex psfonts.map +@item -map @var{filename} +Use @var{filename} for the filename-to-PostScript name mapping file; +default is + +@example +/usr/local/lib/tex/dvips/psfonts.map +@end example + +@item -output-file @var{filename} +@opindex -output-file +@cindex output file, naming +Use @file{@var{filename}.@var{dpi}pk} for the final PK output. + +@opindex -point-size +@item -point-size @var{unsigned} +Render the output at @var{unsigned} points; default is 10. + +@opindex -verbose +@item -verbose +Output progress reports. + +@opindex -version +@item -version +Print the version number. + +@end table diff --git a/doc/imageto.texi b/doc/imageto.texi new file mode 100644 index 0000000..1d9e95c --- /dev/null +++ b/doc/imageto.texi @@ -0,0 +1,518 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Imageto, IMGrotate, File formats, Top +@chapter Imageto + +@pindex imageto + +Imageto converts an image file (currently either in portable bitmap +format (PBM) or GEM's IMG format) to either a bitmap font or an Encapsulated +PostScript file (EPSF). An @dfn{image file} is simply a large bitmap. + +If the output is a font, it can be constructed either by outputting a +constant number of scanlines from the image as each ``character'' or +(more usually) by extracting the ``real'' characters from the image. + +@cindex image input formats +The current selection of input formats is rather arbitrary. We +implemented the IMG format because that is what our scanner outputs, and +the PBM format because Ghostscript can output it (@pxref{GSrenderfont}). +Other formats could easily be added. + +@menu +* Imageto usage:: Process for extracting fonts from an image. +* IFI files:: IFI files supply extra information. +* Invoking Imageto:: Command-line options. +@end menu + + +@node Imageto usage, IFI files, , Imageto +@section Imageto usage + +@cindex Imageto usage +@cindex usage of Imageto + +Usually there are two prerequisites to extracting a usable font from an +image file. First, looking at the image, so you can see what you've +got. Second, preparing the IFI file describing the contents of the +image: the character codes to output, any baseline adjustment (as for, +e.g., @samp{j}), and how many pieces each character has. Each +is a separate invocation of Imageto; the first time with either the +@samp{-strips} or @samp{-epsf} option, the second time with neither. + +@cindex scanlines, definition of +@cindex image rows, definition of +@cindex bounding boxes in Imageto +In the second step, Imageto considers the input image as a series of +@dfn{image rows}. Each image row consists of all the scanlines between +a nonblank scanline and the next entirely blank scanline. (A +@dfn{scanline} is a single horizontal row of pixels in the image.) +Within each image row, Imageto looks top-to-bottom, left-to-right, for +@dfn{bounding boxes}: closed contours, i.e., an area whose edge +you can trace with a pencil without lifting it. + +@cindex type specimen image, example of +@cindex problems in scanned images, example +For example, in the following image Imageto would find two image rows, +the first from scanlines 1 to scanline 7, the second consisting of only +scanline 10. There are six bounding boxes in the first image row, only +one in the second. (This example also shows some typical problems in +scanned images: the baseline of the @samp{m} is not aligned with those +of the @samp{i}, @samp{j}, and @samp{l}; a meaningless black line is +present; the @samp{i} and @samp{j} overlap.) + +@example + 01234567890123456789 + 0 + 1 x + 2 x x x + 3 x + 4 x x x xxxxx + 5 x x x x x x + 6 x x x x + 7 xx + 8 + 9 +10 xxxxxxxxxxxxxxx +@end example + +@menu +* Viewing an image:: Seeing what's in an image. +* Image to font conversion:: Extracting a font. +* Dirty images:: Handling scanning artifacts or other noise. +@end menu + + +@node Viewing an image, Image to font conversion, , Imageto usage +@subsection Viewing an image + +@cindex EPS +@cindex Encapsulated PostScript +@pindex gs +@cindex Ghostscript + +@cindex image file, viewing +@cindex viewing image files +Typically, the first step in extracting a font from an image is to see +exactly what is in the image. (Clearly, this is unnecessary if you +already know what your image file contains.) + +@opindex -epsf +@cindex Ghostscript, using to look at images +The simplest way to get a look at the image file, if you have +Ghostscript or some other suitable PostScript interpreter, is to convert +the image file into an EPSF file with the @samp{-epsf} option. Here is +a possible invocation: + +@example +imageto -epsf ggmr.img +@end example + +Here we read an input file @file{ggmr.img}; the output is +@file{ggmr.eps}. You can then view the EPS file with + +@example +gs ggmr.eps +@end example + +@noindent (presuming that @file{gs} invokes your PostScript interpreter). + +@opindex -strips +If you don't have both a suitable PostScript interpreter and enough +disk space to store the EPS file (it uses approximately twice as much +disk space as the original image), the above won't work. Instead, to +view the image you must make a font with the @samp{-strips} option: + +@example +imageto -strips ggmr.img +@end example + +The output of this will be @file{ggmrsp.1200gf} (our image having a +resolution of 1200 dpi). Although the GF font cannot be conveniently +viewed directly, you can use @TeX{} and your favorite DVI processor to +look at it, as follows: + +@flindex strips.tex +@example +fontconvert -tfm ggmrsp.1200 +echo ggmrsp | tex strips +@end example + +This outputs in @file{strips.dvi}, which you can view with your favorite +DVI driver. (@xref{Archives}, for how to obtain the DVI drivers for +PostScript and X we recommend.) + +@file{strips.tex} is distributed in the @file{imageto} directory. + + +@node Image to font conversion, Dirty images, Viewing an image, Imageto usage +@subsection Image to font conversion + +@cindex image to font conversion +@cindex conversion, of image to font +@cindex extracting characters +@cindex characters, extracting from image +@cindex optical character recognition + +Once you can see what is in the image, the next step is to prepare the +IFI file (@pxref{IFI files}) corresponding to its characters. Imageto +relies completely on the IFI files to describe the image; it makes no +attempt at optical character recognition, i.e., guessing what the +characters are from their shapes. + +You must also decide on a few more aspects of the output font, which you +specify with options: + +@itemize @bullet + +@item +@cindex design size in image +@opindex -designsize +The @emph{design size}, which you specify with the @samp{-designsize} +option. The default is 10@dmn{pt}. Even if you know the true design +size of the original scanned image, you may wish to change it. For +example, some of our original specimens were stated to be 30@dmn{pt}, +but that resulted in the 10@dmn{pt} size being too small to our +(20th-century) eyes. So we specified a design size of 26@dmn{pt}. + +@item +@cindex baselines in image +@opindex -baselines +@opindex -print-guidelines +The @emph{baselines}, which you specify with the @samp{-baselines} +option. You can specify the baseline for each image row (the bottom +scanline of each image row is numbered zero, with coordinates increasing +upward). You can make an adjustment for individual characters in the +IFI files, but you save yourself at least some of this hassle by +specifying a general baseline for each row. + +For instance, in the example image in @ref{Imageto usage}, it would be +best to specify @samp{-baselines=2,0}. The @samp{2} is scanline #5 in +that image. The @samp{0} is an arbitrary value for scanline #10, which +we will ignore via the IFI file (@pxref{IFI files}). + +@opindex -print-guidelines @r{example} +For each character written, the @samp{-print-guidelines} option produces +output on the terminal that looks like: +@example +75 (K) 5/315 +@end example + +@noindent This means that character code 75, whose name in +the encoding file is @samp{K}, has its bottom row at row 5, and its top +row at row 315; i.e., the character has five blank rows above the +origin. This is almost certainly wrong (the letter `K' should sit on +the typesetting baseline), so we would want to adjust the baseline +upwards to 0 via an individual character baseline adjustment of 5 +in the IFI file (@pxref{IFI files}). + +@end itemize + +The final invocation to produce the font might look something like this: + +@example +imageto -baselines=121,130,120 -designsize=26 ggmr +@end example + +The output from this would be @file{ggmr26.1200gf}. + + +@node Dirty images, , Image to font conversion, Imageto usage +@subsection Dirty images + +@cindex sex +@cindex dirty images +@cindex noisy images +@cindex spots +@cindex clean images, not having +@cindex scanning artifacts +@cindex artifacts, of scanning + +Your image may not be completely ``clean'', i.e., the scanning process +may have introduced artifacts: black lines at the edge of the paper; +blotches where the original had a speck of dirt or ink; broken lines +where the image had a continuous line. To get a correct output font, +you must correct these problems. + +@cindex blotches in image, ignoring +@vindex .notdef@r{, removing blotches with} +To remove blotches, you can simply put @code{.notdef} in the appropriate +place in the IFI file. You can find the ``appropriate place'' when you +look at the output font; some character will be nothing but a (possibly +tiny) speck, and all the characters following will be in the wrong +position. + +@opindex -print-clean-info @r{example} +@cindex bounding boxes, assigned to characters +@cindex characters, bounding boxes assigned +The @samp{-print-clean-info} option might also help you to +diagnose which bounding boxes are being assigned to which characters, +when you are in doubt. Here is an example of its output: + +@example +[Cleaning 149x383 bitmap: + checking (0,99)-(10,152) ... clearing. + checking (0,203)-(35,263) ... clearing. + checking (0,99)-(130,382) ... keeping. + checking (113,0)-(149,37) ... keeping. +106] +@end example + +@noindent The final @samp{106} is the character code output (ASCII +@samp{j}). The size of the overall bitmap which contains the `j' is 149 +pixels wide and 383 pixels high. The bitmap contained four bounding +boxes, the last two of which belonged to the `j' and were kept, and the +first two from the adjacent character (`i') and were erased. (As shown +in the example image above, the tail of the `j' often overlaps the `i' +in type specimens.) + +If the image has blobs you have not removed with @code{.notdef}, you +will see a small bounding box in this output. The numbers shown are in +``bitmap coordinates'': (0,0) is the upper left-hand pixel of the +bitmap. + + +@cindex baselines and blotches +@opindex -baselines @r{and blotches} +If a blotch appears outside of the row of characters, Imageto will +consider it to be its own (very small) image row. If you are using +@samp{-baselines}, you must specify an arbitrary value corresponding to +the blotch, even though the bounding box in the image will be ignored. +See the section above for an example. + + +@node IFI files, Invoking Imageto, Imageto usage, Imageto +@section IFI files + +@cindex IFI files +@cindex image font information files + +An @dfn{image font information} (IFI) file is a text file which +describes the contents of an image file. You yourself must create it; +as we will see, the information it contains usually cannot be determined +automatically. + +@cindex IFI files, naming +@cindex naming IFI files +If your image file is named @file{@var{foo}.img} (or +@file{@var{foo}.pbm}), it is customary to name the corresponding IFI +file @file{@var{foo}.ifi}. That is what Imageto looks for by default. +If you name it something else, you must specify the name with the +@samp{-ifi-file} option. + +Imageto does not look for an IFI file if either the @samp{-strips} or +@samp{-epsf} options were specified. + +@cindex characters, defining in IFI files +Each nonblank non-comment line in the IFI file represents a a sequence +of bounding boxes in the image, and a corresponding character in the +output font. @xref{Common file syntax}, for a description of syntax +elements common to all data files processed by these programs, including +comments. + +@cindex entries in IFI files +Each line has one to five @dfn{entries}, separated by spaces and/or +tabs. If a line contains fewer than five entries, suitable defaults (as +described below) are taken for the missing trailing entries. (It is +impossible to supply a value for entry #3, say, without also supplying +values for entries #1 and #2.) + +Here is the meaning of each entry, in order: + +@enumerate + +@item +@cindex character name in IFI files +The character name of the output character. Usually, Imageto outputs +the bounding boxes from the image as a character in the output font, +assigning it the character code of the name as defined in the encoding +vector (@pxref{Invoking Imageto}). However, if the character name is +@code{.notdef}, or if the character name is not specified in the +encoding, Imageto just throws away the bounding boxes. @xref{Encoding +files}, for general information on encoding files. + +@item +@cindex baseline in IFI files +@cindex baseline adjustment +@cindex adjustment, to baseline +An adjustment to the baseline of the output character, as a (possibly +signed) decimal number. The default baseline is either the bottom +scanline of the image row, or the value you specified with the +@samp{-baselines} option. The number given here, in the IFI file, is +subtracted from that default. Thus, a positive adjustment moves the +baseline up (i.e., moves the character down relative to the typesetting +baseline), a negative one down. The default adjustment is zero. + +@item +@cindex bounding box count in IFI files +@cindex alternating bounding boxes +@cindex mixed-up characters in image +@cindex out-of-order characters in image +@cindex characters, out-of-order in image +The number of bounding boxes which comprise this character, as a decimal +number. The default is one. If this number is negative, it indicates +that the bounding boxes for this character are not consecutive in the +image; instead, they alternate with the following character. For +example, the tail of an italic `j' might protrude to the left of the +`i'; then Imageto will find the tail of the `j' first (so it should come +first in the IFI file), but it will find the dot of the `i' next. In +this case, the bounding box count for both the `i' and the `j' should be +@code{-2}. + +@item +@cindex side bearings in IFI files +@cindex left side bearing in IFI files +The left side bearing (lsb). Most type specimens unfortunately don't +include side bearing information, but if you happen to have such, you +can give it here. (GSrenderfont (@pxref{GSrenderfont}) uses this +feature). The default is zero. + +You can run Charspace (@pxref{Charspace}) to add side bearings to a font +semi-automatically. This is usually less work than trying to guess +at numbers here. + +@cindex right side bearing in IFI files +@item +The right side bearing. As with the lsb, the default is zero. + +@end enumerate + +Here is a possible IFI file for the image in @ref{Imageto usage}. We +throw away the black line that is the second image row. (Imagine that +it is a scanner artifact.) + +@example +% IFI file for example image. +i 0 2 +j 0 2 +l +m 1 +.notdef % Ignore the black line at the bottom. +@end example + + +@node Invoking Imageto, , IFI files, Imageto +@section Invoking Imageto + +@cindex Imageto options +@cindex invocation of Imageto +@cindex options for Imageto + +This section describes the options that Imageto accepts. +@xref{Command-line options}, for general option syntax. + +The main input filename (@pxref{Main input file}) is called +@var{image-name} below. + +@table @samp + +@item -baselines @var{scanline1},@var{scanline2},@dots{} +@opindex -baselines +@cindex baselines in image +Define the baselines for each image row. The default baseline for the +characters in the first image row is taken to be @var{scanline1}, etc. +The @var{scanline}s are @emph{not} cumulative: the top scanline in each +image row is numbered zero. + +@item -designsize @var{real} +@opindex -designsize +@cindex design size, specifying +@cindex fontsize +Set the design size of the output font to @var{real}; default is 10.0. + +@item -dpi @var{unsigned} +@opindex -dpi +The resolution of the input image, in pixels per inch (required for PBM +input). @xref{Common options}. + +@item -encoding @var{enc-file} +@opindex -encoding +The encoding file to read for the mapping between character names and +character codes. @xref{Encoding files}. If @var{enc-file} has no +suffix, @samp{.enc} is appended. Default is to assign successive +character codes to the character names in the IFI file. + +@item -epsf +@opindex -epsf +Write the image to @file{@var{image-name}.eps} as an Encapsulated +PostScript file. + +@item -help +@opindex -help +Print a usage message. @xref{Common options}. + +@opindex -ifi-file +@itemx -ifi-file @var{filename} +Set the name of the IFI file to @var{filename} (if @var{filename} has an +extension) or @file{@var{filename}.ifi} (if it doesn't). The default is +@file{@var{image-name}.ifi}. + +@item -input-format @var{format} +@opindex -input-format +Specify the format of the input image; @var{format} must be +one of @samp{pbm} or @samp{img}. The default is taken from +@var{image-name}, if possible. + +@item -nchars @var{unsigned} +@opindex -nchars +Only write the first @var{unsigned} (approximately) characters from the +image to the output font; default is all the characters. + +@item -output-file @var{filename} +@opindex -output-file +@cindex output file, naming +Write to @var{filename} if @var{filename} has a suffix. If it doesn't, +then if writing strips, write to @var{filename}sp.@var{dpi}gf; else +write to @file{@var{filename}.@var{dpi}gf}. By default, use +`@var{image-name} @var{designsize}' for @var{filename}. + +@item -print-clean-info +@opindex -print-clean-info +Print the size of each bounding box considered for removal, and the size +of the containing bitmaps. This option implies @samp{-verbose}. +@xref{Dirty images}, for a full explanation of its output. + +@item -print-guidelines +@opindex -print-guidelines +Print the numbers of the top and bottom scanlines for each +character. This implies @samp{verbose}. @xref{Image to font +conversion}, for a full explanation of its output. + +@item -range @var{char1}-@var{char2} +@opindex -range +Only output characters with codes between @var{char1} and @var{char2}, +inclusive. (@xref{Common options}, and @ref{Specifying character codes}.) + +@item -strips +@opindex -strips +Take a constant number of scanlines from the image as each character in +the output font, instead of using an IFI file to analyze the image. + +@item -trace-scanlines +@cindex scanlines, tracing +@cindex image, converting to ASCII +@opindex -trace-scanlines +Show every scanline as we read it as plain text, using @samp{*} and +space characters. This is still another way to view the image +(@pxref{Viewing an image}), but the result takes an enormous amount of +disk space (over eight times as much as the original image) and is quite +difficult to look at (because it's so big). To be useful at all, we +start a giant XTerm window with the smallest possible font and look at +the resulting file in Emacs. This option is primarily for debugging. + +@item -verbose +@opindex -verbose +@kindex . @r{in Imageto verbose output} +@kindex + @r{in Imageto verbose output} +Output progress reports. @xref{Common options}. Specifically, a +@samp{.} is output for every 100 scanlines read, a @samp{+} is +output when an image row does not end on a character boundary, and the +character code is output inside brackets. + +@item -version +@opindex -version +Print the version number. @xref{Common options}. + +@end table diff --git a/doc/imgrotate.texi b/doc/imgrotate.texi new file mode 100644 index 0000000..f4f044d --- /dev/null +++ b/doc/imgrotate.texi @@ -0,0 +1,145 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node IMGrotate, Fontconvert, Imageto, Top +@chapter IMGrotate + +@pindex imgrotate +@cindex rotation, of images +@cindex image rotation + +IMGrotate rotates an IMG file, either 90 or 180 degrees clockwise. We +call the latter---somewhat inaccurately---a ``flip''. (We haven't +needed other rotation angles, so we haven't implemented them.) + +The IMG format is an image format output by a few programs, including the +one that drives the scanner we have. (Again, we haven't needed other +image formats, so we haven't implemented them.) + +Both the input and output are IMG files. + +The current implementation of IMGrotate uses an extremely slow and +stupid algorithm, because it was a quick hack. It would be useful to +replace it with a better algorithm. @xref{Program features}, for a +reference. + +@menu +* IMGrotate usage:: Doing the image rotation. +* Invoking IMGrotate:: Command-line options. +@end menu + + +@node IMGrotate usage, Invoking IMGrotate, , IMGrotate +@section IMGrotate usage + +@cindex IMGrotate usage +@cindex usage of IMGrotate + +The physical construction of a source to be scanned may make it hard +or impossible to end up with an upright image. But the task of +extracting characters from an image is complicated by allowing for a +rotated image. Hence this program to turn rotated images upright. + +@flindex x @r{prefix} +By default, the name of the output file is the same as the input file; +both are extended with @file{.img} if necessary. If this would result +in the output overwriting the input, @samp{x} is prepended to the output +name. + +@menu +* Clockwise rotation:: Rotating clockwise. +* Flip rotation:: FLipping end-for-end. +@end menu + + +@node Clockwise rotation, Flip rotation, , IMGrotate usage +@subsection Clockwise rotation + +@cindex clockwise rotation +@cindex rotation, clockwise +@opindex -rotate-clockwise + +You specify clockwise rotation of an image with the option +@samp{-rotate-clockwise}. This rotates the input 90 degrees clockwise. +For example, the following (an @samp{h} on its side): + +@example + ***** + * + * +*********** +@end example + +@noindent turns upright. + + +@node Flip rotation, , Clockwise rotation, IMGrotate usage +@subsection Flip rotation + +@cindex flip rotation +@cindex rotation, flip + +You specify ``flip'' rotation of an image with the option @samp{-flip}. +This flips the input end for end and reverses left and right, i.e., does +a 180 degree rotation. For example, the following (an @samp{h} upside +down and backwards): + +@example + * * + * * + * * + *** + * + * + * +@end example + +@noindent turns upright. + + +@node Invoking IMGrotate, , IMGrotate usage, IMGrotate +@section Invoking IMGrotate + +@cindex IMGrotate options +@cindex invocation of IMGrotate +@cindex options for IMGrotate + +This section describes the options that IMGrotate accepts. +@xref{Command-line options}, for general option syntax. + +The name of the main input file (@pxref{Main input file}) is called +@var{image-name} below. + +@table @samp + +@opindex -flip +@item -flip +Rotate the input 180 degrees, i.e., flip it end for end and left to +right. @xref{Flip rotation}. + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -output-file +@cindex output file, naming +@item -output-file @var{filename} +Write to @var{filename} if @var{filename} has a suffix. If it doesn't, +write to @file{@var{filename}.img}, unless that would overwrite the +input, in which case write to @file{x@var{filename}.img}. By default, +use @var{image-name} for @var{filename}. + +@opindex -rotate-clockwise +@item -rotate-clockwise +Rotate the input 90 degrees clockwise. @xref{Clockwise rotation}. + +@opindex -verbose +@item -verbose +Output progress reports. @xref{Common options}. + +@opindex -version +@item -version +Print the version number. @xref{Common options}. + +@end table diff --git a/doc/index.texi b/doc/index.texi new file mode 100644 index 0000000..62455ad --- /dev/null +++ b/doc/index.texi @@ -0,0 +1,8 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Index, , Freedom, Top +@unnumbered Index + +@printindex cp diff --git a/doc/install.texi b/doc/install.texi new file mode 100644 index 0000000..bf4e219 --- /dev/null +++ b/doc/install.texi @@ -0,0 +1,341 @@ +@c Copyright (C) 1992, 93 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Installation +@chapter Installation + +@cindex installation +@cindex configuration + +@xref{Prereqs}, for what you need to have installed before you can +compile these programs. + +After that, here's what to do: + +@enumerate + +@item +Run @code{sh configure} in the top-level directory. This tries to figure +out system dependencies and the installation prefix. +@xref{configure, , The @code{configure} script, kpathsea, Kpathsearch +library}, for options and other information about @code{configure}. + +@flindex GNUmakefile@r{, editing} +@flindex include/c-auto.h@r{, editing} +@cindex search paths, defining default +@item +If necessary, edit the paths or other definitions in the top-level +@file{GNUmakefile} and in @file{include/c-auto.h}. + +@item +Run GNU make. For example, if it's installed as @file{make}, just type +@samp{make} in the top-level directory. If all goes well, this will +compile all the programs. + +@item +Install the programs and supporting data files with @code{make install}. + +@end enumerate + +If you encounter problems anywhere along the line, let us know. Known +problems are listed below (@pxref{Problems}). +@xref{Bugs}, for details on how to submit a useful bug report. + +@menu +* Prereqs:: What's needed before installation. +* Problems:: Known trouble. +@end menu + + +@node Prereqs +@section Prerequisites + +@cindex prerequisites to compilation + +To compile and use these programs, the following are necessary: + +@itemize @bullet + +@pindex gcc +@cindex GNU C compiler +@item +The GNU C compiler, version 1.40 or newer. + +@cindex GNU make +@pindex make +@item +GNU Make; probably any version newer than 3.50 or so will do. + +@cindex X11 libraries +@cindex libraries, X11 +@item +X11R4 or R5 unshared libraries and headers. These are only necessary to +run XBfe (@pxref{XBfe}) or for Limn (@pxref{Limn}) to display its +results online. (You also need an X11 server, naturally.) You might be +able to compile using the X11 shared libraries, but we haven't tried +that. + +@pindex gftopk +@pindex pltotf +@cindex Metafont +@cindex @TeX{} +@item +To make any substantial use of the fonts you create, you will probably +need @TeX{}, Metafont, and their friends, especially @code{PLtoTF} and +@code{GFtoPK}. + +@cindex Ghostscript +@pindex gs +@item +Ghostscript, version 2.4 or newer. +You only need this if you want to use GSrenderfont or BZRedit. + +@pindex gawk @r{prerequisite to GSrenderfont} +@item +The GNU Awk program, @code{gawk}. This is only needed if you want to +use GSrenderfont. + +@end itemize + +See the section below for information on how to get all these programs. + +@menu +* Archives:: Where to find programs. +@end menu + + +@node Archives +@subsection Archives + +@cindex software archives +@cindex ftp archives +@cindex archives, software + +@cindex GNU software, obtaining +@flindex prep.ai.mit.edu +The canonical source for all GNU software, including the GNU C compiler, +GNU make, and Ghostscript, is @file{prep.ai.mit.edu:pub/gnu}. That +directory is replicated at many other sites around the world, including: + +@table @asis + +@item United States: +@example +wuarchive.wustl.edu, ftp.cs.widener.edu, + uxc.cso.uiuc.edu, col.hp.com:/mirrors/gnu, + gatekeeper.dec.com:/pub/GNU, ftp.uu.net:/systems/gnu +@end example + +@item Europe: +@example +src.doc.ic.ac.uk:/gnu, ftp.informatik.tu-muenchen.de, + ftp.informatik.rwth-aachen.de:/pub/gnu, nic.funet.fi:/pub/gnu, + ugle.unit.no, isy.liu.se, ftp.stacken.kth.se, ftp.win.tue.nl, + ftp.denet.dk, ftp.eunet.ch, nic.switch.ch:/mirror/gnu, + archive.eu.net, irisa.irisa.fr:/pub/gnu +@end example + +@item Australia: +@example +archie.oz.au:/gnu @r{(@samp{archie.oz} or @samp{archie.oz.au} for ACSnet)} +@end example + +@item Asia +@example +ftp.cs.titech.ac.jp, utsun.s.u-tokyo.ac.jp:/ftpsync/prep, + cair.kaist.ac.kr:/pub/gnu +@end example + +@end table + +@flindex DISTRIB +@cindex prices for GNU software +@cindex ordering GNU software +You can also order tapes with GNU software from the Free Software +Foundation (thereby supporting the development of the font utilities and +the rest of the GNU project); send mail to @samp{gnu@@prep.ai.mit.edu} +for the latest prices and ordering information, or retrieve the file +@file{DISTRIB} from a GNU archive. + +@cindex X window system, obtaining +@flindex export.lcs.mit.edu +@flindex gatekeeper.dec.com +The canonical source for the X window system is +@file{export.lcs.mit.edu:pub/R5}. That directory is also shadowed at +many other sites, including @samp{gatekeeper.dec.com}. The FSF also +sells X distribution tapes. + +@cindex @TeX{}, obtaining +@flindex byron.u.washington.edu +@TeX{} is more scattered. A complete Unix @TeX{} distribution is +available by ordering a tape from the University of Washington (send +email to @samp{elisabet@@u.washington.edu}. Three archives with +complete (and identical) @TeX{} collections: + +@example +ftp.uni-stuttgart.de:/soft/tex +ftp.tex.ac.uk:/pub/archive +pip.shsu.edu:/tex-archive +@end example + +@pindex web2c +@flindex ftp.cs.umb.edu +@flindex ics.uci.edu +@flindex ftp.th-darmstadt.de +The canonical sources for just Web2C---the port of just @TeX{}, +Metafont, and friends to Unix, without DVI processors, fonts, macro +packages, etc.---are: + +@example +ftp.cs.umb.edu:pub/tex/ @r{(Boston)} +ics.uci.edu:TeX/ @r{(California)} +ftp.th-darmstadt.de:pub/tex/src/web2c/ @r{(Germany)} +@end example + +@flindex web.tar.Z +@flindex web2c.tar.Z +At all these sites, the files to retrieve are @file{web.tar.Z} and +@file{web2c.tar.Z}. + +@pindex dvips +@pindex xdvi +@cindex Rokicki, Tom +@cindex Vojta, Paul +@flindex labrea.stanford.edu +The DVI-to-PostScript driver we recommend is Tom Rokicki's Dvips, and +the X window system driver we recommend is Paul Vojta's XDvi. These +programs are available from, respectively, +@example +labrea.stanford.edu:pub/dvips* +export.lcs.mit.edu:contrib/xdvi.tar.Z +@end example + +@cindex path searching +We have modified XDvi and Dvips to use the same path searching code as +the current distribution of @TeX{} and these font utilities; the +modified versions are available from @file{ftp.cs.umb.edu:pub/tex}. + +@flindex modes.mf +@cindex Metafont modes +To use Metafont, you must have a file defining output devices. +(@xref{Metafont and BZRto}.) We recommend you obtain @file{modes.mf} +from +@example +ftp.cs.umb.edu:pub/tex/modes.mf +@end example + +@flindex fontname.texi +@cindex naming scheme for @TeX{} fonts +@cindex filenames for fonts +You can retrieve the document describing all the details of the naming +scheme for @TeX{} fonts from + +@example +ftp.cs.umb.edu:pub/tex/fontname.tar.Z +@end example + + +@node Problems +@section Problems + +@cindex problems in installation +@cindex trouble in installation +@cindex installation problems + +This section lists some things which have caused trouble during +installation. If you encounter other problems, please send a bug +report. @xref{Bugs}, for how to submit a useful bug report. + +@itemize @bullet + +@opindex -static +@cindex static linking, warning about +@item +You may get a warning from the compiler about @samp{-static} being an +unrecognized option. Ignore it. (This has already been reported to +@samp{bug-gcc}.) + +@cindex dynamic linking +@cindex static linking vs.@: dynamic linking +@cindex linking, dynamic +@cindex SunOS linking +@pindex /bin/ld +@item +Under SunOS 4.x, the programs which use X (XBfe and Limn) cannot be +dynamically linked, because (apparently) @file{/bin/ld} pulls in the +entire @file{.sa} file, and the Form, Label, and Viewport widgets are +multiply defined. (To us, this seems to defeat the whole purpose of +having libraries. It also seems bizarre to us that X was written so +that these multibyte functions are always needed (via +@code{__Xsi@dots{}}), and furthermore that the multibyte functions need +to specifically call the dynamic linking functions.) + +@findex dlsym +@findex dlclose +@findex dlopen +The file @file{lib/dlsym.c} (from the MIT X distribution) defines the +@code{dlsym}, @code{dlclose}, and @code{dlopen} symbols, so static +linking should work now. + +@cindex Xaw library, linking with +If the current setup fails, it might work to change @samp{-lXaw} in +the definition of @code{X_libraries} in @file{lib/defs.make} to +the full pathname of the Xaw library. + +@cindex GCC crash +@cindex compiler crash +@flindex imageto/main.c +@item +On many machines (Sun 3 or Sun 4 running SunOS 4.1, Sun386i running +4.0.2, 386 running ISC 2.2), GCC 1.40 gets a fatal error compiling +@file{imageto/main.c} with @samp{-O}. Just use @samp{-g} for that file, +or use a newer version of GCC. + +@flindex math.h@r{, wrong} +@findex fmod@r{, wrong prototype for} +@cindex Interactive Unix +@item +On a 386 running Interactive UNIX 2.2, @file{<math.h>} declares the +wrong prototype for @code{fmod}: the routine takes two doubles, not one. +We simply corrected our system include file. + +@findex XtIsRealized +@findex XtWindowOfObject +@vindex NULL +@cindex warnings in @file{Bitmap.c} +@cindex compiler warnings in @file{Bitmap.c} +@flindex Bitmap.c +@flindex widgets/Bitmap.c +@flindex IntrinsicP.h +@flindex X11/IntrinsicP.h +You may get compiler warnings for the file @file{widgets/Bitmap.c} at +the lines which use the Xt function @code{XtIsRealized} on systems which +define @code{NULL} as @code{(void *) 0}. The reason is that macro +definition of @code{XtIsRealized} in @file{<X11/IntrinsicP.h>} +incorrectly compares the result of @code{XtWindowOfObject} to +@code{NULL}, instead of @code{0}. If the warnings bother you, fix +@file{IntrinsicP.h}. + +@flindex XBfe @r{resource file} +@cindex XBfe failing +@cindex Limn online display failing +@flindex Limn @r{resource file} +@cindex X programs failing +@cindex X resources unrecognized +@cindex application resources, under X +@vindex XAPPLRESDIR +@item +The application resource files @file{limn/Limn} and @file{xbfe/XBfe} +must be installed in a directory where your X server can find them. +This directory varies according to how X was installed; in the default X +distribution, it is @file{/usr/lib/X11/app-defaults}. If you cannot (or +do not want to) write in the default directory, you can install them +elsewhere and set the @code{XAPPLRESDIR} environment variable to that +directory. See the tutorial on resources that comes with the MIT X +distribution (@file{mit/doc/tutorial/resources.txt}) for more +information. + +@end itemize + +Good luck. diff --git a/doc/intro.texi b/doc/intro.texi new file mode 100644 index 0000000..addd75c --- /dev/null +++ b/doc/intro.texi @@ -0,0 +1,33 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Introduction, Installation, Top, Top +@chapter Introduction + +@cindex introduction + +This manual corresponds to version REPLACE-WITH-VERSION of the GNU font +utilities. + +You can manipulate fonts in various ways using the utilities: conversion +of a scanned image to a bitmap font, hand-editing of bitmaps, conversion +of a bitmap font to an outline font, and more. More generally, you can +start with a scanned image of artwork and work your way through to a +finished font with side bearings, accented characters, ligatures, and so +on. + +@cindex Knuth, Donald E. +The font formats recognized by these programs are primarily those used +by the (freely available) @TeX{} typesetting system developed by +@w{Donald E.} Knuth from 1977--1990. The filenames, font searching, and +other aspects of their usage are also based on @TeX{}. They also +support output of PostScript Type 1 fonts. + +@cindex Morris, Robert A. +@cindex Martin, Rick +Some of this software was originally written as part of the research +program in digital typography at the University of Massachusetts at +Boston, directed by @w{Robert A.} Morris. The staff at UMB, Rick Martin in +particular, has been kind enough to let us to continue to use their +computers, despite our completing the Master's program there in 1989. diff --git a/doc/limn.texi b/doc/limn.texi new file mode 100644 index 0000000..7c38f08 --- /dev/null +++ b/doc/limn.texi @@ -0,0 +1,970 @@ +@c Copyright (C) 1992, 93 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Limn, BZRto, Charspace, Top +@chapter Limn + +@pindex limn +@cindex bitmap to outline conversion +@cindex outline fonts, making from bitmap +@cindex spline fitting + +@cindex outline font, definition of +@cindex bitmap font, definition of +These days, fonts to be used on computers are represented in one of two +ways: as a @dfn{bitmap font}, which specifies each individual pixel in +the image of a character; and/or as an @dfn{outline font}, which +specifies the image as a collection of mathematically-specified curves. +Each method has its own advantages and disadvantages; typesetting +programs, page description languages, and output devices can generally +deal with both. + +@cindex autotracing +@cindex tracing outlines on a bitmap +Limn converts a font from a bitmap to an outline by fitting curves to +the pixels. Non-shape-related information in the bitmap font, such as +that for the side bearings, is preserved in the outline output. + +Specifically, the input is a bitmap (GF or PK) font. The output is a +BZR outline font (@pxref{BZR files}), which can then be converted to +(for example) Metafont or PostScript with BZRto (@pxref{BZRto}). + +@cindex Schneider, Philip +@cindex Phoenix +@cindex Plass, Michael +@cindex Stone, Maureen +@cindex Gonczarowski, Jakob +There is a fair amount of literature on converting bitmaps to outlines. +We found three particularly helpful: Philip Schneider's Master's thesis +on his system Phoenix; Michael Plass and Maureen Stone's article +`Curve-fitting with piecewise parametric cubics' published in SIGGRAPH; +and Jakob Gonczarowski's article `A fast approach to auto-tracing (with +parametric cubics)' in the RIDT 91 conference proceedings. See +the file @file{limn/README} for the full citations. + +@menu +* Limn algorithm:: How Limn fits outlines to bitmaps. +* Invoking Limn:: Command-line options. +@end menu + + +@node Limn algorithm, Invoking Limn, , Limn +@section Limn algorithm + +@cindex Limn algorithm +@cindex algorithm for spline fitting +@cindex spline fitting, algorithm for + +Limn can always (barring bugs, of course) fit some sort of outline to +the bitmap input. But its default fit is likely to be far from the +ideal: character features may disappear, curves distorted, straight +lines turned into curves and curves into straight lines, and on and on. + +To control the fitting process, you must specify options to override +Limn's defaults. To describe those options, we must describe the +algorithm Limn uses to do the fitting, which we do in this section. We +mention the options at the appropriate point. + +The next section summarizes all the options, in alphabetical order. + +@flindex fit.c +Here is a schematic of the algorithm. The subsections below go into +detail for each step. Except for the very first step, this is +implemented in @file{limn/fit.c}. + +@example +find pixel outlines +for each pixel outline: + find corners, yielding curve lists + for each curve list: + remove knees + filter + if too small: + fit with straight line + otherwise fit with spline: + set initial t values + find tangents + fit with one spline + while error > reparameterize-threshold, reparameterize + if error > error-threshold, subdivide and recurse + if linearity < line-threshold, change to straight line + revert bad lines + align endpoints +@end example + +@menu +* Finding pixel outlines:: Extracting the edges from the bitmap. +* Finding corners:: Finding subsections of each outline. +* Removing knees:: Removing extraneous points. +* Filtering curves:: Smoothing the outlines. +* Fitting the bitmap curve:: Doing the fitting. +* Changing splines to lines:: Use straight lines where possible. +* Changing lines to splines:: Sometimes it isn't possible. +* Aligning endpoints:: If points are close enough, line them out. +* Displaying fitting online:: Seeing the results as Limn runs. +@end menu + + +@node Finding pixel outlines, Finding corners, , Limn algorithm +@subsection Finding pixel outlines + +@cindex pixel outlines, finding in bitmaps +@cindex cyclic curves + +The first step in the conversion from a character shape represented as a +bitmap to a list of mathematical curves is to find all the cyclical +outlines (i.e., closed curves) in the bitmap image. The resulting list +is called a @dfn{pixel outline list}. Each @dfn{pixel outline} in the +list consists of the pixel coordinates of each edge on the outline. + +For example, the pixel outline list for an @samp{i} has two elements: +one for the dot, and one for the stem. The pixel outline list for an +@samp{o} also has two elements: one for the outside of the shape, and +one for the inside. + +@cindex outside outlines +@cindex inside outlines +@cindex clockwise ordering of outlines +@cindex filling outlines +But we must differentiate between an @dfn{outside outline} (whose +interior is to be filled with black to render the character) and an +@dfn{inside outline} (whose interior is to be filled with white). +Limn's convention is to write the pixel coordinates for outside outlines +in counterclockwise order, and those for inside outlines in clockwise +order. + +@cindex type 1 outlines +This counterclockwise movement of outside outlines is required by the +Type 1 format used for PostScript fonts, which is why we adopted that +convention for Limn. + +For example, consider a pixel outline consisting of a single black pixel +at the origin. The pixel has four corners, and hence the outline will +have four coordinates. Limn looks for starting pixels from top to +bottom, left to right, within a bitmap image. Thus, the list of pixel +coordinates will start at (0,1) and proceed counterclockwise: (0,0) +(1,0) (1,1). Here is a picture: + +@example +start => (0,1)<-(1,1) + | ^ + v | + (0,0)->(0,1) +@end example + + +Because finding pixel outlines does not involve approximation or +estimation, there are no options to control the process. Put another +way, Limn will always find the correct pixel coordinates for each +outline. + +Once these pixel outlines have been found, each is then processed +independently; i.e., all the remaining steps, described in the following +sections, operate on each pixel outline individually. + +@flindex pxl-outline.c +@flindex edge.c +The source code for this is in @file{limn/pxl-outline.c} and +@file{lib/edge.c}. + + +@node Finding corners, Removing knees, Finding pixel outlines, Limn algorithm +@subsection Finding corners + +@cindex corners, finding + +Recall that our final goal is to fit splines, i.e., continuous curves, +to the discrete bitmap image. To that end, Limn looks for @dfn{corners} +in each pixel outline (see the previous section)---points where the +outline makes such a sharp turn that a single curve cannot +possibly fit well. Two corners mark the endpoints of a @dfn{curve}. + +@cindex curve list, definition of +We call the result a @dfn{curve list}, i.e., a list of curves on the +pixel outline: the first curve begins at that first corner and continues +through the second corner; and so on, until the last, which begins with +the last corner found and continues through the first corner. (Each +pixel outline is cyclic by definition; again, see the previous section.) + +@cindex fitting algorithm, adjusting +The corner-finding algorithm described below works fairly well in +practice, but you will probably need to adjust the parameters it uses. +Finding good corners is perhaps the most important part of the entire +fitting algorithm: missing a corner usually leads to a sharp point in +the original image being rounded off to almost nothing; finding an +extraneous corner usually leads to an extremely ugly blob. + +Here is Limn's basic strategy for guessing if a given point @math{p} is +a corner: compute the total displacement (in both @math{x} and @math{y}) +for some number @math{n} of points before @math{p}; do the same for +@math{n} points after @math{p}; find the angle @math{a} between those +two vectors; if that angle is less than some threshold, @math{p} is a +corner. + +@itemize @bullet + +@cindex resolution, dependency of fitting algorithm on +@opindex -corner-surround +The number @math{n} of points to consider is 4 by default; you can +specify a different number with the @samp{-corner-surround} option. If +the resolution of the input font is not 300@dmn{dpi}, +@samp{-corner-surround} should almost certainly be changed +proportionately. + +@opindex -corner-threshold +The threshold is 100 degrees by default; you can change this with the +@samp{-corner-threshold} option. You can see the angles at the chosen +corners via @samp{-log}. + +@end itemize + +However, when Limn finds a point @var{p} whose angle is below +@samp{corner-threshold}, it won't necessarily take @var{p} as the +corner. Instead, it continues looking for another +@samp{corner-surround} points; if it finds another point @math{q} whose +angle is less than that of @math{p}, @var{q} will become the corner. +(And then Limn looks for another @samp{corner-surround} points beyond +@var{q}, and so on.) + +This continued searching prevents having two corners near each other, +which is usually wrong, if the angles at the two would-be corners are +approximately the same. On the other hand, sometimes there are +extremely sharp turns in the outline within @samp{corner-surround} +pixels; in that case, one does want nearby corners after all. + +@opindex -corner-always-threshold +So Limn has one more option, @samp{-corner-always-threshold}. If the +angle at a point is below this value (60 degrees by default), then that +point is considered a corner, regardless of how close it is to other +corners. The search for another corner within @samp{corner-surround} +pixels continues, however. + + +@node Removing knees, Filtering curves, Finding corners, Limn algorithm +@subsection Removing knees + +@cindex knees, removing +@cindex extra pixels, removing + +For each curve in the curve list determined by the corners on the pixel +outline (see the previous section), Limn next removes +@dfn{knees}---points on the inside of the outline that form a ``right +angle'' with its predecessor and successor. That is, either (1) its +predecessor differs only in @math{x}, and its successor only in +@math{y}; or (2) its predecessor differs only in @math{y}, and its +successor only in @math{x}. + +It is hard to describe in words, but here is a picture: + +@example +** + X* + * +@end example + +@noindent The point @samp{X} is a knee, if we're moving in a clockwise +direction. + +Such a ``right angle'' point can be on either the inside or the outside +of the outline. Points on the inside do nothing useful, they just slow +things down and, more importantly, make the curve being fit less +accurate. So we remove them. But points on the outside help to define +the shape of the curve, so we keep those. (For example, if @samp{X} was +moved up one diagonally, we certainly want it as a part of the curve.) + +Although we haven't found a case where removing knees produces an +inferior result, there's no theory about it always helping. Also, you +may just be curious what difference it makes (as we were when we +programmed the operation). So Limn provides an option +@samp{-keep-knees}; if you specify it, Limn simply skips this step. + + +@node Filtering curves, Fitting the bitmap curve, Removing knees, Limn algorithm +@subsection Filtering curves + +@cindex filtering curves +@cindex curves, filtering +@cindex smoothing curves + +After generating the final pixel coordinates for each curve (see the +previous sections), Limn next @dfn{filters} the curves to smooth them. +Before this step, all the coordinates are on integer boundaries, which +makes the curves rather bumpy and difficult to fit well. + +@opindex -filter-percent +@cindex filtering, weighting +To filter a point @math{p}, Limn does the following: + +@enumerate + +@item +Computes the sum of the distances of @math{n} neighbors (points before +and after @math{p}) to @math{p}. These neighbors are always taken from +the original curve, since we don't want a newly filtered point to affect +subsequent points as we continue along the curve; that leads to strange +results. + +@item +Multiplies that sum by a weight, and adds the result to @math{p}. The +weight is one-third by default; you can change this with the +@samp{-filter-percent} option, which takes an integer between zero and +100. + +@end enumerate + +@cindex filter iterations +@opindex -filter-iterations +Repeatedly filtering a curve leads to even more smoothing, at the +expense of fidelity to the original. By default, Limn filters each +curve 4 times; you can change this with the @samp{-filter-iterations} +option. + +@cindex filtering, minimum size of curve for +If the curve has less than five points, filtering is omitted altogether, +since such a short curve tends to collapse down to a single point. + +@opindex -filter-alternative-surround +@opindex -filter-epsilon +@opindex -filter-surround +The most important filtering parameter is the number @math{n} of +surrounding points which are used to produce the new point. Limn has +two different possibilities for this, to keep features from disappearing +in the original curve. Let's call these possibilities @var{n} and +@var{alt_n}; typically @var{alt_n} is smaller than @var{n}. Limn +computes the total distance along the curve both coming into and going +out of the point @math{p} for both @var{n} and @var{alt_n} surrounding +points. Then it computes the angles between the in and out vectors for +both. If those two angles differ by more than some threshold (10 +degrees by default; you can change it with +@opindex -filter-epsilon +the @samp{-filter-epsilon} option), then Limn uses @var{alt_n} to +compute the new point; otherwise, it uses @var{n}. + +Geometrically, this means that if using @var{n} points would result in a +much different new point than using @var{alt_n}, use the latter, smaller +number, thus (hopefully) distorting the curve less. + +@cindex resolution of input, dependency on +@opindex -filter-alternative-surround +@opindex -filter-surround +Limn uses 2 for @var{n} and 1 for @var{alt_n} by default. You can use +the options @samp{-filter-surround} and +@samp{-filter-alternative-surround} to change them. If the resolution +of the input font is not 300@dmn{dpi}, you should scale them +proportionately. (For a 1200@dmn{dpi} font, we've had good results with +@samp{-filter-surround=12} and @samp{filter-alternative-surround= 6}.) + + +@node Fitting the bitmap curve, Changing splines to lines, Filtering curves, Limn algorithm +@subsection Fitting the bitmap curve + +@cindex fitting bitmap curves + +The steps in the previous sections are preliminary to the main fitting +process. But once we have the final coordinates for each (bitmap) +curve, we can proceed to fit it with some kind of continuous +(mathematical) function: Limn uses both straight lines (polynomials of +degree 1) and Bezier splines (degree 3). + +@cindex fitting with straight lines +@cindex lines, fitting with +To begin with, to use a spline the curve must have at least four points. +If it has fewer, we simply use the line going through its first and last +points. (There is no point in doing a fancy ``best fit'' for this case, +since the original curve is so short.) + +@cindex cubic splines, fitting with +@cindex Bezier splines, fitting with +@cindex spline representation +@cindex representation of splines +Otherwise, if the curve has four or more points, we try to fit it with +a (piece of a) Bezier cubic spline. This spline is represented as a +starting point, an ending point, and two ``control points''. Limn uses the +endpoints of the curve as the endpoints of the spline, and adjusts the +control points to try to match the curve. + +@cindex Bezier cubics, drawing +A complete description of the geometric and mathematical properties of +Bezier cubics is beyond the scope of this document. See a computer +graphics textbook for the details. + +We will use the terms ``splines'', ``cubics'', ``Bezier splines'', +``cubic splines'', and so on interchangeably, as is common practice. +(Although Bezier splines are not the only kind of cubic splines, they +are the only kind we use.) + +The sections below describe the spline-fitting process in more detail. + +@menu +* Initializing t:: Initializing the parameter values. +* Finding tangents:: Computing the direction of the curve at + the endpoints. +* Finding the spline:: Where are the control points? +* Reparameterization:: Changing the parameter values. +* Subdivision:: Splitting the curve into pieces. +@end menu + + +@node Initializing t, Finding tangents, , Fitting the bitmap curve +@subsubsection Initializing @math{t} + +@cindex initializing t +@cindex t, initializing +@cindex curve parameter initialization + +Limn must have some way to relate the discrete curve made from the +original bitmap to the continuous spline being fitted to that curve. +This is done by associating another number, traditionally called +@math{t}, with each point on the curve. + +@cindex t, meaning of +Imagine moving along the spline through the points on the curve. Then +@math{t} for a point @math{p} corresponds to how far along the spline +you have traveled to get to @math{p}. In practice, of course, the +spline does not perfectly fit all the points, and so Limn adjusts the +@math{t} values to improve the fit (@pxref{Reparameterization}). (It +also adjusts the spline itself, as mentioned above.) + +@cindex chord-length parameterization +Limn initializes the @math{t} value for each point on the curve using a +method called @dfn{chord-length parameterization}. The details of how +this works do not affect how you use the program, so we will omit them +here. (See the Plass & Stone article cited in @file{limn/README} if +you're curious about them.) + + +@node Finding tangents, Finding the spline, Initializing t, Fitting the bitmap curve +@subsubsection Finding tangents + +@cindex blending of adjacent curves +@cindex adjacent curves, blending +As mentioned above, Limn moves the control points on the spline +to optimally fit the bitmap. But it cannot just move them arbitrarily, +because it must make sure that the spline fitting one part of the bitmap +blends smoothly with those fit to adjacent parts. + +@cindex continuity of curves +@cindex zero-order continuity +@cindex first-order continuity +@cindex G1 continuity +Technically, this smooth blending is called @dfn{continuity}, and it +comes in degrees. Limn is concerned with the first two degrees: zero- +and first-order. Zero-order continuity between two curves simply means +the curves are connected; first-order geometric (G1) continuity means +the tangents to each curve at the point of connection have the same +direction. (There are other kinds of continuity besides ``geometric'', +but they are not important for our purposes.) + +Informally, this means that the final shape will not abruptly turn at +the point where two splines meet. (Any computer graphics textbook will +discuss the properties of tangents, continuity, and splines, if you're +unfamiliar with the subject.) + +@cindex control points, constraints on +To achieve G1 continuity, Limn puts the first control point of a spline +on a line going in the direction of the tangent to the start of the +spline; and it puts the second control point on a line in the direction +of the tangent to the end of the spline. (It would be going far afield +to prove that this together with the properties of Bezier splines imply +G1 continuity, but they do. See Schneider's thesis referenced in +@file{limn/README} for a complete mathematical treatment.) + +@cindex tangents, computing +@cindex resolution of input, dependency on +@opindex -tangent-surround +For the purposes of using Limn, the important thing is that Limn must +compute the tangents to the spline at the beginning and end, and must do +so accurately in order to achieve a good fit to the bitmap. Since Limn +has available only samples (i.e., the pixel coordinates) of the curve +being fit, it cannot compute the true tangent. Instead, it must +approximate the tangent by looking at some number of coordinates on +either side of a point. By default, the number is 3, but you can +specify a different number with the @samp{-tangent-surround} option. If +the resolution of the input font is different than 300@dmn{dpi}, or if +the outline Limn fits to the bitmap seems off, you will want to scale it +proportionately. + + +@node Finding the spline, Reparameterization, Finding tangents, Fitting the bitmap curve +@subsubsection Finding the spline + +@cindex error in fitting +@cindex minimizing error +At last, after all the preprocessing steps described in the previous +sections, we can actually fit a spline to the bitmap. Subject to the +tangent constraints (see the previous section), Limn finds the spline which +minimizes the @dfn{error}---the overall distance to the pixel coordinates. + +@cindex least-squares error metric +@cindex sum of squares of distances +More precisely, Limn uses a @dfn{least-squares error metric} to measure +the ``goodness'' of the fit. This metric minimizes the sum of the +squares of the distance between each point on the bitmap curve and its +corresponding point on the fitted spline. (It is appropriate to square +the distance because it is equally bad for the fitted spline to diverge +from the curve in a positive or negative direction.) + +@cindex t parameter +The correspondence between the fitted spline and the bitmap curve is +defined by the @math{t} value that is associated with each point +(@pxref{Initializing t}). + +@cindex formula for best control points +For a given set of @math{t} values and given endpoints on the spline, +the control points which minimize the least-squares metric are unique. +The formula which determines them is derived in Schneider's thesis (see +the reference in @file{limn/README}); Limn implements that formula. + +Once we have the control points, we can ask how well the resulting +spline actually does fit the bitmap curve. Limn can do two things to +improve the fit: change the @math{t} values (reparameterization); or +break the curve into two pieces and then try to fit each piece +separately (subdivision). + +The following two sections describe these operations in more detail. + + +@node Reparameterization, Subdivision, Finding the spline, Fitting the bitmap curve +@subsubsection Reparameterization + +@cindex reparameterization + +@dfn{Reparameterization} changes the @math{t} value for each point +@math{p} on the bitmap curve, thus changing the place on the spline +which corresponds to @math{p}. Given these new @math{t} values, Limn +will then fit a new spline (see the previous section) to the bitmap, one +which presumably matches it more closely. + +Reparameterization is almost always a win. Only if the initial fit +(@pxref{Initializing t}) was truly terrible will reparameterization be a +waste of time, and be omitted in favor of immediate subdivision (see the +next section). + +@opindex -reparameterize-threshold +@cindex threshold for reparameterization +Limn sets the default threshold for not reparameterizing to be 30 +``square pixels'' (this number is compared to the least-squares error; +see the previous section). This is usually only exceeded in cases such +as that of an outline of @samp{o}, where one spline cannot possibly fit +the entire more-or-less oval outline. You can change the threshold with +the option @samp{-reparameterize-threshold}. + +@opindex -reparameterize-improve +@cindex improvement threshold for reparameterization +If the error is less than @samp{reparameterize-threshold}, Limn +reparameterizes and refits the curve until the difference in the error +from the last iteration is less than some percentage (10 by default; you +can change this with the option @samp{-reparameterize-improve}). + +After Limn has given up reparameterization (either because the initial +fit did not meet the @samp{reparameterize-threshold}, or because the +error did not decrease by at least @samp{reparameterize-improve}), the +final error is compared to another threshold, 2.0 by default. (You can +specify this with the option @samp{-error-threshold}.) If the error is +larger, Limn subdivides the bitmap curve (see the next section) and fits +each piece separately. Otherwise, Limn saves the fitted spline and goes +on to the next piece of the pixel outline. + + +@node Subdivision, , Reparameterization, Fitting the bitmap curve +@subsubsection Subdivision + +@cindex subdivision of curves +@cindex housing developments +@cindex recursive fitting + +When Limn cannot fit a bitmap curve within the @samp{error-threshold} +(see the previous section), it must subdivide the curve into two pieces +and fit each independently, applying the fitting algorithm recursively. + +@cindex subdivision vs. reparameterization +@cindex reparameterization vs. subdivision + +As a strategy to improve the fit, subdivision is inferior to +reparameterization, because it increases the number of splines in the +character definition. This increases the memory required to store the +character, and also the time to render it. However, subdivision is +unavoidable in some circumstances: for example, the outlines on an +@samp{o} cannot be fit by a single spline. + +@cindex subdivision point, choosing +@cindex worst fit, in subdivision +For the initial guess of the point at which to subdivide, Limn chooses +the point of worst error---the point where the fitted spline is farthest +from the bitmap curve. Although this is usually a good choice, +minimizing the chance that further subdivision will be necessary, +occasionally it is not the best: in order to preserve straight lines, +it is better to subdivide at the point where a straight becomes a curve +if that point is close to the worst point. For example, this happens +where a serif joins the stem. + +Limn has three options to control this process: + +@enumerate + +@opindex -subdivide-search +@item +@samp{-subdivide-search @var{percent}} specifies how far away from the +worst point to search for a better subdivision point, as a percentage of +the total number of points in the curve; the default is 10. If you find +Limn missing a join as a subdivision point, resulting in a straight line +becoming a curve, you probably need to increase this. + +@opindex -subdivide-threshold +@item +@samp{-subdivide-threshold @var{real}}: if the distance between a point +@math{p} (within the search range) and a straight line is less than +this, subdivide at @math{p}; default is .03 pixels. + +@opindex -subdivide-surround +@item +@samp{-subdivide-surround @var{unsigned}}: when calculating the linearity +of the curve surrounding a potential subdivision, use this many points; +default is 4. + +@end enumerate + +Because fitting a shorter curve is easier, this process will always +terminate. (Eventually the curve will be short enough to fit with a +straight line (@pxref{Fitting the bitmap curve}), if nothing else.) + + +@node Changing splines to lines, Changing lines to splines, Fitting the bitmap curve, Limn algorithm +@subsection Changing splines to lines + +@cindex splines to lines +@cindex lines, changing splines to + +Upon accepting a fitted spline (see the previous sections), Limn checks +if a straight line would fit the curve as well. If so, that is +preferable, since it is much faster to render straight lines than cubic +splines. + +More precisely, after fitting a cubic spline to a particular (segment of +a) curve, Limn finds the straight line between the spline's endpoints, +and computes the average distance (@pxref{Finding the spline}) between +the line and the curve. If the result is less than some threshold, 1 by +default, then the spline is provisionally (see the next section) changed +to a line. + +@opindex -line-threshold +@cindex threshold, for splines to lines +You can change the theshold with the @samp{-line-threshold} option. + + +@node Changing lines to splines, Aligning endpoints, Changing splines to lines, Limn algorithm +@subsection Changing lines to splines + +@cindex lines to splines +@cindex splines, changing lines to +@cindex reversion of lines to splines + +Once an entire curve (i.e., the bitmap outline between two corners; see +@ref{Finding corners}) has been fit, Limn checks for straight lines that +are adjacent to splines. Unless such lines fit the bitmap +@emph{extremely} well, they must be changed to splines. + +@cindex join point of lines and splines +The reason is that the point at which the line and spline meet will be a +visible ``bump'' in the typeset character unless the two blend smoothly. +Where two splines meet, the continuity is guaranteed from the way we +constructed the splines (@pxref{Finding tangents}). But where a line +and spline meet, nothing makes the join smooth. + +For example, if the outline of a @samp{o} has been subdivided many times +(as typically happens), a spline may end up fitting just a few +pixels---so few that a line would fit just as well. The actions +described in the previous section will therefore change the spline to a +line. But since the adjacent parts of the @samp{o} are being fit with +curves, that line will result in a noticeable flat spot in the final +output. So we must change it back to a spline. + +@cindex threshold for line reversion +We want this reversion to be more likely for short curves than long +curves, since short curves are more likely to be the result of a small +piece of a curved shape. So Limn divides the total distance between the +fitted line and the bitmap curve by the square of the curve length, and +compares the result to a threshold, .01 by default. You can change this +with the @samp{-line-reversion-threshold} option. + + +@node Aligning endpoints, Displaying fitting online, Changing lines to splines, Limn algorithm +@subsection Aligning endpoints + +@cindex aligning endpoints +@cindex endpoints, aligning + +After fitting a mathematical outline of splines and lines to a pixel +outline (@pxref{Finding pixel outlines}), Limn aligns the endpoints on +the fitted outline. This involves simply checking each spline to see if +its starting point and ending point (in either axis) are ``close +enough'' to each other. If they are, then they are made equal to their +average. + +This is useful because even a slight offset of the endpoints can be +produce a noticeable result, especially for straight lines and corners. + +@opindex -align-threshold +By default, ``close enough'' is half a pixel. You can change this with +the @samp{-align-threshold} option. + + +@node Displaying fitting online, , Aligning endpoints, Limn algorithm +@subsection Displaying fitting online + +@cindex online display of fitted outline +@cindex displaying fitted outline online +@cindex fitted outline, displaying online + +@opindex -display +While experimenting with the various fitting options listed in the +preceding sections, you may find it useful to see the results of the +fitting online. Limn can display the filtered (@pxref{Filtering +curves}) bitmap and the fitted outline online if it is run under the X +window system and you specify @samp{-do-display}. + +@opindex -display-continue +Ordinarily, Limn stops at the end of fitting every character for you to +hit return, so you have a chance to examine the result. If you just +want to get a brief glimpse or something, you can specify +@samp{-display-continue}. Then Limn won't stop. + +@vindex DISPLAY @r{environment variable} +@cindex X server, specifying +If you specify @samp{-do-display}, you must set the environment variable +@code{DISPLAY} to the X server you want Limn to use. For example, in +Bourne-compatible shells, you might do: + +@example +DISPLAY=:0 ; export DISPLAY +@end example + +The output is shown on a grid, in which each square represents several +pixels in the input. Corners are shown as filled squares; other pixels +are shown as hollow squares. + +Limn has several options that change the appearance of the online +output: + +@itemize @bullet + +@opindex -display-grid-size +@cindex grid lines, space between +@item @samp{-display-grid-size @var{unsigned}} +The number of expanded pixels shown between the grid lines; default is 10. + +@opindex -display-pixel-size +@cindex expansion of displayed pixels +@cindex displayed pixels, expansion of +@item @samp{-display-pixel-size @var{unsigned}} +The expansion factor; i.e., each input pixel is expanded to a square +this many pixels on a side; default is 9. + +@opindex -display-rectangle-size +@item @samp{-display-rectangle-size @var{unsigned}} +The pixel size; i.e., each pixel shown is a square this many pixels on a +side; default is 6. This must be less than the +@samp{display-pixel-size}, so that black pixels don't merge into each +other. + +@end itemize + +@vindex geometry @r{resource} +@cindex size of Limn window +@cindex Limn window size +@flindex .Xdefaults +@cindex resources for X +@cindex X resources +You can change the size of the window Limn creates with the +@code{geometry} resource in your @file{.Xdefaults} file (see the +documentation in the file @file{mit/doc/tutorials/resources.txt} in the +X distribution if you aren't +familiar with X resources). The class name is @code{Limn}. For +example: + +@example +Limn*geometry: 300x400-0-0 +@end example + +@noindent makes the window 300 pixels wide, 400 pixels high, and located +in the lower right corner of the screen. + + +@node Invoking Limn, , Limn algorithm, Limn +@section Invoking Limn + +@cindex Limn options +@cindex invocation of Limn +@cindex options for Limn + +This section lists the options that Limn accepts in alphabetic +order. The previous section described many of these options in the +context of the fitting algorithm. + +@xref{Command-line options}, for general option syntax. + +The root of the main input fontname is called @var{font-name} below. + +@table @samp + +@opindex -align-threshold +@item -align-threshold @var{real} +If either coordinate of the endpoints on a spline is closer than this, +make them the same; default is .5. @xref{Aligning endpoints}. + +@opindex -corner-always-threshold +@item -corner-always-threshold @var{angle-in-degrees} +If the angle at a pixel is less than this, it is considered a corner, +even if it is within @samp{corner-surround} pixels of another corner; +default is 60. @xref{Finding corners}. + +@opindex -corner-surround +@item -corner-surround @var{unsigned} +Number of pixels on either side of a point to consider when determining +if that point is a corner; default is 4. @xref{Finding corners}. + +@opindex -corner-threshold +@item -corner-threshold @var{angle-in-degrees} +If a pixel, its predecessor(s), and its successor(s) meet at an angle +smaller than this, it's a corner; default is 100. @xref{Finding corners}. + +@opindex -display-continue +@item -display-continue +If you specified @samp{-do-display}, do not wait for you to hit return +after displaying each character online. @xref{Displaying fitting online}. + +@opindex -display-grid-size +@item -display-grid-size @var{unsigned} +Number of expanded pixels between the grid lines; default is 10. +@xref{Displaying fitting online}. + +@opindex -display-pixel-size +@item -display-pixel-size @var{unsigned} +Length of one side of the square that each pixel expands into; default +is 9. @xref{Displaying fitting online}. + +@opindex -display-rectangle-size +@item -display-rectangle-size @var{unsigned} +Length of one side of the square drawn to represent input pixels; +default is 6. Must be less than @samp{display-pixel-size}. +@xref{Displaying fitting online}. + +@opindex -do-display +@item -do-display +Show the results of the fitting in an X window, if the X server +specified in the @code{DISPLAY} environment variable can be opened. +@xref{Displaying fitting online}. + +@opindex -dpi +@item -dpi @var{unsigned} +The resolution, in pixels per inch. @xref{Common options}. + +@opindex -error-threshold +@item -error-threshold @var{real} +Subdivide fitted curves that are off by more pixels than this; default +is 2.0. @xref{Reparameterization}. + +@opindex -filter-alternative-surround +@item -filter-alternative-surround @var{unsigned} +Another choice for filter-surround; default is 1. @xref{Filtering curves}. + +@opindex -filter-epsilon +@item -filter-epsilon @var{real} +If the angles using @samp{filter-surround} and +@samp{filter-alternative-surround} points differ by more than this, use +the latter; default is 10.0. @xref{Filtering curves}. + +@opindex -filter-iterations +@item -filter-iterations @var{unsigned} +Smooth the curve this many times before fitting; default is 4. +@xref{Filtering curves}. + +@opindex -filter-percent +@item -filter-percent @var{percent} +When filtering, use the old point plus distance of neighbors multiplied +by this (as a percentage) to determine the new point; default is 33. +@xref{Filtering curves}. + +@opindex -filter-surround +@item -filter-surround @var{unsigned} +Number of pixels on either side of a point to consider when filtering +that point; default is 2. @xref{Filtering curves}. + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -keep-knees +@item -keep-knees +Do not remove ``knees''---points on the inside of the outline that are +between two others. @xref{Removing knees}. + +@opindex -line-reversion-threshold +@item -line-reversion-threshold @var{real} +If a spline is closer to a straight line than this, keep it a straight +line even if it is a list with curves; default is .01 pixels. +@xref{Changing lines to splines}. + +@opindex -line-threshold +@item -line-threshold @var{real} +If a spline is not more than this far away from the straight line +defined by its endpoints, then output a straight line; default is 1. +@xref{Changing splines to lines}. + +@opindex -log +@item -log +Write detailed progress reports to @file{@var{font_name}.log}. + +@opindex -output-file +@cindex output file, naming +@item -output-file @var{filename} +Write to @var{filename} if it has a suffix and to +@file{@var{filename}.bzr} if it doesn't. Default is +@file{@var{font-name}.bzr}. + +@opindex -range +@item -range @var{char1}-@var{char2} +Only output characters with codes between @var{char1} and @var{char2}, +inclusive. (@xref{Common options}, and @ref{Specifying character codes}.) + +@opindex -reparameterize-improve +@item -reparameterize-improve @var{percent} +If reparameterization doesn't improve the fit by this much, as a +percentage, then stop reparameterizing; default is 10. +@xref{Reparameterization}. + +@opindex -reparameterize-threshold +@item -reparameterize-threshold @var{real} +If an initial fit is off by more pixels than this, don't bother to +reparameterize; default is 30. @xref{Reparameterization}. + +@opindex -subdivide-search +@item -subdivide-search @var{percent} +Percentage of the curve from the initial guess for a subdivision point +to look for a better one; default is 10. @xref{Subdivision}. + +@opindex -subdivide-surround +@item -subdivide-surround @var{unsigned} +Number of points on either side of a point to consider when looking for +a subdivision point; default is 4. @xref{Subdivision}. + +@opindex -subdivide-threshold +@item -subdivide-threshold @var{real} +If a point is this close or closer to a straight line, subdivide there; +default is .03 pixels. @xref{Subdivision}. + +@opindex -tangent-surround +@item -tangent-surround @var{unsigned} +Number of points on either side of a point to consider when computing +the tangent at that point; default is 3. @xref{Finding tangents}. + +@opindex -verbose +@item -verbose +Output progress reports. + +@opindex -version +@item -version +Print the version number. + +@end table diff --git a/doc/overview.texi b/doc/overview.texi new file mode 100644 index 0000000..987d10f --- /dev/null +++ b/doc/overview.texi @@ -0,0 +1,704 @@ +@c Copyright (C) 1992, 93 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node Overview +@chapter Overview + +@cindex overview + +This chapter gives an overview of what you do to create fonts using +these programs. It also describes some things which are common to all +the programs. + +Throughout this document, we refer to various source files in the +implementation. If you can read C programs, you may find these +references useful as points of entry into the source when you are +confused about some program's behavior, or are just curious. + +@menu +* Picture:: A pictorial overview. +* Creating fonts:: How to use the programs together. +* Command-line options:: Many aspects of the command line are + common to all programs. +* Font searching:: How fonts and other files are looked for. +* Font naming:: How to name fonts. +@end menu + + +@node Picture +@section Picture + +@cindex picture of program flow +@cindex information flow, picture of + +Following is a pictorial representation of the typical order in which +these programs are used, as well as their input and output. + +GSrenderfont is not in the picture since it is intended for an entirely +separate purpose (namely, making bitmaps from PostScript outlines). +Fontconvert also has many functions which are not needed for the basic +task of font creation from scanned images. + +@smallexample + --------------- + / --------------------- | fontconvert | + / --------------- + | ^ ^ +scanned v |---------------| | +image TFM v v +and IFI ----------- GF ------------- TFM, GF -------- BZR +========> | imageto | ======> | charspace | =========> | limn | ======... + ^ ----------- ------------- ^ -------- + | ^ | (continued) + v CMI v +------------- -------- +| imgrotate | | xbfe | +------------- -------- + + + + Metafont source ------ GF, TFM + |=====================> | mf | ========= + (continued) | ------ + | + BZR --------- TFM, | PostScript Type 1 (gsf) +... ======> | bzrto |========|======================= + --------- | + ^ | + | | PostScript Type 3 (pf3) + CCC |====================== + | + | + | BPL ------------ BZR + |=========> | bpltobzr | ===== + ------------ +@end smallexample + +@xref{File formats}, for more information on these file formats. + + +@node Creating fonts +@section Creating fonts + +@cindex creating fonts, overview of +@cindex font creation, overview of +@cindex information flow, description of +@cindex overview of font creation + +The previous section described pictorially the usual order in which these +programs are used. This section will do the same in words. + +Naturally, you may not need to go through all the steps described here. +For example, if you are not starting with a scanned image, but already +have a bitmap font, then the first step---running Imageto---is +irrelevant. + +Here is a description of the usual font creation process, starting with +a scanned image of a type specimen and ending with fonts which can be +used by Ghostscript, @TeX{}, etc. + +@enumerate + +@item +@cindex image file, viewing +@cindex scanned image, viewing +To see what an image @var{I} consists of, run Imageto with either +@samp{-strips} or @samp{-epsf}. This produces a bitmap font +@file{@var{I}sp} in which each character is simply a constant number of +scanlines from the image. + +@item +Run Fontconvert (@pxref{Fontconvert}) on @file{@var{I}sp} with the +@samp{-tfm} option, to produce a TFM file. This is because of +the next step: + +@item +@flindex strips.tex +Run @TeX{} on @file{imageto/strips.tex}, telling @TeX{} to use the +font @file{@var{I}sp}. This produces a DVI file which you can print or +preview as you usually do with @TeX{} documents. (If you don't know how +to do this, you'll have to ask someone knowledgeable at your site, or +otherwise investigate.) This will (finally) show you what is in the +image. + +An alternative to the above steps is to run Imageto with the +@samp{-epsf} option. This outputs an Encapsulated PostScript file with +the image given as a simple PostScript bitmap. Then you can use +Ghostscript or some other PostScript interpreter to look at the EPS file. +This method is simpler, but has the disadvantage of using much more +disk space, and needing a PostScript interpreter. + +@item +If the original was not scanned in the normal orientation, the image +must be rotated 90 degrees in some direction and/or flipped end for end. +(Sometimes we have not scanned in the normal orientation because the +physical construction of the book we were scanning made it difficult or +impossible.) In this case, you must rotate the image to be upright. +The program IMGrotate does this, given the @samp{-flip} or +@samp{rotate-clockwise} option. Given an image @var{RI}, this outputs +the upright image @var{I}. + +@item +Once you have an upright image @var{I}, you can use Imageto +(@pxref{Imageto}) to extract the characters from the image and make a +bitmap font @file{@var{I}.@var{dpi}gf}, where @var{dpi} is the +resolution of the image in pixels per inch. (If the image itself does +not contain the resolution, you must specify it on the command line with +@samp{-dpi}.) To do this, you must first prepare an IFI file describing +the image. @xref{IFI files}, for a description of IFI files. + +@item +@flindex testfont.tex +To view the resulting GF file, run Fontconvert to make a TFM file, as +above. Then run @TeX{} on @file{testfont.tex} and use the @code{\table} +or @code{\sample} commands to produce a font table. Next, print or +preview the DVI file that @TeX{} outputs, as before. This will probably +reveal problems in your IFI file, e.g., that not all the characters are +present, or that they are not in the right positions. So you need to +iterate until the image is correctly processed. + +@file{testfont.tex} should have come with your @TeX{} distribution. If +for some reason you do not have it, you can use the one distributed in +the @file{data} directory. + +@item +Once all the characters have been properly extracted from the image, you +have a bitmap font. Unlike the above, the following steps all interact +with each other, in the sense that fixing problems found at one stage may +imply changes in an earlier stage. As a result, you must expect to +iterate them several (billion) times. + +At any rate, given a bitmap font @var{f} you then run Charspace +(@pxref{Charspace}) to add side bearings to @var{f}, producing a new +bitmap font, say @var{g}, and a corresponding TFM file +@file{@var{g}.tfm}. To do this, you must prepare a CMI file specifying +the side bearings. @xref{CMI files}, for a description of CMI files. + +@item +To fit outlines to the characters in a bitmap font, run Limn +(@pxref{Limn}). Given the bitmap font @var{g}, it produces the BZR +(@pxref{BZR files}) outline font @file{@var{g}.bzr}. The side bearings +in @var{g} are carried along. + +Although Limn will (should) always be able to fit some sort of outline +to the bitmaps, you can get the best results only by fiddling with the +(unfortunately numerous) parameters. @xref{Invoking Limn}. + +@item +To convert from the BZR file @file{@var{g}.bzr} that Limn outputs to a +font format that a typesetting program can use, run BZRto +(@pxref{BZRto}). While developing a font, we typically convert it to a +Metafont program (with the @samp{-metafont} option). + +As you get closer to a finished font, you may want to prepare a CCC file +(@pxref{CCC files}) to tell BZRto how construct composite characters +(pre-accented `A's, for example) to complete the font. + +@item +Given the font in Metafont form, you can then either make +the font at its true size for some device, or make an enlarged version +to examine the characters closely. @xref{Metafont and BZRto}, for the +full details. + +Briefly, to do the former, run Metafont with a @code{mode} of whatever +device you wish (the mode @code{localfont} will get you the most +common local device, if Metafont has been installed properly). Then you +can use @file{testfont.tex} to get a font sample, as described above. + +To do the latter, run Metafont with no assignment to @code{mode}. This +should get you @code{proof} mode. You can then use GFtoDVI to get a DVI +file with one character per page, showing you the control points Limn +chose for the outlines. + +@item +Problems can arise at any stage. For example, the character spacing +might look wrong; in that case, you should fix the CMI files and rerun +Charspace (and all subsequent programs, naturally). Or the outlines +might not match the bitmaps very well; then you can change the +parameters to Limn, or use XBfe (@pxref{XBfe}) to hand-edit the bitmaps +so Limn will do a better job. (To eliminate some of tedium of fixing +digitization problems in the scanned image, you might want to use the +filtering options in Fontconvert before hand-editing; see @ref{Character +manipulation options}.) + +Inevitably, as one problem gets fixed you notice new ones @dots{} + +@end enumerate + + +@menu +* Font creation example:: A real-life example. +@end menu + +@node Font creation example, , , Creating fonts +@subsection Font creation example + +@cindex font creation, example of +@cindex creating a font, example of +@cindex example of font creation +@cindex Garamond roman, creating + +@cindex English, Paul +This section gives a real-life example of font creation for the Garamond +roman typeface, which we worked on concomitantly with developing the +programs. We started from a scanned type specimen of 30 point Monotype +Garamond, scanned using a Xerox 9700 scanner loaned to us from +Interleaf, Inc. (Thanks to Paul English and others at Interleaf for +this loan.) + +@enumerate + +To begin, we used Imageto as follows to look at the image file we had +scanned (@pxref{Viewing an image}). Each line is a separate command. +@example +imageto -strips ggmr.img +fontconvert -tfm ggmrsp.1200 +echo ggmrsp | tex strips.tex +xdvi -p 1200 -s 10 strips.dvi +@end example + +@item +@flindex ggmr.ifi +Next, we created the file @file{ggmr.ifi} (distributed in the +@file{data} directory), listing the characters in the order they +appeared in the image, guessing at baseline offsets and (if necessary) +including bounding box counts. Then we ran Imageto again, this time to +get information about the baselines and spurious blotches in the image. +We use the @samp{-encoding} option since some of the characters in the +image are not in the default @code{ASCII} encoding. +@example +imageto -print-guidelines -print-clean-info -encoding=gnulatin ggmr.img +@end example + +@item +Based on the information gleaned from that run, we decided on the final +baselines, adjusted the bounding box counts for broken-up characters, +and extracted the font (@pxref{Image to font conversion}). (In truth, +this took several iterations.) The design size of the original image +was stated in the book to be 30@dmn{pt}. We noticed several +blotches in the image we needed to ignore, and so we added +@code{.notdef} lines to @file{ggmr.ifi} as appropriate. +@example +imageto -verbose -baselines=121,130,120 \ + -designsize=30 -encoding=gnulatin ggmr.img +@end example + +@item +To smooth some of the rough edges caused by the scanner's rasterization +errors, we filtered the bitmaps with Fontconvert (@pxref{Fontconvert}). +@example +fontconvert -verbose -gf -tfm -filter-passes=3 -filter-size=3 \ + ggmr30.1200 -output=ggmr30a +@end example + +@item +For a first attempt at intercharacter and interword spacing, we created +@file{ggmr.1200cmi} (also distributed in the @file{data} directory) and +ran Charspace (@pxref{Charspace}), producing @file{ggmr30b.1200gf} and +@file{ggmr30b.tfm}. To see the results, we ran @file{ggmr30b} through +@file{testfont.tex}, modified the CMI file, reran Charspace, etc., until +the output was somewhat reasonable. We didn't try to fine-tune the +spacing here, since we knew the following steps would affect the +character shapes, which in turn would affect the spacing. +@example +charspace -verbose -cmi=ggmr.1200cmi ggmr30a.1200 -output=ggmr30b +@end example + +@item +Next we ran @file{ggmr30b.1200gf}, created by Charspace, through Limn to +produce the outline font in BZR form, @file{ggmr30b.bzr}. We couldn't +know what the best values of all the fitting parameters were the first +time, so we just increased the ones which are relative to the +resolution. +@example +limn -verbose -corner-surround=4 -filter-surround=6 \ + -filter-alternative-surround=3 -subdivide-surround=6 \ + -tangent-surround=6 ggmr30b.1200 +@end example + +@item +Then we converted @file{ggmr30b.bzr} to a Metafont program using BZRto +(@pxref{BZRto}), and then ran Metafont to create TFM and GF files we +could typeset with (@pxref{Metafont and BZRto}). In order to keep the +Metafont-generated files distinct from the original TFM and GF files, we +use the output stem @file{ggmr30B}. To see the results at the usual +10@dmn{pt}, we then ran the Metafont output through @file{sample.tex} (a +one-line wrapper for @file{testfont.tex}: @samp{\input testfont \sample +\end}). +@example +bzrto -verbose -metafont ggmr30b -output=ggmr30B +mf '\mode:=localfont; input ggmr30B' +echo ggmr30B | tex sample +dvips sample +@end example + +@item +This 10@dmn{pt} output looked too small to us. So we changed the design +size to 26@dmn{pt} (finding the value took several iterations) with +Fontconvert (@pxref{Fontconvert}), then reran Charspace, Limn, BZRto, +Metafont, etc., as above. We only show the Fontconvert step here; the +others have only the filenames changed from the invocations above. +@example +fontconvert -verbose -gf -tfm -designsize=26 ggmr30b.1200 -output=ggmr26c +@end example + +@item +After this, the real work begins. We ran the Metafont program +@file{ggmr26D.mf} in @code{proof} mode, followed by GFtoDVI, so we could +see how well Limn did at choosing the control points for the outlines. +@xref{Proofing with Metafont}. (The @code{nodisplays} tells Metafont +not to bother displaying each character in a window online.) +@example +mf '\mode:=proof; nodisplays; input ggmr26D' +gftodvi ggmr26D.3656gf +@end example + +@item +From this, we went and hand-edited the font @file{ggmr26d.1200gf} with +XBfe (@pxref{XBfe}), and/or tinkered with the options to Limn, trying to +make the outlines reasonable. We still haven't finished @dots{} +@end enumerate + + +@node Command-line options +@section Command-line options + +@cindex arguments, specifying program +@cindex command-line options, syntax of +@cindex options, specifying program +@cindex program arguments, syntax of +@cindex syntax of command-line options + +@findex getopt_long_only +Since these programs do not have counterparts on historical Unix +systems, they need not conform to an existing interface. We chose to +have all the programs use the GNU function @code{getopt_long_only} to +parse command lines. + +As a result, you can give the options in any order, interspersed as you +wish with non-option arguments; you can use @samp{-} or @samp{--} to +start an option; you can use any unambiguous abbreviation for an option +name; you can separate option names and values with either @samp{=} or +one or more spaces; and you can use filenames that would otherwise look +like options by putting them after an option @samp{--}. + +By convention, all the programs accept only one non-option argument, +which is taken to be the name of the main input file. + +If a particular option with a value is given more than once, it is the +last value which is used. + +For example, the following command line specifies the options +@samp{foo}, @samp{bar}, and @samp{verbose}; gives the value @samp{abc} +to the @samp{baz} option, and the value @samp{xyz} to the @samp{quux} +option; and specifies the filename @file{-myfile-}. + +@example +-foo --bar -verb -abc=baz -quux karl -quux xyz -- -myfile- +@end example + +@menu +* Main input file:: Each program operates on a ``main'' font. +* Options: Common options. Some options are accepted by all programs. +* Specifying character codes:: Ways of specifying single characters. +* Values: Common option values. Some options need more information. +@end menu + + +@node Main input file, Common options, , Command-line options +@subsection The main input file + +@cindex main input files +@cindex input filename, specifying + +By convention, all the programs accept only one non-option argument, +which they take to be the name of the main input file. + +Usually this is the name of a bitmap font. By their nature, bitmap +fonts are for a particular resolution. You can specify the resolution +in two ways: with the @samp{-dpi} option (see the next section), or by +giving an extension to the font name on the command line. + +For example, you could specify the font @code{foo} at a resolution of +300@dmn{dpi} to the program @var{program} in either of these two ways +(@samp{$ } being the shell prompt): +@example +$ @var{program} foo.300 +$ @var{program} -dpi=300 foo +@end example + +You can also say, e.g., @samp{@var{program} foo.300gf}, but the @samp{gf} is +ignored. These programs always look for a given font in PK format +before looking for it in GF format, under the assumption that if both +fonts exist, and have the same stem, they are the same. + +@xref{File lookups, , File lookups, kpathsea, Kpathsearch library}, for +more details of the filename lookup. + + +@node Common options +@subsection Common options + +@cindex options, common +@cindex arguments, common command-line + +Certain options are available in all or most of the programs. Rather +than writing identical descriptions in the chapters for each of the +programs, they are described here. + +This first table lists common options which do not convey anything about +the input. They merely direct the program to print additional output. + +@table @samp + +@item -help +@opindex -help +@cindex help, online +Prints a usage message listing all available options on standard error. +The program exits after doing so. + +@item -log +@opindex -log +@cindex log file +Write information about everything the program is doing to the file +@file{@var{foo}.log}, where @var{foo} is the root part of the main input +file. + +@item -verbose +@opindex -verbose +@cindex verbose output +@cindex progress reports +@cindex status reports +@cindex standard output, used for verbose output +@cindex file used for verbose output +Prints brief status reports as the program runs, typically the character +code of each character as it is processed. This usually goes to +standard output; but if the program is outputting other information +there, it goes to standard error. + +@item -version +@opindex -version +@cindex version number, finding +Prints the version number of the program on standard output. If a main +input file is supplied, processing continues; otherwise, the program +exits normally. + +@end table + +This second table lists common options which change the program's +behavior in more substantive ways. + +@table @samp + +@item -dpi @var{dpi} +@cindex dpi, specifying explicitly +@cindex resolution, specifying explicitly +@opindex -dpi +Look for the main input font at a resolution of @var{dpi} pixels per +inch. The default is to infer the information from the main input +filename (@pxref{Main input file}). + +@item -output-file @var{fname} +@opindex -output-file +Write the main output of the program to @var{fname}. If @var{fname} has +a suffix, it is used unchanged; otherwise, it is extended with some +standard suffix, such as @file{@var{resolution}gf}. Unless @var{fname} +is an absolute or explicitly relative pathname, the file is written in +the current directory. + +@item -range @code{@var{start}-@var{end}} +@opindex -range +Only look at the characters between the character codes @var{start} and +@var{end}, inclusive. The default is to look at all characters in the +font. @xref{Specifying character codes}, for the precise syntax of +character codes. + +@end table + + +@node Specifying character codes, Common option values, Common options, Command-line options +@subsection Specifying character codes + +@cindex character codes, specifying + +@flindex charcode.c +@flindex charspec.c +Most of the programs allow you to specify character codes for various +purposes. Character codes are always parsed in the same way (using the +routines in @file{lib/charcode.c} and @file{lib/charspec.c}). + +You can specify the character code directly, as a numeric value, +or indirectly, as a character name to be looked up in an encoding +vector. + +@menu +* Named character codes:: Character names are looked up in the encoding. +* Numeric character codes:: Decimal, octal, hex, or ASCII. +@end menu + + +@node Named character codes, Numeric character codes, , Specifying character codes +@subsubsection Named character codes + +@cindex character codes, as names +@cindex naming characters + +If a string being parsed as a character code is more than one character +long, or starts with a non-digit, it is always looked up as a name in +an encoding vector before being considered as a numeric code. We do +this because you can always specify a particular value in one of the +numeric formats, if that's what you want. + +The encoding vector used varies with the program; you can always define +an explicit encoding vector with the @samp{-encoding} option. If you +don't specify one explicitly, programs which must have an encoding +vector use a default; programs which can proceed without one do not. +@xref{Encoding files}, for more details on encoding vectors. + +As a practical matter, the only character names which have length one +are the 52 letters, @samp{A}--@samp{Z}, @samp{a}--@samp{z}. In virtually +all common cases, the encoding vector and the underlying character set +both have these in their ASCII positions. (The exception is machines +that use the EBCDIC encoding.) + + +@node Numeric character codes, , Named character codes, Specifying character codes +@subsubsection Numeric character codes + +@cindex character codes, numeric + +The following variations for numeric character codes are allowed. The +examples all assume the character set is ASCII. + +@itemize @bullet + +@item +@cindex octal character code +Octal numerals preceded by a zero are taken to be an octal number. For +example, @kbd{0113} also means decimal 75. If a would-be character code +starts with a zero but contains any characters other than the digits +@samp{0} through @samp{7}, it is invalid. + +@item +@cindex hexadecimal character code +Hexadecimal ``digits'' preceded by @samp{0x} or @samp{0X} are taken to +be a hexadecimal number. Case is irrelevant. For example, @kbd{0x4b}, +@kbd{0X4b}, @kbd{0x4B}, and @kbd{0X4B} all mean decimal 75. As with +octal, a would-be character code starting with @samp{0x} and containing +any characters other than @samp{0}--@samp{9}, @samp{a}--@samp{f}, and +@samp{A}--@samp{F} is invalid. + +@item +@cindex decimal character code +A decimal number (consisting of more than one numeral) is itself. For +example, @kbd{75} means the character code decimal 75. As before, a +would-be character code starting with @samp{1}--@samp{9} and containing +any characters other than @samp{0}--@samp{9} is invalid. + +@item +A single digit, or a single character not in the encoding vector as a +name, is taken to represent its value in the underlying character set. +For example, @kbd{K} means the character code decimal 75, and @kbd{0} +(the numeral zero) means the character code decimal 48 (if the machine +uses ASCII). + +@item +If the string being parsed as a character code starts with a digit, the +appropriate one of the previous cases is applied. If it starts with any +other character, the string is first looked up as a name. + +@end itemize + +@cindex maximum character code +Character codes must be between zero and 255 (decimal), inclusive. + + +@node Common option values, , Specifying character codes, Command-line options +@subsection Common option values + +@cindex common option values +@cindex option values +The programs have a few common conventions for how to specify option +values that are more complicated than simple numbers or strings. + +@cindex list as option values +@cindex option value of a list +@cindex option values, taking from a file +Some options take not a single value, but a list. In this case, the +individual values are separated by commas or whitespace, as in +@samp{-omit=1,2,3} or @samp{-omit="1 2 3"}. Although using whitespace to +separate the values is less convenient when typing them interactively, +it is useful when you have a list that is so long you want to put it in +the file. Then you can use @file{cat} in conjunction with shell quoting +to get the value: @samp{-omit="`cat file`"}. + +@cindex keyword/value list as option values +@cindex option value of a keyword/value list +Other options take a list of values, but each value is a keyword +and a corresponding quantity, as in @samp{-fontdimens +@var{name}:@var{real},@var{name},@var{real}}. + +@cindex percentages as option values +@cindex option value of a percentage +Finally, a few options take percentages, which you specify as an integer +between 0 and 100, inclusive. + + +@node Font searching +@section Font searching + +@cindex font searching algorithm + +These programs use the same environment variables and algorithms for +finding font files as does (the Unix port of) @TeX{} and its friends. + +You specify the default paths in the top-level Makefile. The +environment variables @code{TEXFONTS}, @code{PKFONTS}, @code{TEXPKS}, +and @code{GFFONTS} override those paths. Both the default paths and the +environment variable values should consist of a colon-separated list of +directories. + +@vindex GFFONTS @r{environment variable} +@vindex PKFONTS @r{environment variable} +@vindex TEXFONTS @r{environment variable} +@vindex TEXPKS @r{environment variable} +Specifically, a TFM file is looked for along the path specified by +@code{TEXFONTS}; a GF file along @code{GFFONTS}, then @code{TEXFONTS}; a +PK file along @code{PKFONTS}, then @code{TEXPKS}, then @code{TEXFONTS}. + +@xref{Path specifications, , Path specifications, kpathsea, Kpathsea +library}, for details of interpretation of environment variable values. + + +@node Font naming +@section Font naming + +@cindex naming font files +@cindex font files, naming + +Naming font files has always been a difficult proposition at best. On +the one hand, the names should be as portable as possible, so the +fonts themselves can be used on almost any platform. On the +other hand, the names should be as descriptive and comprehensive as +possible. The best compromise we have been able to work out is +described in a separate document: @ref{Top, , Introduction, fontname, +Filenames for @TeX{} fonts}. @xref{Archives}, for where to obtain. + +Filenames for GNU project fonts should start with @samp{g}, for the +``source'' abbreviation of ``GNU''. + +@cindex fonts, versions of +Aside from a general font naming scheme, when @emph{developing} fonts +you must keep the different versions straight. We do this by appending +a ``version letter'' @samp{a}, @samp{b}, @dots{} to the main bitmap +filename. For example, the original Garamond roman font we scanned was +a 30 point size, so the main filename was @file{ggmr30} (@samp{g} for +GNU, @samp{gm} for Garamond, @samp{r} for roman). As we ran the font +through the various programs, we named the output @file{ggmr30b}, +@file{ggmr30c}, and so on. + +@cindex outline fonts, naming +Since the outline fonts produced by BZRto are scalable, we do not +include the design size in their names. (BZRto removes a trailing +number from the input name by default.) diff --git a/doc/update.el b/doc/update.el new file mode 100644 index 0000000..4611cc9 --- /dev/null +++ b/doc/update.el @@ -0,0 +1,6 @@ +;;;; Driver to update all the node pointers and menus in the Texinfo source. + +(setq load-path (append '("/usr/local/gnu/lib/emacs/elisp") load-path)) +(require 'texinfo) +(texinfo-multiple-files-update "fontu.texi" t t) +(save-some-buffers t) diff --git a/doc/xbfe.texi b/doc/xbfe.texi new file mode 100644 index 0000000..46975ee --- /dev/null +++ b/doc/xbfe.texi @@ -0,0 +1,351 @@ +@c Copyright (C) 1992 Free Software Foundation. +@c This is part of the GNU font utilities manual. +@c For copying conditions, see the file fontutil.texi. + +@node XBfe, BZRedit, BPLtoBZR, Top +@chapter XBfe + +@pindex xbfe +@cindex bitmap fonts, hand-editing +@cindex hand-editing bitmap fonts +@cindex editing bitmap fonts + +XBfe (X Bitmap Font Editor) allows you to hand-edit a bitmap font---both +the shapes (i.e., the pixels) and the metric information (set widths, +side bearings, and kerning tables). + +The input is both a bitmap (GF or PK) font and a corresponding TFM file. +If you have only a bitmap font for some reason, you can make a TFM file +with Fontconvert (@pxref{Fontconvert output options}). XBfe outputs (at +your command) the edited files in the current directory @emph{with the +same name}, thus possibly replacing the input file. + +XBfe is intended to edit existing fonts, not create new ones. For +example, it does not provide a way to create new characters in a font. +(you can add characters to a font using Fontconvert, though; +@pxref{Character selection options}). In terms of its interaction with +the other font utilities, it is most useful for making character shapes +more amenable to Limn's outline fitting (@pxref{Limn}). + +@menu +* XBfe usage:: How to edit fonts. +* Invoking XBfe:: Command-line options. +@end menu + + +@node XBfe usage, Invoking XBfe, , XBfe +@section XBfe usage + +@cindex XBfe usage +@cindex usage of XBfe + +XBfe attempts to follow established user interface conventions for X +programs: + +@itemize @bullet + +@item +The location of the mouse determines where keyboard input goes. + +@item +In general, it is the release of a mouse button, and not its being +pressed, that causes action. + +@item +When you've finished typing a piece of information in one of the items +in the XBfe window, you must hit @key{RET} to cause action. + +@findex AsciiText @r{widget} +@cindex key bindings @r{in XBfe} +@item +The text editing facilities for such information are the defaults for +the @code{AsciiText} widget, which is Emacs-like bindings. + +@flindex .Xdefaults +@cindex XBfe resources, customizing +@cindex customizing XBfe resources +@item +You can customize the bindings of all actions described below, the fonts +used, window sizes, and so on, via your resource file @file{.Xdefaults}. +See the documentation in the file + +@example +.../mit/doc/tutorials/resources.txt +@end example + +@cindex class name of XBfe +@noindent in the X distribution if you aren't familiar with X resources. The +class name is @code{XBfe}. The font utilities distribution comes with +an application resource file @file{XBfe} (which must be installed for +the program to function properly); see that file for possibilities of +what you might change. + +@end itemize + +The sections below describe the specific operations XBfe provides. + +@menu +* Controlling XBfe:: Controlling XBfe. +* Shape: XBfe shape editing. Changing the pixels. +* Metrics: XBfe metrics editing. Changing the side bearings. +@end menu + + +@node Controlling XBfe , XBfe shape editing, , XBfe usage +@subsection Controlling XBfe + +This section describes a few operations which do not directly involve +editing, but rather managing of the editing session itself. + +@cindex XBfe, exiting +@cindex exiting XBfe +To exit XBfe, click on the @samp{Exit} button. Any changes made since +the last save are lost. + +@cindex XBfe, saving changes +@cindex saving changes in XBfe +@vindex TMPDIR +@flindex /tmp +To save changes, click on the @samp{Save} button. The new files are +written in the current directory---unless that would overwrite the input +files, in which case they are written to the directory @file{/tmp} (or +the value of the environment variable @code{TMPDIR}, if it's set). When +you exit XBfe normally, the files are moved from the temporary directory +to your current directory, thus possibly overwriting the input. + +@cindex XBfe, reverting characters +@cindex reverting characters in XBfe +@cindex undoing changes in XBfe +To go back to the last saved version of a character you are editing, +click on the @samp{Revert} button. This is useful when you've made +changes you didn't intend. If you exit without saving first, all +changes (since the last save) will be lost, as mentioned above. + +@cindex XBfe, changing characters +@cindex changing characters in XBfe +@cindex moving between characters in XBfe +@cindex next character, finding in XBfe +@cindex previous character, finding in XBfe +You can move to the previous character in the font, i.e., the one with +the character code next smallest to the current one, by clicking on the +@samp{Prev} button. Similarly, you can move to the next character by +clicking on the @samp{Next} button. You can move to a specified +character by typing its character code in the @samp{Char} item and +hitting @key{RET}. @xref{Specifying character codes}, for the various +possibilities for character codes. + + +@node XBfe shape editing, XBfe metrics editing, Controlling XBfe , XBfe usage +@subsection XBfe shape editing + +@cindex shape editing +@cindex character bitmap hand-editing +@cindex editing character bitmaps +@cindex hand-editing character bitmaps + +@cindex changing pixels +@cindex inverting pixels +@cindex pixels, changing +The most basic operation for editing character bitmaps is to change +black pixels to white or the reverse; put another way, inverting the +pixel the mouse is on. You do this by clicking the third mouse button. + +@cindex pen tracks +Technically, this is just a special case of changing more than one +pixel: when you press the third button, the current pixel inverts; then, +as you move the mouse, the pixels it touches change to the @emph{color +the first pixel changed to}. Thus, if you press the third button on a +white pixel, the mouse effectively becomes a ``black pen'' (until you +release the button). + +@menu +* Selections:: Marking pixel regions for later operations. +* Enlarging the bitmap:: Give yourself more room at the edges. +@end menu + + +@node Selections, Enlarging the bitmap, , XBfe shape editing +@subsubsection Selections + +@cindex selection of rectangles in bitmaps +@cindex bitmaps, selecting rectangles from +XBfe supports selection, pasting, and filling operations on a +rectangle of pixels, as follows. + +To select an arbitrary rectangle, press the left mouse button to +determine the first corner; then move the mouse (with the button still +down) to update the other corner of the rectangle; and release the +button to define the rectangle. (If you release the button when the mouse +is off the character bitmap, the selection rectangle remains unchanged.) + +@cindex pasting selections +@cindex selections, pasting +Once a rectangle has been selected, you can @dfn{paste} it, either +within the same character from which it was selected, or in a different +character. To do this, press the middle button; this outlines the +region that will be changed; as you move the mouse (with the button +still down), the outline moves accordingly; when you release the +middle button, the selected rectangle is pasted onto the current bitmap, +erasing whatever was in the affected area. + +@cindex pasting and flipping or rotating +@cindex flipping and pasting +@cindex rotation and flipping +Pasting has several variations: if you have the @kbd{Alt} (a.k.a.@: +Meta) key down when you release the middle button, the selection is +flipped vertically; if the @kbd{Control} key is down, the selection is +flipped horizontally; and if both are down, the selection is flipped in +both directions. Here is a minimal example: + +@example +@r{original} @r{vertical} @r{horizontal} @r{both} + ** * ** * + * ** * ** +@end example + +@cindex serifs, unifying +@cindex consistent serifs +@noindent This is useful when pasting serifs, since serifs are attached +to the main stems in different orientations. (Incidentally, +making the serif shapes consist of exactly the same pixels may actually +make the serifs look different, because of surrounding character +features or the difference in orientation. But it is still a good place +to start.) + +@cindex filling rectangles in XBfe +@cindex erasing rectangles in XBfe +@cindex selections, filling in XBfe +@cindex selections, erasing in XBfe +@cindex rectangles, filling in XBfe +@cindex rectangles, erasing in XBfe +You can also fill the selected rectangle, i.e., change it to entirely +black or white, by holding the @key{Alt} key down and pressing the right +mouse button. The selection is filled with the color of the pixel the +mouse is on. This is how you entirely erase a portion of the bitmap. + + +@node Enlarging the bitmap, , Selections, XBfe shape editing +@subsubsection Enlarging the bitmap + +@cindex enlarging bitmaps +@cindex bitmaps, enlarging + +You can enlarge the bitmap on all four sides by clicking on the +@samp{Expand} button; i.e., this adds one blank row at the top and +bottom, and one blank column at the left and right. This is useful when +you need to fill out a truncated curve, lengthen a stem or serif, etc. + +XBfe correspondingly changes the side bearings and baseline position so +that the origin of the character does not change. In other words, the +new row at the bottom is below the baseline, and the new columns are in +what was the side bearing space. You can change the baselines with +Fontconvert (@pxref{Character manipulation options}, and the side +bearings with Charspace (@pxref{Charspace}). + + +@node XBfe metrics editing, , XBfe shape editing, XBfe usage +@subsection XBfe metrics editing + +@cindex character metrics, hand-editing +@cindex metrics, hand-editing +@cindex hand-editing character metrics +@cindex editing character metrics + +@cindex side bearings, hand-editing +@cindex hand-editing side bearings +@cindex editing side bearings +You can change the left side bearing for the current character by typing +the new value in the @samp{lsb} item (and hitting @key{RET}, as always +for information you type). Likewise for the right side bearing and the +@samp{rsb} item. The side bearing values must be integers. + +@cindex kerns, hand-editing +@cindex hand-editing kerns +@cindex editing kerns +XBfe shows a box with any kerns for the current character. Each item in +the kern box looks like @samp{@var{code}: @var{kern}}, where @var{code} +is the character code (in decimal) of the character kerned with, and +@var{kern} is the kern distance (in pixels). You can edit the kern +distances just as with the side bearings; the values here are real +numbers. + +@cindex adding kerns +@cindex kerns, adding +@cindex deleting kerns +@cindex kerns, deleting +You can add new kerns by typing the character code of the new +kerned-with character in the @samp{Add kern} item; then a kern item with +that code is added to the kern box, with a distance of zero (which you +can then change to whatever you want). Similarly, you can delete a kern +by typing the character code in the @samp{Del kern} item. + + +@node Invoking XBfe, , XBfe usage, XBfe +@section Invoking XBfe + +@cindex XBfe options +@cindex invocation of XBfe +@cindex options for XBfe + +This section describes the options that XBfe accepts. +@xref{Command-line options}, for general option syntax. + +@table @samp + +@opindex -dpi +@item -dpi @var{unsigned} +The resolution, in pixels per inch. @xref{Common options}. + +@opindex -expansion +@cindex pixel expansion +@cindex expansion pixel display +@cindex displaying pixels +@item -expansion @var{unsigned} +Expand each pixel in the character bitmaps to this many pixels +square on the display; default is 12, i.e., each pixel in the original +bitmap will become a 12 by 12 rectangle. + +You can't use `=' here to separate the option name and value. + +@flindex .Xdefaults +@cindex resources for X +@cindex X resources +@vindex expansion @r{resource} +You can also set this value by setting the resource @samp{expansion} in +@file{.Xdefaults}. + +@opindex -initial-char +@cindex first character displayed +@cindex initial character displayed +@cindex character displayed, first +@item -initial-char @var{charcode} +Initially display the character @var{charcode}; default is the first +character in the font, i.e., the one with the lowest character code. + +@opindex -help +@item -help +Print a usage message. @xref{Common options}. + +@opindex -output-file +@item -output-file @var{filename} +Write the output to @file{@var{filename}.@var{dpi}gf} and +@file{@var{filename}.tfm}. The default is to use the name of the main +input file for @var{filename}. + +@opindex -version +@item -version +Print the version number. + +@end table + +@cindex X toolkit options +@cindex options, X toolkit +@opindex -display +@cindex X server, specifying +In addition to the above options, XBfe also accepts the standard X +toolkit options (and resources), such as @samp{-display} to specify the +X server to use. See the documentation for any X program for a +description of these options. Unlike the options above, you cannot use +@samp{--} to start X toolkit options, nor can you use @samp{=} to +separate option names and values; for example, neither @samp{--display +host:0} nor @samp{-display=host:0} are recognized. diff --git a/fontconvert/ChangeLog b/fontconvert/ChangeLog new file mode 100644 index 0000000..ec8be64 --- /dev/null +++ b/fontconvert/ChangeLog @@ -0,0 +1,604 @@ +Sat Mar 30 07:17:23 1996 Kathy Hargreaves <letters@cs.umb.edu> + + * output-epsf.c: don't assign NAME to OUTPUT_NAME, as NAME is + already it. Doc fix. + + * output-gf.c (gf_start_output): copy gf_name and write actual + filenames when prepending an `x' to the output filename. + +Fri Nov 24 07:03:53 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * main.c: call kpse_set_progname(argv[0]). + +Thu Nov 23 06:25:51 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * output-tfm.c: (tfm_start_output): call kpse_find_tfm instead of + find_tfm_filename. + + * main.c (tfm): Added warning about below to help. + + * output-tfm.c: (tfm_start_output): Added warning about outputting + to a file with the input PL filename except with an `x' prepended, + analogous to the one for the GF output filename. + +Mon Oct 16 06:11:45 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * output-tfm.c (tfm_start_output): no longer extend output_root to + have .pl for pl_name, as pltotf adds it (which may be a bug). + +Sat Aug 7 11:55:02 1993 Karl Berry (karl@cs.umb.edu) + + * *.h: types.h now in kpathsea. + +Thu Dec 3 15:40:46 1992 Karl Berry (karl@cs.umb.edu) + + * main.c: Don't bother to include getopt.h, cmdline.h already does. + +Tue Oct 27 13:01:55 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Fri Oct 23 14:15:22 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (main): Remove the -space option. + * output-gf.c (gf_finish_output): And remove the code that + implemented it. + (space_char): And this global. + * output-gf.h (space_char): And the decl. + +Tue Oct 20 11:54:55 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (main): Change the reporting so the space or newline + comes before the character, not after. + + * main.c (main): Don't remove the suffix when making the output + filename, as we already did; pass the input name to + `gf_start_output', not the full bitmap filename. + +Mon Oct 5 10:12:03 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (read_command_line): If -text is given, set `report_file' + to stderr. + +Sun Oct 4 14:03:53 1992 Karl Berry (karl@cs.umb.edu) + + * output-tfm.c (tfm_start_output): Report the TFM filename if we + are reading one. + + * main.c (main): Report the full pathname of the font, not just + what the user gave us. + + * main.c (main): Call `tfm_finish_output' before `gf_finish_output'. + +Tue Sep 22 16:30:25 1992 Karl Berry (karl@cs.umb.edu) + + * output-gf.c (gf_finish_output): output a newline after the space + char's code. + +Thu Sep 3 09:30:31 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Mon Aug 24 16:41:02 1992 Karl Berry (karl@hayley) + + * random.c (random_number): seed the random number with the + process ID. + +Sun Aug 23 13:37:00 1992 Karl Berry (karl@hayley) + + * main.c (USAGE): put a newline before concatenating GETOPT_USAGE. + +Fri Jul 3 19:12:36 1992 Karl Berry (karl@hayley) + + * main.c (encoding_name, encoding_info_ptr): delete these globals. + (most parsing routines): just use `encoding_info'. + + * main.c (read_command_line): use xparse_charspec for -space. + +Sat Jun 27 11:10:01 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (charspec.h, encoding.h, libfile.h): included. + (encoding_name, encoding_info, encoding_info_ptr): added. + (main): added newline after font_name report. + (USAGE): added `encoding', updated `omit' + (read_command_line): added `encoding' option. + (scan_*): use ARG_SEP instead of a comma. Use xparse_charspec + instead of xparse_charcode. + +Sun Jun 14 08:45:21 1992 Karl Berry (karl@hayley) + + * output-tfm.c (tfm_output_char): compare elt of `baseline_adjust' + to 0, not NULL. + + * output-tfm.c (tfm_do_chars_defaults): update for new tfm routines. + +Mon Jun 8 15:24:49 1992 Karl Berry (karl@hayley) + + * output-tfm.c (tfm_do_chars_defaults): pass kern list to + tfm_set_kern instead of the whole TFM char. + +Fri Jun 5 09:19:27 1992 Karl Berry (karl@hayley) + + * filter.c (filter_once): look at all the pixels, and don't crash + when `filter_size' is bigger than the bitmap. + + * main.c (main): `return 0' instead of `exit (0)'. (From Paul Eggert) + +Sun May 31 08:04:27 1992 Karl Berry (karl@hayley) + + * main.c: rename `design-size' option to `designsize'. + + * main.c (read_command_line): have the arg to -space be optional, + and make the default 32. + * output-gf.c (gf_finish_output): report the charcode of the space + if we output it. + + * output-tfm.c (tfm_start_font): new routine. + (main_input_font_p): new static. + (tfm_output_char): don't look in TFM file for the main font if + we're on some subsequent (concatenated) font. + * output-tfm.h (tfm_start_font): declare it. + * main.c (main): call it as we start each font. + + * main.c (main): report the input font names as we process them. + + * main.c (USAGE): doc fix. + +Sat May 30 14:54:37 1992 Karl Berry (karl@hayley) + + * output-tfm.c (tfm_start_output): remove any suffix before adding + `pl'; prepend an `x' if we'd overwrite the input. + (output_tfm_name): new static. + +Fri May 29 11:45:05 1992 Karl Berry (karl@hayley) + + * main.c (main): change return type to `int'. + +Wed May 27 10:38:45 1992 Karl Berry (karl@hayley) + + * main.c (main): remove `output_basename', and redo the code for + deciding on the output name. + +Sun May 24 12:40:38 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (fontname_list): doc change. + +Fri May 15 09:04:39 1992 Karl Berry (karl@hayley) + + * random.c (random_number): `srand' is now `seed_rand', `rand' + is `k_rand'. + +Mon May 4 09:31:34 1992 Karl Berry (karl@hayley) + + * output-tfm.c (tfm_do_chars_defaults, tfm_output_char, + tfm_finish_output): if we don't have an existing file, don't + read from it. + + * output-tfm.c (tfm_start_output): fix designsize algorithm. + + * main.c (report): remove; it's defined in report.c. + +Wed Apr 15 15:26:30 1992 Karl Berry (karl@hayley) + + * output-{gf,tfm}.c: `make_output_filename' is now `extend_filename'. + +Thu Apr 9 08:20:46 1992 Karl Berry (karl@hayley) + + * output-gf.c (gf_finish_output): convert the space width from + points to fixes. + +Wed Apr 8 15:16:17 1992 Karl Berry (karl@hayley) + + * output-gf.c (gf_finish_output): output a space character, if + desired. + (space_char): new global. + * gf-output.h (space_char): declare it. + * main.c (read_command_line): new option `-space' to set it. + (USAGE): document it. + +Fri Apr 3 13:30:02 1992 Karl Berry (karl@hayley) + + * random.c: include rand.h; remove conditional decls of RAND_MAX, + rand, srand. + +Sun Mar 29 19:10:18 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): remove empty else. + +Sat Mar 28 07:48:07 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Wed Mar 25 08:30:41 1992 Karl Berry (karl at hayley) + + * random.c [!STDC_HEADERS]: declare rand, srand. + [!RAND_MAX]: define RAND_MAX. + (random_number): use rand instead of drand48. + +Mon Mar 23 14:59:49 1992 Kathy Hargreaves (kathy at hayley) + + * output-tfm.c (tfm_start_output): only try to set design size to + user's if it's been set. + +Sun Mar 22 13:46:31 1992 Kathy Hargreaves (kathy at hayley) + + * output_gf.[hc] (gf_output_char): added DESIGN_SIZE_RATIO. + Multiply char's TFM width by this. + + * main.c [design_size_ratio]: added. + + * main.c (main): if unset, set design_size to the bitmap one *after* + calling tfm_set_design_size, and then check that it's in range. + + * output_tfm.c (tfm_start_output): added USER_DESIGN_SIZE. + Call with `design_size' for USER_DESIGN_SIZE and the bitmap's + design size for DEFAULT_DESIGN_SIZE. + After saving value in new variable `tfm_file_design_size', zero + out tfm_info's design size if got it from a TFM file. After + calling tfm_set_header, try setting design_size in following + order: to USER_DESIGN_SIZE, tfm_file_design_size, + DEFAULT_DESIGN_SIZE. + +Sat Mar 21 11:53:04 1992 Kathy Hargreaves (kathy at hayley) + + * output_tfm.c (tfm_start_output): set the fontsize if wasn't done + already as a TFM header option. + Move TFM_CHECK_DESIGNSIZE from main. + Set design size to the default only if it isn't set yet. + +Thu Mar 19 12:52:46 1992 Kathy Hargreaves (kathy at hayley) + + * output_tfm.c (tfm_output_char): OR (not AND) the conditions for + recalculating dimensions and italic corrections. + +Wed Mar 18 12:20:38 1992 Kathy Hargreaves (kathy at hayley) + + * output-tfm.c (tfm_do_chars_defaults): added. + + * output-tfm.c (tfm_output_char): only recalculate dimensions and + initialize the italic correction if we've altered the bitmap; + otherwise, use that of the original TFM character. + + * output-tfm.c (tfm_finish_output): moved tfm_close_input_file + from tfm_start_output to here. + +Tue Mar 17 16:01:09 1992 Kathy Hargreaves (kathy at hayley) + + * main.c [USAGE], (read_command_line): added design-size option. + (global): moved `design_size' from main. + + * main.c (do_char): filter bitmap if `filter_passes' > 0. + + * filter.[hc]: deleted `wants_filter'; default `filter_passes' to 0. + + * main.c [USAGE], (read_command_line): deleted -filter option. + + * output_tfm.c (tfm_start_ouput): fill in nonrequested TFM header + items and fontdimens with tfm_info from input_basename.tfm, if + it exists. If it does, zero out the checksum. + + +Mon Mar 16 12:28:15 1992 Kathy Hargreaves (kathy at hayley) + + * output_tfm.c (tfm_start_ouput): call tfm_set_header. + Set tfm_info's design size only if unset. + + * main.c [USAGE], (read_command_line): added -tfm-header option. + +Sun Mar 15 16:49:32 1992 Karl Berry (karl at hayley) + + * main.c: doc fix. + +Sat Mar 7 13:11:59 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main): fatal if wants_gf and want_tfm and the output + filename has a suffix. + +Sat Mar 7 09:52:57 1992 Karl Berry (karl at hayley) + + * GNUmakefile (libraries): define again. + (files, headers, sources): replace with `c_and_h', etc. + +Thu Mar 5 17:50:04 1992 Karl Berry (karl at claude.cs.umb.edu) + + * main.c (do_char): do the baseline adjustment after + randomization, to preserve the baselines when randomizing. + * random.c (randomize_bitmap): return the number of rows/columns + added at each side of the bitmap. + * random.h (randomize_bitmap): change declaration. + + * main.c (do_char): use puts instead of printf where possible. + +Wed Mar 4 15:31:23 1992 Kathy Hargreaves (kathy at hayley) + + * output_tfm.c (tfm_start_output): changed OUTPUT_BASENAME to + OUTPUT_NAME and call make_output_filename to make pl_name. + + * output_epst.c (epsf_start_output): changed global + `output_basename' to `output_name' and BASE_NAME to NAME. + Fatal if NAME has a suffix. + + * output-gf.c (gf_start_output): changed `font_basename' to + `output_name' and call make_output_filename to make gf_name. + +Wed Mar 4 11:18:22 1992 Karl Berry (karl at hayley) + + * GNUmakefile (libraries): remove. + +Mon Feb 10 16:09:25 1992 Karl Berry (karl at claude.cs.umb.edu) + + * random.c (random_threshold): new global to say how often to move a + pixel at all. + * random.h (random_threshold): declare it. + * main.c (read_command_line): new option `random-threshold. + + * output-tfm.c (tfm_start_output): check for a TFM file if the + user hasn't given us a fontdimen string. Take the input + filename to construct the TFM name. + * output-tfm.h (tfm_start_output): change declaration. + * main.c (main): change call. + +Mon Feb 10 10:04:00 1992 Karl Berry (karl at hayley) + + * main.c (do_split_char, do_char): free the bitmap here. + (main): not here. + + * random.c (randomize_bitmap): fix algorithm for pixels moved more + than one. + +Thu Feb 6 18:26:11 1992 Karl Berry (karl at claude.cs.umb.edu) + + * random.c (enlarge_bitmap): return the result, of changing an arg. + + * random.c: do not include global.h and <math.h>; they already are. + +Sat Feb 1 15:16:13 1992 Karl Berry (karl at hayley) + + * output-gf.c: include filename.h. + +Fri Jan 31 17:07:31 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): declare `option_index' (for new + getopt). + +Wed Jan 22 12:49:25 1992 Kathy Hargreaves (kathy at hayley) + + * output-gf.c (gf_start_output): use make_prefix instead of concat + when prepending an `x' onto a filename. + +Thu Jan 9 08:30:12 1992 Karl Berry (karl at hayley) + + * main.c (scan_column_split): rename `scan_integer_list' to + `scan_unsigned_list'. + + * *.c: do not include global.h. + + * *.h: remove #pragma once. + +Wed Jan 8 15:28:56 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + +Mon Jan 6 16:49:26 1992 Karl Berry (karl at claude.cs.umb.edu) + + * main.c (USAGE): new option `randomize'. + (do_char): if set, call `randomize_bitmap'. + * random.[ch]: new files. + (random_max): new global. + +Thu Sep 12 10:24:14 1991 Karl Berry (karl at hayley) + + * main.c (read_command_line): new option, `-epsf'. + (main): initialize and finalize epsf output (if desired). + (do_char): output the characters in epsf (if desired). + * epsf-output.[ch]: new files. + * GNUmakefile (files): add `epsf-output'. + + * output-tfm.c (tfm_output_char): set the character code. + +Tue Jul 30 13:17:47 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Mon Jun 17 15:21:49 1991 Karl Berry (karl at hayley) + + * output-tfm.c (tfm_output_char): change calls to `PIXELS_TO_POINTS'. + +Thu Jun 6 07:26:13 1991 Karl Berry (karl at hayley) + + * All files: change to version 2 of the GPL. + +Sun Mar 24 16:22:44 1991 Karl Berry (karl at hayley) + + * main.c (read_command_line): don't concatenate with the old + fontdimens, just assign `fontdimens' from the argument. + * output-tfm.c (fontdimens): move definition of global here from + `main.c'. + * output-tfm.h (fontdimens): declare it. + +Sun Mar 10 10:21:52 1991 Karl Berry (karl at hayley) + + * output-tfm.c (tfm_start_output): call `tfm_init_global_info', + and don't bother setting the checksum and coding scheme. + +Sat Mar 9 16:17:39 1991 Karl Berry (karl at hayley) + + * GNUmakefile (files): add main, since we now have main.h. + * main.h: new file. + * main.c (read_command_line): new option `-fontdimens'. + * output-tfm.c (tfm_start_output): set the font parameters + according to -fontdimens. + +Thu Mar 7 07:32:21 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Tue Mar 5 15:19:04 1991 Karl Berry (karl at hayley) + + * main.c (scan_baseline_adjust): new routine. + (baseline_adjust): new global variable. + (read_command_line): new option `-baseline-adjust'. + (do_char): adjust the baselines of each character before we + process it. + +Mon Mar 4 14:42:30 1991 Karl Berry (karl at hayley) + + * main.c (do_char): don't do a character if we've already done it. + + * main.c (fontname_list): new global variable to hold all the + fonts we deal with. + (read_command_line): new option `-concat-lists'. + +Tue Feb 26 06:45:57 1991 Karl Berry (karl at hayley) + + * output-tfm.c (tfm_finish_output): call `tfm_convert_pl' with the + argument `verbose'. + +Mon Feb 25 13:30:57 1991 Karl Berry (karl at hayley) + + * output-gf.c: use `gf_...' instead of `..._gf_...'. + + * output-tfm.c: use `tfm_...' instead of `..._tfm_...'. + + * output-gf.c: include file-misc.h. + +Sun Feb 17 09:30:23 1991 Karl Berry (karl at hayley) + + * *.c: include config.h. + +Sun Jan 13 16:49:03 1991 Karl Berry (karl at hayley) + + * main.c (read_command_line): set `explicit_dpi' via the option + table. + +Mon Jan 7 15:09:15 1991 Karl Berry (karl at hayley) + + * main.c: include file-misc.h. + +Sun Nov 4 09:23:28 1990 Karl Berry (karl at hayley) + + * filter.c (read_command_line): use atou to do -filter-size. + + * These changes suggested by rich@rice.edu: + * filter.h (filter_passes): declare it. + * filter.c (filter_passes): new variable. + (filter_bitmap): loop through the number of passes. + (filter_once): new routine. + * main.c (read_command_line): new option, `filter-passes'. + * README: warn that filtering rounds off corners. + +Wed Oct 24 14:58:15 1990 Karl Berry (karl at aten) + + * Version 0.1. + +Sun Oct 14 07:05:51 1990 Karl Berry (karl at hayley) + + * filter.c (filter_bitmap): don't invert the pixel, set it to the + right intensity. + +Tue Oct 9 09:43:03 1990 Karl Berry (karl at hayley) + + * main.c (read_command_line): new option, -output-file. + (output_name): new global. + (main): use it, if it's set. + + * main.c (do_split_char, do_char, scan_column_split): new + routines. + (read_command_line): new argument, -column-split. + (main): split each character at given columns, if requested. + +Mon Oct 8 05:55:50 1990 Karl Berry (karl at hayley) + + * main.c: include cmdline.h. + + * main.c (main): filter the character, if desired. + (read_command_line): new options -filter, -filter-size, + -filter-threshold. + * filter.h, filter.c: new files. + * GNUmakefile (files): add filter. + (This stuff contributed by rich@rice.edu.) + +Tue Oct 2 17:25:22 1990 Karl Berry (karl at hayley) + + * output-gf.c (gf_start_output): assign to gf_name after the + warning, not before. + +Sat Sep 29 07:10:11 1990 Karl Berry (karl at hayley) + + * output-gf.c (gf_start_output): announce it to the user when we + change the output filename. + + * main.c (main): use atou (dpi), not atoi. + +Fri Sep 28 13:47:34 1990 Karl Berry (karl at hayley) + + * main.c (read_command_line): new argument, `omit'. + (scan_remap_list): don't make a target character code of -1 mean + omit the original. + (scan_omit_list): new routine. + +Fri Sep 21 11:32:45 1990 Karl Berry (karl at hayley) + + * main.c (read_command_line): return NULL at the end. + +Fri Sep 14 12:01:26 1990 Karl Berry (karl at hayley) + + * main.c: include "getopt.h", not <getopt.h>. + +Thu Sep 13 10:58:45 1990 Karl Berry (karl at hayley) + + * main.c (main): report omitted characters. + +Tue Sep 11 07:02:50 1990 Karl Berry (karl at hayley) + + * main.c (scan_remap_list): set `omit' if a target ``character + code'' is -1. Also, parse the character codes correctly. + (omit): new global variable. + (main): if `omit' is true, skip the character. + +Sat Sep 8 10:58:03 1990 Karl Berry (karl at hayley) + + * main.c (scan_remap_list): use PARSE_CHAR_CODE. + + * main.c (read_command_line): use GET_RANGE. + +Thu Sep 6 06:42:24 1990 Karl Berry (karl at hayley) + + * main.c (scan_remap_list): new routine. + (read_command_line): new option, -remap. + (translate): new global to remap character codes. + (main): map each character as we read it. + +Wed Sep 5 06:22:18 1990 Karl Berry (karl at hayley) + + * output-gf.c (gf_start_output): don't overwrite the input file. + * main.c (main): pass the filename of the input font. + + * main.c (main): output a GF file if asked. + (read_command_line): new option, -gf. + * output-gf.[ch]: new files. + * GNUmakefile (files): add them. + + * main.c (main): free the bitmap for each character. */ + + * main.c (main): output a TFM file if asked. + (read_command_line): new option, -tfm. + * output-tfm.[ch]: new files. + * GNUmakefile (files): add them. + +Sat Sep 1 09:27:14 1990 Karl Berry (karl at hayley) + + * main.c (main): output a newline at the end of the program if + warranted. + + * main.c (main): use `get_bitmap_font' instead of `get_font'. + +Sat Aug 25 13:52:43 1990 Karl Berry (karl at hayley) + + * main.c (main): print a newline before each character output as + text. diff --git a/fontconvert/GNUmakefile b/fontconvert/GNUmakefile new file mode 100644 index 0000000..f8dec27 --- /dev/null +++ b/fontconvert/GNUmakefile @@ -0,0 +1,29 @@ +# Makefile for font conversion program. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +program = fontconvert + +c_and_h = filter main output-epsf output-gf output-tfm random +c_only = version + +libraries = $(bitmap_libs) tfm + +include ../data/defs.make +include ../data/defsprog.make + +include M.depend diff --git a/fontconvert/README b/fontconvert/README new file mode 100644 index 0000000..e5da2ac --- /dev/null +++ b/fontconvert/README @@ -0,0 +1,18 @@ +This program converts a bitmap font file to ``something else''. For +example, a representation as plain text; a TFM file; or a GF file. + +Plain text is useful if you want to see exactly which pixels are on and +off in the bitmaps. + +Having a TFM file is necessary to use the font with TeX. No side +bearings, kerning, or ligature information is added to the TFM file, so +it is only useful for proofing, but that's better than nothing. + +You can also select a range of characters, omit individual characters, +and change the character codes. With these options, you want to output +another bitmap file; hence, the last option. + +You can also filter the bitmaps through a simple averaging filter. This +is useful as a preliminary cleanup of scanned images. The filtering +removes a fair amount of the noise, but it also fills in and/or rounds +off sharp corners. diff --git a/fontconvert/filter.c b/fontconvert/filter.c new file mode 100644 index 0000000..29fed9d --- /dev/null +++ b/fontconvert/filter.c @@ -0,0 +1,101 @@ +/* filter.c: run an averaging filter over a bitmap. + This code is based on an initial implementation written by Richard Murphey. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "filter.h" + + +/* How many passes to make over the bitmap. (-filter-passes) */ +unsigned filter_passes = 0; + +/* How many rows and columns of neighbors to look at; i.e., a side of + the filter cell is `filter_size' * 2 - 1. Although only values > 0 + are meaningful, if we make it unsigned, comparisons to ints below + fail. (-filter-size) */ +int filter_size = 1; + +/* The filter threshold at which we change the pixel. + (-filter-threshold) */ +real filter_threshold = .5; + + +static void filter_once (bitmap_type); + +/* Filter the bitmap B `filter_passes' times. */ + +void +filter_bitmap (bitmap_type b) +{ + unsigned this_pass; + + for (this_pass = 0; this_pass < filter_passes; this_pass++) + filter_once (b); +} + + +/* Filter the bitmap in B with an averaging filter. See, for example, + Digital Image Processing, by Rosenfeld and Kak. The general idea is + to average the intensity of the neighbors of each pixel. If the + difference between the pixel value and the intensity is more than + `filter_threshold', flip the value of the pixel. */ + +static void +filter_once (bitmap_type b) +{ + unsigned row, col; + unsigned all_black = SQUARE (2 * filter_size + 1) - 1; + unsigned t = filter_threshold * all_black; /* Rounded threshold. */ + + /* For each pixel in the bitmap... */ + for (row = 0; row < BITMAP_HEIGHT (b); row++) + { + /* Don't look at pixels outside the bitmap. */ + unsigned min_row = MAX ((int) row - filter_size, 0); + unsigned max_row = MIN (row + filter_size, BITMAP_HEIGHT (b) - 1); + + for (col = 0; col < BITMAP_WIDTH (b); col++) + { + int cell_row, cell_col; + unsigned sum = 0; + + unsigned min_col = MAX ((int) col - filter_size, 0); + unsigned max_col = MIN (col + filter_size, BITMAP_WIDTH (b) - 1); + + /* For each pixel in the cell... */ + for (cell_row = min_row; cell_row <= max_row; cell_row++) + for (cell_col = min_col; cell_col <= max_col; cell_col++) + { + sum += BITMAP_PIXEL (b, cell_row, cell_col); + } + + /* Subtract the value for the pixel we're actually on. I'm not + sure why this is a good idea. (It is much more efficient to + do this than test for every pixel, though.) */ + sum -= BITMAP_PIXEL (b, row, col); + + /* We've computed the sum of the neighbors. Now change the + pixel if the difference is greater than the threshold. Doing + integer arithmetic is not as precise as floating point (since + the threshold is rounded), but it's much faster. */ + if (abs (sum - (all_black * BITMAP_PIXEL (b, row, col))) > t) + BITMAP_PIXEL (b, row, col) = ((double) sum) / all_black; + } + } +} diff --git a/fontconvert/filter.h b/fontconvert/filter.h new file mode 100644 index 0000000..0e1dc4b --- /dev/null +++ b/fontconvert/filter.h @@ -0,0 +1,33 @@ +/* filter.h: declarations for filtering a bitmap. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILTER_H +#define FILTER_H + +#include <kpathsea/types.h> +#include "bitmap.h" + + +/* See filter.c. */ +extern unsigned filter_passes; +extern int filter_size; +extern real filter_threshold; + +extern void filter_bitmap (bitmap_type); + +#endif /* not FILTER_H */ diff --git a/fontconvert/main.c b/fontconvert/main.c new file mode 100644 index 0000000..a50b311 --- /dev/null +++ b/fontconvert/main.c @@ -0,0 +1,747 @@ +/* fontconvert -- various operations on a bitmap font. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "charspec.h" +#include "cmdline.h" +#include "encoding.h" +#include "font.h" +#include "libfile.h" +#include "list.h" +#include "report.h" + +#include "filter.h" +#include "output-epsf.h" +#include "output-gf.h" +#include "output-tfm.h" +#include "random.h" + + +/* How much to adjust the baseline of output characters by. We rely on + this being initialized to all zeros by C. (-baseline-adjust) */ +int baseline_adjust[MAX_CHARCODE + 1]; + +/* If `column_split[N]' is non-NULL, we break character N into new + characters at each of the columns specified. We depend on this being + initialized to all zeros. (-column-split) */ +int *column_split[MAX_CHARCODE + 1]; + +/* The names of fonts to be concatenated onto the main font in the + output. (-concat) */ +list_type fontname_list; + +/* The resolution of the font we will read, in pixels per inch. We + don't deal with nonsquare pixels. (-dpi) */ +string dpi = "300"; + +/* The design size which will affect both the GF and TFM output, unless + the tfm-header `designsize' option overrides it. (-designsize) + `design_size_ratio' is the ratio of the input design size to the + output design size. */ +real design_size = 0.0; +static real design_size_ratio; + +/* The name of the encoding file specified by the user, and the + structure we parse it into. (-encoding) */ +static encoding_info_type *encoding_info = NULL; + +/* If `omit[n]' is true for an element N, we throw away that character + in that output. (-omit) */ +static boolean omit[MAX_CHARCODE + 1]; + +/* An explicitly specified output filename. (-output-file) */ +const_string output_name = NULL; + +/* Says which characters we should process. This is independent of the + ordering in the font file. (-range) */ +int starting_char = 0; +int ending_char = MAX_CHARCODE; + +/* The variable `translate' maps character codes in the input font to + character codes in the output; by default, maps everything to + themselves. (-remap) */ +charcode_type translate[MAX_CHARCODE + 1]; + +/* Says whether to output an EPS file for each character. (-epsf) */ +boolean wants_epsf = false; + +/* Says whether to output a GF file. (-gf) */ +boolean wants_gf = false; + +/* Says whether to output the font as plain text. (-text) */ +boolean wants_text = false; + +/* Says whether to output a TFM file. (-tfm) */ +boolean wants_tfm = false; + + + +static void append_concat_list (list_type *, string); +static bitmap_type column_extract (bitmap_type, unsigned, unsigned); +static void do_char (char_info_type); +static void do_split_char (char_info_type, int[]); +static string read_command_line (int, string []); +static void scan_baseline_adjust (string); +static void scan_column_split (string); +static void scan_omit_list (string); +static void scan_remap_list (string); + +/* Fontconvert provides a grabbag of operations: almost every + manipulation on bitmap fonts we found useful we threw here. */ + +int +main (int argc, string argv[]) +{ + int code; + bitmap_font_type f; + string *first_element; + string font_name; + unsigned this_font; + unsigned char_count = 0; + + /* Use Kpathsea path searching. */ + kpse_set_progname (argv[0]); + + /* Initialize the character code translation array before parsing the + command line, since we probably will not be told to remap every + character. */ + for (code = 0; code <= MAX_CHARCODE; code++) + translate[code] = code; + + /* Initialize the list of fonts to do to have one empty element at the + beginning, which we will fill in with the main font name. */ + fontname_list = list_init (); + first_element = LIST_TAPPEND (&fontname_list, string); + + /* Read all the arguments. */ + font_name = read_command_line (argc, argv); + + /* Put the main font name in the list. */ + *first_element = font_name; + + /* If no output name was specified on the command line, use the root + part of the input name. We've already removed the suffix in + `read_command_line'. */ + if (output_name == NULL) + output_name = basename (font_name); + + if (wants_gf && wants_tfm && find_suffix (output_name) != NULL) + FATAL ("The GF and TFM output files' suffixes can't be the same"); + + /* Open the main font specially, since we need to know some basic + information for most of the output formats. We don't need to close + it again, as opening a font twice does no harm. */ + f = get_bitmap_font (font_name, atou (dpi)); + + if (wants_epsf) + epsf_start_output (output_name); + if (wants_gf) + gf_start_output (font_name, output_name, dpi, + BITMAP_FONT_COMMENT (f)); + if (wants_tfm) + tfm_start_output (font_name, output_name, design_size, + BITMAP_FONT_DESIGN_SIZE (f)); + + + /* Have to do this after `tfm_start_output', as it needs to know if + design_size is set or not. */ + if (design_size == 0.0) + design_size = BITMAP_FONT_DESIGN_SIZE (f); + + design_size_ratio = BITMAP_FONT_DESIGN_SIZE (f) / design_size; + + /* Go through each input font. */ + for (this_font = 0; this_font < LIST_SIZE (fontname_list); this_font++) + { + string font_name = *(string *) LIST_ELT (fontname_list, this_font); + f = get_bitmap_font (font_name, atou (dpi)); + + if (wants_tfm) + tfm_start_font (font_name); + + REPORT1 ("(%s", BITMAP_FONT_FILENAME (f)); + + /* The main loop: convert each character. */ + for (code = starting_char; code <= ending_char; code++) + { + char_info_type *c = get_char (font_name, code); + + if (c == NULL) continue; + + REPORT2 ("%c[%u", ++char_count % 8 ? ' ' : '\n', code); + + if (omit[code]) + REPORT (" omit"); + else + { + /* If this character isn't supposed to split, just output it. + Otherwise, output each of the pieces after splitting. */ + if (column_split[code] == NULL) + do_char (*c); + else + do_split_char (*c, column_split[code]); + } + + REPORT ("]"); + } + + close_font (font_name); + REPORT (")\n"); + } + + if (wants_epsf) + epsf_finish_output (); + + /* We must finish the TFM output before GF, because `gf_finish_output' + might want to open a TFM file -- and we can only have one TFM file + open at a time. (Because we haven't rewritten the TFM library.) */ + if (wants_tfm) + tfm_finish_output (); + + if (wants_gf) + gf_finish_output (design_size, atof (dpi)); + + return 0; +} + +/* Output the character in whatever forms have been requested. */ + +static void +do_char (char_info_type c) +{ + static boolean char_done_p[MAX_CHARCODE + 1]; + + charcode_type original_code = CHARCODE (c); + + /* Do the character code translation. */ + charcode_type code = CHARCODE (c) = translate[original_code]; + + if (char_done_p[code]) + { + WARNING1 ("Character %d already output", CHARCODE (c)); + return; + } + + char_done_p[code] = true; + + if (filter_passes > 0) + filter_bitmap (CHAR_BITMAP (c)); + + if (random_max > 0.0) + { + bounding_box_type adjust_bb; + randomize_bitmap (&CHAR_BITMAP (c), &adjust_bb); + CHAR_MIN_ROW (c) -= MIN_ROW (adjust_bb); + CHAR_MAX_ROW (c) += MAX_ROW (adjust_bb); + CHAR_MIN_COL (c) -= MIN_COL (adjust_bb); + CHAR_MAX_COL (c) += MAX_COL (adjust_bb); + } + + /* If the `baseline_adjust' value is positive, the baseline should + move up, i.e., we subtract from the height and add to the depth. + But since the depth is represented as the minimum row, which can be + negative, we must subtract from it to make it ``larger''. */ + CHAR_MIN_ROW (c) -= baseline_adjust[code]; + CHAR_MAX_ROW (c) -= baseline_adjust[code]; + + /* Text output is already implemented in the library. */ + if (wants_text) + { + puts ("\f"); + print_char (stdout, c); + } + + if (wants_epsf) + epsf_output_char (c); + + if (wants_gf) + gf_output_char (c, design_size_ratio); + + if (wants_tfm) + tfm_output_char (c, atof (dpi)); + + if (original_code != code) + REPORT1 ("->%u", code); + + /* Free the space here, instead of in the caller, since we may + change the bitmap. */ + free_bitmap (&CHAR_BITMAP (c)); +} + + +/* Output the character C in pieces, the division points being the + columns in SPLIT. */ + +static void +do_split_char (char_info_type c, int split[]) +{ + unsigned last_col = 0; + unsigned n_split = 0; + + REPORT (" ("); + + /* We exit the loop after splitting the last character. */ + while (true) + { + int diff; + char_info_type split_char = c; + int this_col = *split++; + unsigned split_col = this_col != -1 + ? this_col : BITMAP_WIDTH (CHAR_BITMAP (c)); + + /* Change the character code of this piece. */ + CHARCODE (split_char) += n_split; + + REPORT1 ("%u", CHARCODE (split_char)); + + /* Take the chunk from the big bitmap. */ + CHAR_BITMAP (split_char) + = column_extract (CHAR_BITMAP (c), last_col, split_col); + + /* Move the right column over. */ + diff = BITMAP_WIDTH (CHAR_BITMAP (c)) + - BITMAP_WIDTH (CHAR_BITMAP (split_char)); + CHAR_MAX_COL (split_char) -= diff; + CHAR_SET_WIDTH (split_char) -= diff; + + /* Output it. */ + do_char (split_char); + + /* Exit the loop if we just output the last piece. */ + if (this_col == -1) + break; + + n_split++; + last_col = this_col; + REPORT (","); + } + + REPORT (")"); + free_bitmap (&CHAR_BITMAP (c)); +} + +/* Return the part of the bitmap SOURCE that lies between the columns + START and FINISH - 1, inclusive. */ + +static bitmap_type +column_extract (bitmap_type source, unsigned start, unsigned finish) +{ + unsigned this_row; + dimensions_type d = { BITMAP_HEIGHT (source), finish - start }; + bitmap_type answer = new_bitmap (d); + + /* Move to the given starting column. */ + BITMAP_BITS (source) += start; + + for (this_row = 0; this_row < BITMAP_HEIGHT (source); this_row++) + { + one_byte *answer_row = BITMAP_ROW (answer, this_row); + + memcpy (answer_row, BITMAP_BITS (source), BITMAP_WIDTH (answer)); + BITMAP_BITS (source) += BITMAP_WIDTH (source); + } + + return answer; +} + +/* Reading the options. */ + +/* This is defined in version.c. */ +extern string version_string; + +#define USAGE "Options: +<font_name> should be a filename, possibly with a resolution, e.g., + `cmr10' or `cmr10.300'.\n" \ + GETOPT_USAGE \ +"baseline-adjust <char1>:<integer1>,<char2>:<integer2>,...: move the baseline + of each <char> by the corresponding <integer>. A positive number + moves the baseline up, a negative one down. +column-split <char>@<column1>,...,<columnN>: split the character with + code <char> (before remapping) before each of the <column>s, producing n + new characters, with codes <char>, <char> + 1, ..., <char> + n, whose + bitmaps go from 0 to <column1> - 1 (inclusive), then <column1> to + <column2> - 1, ..., from <columnN> to the bitmap width. + Give the <column>s in bitmap coordinates, i.e., starting at zero. + To split more than one character, give this option for each. +concat <font_name>,<font_name>,...: concatenate the main input font with + the given <font_name>s; if a character code exists in more than one + font, it's the first occurrence that counts. +designsize <real>: use this as the design size for both the GF and TFM + output files, if any, unless overridden by `designsize' in the + `tfm-header' option. +dpi <unsigned>: use a resolution of <unsigned>; default is 300. +encoding <filename>: read encoding information for the character specs + from `<filename>.enc'; there is no default. Must come before any + options which use character specs. +epsf: output each character as an Encapsulated PostScript file named + <font_name>-<code>.eps, where <code> is the character code in decimal. +filter-passes <unsigned>: do the filtering this many times on each + character; default is 0. +filter-size <unsigned>: half the size of the filter cell, i.e., a side + is this number * 2 + 1; default is 1. +filter-threshold <real>: if the average of the pixels in the filter cell + is greater than this, change the pixel; default is .5. +fontdimens <fontdimen>:<real>,<fontdimen>:<real>,...: assign each <real> + to the corresponding <fontdimen> when outputting a TFM file. A + <fontdimen> can be either one of the standard names (in either upper + or lowercase), or a number between 1 and 30. Each <real> is taken to + be in points (except in the case of the <fontdimen> `slant' (parameter + 1), which is a dimensionless number). +gf: write a GF file to `<font_name>.<dpi>gf'. If this would overwrite the + input file, write to `x<font_name>.<dpi>gf' instead. +help: print this message. +omit <char1>,<char2>,...: omit the characters with the given codes or names + (before remapping) from the output. +output-file <filename>: use <filename> as the output filename if it has + a suffix, and as the base of the output files if it doesn't. It + cannot have a suffix if using the `epsf' option, or both the `gf' and the + `tfm' option. Default is the base part of the input font name. +random <real>: move each pixel a (uniformly) random distance between + -<real> and <real> in both x and y; default is 0. +random-threshold <real>: if randomizing, do not move pixels with + probability <real>; default is 0.2. +range <char1>-<char2>: only process characters between <char1> and + <char2> in the input font, inclusive. +remap <char1>:<char2>,<char1>:<char2>,...: for each pair, make the input + character with code <char1> have code <char2> in the output. +text: output the font to stdout as plain text, using `*'s and ` 's. +tfm: write a TFM file to `<font_name>.tfm'. If this would overwrite the + input file, write to `x<font_name>.tfm' instead. +tfm-header: <header-item>:<value>,<header-item>:<value>,...: assign each + <value> to the corresponding <header-item> when outputting a TFM file. + A <header-item> is one of `checksum', `designsize' or `codingscheme', + with casefolding. `checksum' requires an unsigned integer, + `designsize' a real, with 1.0 <= designsize < 2048, and `codingscheme' + a string of length less than 40 containing no parens or commas. +verbose: print brief progress reports on stdout. +version: print the version number of this program. +" + +/* We return the name of the font to process. */ + +static string +read_command_line (int argc, string argv[]) +{ + int g; /* `getopt' return code. */ + int option_index; + boolean explicit_dpi = false; + boolean printed_version = false; + struct option long_options[] + = { { "baseline-adjust", 1, 0, 0 }, + { "column-split", 1, 0, 0 }, + { "concat", 1, 0, 0 }, + { "designsize", 1, 0, 0 }, + { "dpi", 1, (int *) &explicit_dpi, 1 }, + { "encoding", 1, 0, 0 }, + { "epsf", 0, (int *) &wants_epsf, 1 }, + { "filter-passes", 1, 0, 0 }, + { "filter-size", 1, 0, 0 }, + { "filter-threshold", 1, 0, 0 }, + { "fontdimens", 1, 0, 0 }, + { "gf", 0, (int *) &wants_gf, 1 }, + { "help", 0, 0, 0 }, + { "omit", 1, 0, 0 }, + { "output-file", 1, 0, 0 }, + { "random", 1, 0, 0 }, + { "random-threshold", 1, 0, 0 }, + { "range", 1, 0, 0 }, + { "remap", 1, 0, 0 }, + { "text", 0, (int *) &wants_text, 1 }, + { "tfm", 0, (int *) &wants_tfm, 1 }, + { "tfm-header", 1, 0, 0 }, + { "verbose", 0, (int *) &verbose, 1 }, + { "version", 0, (int *) &printed_version, 1 }, + { 0, 0, 0, 0 } }; + + while (true) + { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') + exit (1); /* Unknown option. */ + + assert (g == 0); /* We have no short option names. */ + + if (ARGUMENT_IS ("baseline-adjust")) + scan_baseline_adjust (optarg); + + else if (ARGUMENT_IS ("column-split")) + scan_column_split (optarg); + + else if (ARGUMENT_IS ("concat")) + append_concat_list (&fontname_list, optarg); + + else if (ARGUMENT_IS ("designsize")) + { + design_size = atof (optarg); + TFM_CHECK_DESIGN_SIZE (design_size); + } + + else if (ARGUMENT_IS ("dpi")) + dpi = optarg; + + else if (ARGUMENT_IS ("encoding")) + { + if (encoding_info == NULL) + encoding_info = XTALLOC1 (encoding_info_type); + *encoding_info = read_encoding_file (optarg); + } + + else if (ARGUMENT_IS ("filter-passes")) + filter_passes = atou (optarg); + + else if (ARGUMENT_IS ("filter-size")) + filter_size = atou (optarg); + + else if (ARGUMENT_IS ("filter-threshold")) + { + filter_threshold = atof (optarg); + if (filter_threshold <= 0.0) + FATAL1 ("The filter threshold should be positive, not %f", + filter_threshold); + } + + else if (ARGUMENT_IS ("fontdimens")) + fontdimens = optarg; + + else if (ARGUMENT_IS ("help")) + { + fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]); + fprintf (stderr, USAGE); + exit (0); + } + + else if (ARGUMENT_IS ("omit")) + scan_omit_list (optarg); + + else if (ARGUMENT_IS ("output-file")) + output_name = optarg; + + else if (ARGUMENT_IS ("range")) + GET_RANGE (optarg, starting_char, ending_char); + + else if (ARGUMENT_IS ("random")) + random_max = atof (optarg); + + else if (ARGUMENT_IS ("random-threshold")) + random_threshold = atof (optarg); + + else if (ARGUMENT_IS ("remap")) + scan_remap_list (optarg); + + else if (ARGUMENT_IS ("text")) + report_file = stderr; + + else if (ARGUMENT_IS ("tfm-header")) + tfm_header = optarg; + + else if (ARGUMENT_IS ("version")) + printf ("%s.\n", version_string); + + /* Else it was just a flag; getopt has already done the assignment. */ + } + + FINISH_COMMAND_LINE (); +} + +/* The string S specifies baseline adjustments for individual + characters: `<charcode>:<adjustment>,...'. We set the element + <charcode> of the global array `baseline_adjust' to the <adjustment>. */ + +static void +scan_baseline_adjust (string s) +{ + string spec; + + for (spec = strtok (s, ARG_SEP); spec != NULL; spec = strtok (NULL, ARG_SEP)) + { + string code; + string adjust = strchr (spec, ':'); + + if (adjust == NULL) + FATAL1 ("Baseline adjustments look like `<code>:<integer>', not `%s'", + spec); + + code = substring (spec, 0, adjust - spec - 1); + + baseline_adjust[xparse_charspec (code, encoding_info)] + = atoi (adjust + 1); + } +} + + +/* The string S says how to split a single character into multiple + characters: `<charcode>@<column1>,...<columnN>'. We set the element + <charcode> of the global array `column_split' to the list of the + integers. */ + +static void +scan_column_split (string s) +{ + string code; + string column_list = strchr (s, '@'); + + if (column_list == NULL) + FATAL1 ("Column splits look like `<code>@<column>,<column>,...', not `%s'", + s); + + code = substring (s, 0, column_list - s - 1); + + column_split[xparse_charspec (code, encoding_info)] + = scan_unsigned_list (column_list + 1); +} + + +/* The string S is a list of font names, separated by commas. We append + each onto CONCAT_LIST. */ + +static void +append_concat_list (list_type *concat_list, string s) +{ + string name; + + /* The main routine must initialize CONCAT_LIST before we are called. */ + assert (concat_list != NULL && LIST_SIZE (*concat_list) > 0); + + for (name = strtok (s, ARG_SEP); name != NULL; name = strtok (NULL, ARG_SEP)) + { + string *new = LIST_TAPPEND (concat_list, string); + *new = name; + } +} + + +/* The string L is a list of character codes separated by commas; we + omit those characters in the output. Here, we parse the list and set + elements of the global array `omit' according to what we find. */ + +static void +scan_omit_list (string l) +{ + string map; + + for (map = strtok (l, ARG_SEP); map != NULL; map = strtok (NULL, ARG_SEP)) + { + charcode_type code = xparse_charspec (map, encoding_info); + omit[code] = true; + } +} + + +/* The string L is a list of remappings to apply, in the form + <code1>:<code2>,<code1>:<code2>,... where <code1> is a character + code in the original font, and <code2> is the character code to write + it as. No checking for remappings to or from the same character is + done here. + + We set elements of the global array `translate' according to what we + find. */ + +static void +scan_remap_list (string l) +{ + string map; /* A single remapping. */ + + for (map = strtok (l, ARG_SEP); map != NULL; map = strtok (NULL, ARG_SEP)) + { + one_byte original, target; + string original_str, target_str; + unsigned length = strlen (map); + + /* Ignore empty mappings, as in `a:b,,c:d'. */ + if (length == 0) + continue; + + else if (length < 3) + { + WARNING1 ("Mapping `%s' too short to be valid", map); + continue; + } + + else if (*map == ':') + { /* Must have form `::<code>'. */ + original_str = ":"; + if (*(map + 1) != ':') + { + WARNING1 ("Mapping `%s' doesn't have form `<code>:<code>'", map); + continue; + } + target_str = map + 2; + } + + else if (*(map + length - 1) == ':') + { /* Must have form `<code>::'. */ + target_str = ":"; + if (*(map + length - 2) != ':') + { + WARNING1 ("Mapping `%s' doesn't have form `<code>:<code>'", map); + continue; + } + original_str = substring (map, 0, length - 3); + } + + else + { /* Must have form `<code>:<code>'. */ + target_str = strchr (map, ':'); + if (target_str == NULL) + { + WARNING1 ("Mapping `%s' doesn't have form `<code>:<code>'", map); + continue; + } + target_str++; + original_str = substring (map, 0, target_str - 2 - map); + } + + original = xparse_charspec (original_str, encoding_info); + target = xparse_charspec (target_str, encoding_info); + translate[original] = target; + } +} + + + +/* xx use the macro instead */ +/*string +finish_command_line() +{ + do + { + if (printed_version && optind == argc) exit (0); + + if (optind + 1 == argc && *argv[optind] != 0) + { + FIND_CMDLINE_DPI (); + return MAYBE_REMOVE_SUFFIX (argv[optind]); + } + else + { + fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]); + fprintf (stderr, "(%s.)\n", optind == argc ? "Missing <font_name>" + : "Too many <font_name>s"); + fputs ("For more information, use ``-help''.\n", stderr); + exit (1); + } + return NULL; + } + while (0) +} +*/ diff --git a/fontconvert/main.h b/fontconvert/main.h new file mode 100644 index 0000000..8e4aeaf --- /dev/null +++ b/fontconvert/main.h @@ -0,0 +1,34 @@ +/* main.h: global variable declarations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef MAIN_H +#define MAIN_H + +#include <kpathsea/types.h> +#include "font.h" + +/* See main.c for explanations of these globals. */ +extern int baseline_adjust[MAX_CHARCODE + 1]; +extern int *column_split[MAX_CHARCODE + 1]; +extern string fontdimens; +extern charcode_type translate[MAX_CHARCODE + 1]; +extern boolean verbose; + +#endif /* not MAIN_H */ + + diff --git a/fontconvert/output-epsf.c b/fontconvert/output-epsf.c new file mode 100644 index 0000000..d7de3ba --- /dev/null +++ b/fontconvert/output-epsf.c @@ -0,0 +1,135 @@ +/* output-epsf.c: output EPS files. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "output-epsf.h" + + +/* The base part of the fontname to output to. */ +static string output_name; + + +/* It's a fatal error if NAME has a suffix, since that could mean + overwriting the same file several times with different information. */ + +void +epsf_start_output (const_string name) +{ + if (find_suffix (name) != NULL) + FATAL ("You can't specify a suffix and EPS output"); +} + + +/* Write a single character to the file `output_name-CODE.eps', + where CODE is the character code. */ + +/* Output the lower eight bits of VALUE to FILE as two hex digits. For + reasons I don't understand, when I write these same expressions in + the arguments to the fprintf, values less than 128 are copied into + the high nybble; that is, 1 is output as `11'. */ +#define OUTPUT_HEX(file, value) \ + do \ + { one_byte v1 = (value) & 0xf0; \ + one_byte v2 = (value) & 0xf; \ + fprintf (file, "%x%x", v1 >> 4, v2); \ + } \ + while (0) + +void +epsf_output_char (char_info_type c) +{ + unsigned row; + bitmap_type b = CHAR_BITMAP (c); + unsigned height = BITMAP_HEIGHT (b); + unsigned width = BITMAP_WIDTH (b); + charcode_type code = CHARCODE (c); + string title = concat3 (output_name, "-", itoa (code)); + string eps_name = concat (title, ".eps"); + FILE *eps = xfopen (eps_name, "w"); + + /* Write the header. */ + fputs ("%!PS-Adobe-3.0 EPSF-3.0\n", eps); + fprintf (eps, "%%%%BoundingBox: 0 0 %u %u\n", + BITMAP_WIDTH (b), BITMAP_HEIGHT (b)); + fprintf (eps, "%%%%Title: (%s)\n", title); + fputs ("%%Creator: fontconvert -epsf\n", eps); + fprintf (eps, "%%%%CreationDate: %s\n", now ()); + fputs ("%%EndComments\n", eps); + + /* Write the bitmap as an image. */ + + /* First arrange to scale the image to its original size. */ + fprintf (eps, "%u %u scale\n", width, height); + + /* Push the imagemask parameters. */ + fprintf (eps, "%u %u true [%u 0 0 -%u 0 %u]\n", + width, height, width, height, height); + + /* Output the bits. */ + fputs ("{<", eps); + for (row = 0; row < height; row++) + { + unsigned col; + one_byte byte = 0; + unsigned bit = 7; + + for (col = 0; col < width; col++) + { + byte |= BITMAP_PIXEL (b, row, col) << bit; + + /* Output eight bits at a time, since imagemask expects that. */ + if (bit == 0) + { + OUTPUT_HEX (eps, byte); + byte = 0; + bit = 8; + } + + /* Decrement `bit' after, so that the test `bit == 0' above is + true at the right time. */ + bit--; + } + + /* If the width isn't a multiple of eight, have to output the + remainder. */ + if (bit < 7) + OUTPUT_HEX (eps, byte); + + /* In any case, output a newline, just to make the output easier + to read, in case somebody wants to read it. */ + fputs ("\n", eps); + } + fputs (">}\nimagemask\n", eps); + + /* Write the trailer. */ + fputs ("showpage\n", eps); + fputs ("%%EOF\n", eps); + + xfclose (eps, eps_name); + free (eps_name); + free (title); +} + + +/* We don't have anything to do at the end. */ + +void +epsf_finish_output (void) +{ +} diff --git a/fontconvert/output-epsf.h b/fontconvert/output-epsf.h new file mode 100644 index 0000000..2d243ea --- /dev/null +++ b/fontconvert/output-epsf.h @@ -0,0 +1,30 @@ +/* output-epsf.h: declarations for writing EPS files. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUTPUT_EPSF_H +#define OUTPUT_EPSF_H + +#include <kpathsea/types.h> +#include "font.h" + + +extern void epsf_start_output (const_string base_name); +extern void epsf_output_char (char_info_type); +extern void epsf_finish_output (void); + +#endif /* not OUTPUT_EPSF_H */ diff --git a/fontconvert/output-gf.c b/fontconvert/output-gf.c new file mode 100644 index 0000000..9a64171 --- /dev/null +++ b/fontconvert/output-gf.c @@ -0,0 +1,86 @@ +/* output-gf.c: write a GF file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "filename.h" +#include "gf.h" +#include "report.h" + +#include "output-gf.h" + +/* The basename of the input file. */ +static string input_basename; + +/* Open the output file and write the preamble. We don't bother to + change the comment to identify ourselves, since the changes we will + make aren't likely to be drastic. We have to ensure that we do not + overwrite the input file; if INPUT_NAME and our constructed output + name do refer to the same file, we simply prepend an `x' to the + output name. Not very elegant, but it does solve the problem. */ + +void +gf_start_output (string input_name, const_string output_name, string dpi, + string comment) +{ + string gf_name = extend_filename (output_name, concat (dpi, "gf")); + + if (same_file_p (input_name, gf_name)) + { + string old_gf_name = gf_name; + + gf_name = make_prefix ("x", gf_name); + WARNING2 ("fontconvert: The output file (%s) is also the \ +the input file, so I am writing to `%s'", old_gf_name, gf_name); + } + + if (!gf_open_output_file (gf_name)) + FATAL_PERROR (gf_name); + + gf_put_preamble (comment); + + /* We might need this in `gf_finish_output', to open the TFM file. */ + input_basename = basename (input_name); +} + +/* Write a single character. */ + +void +gf_output_char (char_info_type c, real design_size_ratio) +{ + gf_char_type gf_char; + + GF_CHARCODE (gf_char) = CHARCODE (c); + GF_BITMAP (gf_char) = CHAR_BITMAP (c); + GF_CHAR_BB (gf_char) = CHAR_BB (c); + GF_H_ESCAPEMENT (gf_char) = CHAR_SET_WIDTH (c); + GF_TFM_WIDTH (gf_char) = design_size_ratio * CHAR_TFM_WIDTH (c); + + gf_put_char (gf_char); +} + +/* Write the postamble and close the file. */ + + +void +gf_finish_output (real design_size, real dpi) +{ + gf_put_postamble (real_to_fix (design_size), dpi, dpi); + gf_close_output_file (); +} + diff --git a/fontconvert/output-gf.h b/fontconvert/output-gf.h new file mode 100644 index 0000000..ac0a953 --- /dev/null +++ b/fontconvert/output-gf.h @@ -0,0 +1,31 @@ +/* output-gf.h: declarations for writing a GF file. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUTPUT_GF_H +#define OUTPUT_GF_H + +#include <kpathsea/types.h> +#include "font.h" + +/* Initialize GF output, output a character, and finish it up. */ +extern void gf_start_output + (string input_name, const_string base_name, string dpi, string comment); +extern void gf_output_char (char_info_type, real design_size_ratio); +extern void gf_finish_output (real design_size, real dpi); + +#endif /* not OUTPUT_GF_H */ diff --git a/fontconvert/output-tfm.c b/fontconvert/output-tfm.c new file mode 100644 index 0000000..62f7a0b --- /dev/null +++ b/fontconvert/output-tfm.c @@ -0,0 +1,279 @@ +/* output-tfm.c: write a TFM file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/tex-file.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/paths.h> + +#include "filename.h" +#include "random.h" +#include "report.h" +#include "tfm.h" + +#include "filter.h" +#include "main.h" +#include "output-tfm.h" + + +/* User assignments to the TFM character header values. */ +string tfm_header = NULL; + +/* User assignments to the TFM fontdimen values. */ +string fontdimens = NULL; + + +/* `false' if we're doing any font other than the main one (which is + done first). */ +static boolean main_input_font_p = true; + +/* `true' if we have an input TFM file from which to get defaults. */ +static boolean have_file_info = false; + +/* This accumulates the information about each character. */ +static tfm_char_type *tfm_chars; + +/* This holds the information about each character old TFM character. */ +static tfm_char_type *old_tfm_chars; + +/* The name of the TFM file we finally write. */ +static string output_tfm_name; + + +static void tfm_do_chars_defaults (void); + +/* At the beginning, we can set up the output file and write the fontwide + information. This includes the fontdimen parameters (in the global + `fontdimens'), and the header bytes (in `tfm_header'), if the user + specified them. */ + +void +tfm_start_output (string input_name, const_string output_name, + real user_design_size, real default_design_size) +{ + tfm_global_info_type tfm_info; + string input_tfm_name = kpse_find_tfm (input_name); + + /* We remove the suffix before making the PL name because if the user + said `-output-file=foo.bar', it's the TFM file which should be + named `foo.bar'; the PL file is still named `foo.pl'. */ + string output_root = remove_suffix (output_name); + string pl_name = extend_filename (output_name, "pl"); + output_tfm_name = extend_filename (output_name, "tfm"); + + /* If we'd overwrite the input, change the name. */ + if (input_tfm_name != NULL && same_file_p (input_tfm_name, output_tfm_name)) + { + string old_pl_name = pl_name; + string old_output_tfm_name = output_tfm_name; + + pl_name = make_prefix ("x", pl_name); + output_tfm_name = make_prefix ("x", output_tfm_name); + + WARNING2 ("fontconvert: The output file (%s) is also the \ +the input file, so I am writing to `%s'", old_pl_name, pl_name); + WARNING2 ("fontconvert: The output file (%s) is also the \ +the input file, so I am writing to `%s'", old_output_tfm_name,\ +output_tfm_name); + } + + if (!tfm_open_pl_output_file (pl_name)) + FATAL_PERROR (pl_name); + + /* Initialize `tfm_info' with the data from an existing file, if we + have it. + + For the design size in the output TFM file, use the following, in + order of preference: + 1) `designsize' parameter given by the user in the -tfm-header option; + 2) `-design-size' option (which is `user_design_size'); + 3) the designsize from an existing TFM file; + 4) the `default_design_size' passed in (which is the designsize in + the input bitmap font). */ + + if (input_tfm_name != NULL && tfm_open_input_file (input_tfm_name)) + { + tfm_info = tfm_get_global_info (); + have_file_info = true; + + REPORT1 ("Reading %s.\n", input_tfm_name); + + /* Never carry along the checksum. */ + TFM_CHECKSUM (tfm_info) = 0; + + /* A user-supplied design size (#2) overrides the design size from + the file (#3). (The -tfm-header (#1) override is below.) */ + if (user_design_size != 0.0) + TFM_DESIGN_SIZE (tfm_info) = user_design_size; + } + else + { /* No existing TFM file. */ + tfm_info = tfm_init_global_info (); + + /* Use the bitmap font's design size (#4). */ + TFM_DESIGN_SIZE (tfm_info) = default_design_size; + } + + /* Be sure the design size in the header bytes and the fontdimen + parameter agree. */ + tfm_set_fontsize (&tfm_info); + + /* Update `tfm_info' with any user-supplied strings. */ + if (tfm_header != NULL) + tfm_set_header (tfm_header, &tfm_info); + + if (fontdimens != NULL) + tfm_set_fontdimens (fontdimens, &tfm_info); + + /* Output this to start us off. */ + tfm_put_global_info (tfm_info); + + /* Initialize the array where we will store the character information. */ + tfm_chars = tfm_new_chars (); +} + +/* We could do something more complicated here, if we wanted to get the + TFM information for each input font: close the first font (after + first getting everything we need), open the next one, then close it + next time we're called, etc. (Or make the TFM library able to handle + more than one open font.) Then we could combine all the lig/kern + information, besides using the character dimensions. But none of + this seems worth it (i.e., we haven't needed to do it yet). + + So instead we just remember whether we're doing the first font -- + which is the main one -- so we can skip looking in the TFM file for + font #1 when we're doing fonts #2, #3, ... */ + +void +tfm_start_font (string font_name) +{ + if (main_input_font_p) + main_input_font_p = false; +} + +/* Store the relevant information about the character C into `tfm_chars'. */ + +void +tfm_output_char (char_info_type c, real dpi_real) +{ + tfm_char_type *new_tfm_char = &tfm_chars[CHARCODE (c)]; + + TFM_CHAR_EXISTS (*new_tfm_char) = true; + TFM_CHARCODE (*new_tfm_char) = CHARCODE (c); + + /* If we're doing radical things to the characters, don't use the + default information from an existing file even if we have one. */ + if (baseline_adjust[CHARCODE (c)] != 0 + || column_split[CHARCODE (c)] != NULL + || filter_passes > 0 + || random_max > 0.0 + || !have_file_info + || !main_input_font_p) + { + TFM_WIDTH (*new_tfm_char) + = PIXELS_TO_POINTS (CHAR_SET_WIDTH (c), dpi_real); + + TFM_HEIGHT (*new_tfm_char) + = PIXELS_TO_POINTS (CHAR_HEIGHT (c), dpi_real); + + TFM_DEPTH (*new_tfm_char) = PIXELS_TO_POINTS (CHAR_DEPTH (c), dpi_real); + TFM_ITALIC_CORRECTION (*new_tfm_char) = 0.0; + } + else + { + tfm_char_type *old_tfm_char = tfm_get_char (CHARCODE (c)); + + TFM_WIDTH (*new_tfm_char) = TFM_WIDTH (*old_tfm_char); + TFM_HEIGHT (*new_tfm_char) = TFM_HEIGHT (*old_tfm_char); + TFM_DEPTH (*new_tfm_char) = TFM_DEPTH (*old_tfm_char); + TFM_ITALIC_CORRECTION (*new_tfm_char) + = TFM_ITALIC_CORRECTION (*old_tfm_char); + } + + /* We do the ligatures and kerns when we have gone through all the + characters. */ +} + + +/* If we have an existing TFM file, use it to get the lig/kern info. */ + +static void +tfm_do_chars_defaults () +{ + unsigned code; + + if (!have_file_info) + return; + + old_tfm_chars = tfm_get_chars (); + + for (code = 0; code < TFM_SIZE; code++) + { + tfm_char_type *new_tfm_char = &tfm_chars[code]; + + if (TFM_CHAR_EXISTS (*new_tfm_char)) + { + unsigned this_one; + tfm_char_type *old_tfm_char = &old_tfm_chars[code]; + list_type old_kern_table = TFM_KERN (*old_tfm_char); + list_type old_lig_table = TFM_LIGATURE (*old_tfm_char); + + for (this_one = 0; this_one < LIST_SIZE (old_kern_table); this_one++) + { + tfm_kern_type *old_kern = LIST_ELT (old_kern_table, this_one); + tfm_char_type *old_kern_char + = &tfm_chars[translate[old_kern->character]]; + + if (TFM_CHAR_EXISTS (*old_kern_char)) + tfm_set_kern (&TFM_KERN (*new_tfm_char), + CHARCODE (*old_kern_char), old_kern->kern); + } + + for (this_one = 0; this_one < LIST_SIZE (old_lig_table); this_one++) + { + tfm_ligature_type *old_lig = LIST_ELT (old_lig_table, this_one); + tfm_char_type *old_lig_char + = &tfm_chars[translate[old_lig->character]]; + tfm_char_type *old_lig_ligature + = &tfm_chars[translate[old_lig->ligature]]; + + if (TFM_CHAR_EXISTS (*old_lig_char) + && TFM_CHAR_EXISTS (*old_lig_ligature)) + tfm_set_ligature (&TFM_LIGATURE (*new_tfm_char), + CHARCODE (*old_lig_char), + CHARCODE (*old_lig_ligature)); + } + } /* new TFM char exists */ + } +} + +/* Output `tfm_chars' and close up. */ + +void +tfm_finish_output () +{ + tfm_do_chars_defaults (); + + tfm_put_chars (tfm_chars); + tfm_convert_pl (output_tfm_name, verbose); + tfm_close_pl_output_file (); + + if (have_file_info) + tfm_close_input_file (); +} diff --git a/fontconvert/output-tfm.h b/fontconvert/output-tfm.h new file mode 100644 index 0000000..b819ceb --- /dev/null +++ b/fontconvert/output-tfm.h @@ -0,0 +1,45 @@ +/* output-tfm.h: declarations for writing a TFM file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUTPUT_TFM_H +#define OUTPUT_TFM_H + +#include <kpathsea/types.h> +#include "font.h" + + +/* See tfm_output.c. */ +extern string tfm_header; +extern string fontdimens; + + +/* Called once at the beginning to initialize things. */ +extern void tfm_start_output (string input_name, const_string output_name, + real user_design_size, real default_design_size); + +/* Called per each input font: the main one first and then each one + specified with -concat. */ +extern void tfm_start_font (string font_name); + +/* Called for every character in every font. */ +extern void tfm_output_char (char_info_type, real dpi); + +/* Called at the very end. */ +extern void tfm_finish_output (void); + +#endif /* not OUTPUT_TFM_H */ diff --git a/fontconvert/random.c b/fontconvert/random.c new file mode 100644 index 0000000..f683377 --- /dev/null +++ b/fontconvert/random.c @@ -0,0 +1,171 @@ +/* random.c: distort a bitmap. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "rand.h" + +#include "random.h" + +/* Distort the bitmap (see below). (-randomize) */ +real random_max = 0.0; +real random_threshold = 0.2; + + +static bitmap_type enlarge_bitmap (bitmap_type, int, int); +static real random_number (void); + + + +/* Randomize the bitmap B by moving each black pixel a randomly chosen + distance between -random_max and random_max (both horizontally and + vertically). Return the enlargement of B on all four side in ADJUST. + */ + +void +randomize_bitmap (bitmap_type *b, bounding_box_type *adjust) +{ + unsigned this_row, this_col; + + MIN_ROW (*adjust) = MAX_ROW (*adjust) = MIN_COL (*adjust) = MAX_COL (*adjust) + = 0; + + for (this_row = 0; this_row < BITMAP_HEIGHT (*b); this_row++) + for (this_col = 0; this_col < BITMAP_WIDTH (*b); this_col++) + { + if (BITMAP_PIXEL (*b, this_row, this_col) != WHITE) + { + int row_enlarge, col_enlarge; + /* Generate two random numbers between -random_max and + random_max to give rise to the new x and y. */ + real random1 = random_number (); + int row_delta = random1 + .5 * SIGN (random1); + int new_row = this_row + row_delta; + + real random2 = random_number (); + int col_delta = random2 + .5 * SIGN (random2); + int new_col = this_col + col_delta; + + /* Clear the old location before we (possibly) mess with the + bitmap dimensions. */ + BITMAP_PIXEL (*b, this_row, this_col) = WHITE; + + /* Check if the new location is outside the current bitmap. */ + if (new_row < 0) + { + row_enlarge = new_row; + /* Negative rows are off the top of the bitmap -- it's + in C coordinates, not Cartesian. */ + MAX_ROW (*adjust) -= row_enlarge; + } + else if (new_row >= BITMAP_HEIGHT (*b)) + { + row_enlarge = new_row - BITMAP_HEIGHT (*b) + 1; + MIN_ROW (*adjust) += row_enlarge; + } + else + row_enlarge = 0; + + if (new_col < 0) + { + col_enlarge = new_col; + MIN_COL (*adjust) -= col_enlarge; + } + else if (new_col >= BITMAP_WIDTH (*b)) + { + col_enlarge = new_col - BITMAP_WIDTH (*b) + 1; + MAX_COL (*adjust) += col_enlarge; + } + else + col_enlarge = 0; + + if (row_delta != 0 || col_delta != 0) + { /* Enlarge the bitmap to make the new location valid. */ + bitmap_type new_b + = enlarge_bitmap (*b, row_enlarge, col_enlarge); + free_bitmap (b); + *b = new_b; + + /* We've made the new row/column at the edge. */ + if (new_row < 0) new_row = 0; + if (new_col < 0) new_col = 0; + } + + BITMAP_PIXEL (*b, new_row, new_col) = BLACK; + } + } +} + + +/* Return the enlargement of the bitmap B by ROW_DELTA and COL_DELTA. + Negative deltas enlarge to the bottom/left, positive to the + top/right. */ + +static bitmap_type +enlarge_bitmap (bitmap_type b, int row_delta, int col_delta) +{ + bitmap_type new; + dimensions_type new_size; + unsigned row; + int row_addend = row_delta < 0 ? abs (row_delta) : 0; + int col_addend = col_delta < 0 ? abs (col_delta) : 0; + + DIMENSIONS_HEIGHT (new_size) = BITMAP_HEIGHT (b) + abs (row_delta); + DIMENSIONS_WIDTH (new_size) = BITMAP_WIDTH (b) + abs (col_delta); + + new = new_bitmap (new_size); + + /* `new_bitmap' initializes all the pixels to white, so we don't have + to do anything to the new rows and columns. */ + for (row = 0; row < BITMAP_HEIGHT (b); row++) + { + one_byte *source = BITMAP_ROW (b, row); + one_byte *target = BITMAP_ROW (new, row + row_addend) + col_addend; + + memcpy (target, source, BITMAP_WIDTH (b)); + } + + return new; +} + + + +/* Return a random number between -random_max and random_max. */ + +static real +random_number () +{ + static boolean initialized = false; + real r; + + if (!initialized) + { + seed_rand (getpid ()); + initialized = true; + } + + /* If the random number is less than `random_threshold', return zero. + Otherwise, return a random number in the interval + [-random_max,random_max]. */ + r = (real) k_rand () / RAND_MAX; + r = r > random_threshold + ? (real) k_rand () / RAND_MAX * random_max - random_max + : 0; + + return r; +} diff --git a/fontconvert/random.h b/fontconvert/random.h new file mode 100644 index 0000000..3fa60e9 --- /dev/null +++ b/fontconvert/random.h @@ -0,0 +1,37 @@ +/* random.h: declarations for randomizing a bitmap. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef RANDOM_H +#define RANDOM_H + +#include <kpathsea/types.h> +#include "bitmap.h" +#include "bounding-box.h" + +/* See random.c. */ +extern real random_max; +extern real random_threshold; + +/* Move each pixel in B by a random amount between -random_max and + random_max (enlarging the bitmap as necessary). Return the number of + rows/columns added at each side of bitmap (i.e., all numbers are + positive) in ADJUST. (This is not actually a bounding box, but that + type is a convenient way to return the four numbers.) */ +extern void randomize_bitmap (bitmap_type *b, bounding_box_type *adjust); + +#endif /* not RANDOM_H */ diff --git a/fontconvert/version.c b/fontconvert/version.c new file mode 100644 index 0000000..66aab18 --- /dev/null +++ b/fontconvert/version.c @@ -0,0 +1 @@ +char *version_string = "fontconvert version REPLACE-WITH-VERSION"; diff --git a/gf/ChangeLog b/gf/ChangeLog new file mode 100644 index 0000000..b7178de --- /dev/null +++ b/gf/ChangeLog @@ -0,0 +1,308 @@ +Sun Feb 20 17:08:21 1994 Kathy Hargreaves (karl@cs.umb.edu) + + * gf_output.c: changed doc. + +Tue Oct 27 12:56:09 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Mon Sep 21 13:20:29 1992 Karl Berry (karl@cs.umb.edu) + + * gf_output.c (start_put_char): don't claim we are part of the + nonexistent put_gf_char in the warning. + +Thu Sep 3 09:30:43 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Sat Jun 6 10:03:52 1992 Karl Berry (karl@hayley) + + * gf_input.c (gf_get_postamble): if the input file is empty, give + a decent error message. + +Mon May 4 09:28:57 1992 Karl Berry (karl@hayley) + + * gf_output.c (start_put_char): use `put_gf_char' in the warning. + +Sat Apr 4 13:53:55 1992 Karl Berry (karl@hayley) + + * gf_output.c (gf_put_char): remove unneeded local `charcode'. + +Sat Mar 28 07:48:16 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Sat Mar 7 13:18:42 1992 Karl Berry (karl at fosse) + + * gf_input.c (gf_get_three): complete prototype. + * gf_output.c (init_locators, put_locators): likewise. + +Sat Mar 7 09:12:14 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files, headers, sources): replace with `c_and_h', etc. + + * gf_input.c (get_character_bitmap): use puts instead of printf + where possible. + +Thu Jan 9 08:30:06 1992 Karl Berry (karl at hayley) + + * *.c: do not include global.h. + + * *.h: remove #pragma once. + +Wed Jan 8 15:28:34 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + +Wed Jan 1 16:45:14 1992 Kathy Hargreaves (kathy at hayley) + + * gf_output.c (gf_put_preamble): Just truncate comment if it's too + long, instead of fataling. + +Tue Oct 1 07:52:47 1991 Karl Berry (karl at hayley) + + * gf_input.c (deblank): remove blank rows at the top and bottom. + +Tue Jul 30 13:18:02 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Sat Jun 15 09:50:04 1991 Karl Berry (karl at hayley) + + * all files: change `checked_' to `x'. + +Thu Jun 6 07:28:10 1991 Karl Berry (karl at hayley) + + * all files: change to version 2 of the GPL. + +Tue Apr 23 13:39:09 1991 Karl Berry (karl at ra.cs.umb.edu) + + * gf_input.c (get_paint): remove assertion that we're at a valid + location. + +Thu Mar 7 07:32:38 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Mon Feb 25 16:15:06 1991 Karl Berry (karl at hayley) + + * gf_output.c (put_boc): declare static + + * gf_{input,output}.c: change names to `gf_...' from `..._gf_...'. + + * GNUmakefile (sources): remove `gf_common.c'. + * gf_input.c (gf_get_postamble): initialize the postamble inline. + +Sun Feb 17 09:31:14 1991 Karl Berry (karl at hayley) + + * *.c: include config.h. + +Sun Jan 13 09:37:11 1991 Karl Berry (karl at hayley) + + * gf_input.c (get_raw_gf_char, append_byte, append_n_bytes): use + `raw_char_type' instead of `raw_gf_char_type', and RAW_... + macros instead of GF_RAW... + * gf_output.c (put_raw_gf_char): likewise. + + * gf_input.c (get_raw_gf_char): loop until eoc reading the + character, instead of while (0). + + * gf_input.c (ENSURE_AVAILABLE): loop as long as we need more + space, instead of testing once. + + * gf_input.c (get_raw_gf_char): allocate the space for the new + character before storing into it. + +Sat Jan 12 14:56:18 1991 Karl Berry (karl at hayley) + + * gf_input.c (get_raw_gf_char, append_byte, append_n_bytes, + new_gf_raw_char): new routines to handle reading raw characters. + * gf_output.c (start_put_char, put_raw_gf_char): more new + routines. + +Sat Nov 17 12:46:52 1990 Karl Berry (karl at hayley) + + * gf_input.c, gf_output.c: include appropriate file-...h files. + +Wed Oct 17 18:06:17 1990 Karl Berry (karl at aten) + + * gf_input.c (deblank): when the bitmap is all zero, ensure that + all its dimensions are also zero. + +Fri Oct 5 07:03:35 1990 Karl Berry (karl at hayley) + + * gf_input.c (close_gf_input_file): null the elements of + `char_list'. + (get_given_gf_char): make `char_list' global to the file. + +Wed Aug 29 14:13:08 1990 Karl Berry (karl at hayley) + + * gf_input.c (gf_get_byte, ...): pass gf_input_filename, and + rewrite as macros. + * gf_output.c (gf_put_byte, ...): likewise. + +Tue Jul 24 13:19:40 1990 Karl Berry (karl at hayley) + + * gf_output.c (put_gf_postamble): the pointer after the POST byte + is still wrong. + +Thu Jul 5 06:30:56 1990 Karl Berry (karl at hayley) + + * gf_output.c (put_gf_postamble): output the right pointer after + the POST byte. + +Wed Jul 4 09:00:19 1990 Karl Berry (karl at hayley) + + * gf_input.c (get_full_boc): allow the character with code + MAX_CHAR_CODE. + +Wed Jun 20 07:24:23 1990 Karl Berry (karl at hayley) + + * gf_output.c (put_gf_preamble): just output the characters of the + comment here, instead of calling gf_put_string. Also, don't give + a fatal message if the comment is too long. + (gf_put_string): delete this. + + * gf_input.c (gf_cur_pos): use checked_ftell; rename to gf_ftell, + and change callers. + (gf_set_pos): rename to gf_fseek. + * gf_output.c (gf_cur_pos): likewise. + +Tue Jun 19 10:56:10 1990 Karl Berry (karl at hayley) + + * gf_input.c (open_gf_input_file): complain if the input file + already exists and the caller tries to open a second. + +Sun Jun 3 11:06:31 1990 Karl Berry (karl at hayley) + + * gf_input.c (get_character_bitmap): ignore NO_OPs before the EOC + of a blank character. + +Fri Jun 1 15:14:29 1990 Karl Berry (karl at hayley) + + * gf_output.c (close_gf_output_file): use checked_fclose. + + * gf_output.c (open_gf_output_file): make sure the output file + hasn't already been opened. + +Wed May 30 15:36:46 1990 Karl Berry (karl at hayley) + + * gf_input.c (get_full_boc): make sure the character code is in + range. + +Thu May 3 09:29:17 1990 Karl Berry (karl at hayley) + + * gf_common.c (new_gf_char): delete this. + * gf_input.c (get_gf_char): don't call it. + +Sat Apr 21 09:43:34 1990 Karl Berry (karl at hayley) + + * gf_input.c (gf_get_string): add a trailing null to the end of + the returned string. + +Thu Apr 19 16:10:21 1990 Karl Berry (karl at hayley) + + * gf_common.c (new_gf_postamble): forgot to initialize character + #255 in a new postamble. + + * gf_input.c (get_postamble): don't ignore the checksum. + +Mon Apr 16 07:21:42 1990 Karl Berry (karl at hayley) + + * gf_opcodes.h: add #pragma once. + +Sat Apr 14 17:04:40 1990 Karl Berry (karl at hayley) + + * gf_input.c (get_character_bitmap): call get_specials when we see + a special opcode, so that we skip over the arguments. + +Mon Apr 9 07:11:48 1990 Karl Berry (karl at hayley) + + * gf_common.c (new_gf_postamble): remove references to the + specials; upcase `max_char_code' and `null_byte_ptr'. + (new_gf_char): new name for `new_generic_char'; remove references + to the specials. + gf_input.c (thoughout): use macros to look at the postamble and + character structures; upcase `fatal' and other global macros. + gf_output.c: likewise. + GNUmakefile: remove references to gf_util.c and generic.h. + +Tue Apr 3 17:32:24 1990 Karl Berry (karl at hayley) + + * gf_input.c (deblank): forgot to initialize width and height. + +Thu Mar 1 11:19:06 1990 Karl Berry (karl at hayley) + + * gf_output.c (put_gf_char): don't fail when a character is output + more than once; just give a warning (and only outpt the first one). + + * gf_input.c (deblank): don't fail if the character is all white + (in which case white_on_right=white_on_left, and we don't want to + subtract them both from the width). + + * gf_input.c (get_character_bitmap): and fix the same off-by-one + bug fixed on Feb 23, this time for the height. Will I ever get + this right? + [no, rescind that. The height IS inclusive, and the width is NOT + inclusive.] + + * gf_input.c (get_character_bitmap): if the character is zero + wide, read the EOC following. + + * gf_input.c (get_character_bitmap): don't assert that the + max_row >= min_row (or col), because if the character is zero + high (or wide), it won't be. + (deblank): make this_col be int, not unsigned, since we subtract + one from it. + +Tue Feb 27 20:58:52 1990 Kathy Hargreaves (kathy at hayley) + + * gf_input.c (gf_get_string): if the length is zero, don't try to + read anything from the file. + +Fri Feb 23 13:28:07 1990 Karl Berry (karl at hayley) + + * gf_input.c (get_character_bitmap): fix off-by-one in deciding how + wide the bitmap should be. + +Sat Feb 3 10:28:28 1990 Karl Berry (karl at hayley) + + * Makefile: rename to GNUmakefile. + +Wed Jan 24 17:49:01 1990 Karl Berry (karl at hayley) + + * gf_util.c (ascender_part): new routine. + +Mon Oct 30 18:41:42 1989 Karl Berry (karl at hayley) + + * all files: add the copyleft. + +Sun Oct 29 07:33:50 1989 Karl Berry (karl at hayley) + + * gf_output.c (put_boc): have to test the maximums of the bounding + box for sign, as well as the deltas. + +Sat Oct 28 15:20:26 1989 Karl Berry (karl at hayley) + + * gf_output.c (put_skip): correct misinterpretation of the SKIP0 + opcode. + + * gf_output.c (put_paint, put_skip, put_new_row): define these. + + * gf_output.c (font_bb): initialize using MAXINT, from <values.h>. + +Tue Oct 17 21:36:31 1989 Karl Berry (karl at hayley) + + * gf_input.c (get_locators): CHAR_LOC commands take a one-byte + character residue, like CHAR_LOC0 commands, not four-byte + character codes. + +Fri Oct 6 19:18:58 1989 Karl Berry (karl at hayley) + + * gf_util.c (print_gf_char): pass in a file parameter, instead of + always writing to stdout. diff --git a/gf/GNUmakefile b/gf/GNUmakefile new file mode 100644 index 0000000..d5e2d01 --- /dev/null +++ b/gf/GNUmakefile @@ -0,0 +1,27 @@ +# Makefile for the GF library. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +library = gf + +h_only = gf_opcodes +c_only = gf_input gf_output + +include ../data/defs.make +include ../data/defslib.make + +include M.depend diff --git a/gf/README b/gf/README new file mode 100644 index 0000000..9e071d5 --- /dev/null +++ b/gf/README @@ -0,0 +1,12 @@ +This library provides for reading and writing of generic font (GF) +bitmap files. Only a single file may be read or written at a time. + +None of the code that processes the GF commands actually explains what +the precise definition of those commands are. For that, you should look +at the definition of the GF format in Metafont: The Program, by Don +Knuth, chapter 45. It is also in the METAFONTware programs that convert +to or from GF format. + +The header file is ../include/gf.h. It explains the basics of how to +use the routines. The source files in this directory do not repeat that +explanation. diff --git a/gf/gf_input.c b/gf/gf_input.c new file mode 100644 index 0000000..d0c81e6 --- /dev/null +++ b/gf/gf_input.c @@ -0,0 +1,976 @@ +/* gf_input.c: read objects from one GF file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" +#include "gf.h" +#include "scaled-num.h" + +#include "gf_opcodes.h" + + +/* If true, print out what we read. */ +static boolean tracing_gf_input = false; + + +/* These identify the file we're reading, for our own use. */ +static string gf_input_filename; +static FILE *gf_input_file; + + +/* Low-level input. These macros call the corresponding routines in + kbase, using the static variables for the input file and filename. */ + +#define GF_FTELL() xftell (gf_input_file, gf_input_filename) +#define GF_FSEEK(offset, from_where) \ + xfseek (gf_input_file, offset, from_where, gf_input_filename) +#define GF_GET_BYTE() get_byte (gf_input_file, gf_input_filename) +#define GF_GET_PREVIOUS() get_previous_byte (gf_input_file, gf_input_filename) +#define GF_GET_TWO() get_two (gf_input_file, gf_input_filename) +#define GF_GET_FOUR() get_four (gf_input_file, gf_input_filename) +#define GF_GET_SIGNED_FOUR() \ + get_signed_four (gf_input_file, gf_input_filename) +#define GF_GET_PREVIOUS_FOUR() \ + get_previous_four (gf_input_file, gf_input_filename) +#define GF_MATCH_BYTE(expected) \ + match_byte (expected, gf_input_file, gf_input_filename) + +static void get_specials (byte_count_type special_ptr); +static string gf_get_string (unsigned string_length); +static four_bytes gf_get_three (void); + + +/* We have occasion to refer to the postamble when reading the characters, + so we keep a copy for ourselves. */ +static gf_postamble_type *private_postamble; + +/* This reads into `private_postamble'. */ +static void get_postamble (void); + +static void get_locators (void); + + +/* Pointers to the characters we have read. */ +static gf_char_type *char_list[MAX_CHARCODE + 1]; + + +/* Subroutines for reading a character. */ +static void get_full_boc (gf_char_type *); +static void get_abbreviated_boc (gf_char_type *); +static void get_character_bitmap (gf_char_type *); +static void get_postamble_info (gf_char_type *); +static void deblank (gf_char_type *); + +/* Subroutines for reading the bitmap. */ +static void get_paint (coordinate_type *, boolean *, one_byte, gf_char_type *); +static void get_skip (coordinate_type *, boolean *, one_byte, gf_char_type *); +static void get_new_row + (coordinate_type *, boolean *, one_byte, gf_char_type *); + +/* For handling raw characters. */ +static void append_byte (raw_char_type *, one_byte); +static void append_n_bytes (raw_char_type *, four_bytes, one_byte *); +static raw_char_type new_raw_gf_char (gf_char_locator_type); + +/* Start reading FILENAME. Return false if it can't be opened. */ + +boolean +gf_open_input_file (string filename) +{ + if (gf_input_file != NULL) + FATAL2 ("gf_open_input_file: Attempt to open `%s', but `%s' is +already open", filename, gf_input_filename); + + gf_input_filename = filename; + gf_input_file = fopen (filename, "r"); + + return gf_input_file != NULL; +} + + +void +gf_close_input_file () +{ + unsigned code; + + assert (gf_input_file != NULL); + + xfclose (gf_input_file, gf_input_filename); + + gf_input_filename = NULL; + gf_input_file = NULL; + private_postamble = NULL; + + for (code = 0; code <= MAX_CHARCODE; code++) + char_list[code] = NULL; +} + +/* The only interesting thing in the preamble, either to the user or to + us, is the comment. + + It is wrong to save and restore the position in the gf file, since + this routine is primarily useful if the user intends to use + `gf_get_next_char', i.e., read the characters in the order they + appear. In that case, the user has to read the preamble first. */ + +string +gf_get_preamble () +{ + one_byte comment_length; + string answer; + + assert (gf_input_file != NULL); + + GF_MATCH_BYTE (PRE); + GF_MATCH_BYTE (GF_ID); + + comment_length = GF_GET_BYTE (); + answer = gf_get_string (comment_length); + + return answer; +} + +/* Reading the postamble. This is the user-level call. We make no + assumptions about the current position of the file pointer. */ + +gf_postamble_type +gf_get_postamble () +{ + one_byte b; + byte_count_type old_pos, post_ptr; + unsigned this_char; + + assert (gf_input_file != NULL); + + if (private_postamble != NULL) /* Previously read it? */ + return *private_postamble; + + old_pos = GF_FTELL (); + GF_FSEEK (0, SEEK_END); + + /* If the input file is empty, give a better message than `Invalid + argument' (because we are trying to seek before the beginning). */ + if (GF_FTELL () == 0) + FATAL1 ("%s: empty file", gf_input_filename); + + do + b = GF_GET_PREVIOUS (); + while (b == GF_SIGNATURE); + + if (b != GF_ID) + FATAL2 ("Expected GF id (%u), found %u", GF_ID, b); + + post_ptr = GF_GET_PREVIOUS_FOUR (); + + private_postamble = xmalloc (sizeof (gf_postamble_type)); + + for (this_char = 0; this_char <= MAX_CHARCODE; this_char++) + { + GF_CHAR_LOC (*private_postamble, this_char).charcode + = this_char; + GF_CHAR_LOC (*private_postamble, this_char).char_pointer + = NULL_BYTE_PTR; + } + + GF_FSEEK (post_ptr, SEEK_SET); + get_postamble (); /* Fills in `private_postamble'. */ + + GF_FSEEK (old_pos, SEEK_SET); + return *private_postamble; +} + + +/* Assume we are positioned at the beginning of the postamble. Fill in + `private_postamble' with what we find. */ + +static void +get_postamble () +{ + GF_MATCH_BYTE (POST); + + (void) GF_GET_FOUR (); /* Ignore the special pointer. */ + + GF_DESIGN_SIZE (*private_postamble) = GF_GET_FOUR (); + GF_CHECKSUM (*private_postamble) = GF_GET_FOUR (); + + /* The resolution values are stored in the file as pixels per point, + scaled by 2^16. */ + GF_H_RESOLUTION (*private_postamble) = GF_GET_FOUR (); + GF_V_RESOLUTION (*private_postamble) = GF_GET_FOUR (); + + MIN_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); + MAX_COL (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); + MIN_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); + MAX_ROW (GF_FONT_BB (*private_postamble)) = GF_GET_SIGNED_FOUR (); + + get_locators (); +} + + +/* We do not know in advance how many character locators exist, but we do + place a maximum on it (contrary to what the GF format definition + says), namely, MAX_CHARCODE. */ + +static void +get_locators () +{ + do + { + one_byte code; + one_byte b = GF_GET_BYTE (); + + if (b == POST_POST) + break; + + code = GF_GET_BYTE (); + + if (b == CHAR_LOC) + { + GF_CHAR_LOC (*private_postamble, code).h_escapement + = scaled_to_real (GF_GET_FOUR ()) + .5; + (void) GF_GET_FOUR (); /* Ignore vertical escapement. */ + } + else if (b == CHAR_LOC0) + GF_CHAR_LOC (*private_postamble, code).h_escapement = GF_GET_BYTE (); + else + FATAL1 ("Expected a char_loc command, not %u", b); + + GF_CHAR_LOC (*private_postamble, code).tfm_width = GF_GET_FOUR (); + GF_CHAR_LOC (*private_postamble, code).char_pointer = GF_GET_FOUR (); + } + while (true); +} + +/* Unlike `gf_get_next_char' (which comes next), this routine will get any + character by its code. It is meant to be called by the user. We + save all the characters we read in the static `char_list', to avoid + going out to the file each time. */ + +gf_char_type * +gf_get_char (one_byte charcode) +{ + gf_char_locator_type char_locator; + byte_count_type char_pointer; + + if (char_list[charcode] != NULL) + return char_list[charcode]; + + (void) gf_get_postamble (); + assert (private_postamble != NULL); + + char_locator = GF_CHAR_LOC (*private_postamble, charcode); + char_pointer = char_locator.char_pointer; + + if (char_pointer != NULL_BYTE_PTR) + { + boolean found; + byte_count_type old_pos = GF_FTELL (); + GF_FSEEK (char_pointer, SEEK_SET); + + char_list[charcode] = xmalloc (sizeof (gf_char_type)); + *(char_list[charcode]) = gf_get_next_char (&found); + assert (found); + + GF_FSEEK (old_pos, SEEK_SET); + } + + return char_list[charcode]; +} + + +/* This reads the character starting from the current position (but some + specials might come first). */ + +gf_char_type +gf_get_next_char (boolean *found) +{ + one_byte c; + gf_char_type gf_char; + + get_specials (GF_FTELL ()); + + c = GF_GET_BYTE (); + + if (c == BOC) + get_full_boc (&gf_char); + + else if (c == BOC1) + get_abbreviated_boc (&gf_char); + + else if (c == POST) + { + *found = false; + return gf_char; /* We are returning garbage, but that's OK. */ + } + + else + FATAL1 ("Expected a character (or the postamble), found %u", c); + + get_character_bitmap (&gf_char); + get_postamble_info (&gf_char); + + deblank (&gf_char); + + *found = true; + return gf_char; +} + + +/* If the back pointer actually points somewhere, this character is a + ``residue'', and the font is probably too big. */ + +static void +get_full_boc (gf_char_type *gf_char) +{ + signed_4_bytes back_pointer, charcode; + + charcode = GF_GET_SIGNED_FOUR (); + if (charcode < 0 || charcode > MAX_CHARCODE) + /* Someone is trying to use a font with character codes that are + out of our range. */ + FATAL1 ("Character code %d out of range 0..255 in GF file (sorry)", + charcode); + + GF_CHARCODE (*gf_char) = charcode; + + back_pointer = GF_GET_SIGNED_FOUR (); + if (back_pointer != -1) + WARNING2 ("Character %u has a non-null back pointer (to %d)", + GF_CHARCODE (*gf_char), back_pointer); + + GF_CHAR_MIN_COL (*gf_char) = GF_GET_SIGNED_FOUR (); + GF_CHAR_MAX_COL (*gf_char) = GF_GET_SIGNED_FOUR (); + GF_CHAR_MIN_ROW (*gf_char) = GF_GET_SIGNED_FOUR (); + GF_CHAR_MAX_ROW (*gf_char) = GF_GET_SIGNED_FOUR (); +} + + +static void +get_abbreviated_boc (gf_char_type *gf_char) +{ + one_byte col_delta, row_delta; + + GF_CHARCODE (*gf_char) = GF_GET_BYTE (); + + col_delta = GF_GET_BYTE (); + GF_CHAR_MAX_COL (*gf_char) = GF_GET_BYTE (); + GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char) - col_delta; + + row_delta = GF_GET_BYTE (); + GF_CHAR_MAX_ROW (*gf_char) = GF_GET_BYTE (); + GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) - row_delta; +} + + +/* We also want to return the horizontal escapement (i.e., set width) + and the TFM width as part of the character, although this information is + not part of the boc..eoc, but rather the postamble. */ + +static void +get_postamble_info (gf_char_type *gf_char) +{ + gf_char_locator_type char_locator; + + (void) gf_get_postamble (); /* Use `private_postamble'. */ + assert (private_postamble != NULL); + + char_locator = GF_CHAR_LOC (*private_postamble, GF_CHARCODE (*gf_char)); + + GF_H_ESCAPEMENT (*gf_char) = char_locator.h_escapement; + GF_TFM_WIDTH (*gf_char) = char_locator.tfm_width; +} + + +/* The GF format does not guarantee that the bounding box is the + smallest possible, i.e., that the character bitmap does not have + blank rows or columns at an edge. We want to remove such blanks. */ + +static void +deblank (gf_char_type *gf_char) +{ + boolean all_white; + bitmap_type gf_bitmap = GF_BITMAP (*gf_char); + unsigned width = BITMAP_WIDTH (gf_bitmap), + height = BITMAP_HEIGHT (gf_bitmap); + unsigned white_on_left = 0, white_on_right = 0, + white_on_top = 0, white_on_bottom = 0; + int this_col, this_row; /* int in case GF_CHAR is zero pixels wide. */ + + /* Let's start with blank columns at the left-hand side. */ + all_white = true; + for (this_col = 0; this_col < width && all_white; this_col++) + { + for (this_row = 0; this_row < height && all_white; this_row++) + { + if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != 0) + all_white = false; + } + if (all_white) + white_on_left++; + } + + /* Now let's check the right-hand side. */ + all_white = true; + for (this_col = width - 1; this_col >= 0 && all_white; this_col--) + { + for (this_row = 0; this_row < height && all_white; this_row++) + { + if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) + all_white = false; + } + if (all_white) + white_on_right++; + } + + /* Check for all-white rows on top now. */ + all_white = true; + for (this_row = 0; this_row < height && all_white; this_row++) + { + for (this_col = 0; this_col < width && all_white; this_col++) + { + if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) + all_white = false; + } + if (all_white) + white_on_top++; + } + + /* And, last, for all-white rows on the bottom. */ + all_white = true; + for (this_row = height - 1; this_row >= 0 && all_white; this_row--) + { + for (this_col = 0; this_col < width && all_white; this_col++) + { + if (BITMAP_PIXEL (gf_bitmap, this_row, this_col) != WHITE) + all_white = false; + } + if (all_white) + white_on_bottom++; + } + + /* If we have to remove columns at either the left or the right, we + have to reallocate the memory, since much code depends on the fact + that the bitmap is in contiguous memory. If we have to remove + rows, we don't necessarily have to reallocate the memory, but we + might as well, to save space. */ + if (white_on_left > 0 || white_on_right > 0 + || white_on_top > 0 || white_on_bottom > 0) + { + bitmap_type condensed; + + if (white_on_left + white_on_right > width) + { /* The character was entirely blank. */ + BITMAP_WIDTH (condensed) = BITMAP_HEIGHT (condensed) = 0; + GF_CHAR_MIN_COL (*gf_char) = GF_CHAR_MAX_COL (*gf_char) + = GF_CHAR_MIN_ROW (*gf_char) = GF_CHAR_MAX_ROW (*gf_char) = 0; + BITMAP_BITS (condensed) = NULL; + } + else + { + dimensions_type d; + DIMENSIONS_HEIGHT (d) = height - white_on_top - white_on_bottom; + DIMENSIONS_WIDTH (d) = width - white_on_left - white_on_right; + condensed = new_bitmap (d); + + for (this_row = 0; this_row < BITMAP_HEIGHT (condensed); this_row++) + for (this_col = 0; this_col < BITMAP_WIDTH (condensed); this_col++) + { + BITMAP_PIXEL (condensed, this_row, this_col) + = BITMAP_PIXEL (gf_bitmap, this_row + white_on_top, + this_col + white_on_left); + } + GF_CHAR_MIN_ROW (*gf_char) += white_on_bottom; + GF_CHAR_MAX_ROW (*gf_char) -= white_on_top; + GF_CHAR_MIN_COL (*gf_char) += white_on_left; + GF_CHAR_MAX_COL (*gf_char) -= white_on_right; + } + + free_bitmap (&GF_BITMAP (*gf_char)); + GF_BITMAP (*gf_char) = condensed; + } +} + + +/* The ``bitmap'' is a sequence of commands that describe it in terms of + run-length encoding. + + GF's row and column numbers are the lower left corner of a pixel. + GF (0,0) is the Cartesian unit square: 0 <= x (col) <= 1, + 0 <= y (row) <= 1. Yes, it's <=, not <. What does this mean for + the maxes and mins? Let's take the height first: if a character has + min_row = 0 and max_row = 10, we start the ``current'' y at 10, + (possibly) paint some pixels on that row, ..., and end up with it at + zero, (possibly) painting some pixels on that row. Thus, there are + 11 (10 - 0 + 1) rows in which we might paint pixels. Now the width: + if a character has min_row = 0 and max_row = 4, the current x starts + at zero, we paint four pixels (let's say), and now the current x is + four (the max possible), so we cannot paint any more. Thus there are + four (4 - 0) columns in which we might paint pixels. + + Weird, huh? */ + +static void +get_character_bitmap (gf_char_type *gf_char) +{ + /* We expect these to be >= 0, but if the GF file is improper, they + might turn to be negative. */ + int height, width; + dimensions_type matrix_dimensions; + coordinate_type current; /* This will be the GF position. */ + boolean painting_black = false; + + current.x = GF_CHAR_MIN_COL (*gf_char); + current.y = GF_CHAR_MAX_ROW (*gf_char); + + width = GF_CHAR_MAX_COL (*gf_char) - GF_CHAR_MIN_COL (*gf_char); + height = GF_CHAR_MAX_ROW (*gf_char) - GF_CHAR_MIN_ROW (*gf_char) + 1; + + /* If the character has zero or negative extent in either dimension, + it's not going to have a bitmap. (If this happens, the GF file is + incorrect; but the discrepancy isn't serious, so we may as well not + bomb out when it happens, especially since PKtoGF has a bug that + produces such a bounding box when the character is all blank.) */ + if (width <= 0 || height <= 0) + { + one_byte b; + BITMAP_HEIGHT (GF_BITMAP (*gf_char)) + = BITMAP_WIDTH (GF_BITMAP (*gf_char)) + = 0; + BITMAP_BITS (GF_BITMAP (*gf_char)) = NULL; + + /* The next non-NO_OP byte should be EOC. */ + while ((b = GF_GET_BYTE ()) == NO_OP) + /* do nothing */ ; + if (b != EOC) + FATAL1 ("Expected eoc (for a blank character), found %u", b); + + return; + } + + DIMENSIONS_HEIGHT (matrix_dimensions) = height; + DIMENSIONS_WIDTH (matrix_dimensions) = width; + GF_BITMAP (*gf_char) = new_bitmap (matrix_dimensions); + + do + { + one_byte c = GF_GET_BYTE (); + + if (c == EOC) + break; + + /* No need to test if `PAINT_0 <= c'; it must be, since PAINT_0 is + zero and `c' is unsigned. */ + if (/* PAINT_0 <= c && */ c <= PAINT3) + get_paint (¤t, &painting_black, c, gf_char); + + else if (SKIP0 <= c && c <= SKIP3) + get_skip (¤t, &painting_black, c, gf_char); + + else if (NEW_ROW_0 <= c && c <= NEW_ROW_164) + get_new_row (¤t, &painting_black, c, gf_char); + + else if (c == NO_OP) + /* do nothing */ ; + + else if ((XXX1 <= c && c <= XXX4) || c == YYY) + get_specials (GF_FTELL ()); + + else + FATAL1 ("Expected paint or skip or new_row, found %u", c); + } + while (true); + + if (tracing_gf_input) + puts (""); +} + + +/* The paint commands come in two varieties -- either with the length + implicitly part of the command, or where it is specified as a separate + parameter. */ + +static void +get_paint (coordinate_type *current, boolean *painting_black, + one_byte command, gf_char_type *gf_char) +{ + unsigned length; + + /* No need to test if `PAINT_0 <= command'; it must be, since PAINT_0 is + zero and `command' is unsigned. */ + if (/* PAINT_0 <= command && */ command <= PAINT_63) + length = command - PAINT_0; + else + { + switch (command) + { + case PAINT1: + length = GF_GET_BYTE (); + break; + + case PAINT2: + length = GF_GET_TWO (); + break; + + case PAINT3: + length = gf_get_three (); + break; + + default: + FATAL1 ("Expected a paint command, found %u", command); + } + } + + /* We have to translate from Cartesian to C coordinates. That means the + x's are the same, but the y's are flipped. */ + if (*painting_black) + { + unsigned matrix_y = GF_CHAR_MAX_ROW (*gf_char) - current->y; + + if (tracing_gf_input) + printf ("%u", length); + + for (; length != 0; length--) + { + unsigned matrix_x = current->x - GF_CHAR_MIN_COL (*gf_char); + + BITMAP_PIXEL (GF_BITMAP (*gf_char), matrix_y, matrix_x) = 1; + + current->x++; + } + } + else + { + current->x += length; + + if (tracing_gf_input) + printf ("(%u)", length); + } + *painting_black = !*painting_black; +} + + +/* Skip commands move down in the GF character, leaving blank rows. */ + +static void +get_skip (coordinate_type * current, boolean * painting_black, + one_byte command, gf_char_type *gf_char) +{ + unsigned rows_to_skip; + + switch (command) + { + case SKIP0: + rows_to_skip = 0; + break; + + case SKIP1: + rows_to_skip = GF_GET_BYTE (); + break; + + case SKIP2: + rows_to_skip = GF_GET_TWO (); + break; + + case SKIP3: + rows_to_skip = gf_get_three (); + break; + + default: + FATAL1 ("Expected skip command, found %u", command); + } + + current->y -= rows_to_skip + 1; + current->x = GF_CHAR_MIN_COL (*gf_char); + *painting_black = false; + + if (tracing_gf_input) + printf ("\nskip %u (y now %d) ", rows_to_skip + 1, current->y); +} + + +/* `new_row' commands move to the next line down and then over. */ + +static void +get_new_row (coordinate_type *current, boolean *painting_black, + one_byte command, gf_char_type *gf_char) +{ + current->y--; + current->x = GF_CHAR_MIN_COL (*gf_char) + command - NEW_ROW_0; + *painting_black = true; + + if (tracing_gf_input) + printf ("\nnew_row %u (x,y now %d,%d) ", command - NEW_ROW_0, + current->x, current->y); +} + +/* Instead of building a bitmap, this routine just reads the bytes that + define the character CHARCODE. If the character doesn't exist, we + return NULL. */ + +/* Append the byte `b' to the buffer in `raw_char', followed by (if + WITH_SIZE_P is true) SIZE, followed SIZE bytes of the input. */ +#define COMMON_APPEND(size, with_size_p) \ + do \ + { \ + append_byte (raw_char, b); \ + if (with_size_p) append_byte (raw_char, size); \ + if (size > 0) append_n_bytes (raw_char, size, get_n_bytes (size, \ + gf_input_file, gf_input_filename)); \ + } \ + while (0) + +#define APPEND_BYTES(n) COMMON_APPEND (n, false) +#define APPEND_VAR_BYTES(n) COMMON_APPEND (n, true) + +raw_char_type * +gf_get_raw_char (one_byte charcode) +{ + one_byte b; /* Command byte we've just read. */ + gf_char_locator_type char_locator; + byte_count_type char_pointer; + byte_count_type old_pos; + raw_char_type *raw_char; + + (void) gf_get_postamble (); + assert (private_postamble != NULL); + + char_locator = GF_CHAR_LOC (*private_postamble, charcode); + char_pointer = char_locator.char_pointer; + + /* If the character doesn't exist in the font, we're done. */ + if (char_pointer == NULL_BYTE_PTR) + return NULL; + + /* Save where we are in the file; we'll restore it when we're done. */ + old_pos = GF_FTELL (); + GF_FSEEK (char_pointer, SEEK_SET); + + raw_char = xmalloc (sizeof (raw_char_type)); + *raw_char = new_raw_gf_char (char_locator); + + /* Unfortunately, the GF format doesn't tell us how many bytes long + the character description is. So, we must decode it enough to + figure out how much to read. */ + + /* The first step is the boc: it might be either the one-byte or + four-byte variant. */ + b = GF_GET_BYTE (); + if (b == BOC) + /* The character code, the backpointer (which will probably be wrong + in the new file, if it exists, but we don't handle non-null + backpointers anyway), the bounding box. */ + APPEND_BYTES (24); + else /* b == BOC1 */ + APPEND_BYTES (5); + + /* Read the character definition; exit when we get to EOC. */ + while ((b = GF_GET_BYTE ()) != EOC) + { + /* First test all the commands that have no parameters. No need to + test if `PAINT_0 <= b'; it must be, since PAINT_0 is zero and + `b' is unsigned. */ + if ((/* PAINT_0 <= b && */ b <= PAINT_63) + || b == SKIP0 + || (NEW_ROW_0 <= b && b <= NEW_ROW_164)) + APPEND_BYTES (0); + + /* Now the ones with a one-byte parameter. */ + else if (b == PAINT1 || b == SKIP1) + APPEND_BYTES (1); + + /* A two-byte parameter. */ + else if (b == PAINT2 || b == SKIP2) + APPEND_BYTES (2); + + /* Three-byte. */ + else if (b == PAINT3 || b == SKIP3) + APPEND_BYTES (3); + + /* Four. */ + else if (b == YYY) + APPEND_BYTES (4); + + /* Commands with a variable-size parameter. */ + else if (b == XXX1) + { + one_byte size = GF_GET_BYTE (); + APPEND_VAR_BYTES (size); + } + + else if (b == XXX2) + { + two_bytes size = GF_GET_TWO (); + APPEND_VAR_BYTES (size); + } + + else if (b == XXX3) + { + four_bytes size = gf_get_three (); + APPEND_VAR_BYTES (size); + } + + else if (b == XXX4) + { + four_bytes size = GF_GET_FOUR (); + APPEND_VAR_BYTES (size); + } + + else if (b == NO_OP) + /* do nothing */; + + else + FATAL1 ("gf_get_raw_char: Bad command byte %u", b); + } + + /* This appends the `eoc'---and now we're done. */ + APPEND_BYTES (0); + + GF_FSEEK (old_pos, SEEK_SET); + return raw_char; +} + + +/* This macro makes sure the raw character RGC has at least NEEDED + bytes free. */ +#define ENSURE_AVAILABLE(rgc, needed) \ + while (RAW_CHAR_ALLOCATED (rgc) - RAW_CHAR_USED (rgc) < needed) \ + { \ + RAW_CHAR_ALLOCATED (rgc) *= 2; \ + RAW_CHAR_BYTES (rgc) \ + = xrealloc (RAW_CHAR_BYTES (rgc), RAW_CHAR_ALLOCATED (rgc)); \ + } + + +/* Append the byte B to the end of the RAW_CHAR's buffer. */ + +static void +append_byte (raw_char_type *raw_char, one_byte b) +{ + ENSURE_AVAILABLE (*raw_char, 1); + RAW_CHAR_UNUSED_START (*raw_char) = b; + RAW_CHAR_USED (*raw_char)++; +} + + +/* Append the N bytes of data pointed to by DATA to the end of + RAW_CHAR's buffer. Free DATA after copying. */ + +static void +append_n_bytes (raw_char_type *raw_char, four_bytes n, one_byte *data) +{ + ENSURE_AVAILABLE (*raw_char, n); + memcpy (&RAW_CHAR_UNUSED_START (*raw_char), data, n); + RAW_CHAR_USED (*raw_char) += n; + free (data); +} + + +/* Make a new raw character. We have to start off the buffer with some + nonempty amount of memory, so that the reallocation will have + something to double. */ + +static raw_char_type +new_raw_gf_char (gf_char_locator_type locator) +{ + raw_char_type c; + + RAW_CHAR_ALLOCATED (c) = 1; + RAW_CHAR_BYTES (c) = xmalloc (RAW_CHAR_ALLOCATED (c)); + RAW_CHAR_USED (c) = 0; + + GF_CHARCODE (c) = locator.charcode; + GF_H_ESCAPEMENT (c) = locator.h_escapement; + GF_TFM_WIDTH (c) = locator.tfm_width; + GF_CHAR_BB (c) = GF_FONT_BB (*private_postamble); + + /* Since we don't want to interpret the bounding box information in + the character, we just make our bounding box be the font bounding + box. Since the only thing a raw character is good for is being + immediately written back out, this doesn't hurt. (The actual + bounding box information in the character isn't lost.) */ + return c; +} + +/* Read all specials beginning from the given location, leaving the file + pointer at the first non-special. We do not save the specials, + though. */ + +static void +get_specials (byte_count_type special_ptr) +{ + boolean found_special = true; + + GF_FSEEK (special_ptr, SEEK_SET); + + do + { + one_byte c = GF_GET_BYTE (); + + switch (c) + { + case XXX1: + (void) gf_get_string (GF_GET_BYTE ()); + break; + + case XXX2: + (void) gf_get_string (GF_GET_TWO ()); + break; + + case XXX3: + (void) gf_get_string (gf_get_three ()); + break; + + case YYY: + (void) GF_GET_FOUR (); + break; + + default: + found_special = false; + GF_FSEEK (-1, SEEK_CUR); + } + } + while (found_special); +} + + +static string +gf_get_string (unsigned length) +{ + string s; + + if (length == 0) return ""; + + s = get_n_bytes (length, gf_input_file, gf_input_filename); + s = xrealloc (s, length + 1); + s[length] = 0; + return s; +} + + +/* C does not provide an obvious type for a 24-bit quantity, so we + return a 32-bit one. */ + +static four_bytes +gf_get_three () +{ + four_bytes v = get_two (gf_input_file, gf_input_filename) << 8; + v |= get_byte (gf_input_file, gf_input_filename); + + return v; +} diff --git a/gf/gf_opcodes.h b/gf/gf_opcodes.h new file mode 100644 index 0000000..f8014bf --- /dev/null +++ b/gf/gf_opcodes.h @@ -0,0 +1,58 @@ +/* gf_opcodes.h: symbolic names for the GF commands. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef GF_OPCODES_H +#define GF_OPCODES_H + +#define PRE 247 +#define POST 248 +#define POST_POST 249 + +#define GF_SIGNATURE 223 +#define GF_ID 131 + +#define BOC 67 +#define BOC1 68 +#define EOC 69 + +#define PAINT_0 0 +#define PAINT_63 63 +#define PAINT1 64 +#define PAINT2 65 +#define PAINT3 66 + +#define SKIP0 70 +#define SKIP1 71 +#define SKIP2 72 +#define SKIP3 73 + +#define NEW_ROW_0 74 +#define NEW_ROW_164 238 + +#define XXX1 239 +#define XXX2 240 +#define XXX3 241 +#define XXX4 242 +#define YYY 243 + +#define NO_OP 244 + +#define CHAR_LOC 245 +#define CHAR_LOC0 246 + +#endif /* not GF_OPCODES_H */ diff --git a/gf/gf_output.c b/gf/gf_output.c new file mode 100644 index 0000000..933b0cc --- /dev/null +++ b/gf/gf_output.c @@ -0,0 +1,438 @@ +/* gf_output.c: write objects to one GF file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-output.h" +#include "gf.h" +#include "scaled-num.h" + +#include "gf_opcodes.h" + + +/* The file we are writing to. */ +static FILE *gf_output_file = NULL; +static string gf_output_filename; + + +/* The bounding box of all the characters we have written. The values + here should be the largest and smallest possible integers. */ +static bounding_box_type font_bb + = { INT_MAX, INT_MIN, INT_MAX, INT_MIN }; + + +/* We keep track of the character locator information as we output + characters, to save the caller from doing the bookkeeping. */ +static gf_char_locator_type char_loc[MAX_CHARCODE + 1]; + +static void init_locators (void); +static void put_locators (void); + + +/* Other parts of the GF file that deserve their own routines. */ +static void put_boc (gf_char_type); +static void put_bitmap (bitmap_type); + + +/* Subroutines for writing the bitmap. */ +static void put_paint (unsigned); +static void put_skip (unsigned); +static void put_new_row (unsigned); + +/* Low-level output. These macros call the corresponding routines in + fontutils, using the static variables for the input file and filename. */ + +#define GF_FTELL() xftell (gf_output_file, gf_output_filename) +#define GF_PUT_BYTE(b) put_byte (b, gf_output_file, gf_output_filename) +#define GF_PUT_TWO(b) put_two (b, gf_output_file, gf_output_filename) +#define GF_PUT_THREE(n) put_three (n, gf_output_file, gf_output_filename) +#define GF_PUT_FOUR(n) put_four (n, gf_output_file, gf_output_filename) +#define GF_PUT_SIGNED_FOUR(n) \ + put_signed_four (n, gf_output_file, gf_output_filename); + +/* Routines to start and end writing a file. (For the user to call.) + We make sure the caller can't have two output files open + simultaneously. */ + +boolean +gf_open_output_file (string filename) +{ + assert (gf_output_file == NULL); + + gf_output_filename = filename; + gf_output_file = fopen (filename, "w"); + + if (gf_output_file != NULL) + { + init_locators (); + return true; + } + else + return false; +} + + +void +gf_close_output_file () +{ + assert (gf_output_file != NULL); + + xfclose (gf_output_file, gf_output_filename); + + gf_output_filename = NULL; + gf_output_file = NULL; +} + +/* Write the preamble. */ + +void +gf_put_preamble (string comment) +{ + unsigned comment_length, c; + + assert (gf_output_file != NULL); + + GF_PUT_BYTE (PRE); + GF_PUT_BYTE (GF_ID); + + comment_length = strlen (comment); + + if (comment_length > 255) + comment_length = 255; + + GF_PUT_BYTE (comment_length); + /* We can't just output all the characters in the string, since the + string might have been too long. */ + for (c = 0; c < comment_length; c++) + GF_PUT_BYTE (*(comment + c)); +} + +/* Write the postamble. */ + +void +gf_put_postamble (fix_word design_size, real h_resolution, real v_resolution) +{ + byte_count_type post_ptr; + unsigned i; + + assert (gf_output_file != NULL); + + fflush (gf_output_file); + post_ptr = GF_FTELL (); + GF_PUT_BYTE (POST); + GF_PUT_FOUR (post_ptr); /* No specials before the postamble. */ + GF_PUT_FOUR (design_size); + GF_PUT_FOUR (0); /* Don't bother with a checksum. */ + + /* The resolution values are given to us in pixels per inch, but we + must write them in pixels per point (as well as scaling them). */ + GF_PUT_FOUR (real_to_scaled (h_resolution / POINTS_PER_INCH)); + GF_PUT_FOUR (real_to_scaled (h_resolution / POINTS_PER_INCH)); + + GF_PUT_SIGNED_FOUR (MIN_COL (font_bb)); + GF_PUT_SIGNED_FOUR (MAX_COL (font_bb)); + GF_PUT_SIGNED_FOUR (MIN_ROW (font_bb)); + GF_PUT_SIGNED_FOUR (MAX_ROW (font_bb)); + + put_locators (); + + GF_PUT_BYTE (POST_POST); + GF_PUT_FOUR (post_ptr); + GF_PUT_BYTE (GF_ID); + + for (i = 0; i < 4; i++) + GF_PUT_BYTE (GF_SIGNATURE); +} + + +/* Here we output the information we have accumulated in the `char_loc' + array. GF format allows for two different `char_loc' commands, one + more efficient (but less general) than the other. We use the + appropriate one. */ + +static void +put_locators () +{ + unsigned this_char; + + for (this_char = 0; this_char <= MAX_CHARCODE; this_char++) + { + gf_char_locator_type this_char_loc = char_loc[this_char]; + + if (this_char_loc.char_pointer != NULL_BYTE_PTR) + { + int h_escapement = this_char_loc.h_escapement; + + /* Decide if we can use CHAR_LOC0. */ + if (h_escapement >= 0 && h_escapement < ONE_BYTE_BIG) + { + GF_PUT_BYTE (CHAR_LOC0); + GF_PUT_BYTE (this_char); + GF_PUT_BYTE (h_escapement); + } + else + { + GF_PUT_BYTE (CHAR_LOC); + GF_PUT_BYTE (this_char); + GF_PUT_FOUR (real_to_scaled ((real) h_escapement)); + GF_PUT_FOUR (0); /* No vertical escapement. */ + } + + GF_PUT_FOUR (this_char_loc.tfm_width); + GF_PUT_SIGNED_FOUR (this_char_loc.char_pointer); + } + } +} + + +/* We must initialize the character locators to all null values. */ + +static void +init_locators () +{ + unsigned this_char; + + for (this_char = 0; this_char <= MAX_CHARCODE; this_char++) + char_loc[this_char].char_pointer = NULL_BYTE_PTR; +} + +/* Do what's necessary to prepare for outputting a character. */ + +static void +start_put_char (charcode_type charcode, unsigned h_escapement, + fix_word tfm_width, bounding_box_type char_bb) +{ + gf_char_locator_type *this_char_loc = &(char_loc[charcode]); + + assert (gf_output_file != NULL); + + if (this_char_loc->char_pointer != NULL_BYTE_PTR) + { + WARNING1 ("gf_put_char: Character %u already output", charcode); + return; + } + + /* Update the character locator information (part of the postamble). */ + this_char_loc->char_pointer = GF_FTELL (); + this_char_loc->h_escapement = h_escapement; + this_char_loc->tfm_width = tfm_width; + this_char_loc->charcode = charcode; + + /* Update the font bounding box. */ + if (MIN_COL (char_bb) < MIN_COL (font_bb)) + MIN_COL (font_bb) = MIN_COL (char_bb); + if (MAX_COL (char_bb) > MAX_COL (font_bb)) + MAX_COL (font_bb) = MAX_COL (char_bb); + if (MIN_ROW (char_bb) < MIN_ROW (font_bb)) + MIN_ROW (font_bb) = MIN_ROW (char_bb); + if (MAX_ROW (char_bb) > MAX_ROW (font_bb)) + MAX_ROW (font_bb) = MAX_ROW (char_bb); +} + + +/* Output the character GF_CHAR. */ + +void +gf_put_char (gf_char_type gf_char) +{ + start_put_char (GF_CHARCODE (gf_char), GF_H_ESCAPEMENT (gf_char), + GF_TFM_WIDTH (gf_char), GF_CHAR_BB (gf_char)); + put_boc (gf_char); + put_bitmap (GF_BITMAP (gf_char)); + GF_PUT_BYTE (EOC); +} + + +/* Output the BOC command that begins each character. BOC commands come + in two flavors, one of which takes less space but is less general. */ + +static void +put_boc (gf_char_type gf_char) +{ + signed_4_bytes row_delta = (GF_CHAR_MAX_ROW (gf_char) + - GF_CHAR_MIN_ROW (gf_char)); + signed_4_bytes col_delta = (GF_CHAR_MAX_COL (gf_char) + - GF_CHAR_MIN_COL (gf_char)); + + /* Decide if we can use BOC1, the abbreviated form. */ + if (row_delta < ONE_BYTE_BIG && row_delta >= 0 + && col_delta < ONE_BYTE_BIG && col_delta >= 0 + && GF_CHAR_MAX_ROW (gf_char) < ONE_BYTE_BIG + && GF_CHAR_MAX_ROW (gf_char) >= 0 + && GF_CHAR_MAX_COL (gf_char) < ONE_BYTE_BIG + && GF_CHAR_MAX_COL (gf_char) >= 0) + { + GF_PUT_BYTE (BOC1); + GF_PUT_BYTE (GF_CHARCODE (gf_char)); + GF_PUT_BYTE (col_delta); + GF_PUT_BYTE (GF_CHAR_MAX_COL (gf_char)); + GF_PUT_BYTE (row_delta); + GF_PUT_BYTE (GF_CHAR_MAX_ROW (gf_char)); + } + else + { + GF_PUT_BYTE (BOC); + GF_PUT_FOUR (GF_CHARCODE (gf_char)); + GF_PUT_SIGNED_FOUR (NULL_BYTE_PTR); /* We never have a backpointer. */ + GF_PUT_SIGNED_FOUR (GF_CHAR_MIN_COL (gf_char)); + GF_PUT_SIGNED_FOUR (GF_CHAR_MAX_COL (gf_char)); + GF_PUT_SIGNED_FOUR (GF_CHAR_MIN_ROW (gf_char)); + GF_PUT_SIGNED_FOUR (GF_CHAR_MAX_ROW (gf_char)); + } +} + + +/* Bitmaps in GF format are run-encoded. There are three commands: + `paint', which writes a run of pixels (either black or white); + `skip', which leaves entirely blank rows; and `new_row', which begins + a new row with the first black pixel some number of pixels from the + left edge. */ + +static void +put_bitmap (bitmap_type b) +{ + unsigned run = 0; /* Length of the current run. */ + one_byte current_color = WHITE; + boolean recent_eol = false; /* Have we seen only white since eol? */ + unsigned all_white = 0; /* Count of entirely blank rows. */ + unsigned this_row, this_col; + + + for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++) + { + for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++) + { + one_byte p = BITMAP_PIXEL (b, this_row, this_col); + + if (p == current_color) + run++; + else + { + if (recent_eol) + { /* First transition to black on new row? */ + recent_eol = false; + put_skip (all_white); + all_white = 0; + /* We've seen only white up to now, since + `current_color' is zero after each row. */ + put_new_row (run); + } + else + put_paint (run); + + current_color = p; + run = 1; + } + } + + if (current_color == BLACK) + { + put_paint (run); /* The row ended with black. */ + current_color = WHITE; + } + + else if (recent_eol) + all_white++; /* The row was entirely white. */ + + recent_eol = true; + run = 0; + } +} + + +/* Routines to output the actual GF commands that describe the bitmap. + We use the shortest possible command. */ + +static void +put_paint (unsigned run) +{ + if (run < 64) + GF_PUT_BYTE (run); + else if (run < ONE_BYTE_BIG) + { + GF_PUT_BYTE (PAINT1); + GF_PUT_BYTE (run); + } + else if (run < TWO_BYTES_BIG) + { + GF_PUT_BYTE (PAINT2); + GF_PUT_TWO (run); + } + else if (run < THREE_BYTES_BIG) + { + GF_PUT_BYTE (PAINT3); + GF_PUT_THREE (run); + } + else + FATAL1 ("put_paint: Run of %u pixels too long for GF format", run); +} + + +static void +put_skip (unsigned all_white) +{ + if (all_white == 0) + ; /* Do nothing. */ + else if (all_white == 1) + GF_PUT_BYTE (SKIP0); + else if (all_white < ONE_BYTE_BIG) + { + GF_PUT_BYTE (SKIP1); + GF_PUT_BYTE (all_white - 1); + } + else if (all_white < TWO_BYTES_BIG) + { + GF_PUT_BYTE (SKIP2); + GF_PUT_TWO (all_white - 1); + } + else if (all_white < THREE_BYTES_BIG) + { + GF_PUT_BYTE (SKIP3); + GF_PUT_THREE (all_white - 1); + } + else + FATAL1 ("put_skip: %u rows is too many for GF format", all_white); +} + + +static void +put_new_row (unsigned indent) +{ + if (indent <= 164) + GF_PUT_BYTE (NEW_ROW_0 + indent); + else + { + /* Too large for a new_row command; have to skip and then paint. */ + GF_PUT_BYTE (SKIP0); + put_paint (indent); + } +} + + +/* Output a raw character. */ + +void +gf_put_raw_char (raw_char_type raw_char) +{ + one_byte charcode = GF_CHARCODE (raw_char); + + start_put_char (charcode, GF_H_ESCAPEMENT (raw_char), + GF_TFM_WIDTH (raw_char), GF_CHAR_BB (raw_char)); + put_n_bytes (RAW_CHAR_USED (raw_char), RAW_CHAR_BYTES (raw_char), + gf_output_file, gf_output_filename); +} diff --git a/imageto/ChangeLog b/imageto/ChangeLog new file mode 100644 index 0000000..7870509 --- /dev/null +++ b/imageto/ChangeLog @@ -0,0 +1,1113 @@ +Mon Apr 8 09:25:30 1996 Kathy Hargreaves <letters@cs.umb.edu> + + * out-chars.c: doc fix. + +Sat Dec 9 07:21:29 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (do_image_line): doc fix. + +Wed Dec 6 08:28:15 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (output_chars): doc fix. + +Tue Dec 5 09:40:23 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: doc fix. + +Mon Dec 4 07:40:24 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * main.c (USAGE): doc fix. + + * out-chars.c: doc fix. Changed image_bitmap to image_line_bitmap. + (do_image_line): Changed original_box_count to previous_box_count. + +Sun Dec 3 09:05:05 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (do_image_line): doc fix. + +Thu Nov 30 09:03:47 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (output_chars): doc fix. + +Tue Nov 28 09:47:19 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (output_chars): reconsider the current bounding box + if the current character is ignored. + +Thu Nov 23 08:36:07 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (bitmap_to_gf_char): call kpse_find_tfm instead of + find_tfm_filename. + +Thu Nov 16 09:01:31 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (bitmap_to_gf_char): Remove output_name's suffix + before calling find_tfm_filename with it. + + * main.c: (OUTPUT_NAME): Made on-static so could do below. + + * main.h: Added output_name extern declaration. + + * out-chars.c: (bitmap_to_gf_char): Call kpse_find_tfm with + find_tfm_filename(output_name) instead of something built with + input_name, so that will have the design size in the name. + +Tue Nov 14 07:28:21 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * ifi.c: (read_ifi_file): increment n after setting the charcode, + not before, so first character will have charcode 0. + +Sat Oct 14 14:54:27 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * out-chars.c: (bitmap_to_gf_char): Also have to call + remove_suffix on input name passed to kpse_find_tfm. + +Thu Oct 12 10:44:23 1995 Karl Berry <karl@cs.umb.edu> + + * out-chars.c (bitmap_to_gf_char): Have to call basename on the + input name passed to kpse_find_tfm. + +Sun Aug 13 18:01:11 1995 Karl Berry <karl@cs.umb.edu> + + * main.c: Call kpse_set_progname. + +Sun May 15 11:32:54 1994 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (output_chars): Change `x' to `<ignored>'. + +Fri May 13 15:27:29 1994 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (bitmap_to_gf_char): Call kpse_find_tfm, now that it + exists. + +Sun Aug 22 13:32:49 1993 Karl Berry (karl@cs.umb.edu) + + * out-epsf.c (PIXELS_TO_BP): No longer needed. + +Sat Aug 7 13:44:10 1993 Karl Berry (karl@cs.umb.edu) + + * input-img.c (img_get_header): Allow grayscale images. + + * *.h: types.h now in kpathsea. + +Tue Jul 27 09:04:12 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile (libraries): Add tfm. + +Sun Jul 25 19:20:04 1993 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (bitmap_to_gf_char): Get TFM width from existing TFM + file, if we can find one. Convert for use with kpathsea. + +Thu May 20 17:11:25 1993 Karl Berry (karl@cs.umb.edu) + + * ifi.c: Doc fix. + +Mon Nov 9 09:46:32 1992 Karl Berry (karl@cs.umb.edu) + + * image-header.h: Doc fix. + +Tue Oct 27 13:02:04 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Sat Oct 24 05:13:02 1992 Karl Berry (karl@cs.umb.edu) + + * ifi.c (read_ifi_file): Just do successive character codes if we + don't have an encoding file. + * main.c (USAGE): Change doc. + +Fri Oct 23 10:43:46 1992 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (output_chars): Free the bounding box list we construct. + + * out-chars.c (output_chars): If the IFI struct says no bounding + boxes, don't read any of the bitmap, and reconsider the current bb. + +Tue Oct 20 17:17:26 1992 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile (install): Make the second arg a file, not a directory. + +Fri Oct 16 15:40:53 1992 Karl Berry (karl@cs.umb.edu) + + * out-epsf.c: Doc fix. + +Mon Oct 5 09:31:30 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (read_command_line): Make -print-clean-info imply -verbose. + (main): Remove now-redundant test for `print_clean_info'. + + * out-chars.c (write_image_chars): Only report "+" if we have to + keep reading vertically, not horizontally. + (do_image_line): Remove the report from here. + +Sun Oct 4 08:59:55 1992 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (write_image_chars): Don't keep adding to + `row_height' for appended image rows, just assign. + + * main.c (main): Test for zero resolution here. + (set_input_format): Not here. + + * out-chars.c (clean_threshold): Remove. + * out-chars.h: Likewise. + * main.c (USAGE, read_command_line): And here. + + * out-chars.c (bb_equal_p): New fn. + + * out-chars.c (offset_bb_list): Function moved here from bb-outline.c. + + * out-chars.c (clean_bitmap): Rewrite to take a list of known + boxes, and remove those that aren't in the list. + (output_chars): Only call `clean_bitmap' once, after we've + combined everything. + (image_to_bitmap_bbs): New fn. + +Sat Oct 3 13:54:39 1992 Karl Berry (karl@cs.umb.edu) + + * out-chars.c (write_image_chars): Don't abort if the image ends + prematurely, just give a warning and return. + + * out-chars.c (OUTPUT_CHAR_P): New macro. + (output_chars): Use it, instead of repeating the same expr several + times. + +Fri Oct 2 16:14:03 1992 Karl Berry (karl@cs.umb.edu) + + * out-chars.[ch]: New files constructed from main.[ch]. + * main.c: Include out-chars.h. + + * extract.c (REPORT_SCANLINE): use REPORT. + + * main.c (-info-filename): remove this option. + + * {epsf,strips}.[ch]: Rename to out-*. + * GNUmakefile (c_and_h): Likewise. + + * ifi.[ch]: New files constructed from image-char.[ch] and main.c. + * main.c: include ifi.h. + (extract_chars): Change call to read_ifi_file. + * GNUmakefile (c_and_h): add `ifi', remove `image-char'. + +Mon Sep 28 11:11:59 1992 Karl Berry (karl@cs.umb.edu) + + * main.c: change `fprintf (stderr's to use REPORT*. + + * main.c (clean_bitmap): print the size of the bounding box being + cleaned, not that of the enclosing character. (halvers@sol.crd.ge.com) + +Tue Sep 22 13:01:54 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (read_ifi_file): call make_suffix to make the default IFI + filename, instead of appending to the root. + (input_rootname): remove. + (main): don't assign to input_rootname; just set output_name to + the fn call. + (input_name): new static. + + * main.c (clean_bitmap): if clean_threshold is 1.0, do nothing; + else only clean if the gray value is > threshold, not >=. + + * main.c: make diagnostic messages consistent. + + * main.c (do_image_line): set `bb_offset' to just the width + of the previous bb, since we're already incorporating the + interbb whitespace in the second bb. + +Mon Sep 21 10:32:07 1992 Karl Berry (karl@cs.umb.edu) + + * main.c (read_command_line): new option -ifi-file, a synonym for + -info-file. + (USAGE): document it. + + * main.c (set_input_format): don't call strcmp on NULL if the + input filename lacks an extension. + +Thu Sep 3 09:30:54 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Sat Aug 29 16:14:35 1992 Karl Berry (karl@hayley) + + * GNUmakefile (dist, install): new targets to deal with strips.tex. + +Fri Aug 21 16:14:10 1992 Karl Berry (karl@hayley) + + * main.c (read_ifi_file): improve warning message. + +Mon Jul 13 16:58:44 1992 Karl Berry (karl@hayley) + + * epsf.c (write_epsf): use `width_used' for the width of image buffer. + +Thu Jul 2 14:06:09 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (BB_TO_CARTESIAN): subtract IMAGE_CHAR_BASELINE_ADJUST(.) + instead of adding it. + + * main.c (bitmap_to_gf_char): removed `char_baseline'. + +Sun Jun 28 11:54:23 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (bitmap_to_gf_char): added cartesian_bb; fill it using + BB_TO_CARTESIAN and assign to the GF char. Print out the GF + char's rows for baseline adjustment. + +Fri Jun 26 13:45:20 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (read_ifi_file): changed warning to include encoding name. + +Mon Jun 15 07:37:29 1992 Karl Berry (karl@hayley) + + * extract.c (get_image_row): allocate more than one row at a time. + + * extract.c (get_image_row): don't realloc if we're keeping + leading white rows. + + * main.c (extract_chars): change `nchars_per_line' to one if + `print_guidelines' is true. + + * main.c (read_ifi_file): if the character name is undefined in + the encoding, omit it from the output. + + * main.c (get_image_info): rename to `read_ifi_file'. + + * main.c (get_image_info): make `.notdef' mean omission, instead + of `-1'. + + * image-char.h (image_char_type): new field `charname'. + (IMAGE_CHARNAME): new accessor macro. + * main.c (bitmap_to_gf_char): print the character name, instead of + relying on %c. + (get_image_info): set it. + + * main.h (print_scanline): new routine. + * main.c (print_scanline): define it. + * input-img.c (img_get_scanline): print the scanlines if + `trace_scanlines' is set. + * input-pbm.c (pbm_get_scanline): call it, instead of doing the + printing inline. + +Sat Jun 13 12:04:00 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (get_image_info): renamed charcode_str to charname_str. + Removed comment-handling stuff. + + * main.c (encoding_name, encoding_info): added. + (get_image_info): added `encoding_info'; call `encoding_number' + on `charcode_str' instead of `xparse_charcode'. + (USAGE, read_command_line): added -encoding option. + +Tue Jun 9 13:45:42 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (output_chars): deleted clean_all_bbs. + (clean_bitmap): deleted CLEAN_ALL_BBS; call find_outline_bbs + with false instead of this. Updated doc. Now only check + bounding boxes which don't enclose the whole character, instead + of those which also are on the edge, unless clean_all_bbs is + true, whereupon check those also. + (get_image_info): don't handle CLEAN_ALL_BBS_FLAG anymore. + + * image-char.h (image_char_type): deleted clean_inner_bbs field. + (IMAGE_CHAR_CLEAN_ALL_BBS, CLEAN_ALL_BBS_FLAG): deleted + +Mon Jun 8 12:33:45 1992 Kathy Hargreaves (kathy@hayley) + + * input-pbm.c (pbm_get_scanline): increment scanline_count after + printing it. + + * main.c (BB_TO_CARTESIAN): added. + (bitmap_to_gf_char): when print-guidelines is true, print the + bounding box's max and min (in that order) row in Cartesian + coordinates, not the GF char's min and max row. + +Fri Jun 5 21:18:12 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (output_chars): don't clean bounding boxes unless + outputting the character. + + * main.c (get_image_info): set clean_all_bbs field of `c' false if + there's not a CLEAN_ALL_BBS_FLAG at the end of the character string. + +Fri Jun 5 09:19:48 1992 Karl Berry (karl@hayley) + + * main.c (main): `return 0' instead of `exit (0)'. (From Paul Eggert) + +Tue Jun 2 18:03:52 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (output_chars): call clean_bitmap with 0's for LEFT_MARK + and RIGHT_MARK if clean_all_bbs is true. + +Mon Jun 1 11:19:46 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (output_chars): added clean_all_bbs to send to clean_bitmap. + + * main.c (clean_bitmap): clean only those boxes which are on the + edges only if CLEAN_ALL_BBS is false; otherwise, clean them all. + + * main.c (get_image_info): if there's a CLEAN_ALL_BBS_FLAG appended + to the character code, then set the clean_all_bbs field of c. + + * image-char.h (image_char_type): added clean_all_bbs field. + +Sun May 31 13:10:48 1992 Karl Berry (karl@hayley) + + * main.c: rename `design-size' option to `designsize'. + + * epsf.c (write_epsf): change the EPS output to not write one + gigantic image. + +Sat May 30 11:58:02 1992 Kathy Hargreaves (kathy@hayley) + + * main.c (USAGE -clean-threshold): doc fix. + +Fri May 29 11:34:52 1992 Karl Berry (karl@hayley) + + * main.c (main): declare to return an int. + +Tue May 26 07:56:34 1992 Karl Berry (karl@hayley) + + * main.c: simplify comments on IFI file format, since now the real + documentation describes it. + +Mon May 25 11:45:49 1992 Karl Berry (karl@hayley) + + * main.c (clean_bitmap): wasn't printing clean info for bbs that + weren't cleared. + + * main.c (read_command_line): make -print-guidelines => -verbose. + (USAGE): document this. + (main): don't bother to test `print_guidelines' anymore when we + doing verbose things. + + * main.c (main): use `output_name', not `gf_name' (which we no + longer need). + + * main.c (set_{pbm,img}_input_format): set `input_extension' to + just `pbm' or `img', omitting the leading `.'. + +Sun May 24 18:03:09 1992 Karl Berry (karl@hayley) + + * main.c (read_command_line): in -input-format, complain if they + give an unrecognized input format. + (main): call set_input_format. + (set_input_format): new routine to intuit the input format from + the input filename if they didn't specify. + (set_{pbm,img}_input_format): new routines. + +Thu May 21 10:59:23 1992 Karl Berry (karl@hayley) + + * GNUmakefile, version.c, main.c: change `imagetofont' to `imageto'. + + * strips.c (write_chars_as_strips): don't bother to initialize + `gf_row'. + +Wed May 20 07:34:38 1992 Karl Berry (karl@hayley) + + * strips.h: include image-header.h, not input-img.h. + + * main.c (extract_chars): new fn (to shorten main). + (main): call it. + + * main.c (do_epsf): new global. + (read_command_line): new option `-epsf'. + (main): call `write_epsf' if set. + * GNUmakefile (c_and_h): add epsf. + * epsf.[ch]: new files. + +Mon May 4 09:27:55 1992 Karl Berry (karl@hayley) + + * main.c (main): don't lose the `<dpi>gf' from the output name. + + * strips.c (write_chars_as_strips): add one to `lines_per_char' to + compensate for roundoff error. + + * main.c (verbose): remove this, as it's defined in report.c. + +Sun May 3 19:31:29 1992 Karl Berry (karl@hayley) + + * strips.c (write_chars_as_strips): use REPORT for the progress + report. + +Tue Apr 21 07:44:36 1992 Karl Berry (karl@hayley) + + * extract.c (append_next_image_row): use XTALLOC1. + +Mon Apr 20 12:53:43 1992 Karl Berry (karl@hayley) + + * main.c (main): simplify logic again for figuring out the output + filename; remove any suffix from the input filename before it is + used to make the IFI or output filename. + (get_image_info): the variable is named `input_rootname' now, not + `input_basename'. + +Wed Apr 15 15:26:53 1992 Karl Berry (karl@hayley) + + * main.c (main): `make_output_filename' is now `extend_filename'. + +Wed Apr 8 12:28:59 1992 Karl Berry (karl@hayley) + + * main.c (do_image_line): don't increment the max_col transition + in the horizontally concatenated block, either. + + * main.c: make most of the globals static. + * main.h: remove declarations for unneeded globals. + + * main.c (debug): add this. + +Mon Apr 6 16:43:39 1992 Karl Berry (karl@hayley) + + * extract.c (get_image_row): count white rows in image size; free + the scanline storage after we've copied it. + +Sun Apr 5 11:46:33 1992 Karl Berry (karl@hayley) + + * main.c (do_image_line): don't increment the transition which we + use for the maximum column. + +Sat Apr 4 12:57:15 1992 Karl Berry (karl@hayley) + + * main.c (do_image_line): move test for enough boxes to above + dealing with the current bitmap, so garbage at the end doesn't + mess us up. (from wales@cs.ucla.edu) + +Wed Apr 1 16:17:18 1992 Karl Berry (karl at hayley) + + * main.c (main): simplify the output name creation code. + + * main.c (font_name_extension): rename to `input_extension', and + don't bother to initialize it. + +Sat Mar 28 07:48:43 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Mon Mar 9 16:46:10 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main): move setting of dpi to above (and out of) + do_strips test. + + * main.c (main): set output_name_suffix with static strings + and xmalloc dpi and design_size_str. + + * main.c (main): if output_name has no suffix, append either + output_name_suffix or design_size to its stem before appending + a suffix. + +Sat Mar 7 09:55:42 1992 Karl Berry (karl at hayley) + + * GNUmakefile (libraries): define again. + (files, headers, sources): replace with `c_and_h', etc. + +Thu Mar 5 06:47:26 1992 Karl Berry (karl at hayley) + + * main.c (output_filename): rename to `output_name', and remove + the other `output_name' declaration. + +Wed Mar 4 17:21:32 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main) changed `output_basename' to `output_name'. + Deleted add_suffix and add_design_size. + Added dpi, design_size_str, and output_name_suffix. + Use make_output_filename to check if output name has a suffix. + If output_name not given and not doing strips, set design_size_str. + If doing strips, set output_name_suffix to "sp". + Always set dpi. + +Mon Mar 2 12:15:52 1992 Karl Berry (karl at hayley) + + * main.c (main): decrease nchars_per_line to 11. + +Sun Mar 1 13:03:23 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files): remove bb-outline. + + * GNUmakefile (need_pbm_library): define. + (sources): remove the PBM stuff. + +Fri Feb 28 07:53:09 1992 Karl Berry (karl at hayley) + + * extract.c (image_row_transitions): new routine. + (some_black_to_all_white_row): call it after getting the image row. + (append_next_image_row): call it after appending. + (get_image_row): do not compute the transitions here. + + * main.c (bitmap_to_gf_char): the GF min_row is the depth, the GF + max_row is the height; we had it the other way around. Also, + `row_baseline' is one-origin, but char rows are 0-origin. + +Tue Feb 25 14:40:54 1992 Karl Berry (karl at hayley) + + * main.c (main): decrease number of chars reported without + guidelines to 12. + + * input-pbm.c (pbm_get_scanline): declare the test character for + EOF as int, not char. Also, print the scanlines if + trace_scanlines is set. + * main.c (trace_scanlines): new global. + (read_command_line): new option. + + * bitmap2.c (bitmap_vconcat): put one blank row between the + bitmaps, to compensate for what some_black... removed. + + * extract.c (get_image_row): don't keep leading white rows if + there weren't any; always append scanline, even if there were. + +Fri Jan 31 17:08:38 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): declare `option_index' (for new + getopt). + +Tue Jan 21 11:47:26 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main): wasn't putting the suffix on the gf name when + gave an output filename without a suffix because was finding the + dot in the pathname `../fonts'. + + * main.c (bitmap_to_gf_char): were switching the minimum and + maximum rows when assigning to the gf char. + + * main.c (main): malloc gf_name more precisely. + + * main.c (bitmap_to_gf_char): fixed calculation of gf char's rows. + (main): changed how build the gf output filename: if the user + specifies an output file, don't ever add on a design size and don't + add a suffix if there's one already. + + * main.c (bitmap_to_gf_char): now print gf character's (baseline- + adjusted) row instead of the bounding box's (unadjusted) ones. + +Mon Jan 20 14:46:16 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (main): added variable `output_basename' so user could + specify an output file basename. + (read_command_line): Added `output-file' option. + +Tue Jan 14 13:14:46 1992 Kathy Hargreaves (kathy at hayley) + + * main.c (get_image_info): when call libfile_start with + info_filename, specify "ifi" as the (now-default) suffix. + + * main.c [USAGE] (info-file): use <filename>.ifi if <filename> + doesn't have a dotted suffix; otherwise use <filename>. + +Thu Jan 9 08:29:52 1992 Karl Berry (karl at hayley) + + * main.c (read_command_line): rename `scan_integer_list' to + `scan_unsigned_list'. + + * *.c: do not include global.h. + + * *.h: remove #pragma once. + +Wed Jan 8 15:28:00 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + +Tue Jul 30 13:18:48 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Fri Jul 26 07:02:28 1991 Karl Berry (karl at hayley) + + * main.c (get_image_info): read the left and side bearings from + the IFI file, if present. + (bitmap_to_gf_char): use these numbers. + * image-char.h (image_char_type): new members `lsb' and `rsb'. + (IMAGE_CHAR_{L,R}SB): new accessor macros. + +Wed Jul 24 06:07:11 1991 Karl Berry (karl at hayley) + + * bitmap2.c (bitmap_concat): the height of the result is the + height of one, not twice that. + + * main.c (do_image_line): rename `concat_bitmaps' to + `bitmap_concat'. + * GNUmakefile (files): new file `bitmap2'. + + * main.c (do_image_line): return a boolean saying if we need + another image row. + (main): if `do_image_line' fails, read more of the image. + * extract.h (append_next_image_row): declare new routine. + * extract.c (append_next_image_row): define it. + (get_image_row): new routine. + (some_black_to_all_white_row): call `get_image_row'. + + * make-gsfont.ps (octal-value): prepend 0 to the character code. + + * extract.c (some_black_to_all_white_row): use xcalloc to initialize + `or_of_all', not allocate. We need it to be all zeroes + initially. + + * main.c, version.c: change `imgtogf' to `imagetofont'. + + * make-gsfont.ps: remove all the if-verbose's. + + * main.c: doc fix. + +Mon Jul 22 07:54:42 1991 Karl Berry (karl at hayley) + + * make-gsfont.ps (output-encoding): set /output-encoding to the + dictionary. + + * main.c: output ``imagetofont'' as our name in the GF file header, + instead of ``IMGtoGF''. + + * make-gsfont.ps (print-char-dimensions-if-verbose): lose the + `-if-verbose'. + + * make-gsfont.ps (octal-value): `get' the character name, don't + `load' it, so we find it in the right dictionary. + + * libpbm1.c: declare parms, external functions to avoid warnings. + +Sat Jun 15 09:50:46 1991 Karl Berry (karl at hayley) + + * input-*.c: change `checked_' to `x'. + +Thu Jun 6 07:29:06 1991 Karl Berry (karl at hayley) + + * All files: change to version 2 of the GPL. + +Sat Jun 1 15:18:11 1991 Kathy Hargreaves (kathy at hayley) + + * main.c (get_image_info): Now build an info filename if the + variable info_filename *is* NULL, not when it's not. + (USAGE): Deleted that resolution was set only for pbm input. + Stated that input-format is required and shortened comment. + +Fri May 31 14:30:01 1991 Kathy Hargreaves (kathy at hayley) + + * imgtogf: Moved directory to `imagetofont'. + + * GNUmakefile: Changed program name from `imgtogf' to `imagetofont'. + + * main.c (get_image_info): Make default image info file be + <fontname>.ifi instead of imginf.<fontname>. + + * main.[hc], input-*.[hc]: *_get_header now don't return a + header but rather modify the global header in main.c. Changed + all references to `[img, pbm]_header->' to `image_header.'. + + * main.c, image-char.[hc]: Replaced all instances of `img_char' + with `image_char'. + + * image-char.[hc]: Moved from img-char.[hc]. + + * main.h (image_header): Made this visible to the outside. + + * input-[pbm, img].c ([pbm, img]_get_header): Set h to + image_header in main.c. #include main.h. + + * main.c (read_command_line): Cast the assignment to + image_header.hres to type two_bytes. + + * image-header.h, input-*.[hc], main.[hc]: Changed `img-header.h' + to `image-header.h'. + + * main.c: Replaced all instances of `img_header*' with + `image_header*'. Moved `img_' and `pbm_' to the front of the + function names. + + * img-header.h: Moved to image_header.h and replaced all + instances of `img_header*' with `image_header*'. + + * input-img.[hc] (*_img_*): Moved `img_' to the front of the + variable names. Replaced instances of `img_header_type' with + `image_header_type'. + + * input-pbm.[hc] (*_pbm_*): Moved `pbm_' to the front of the + variable names. + + * extract.c, strips.c: (ptr_get_scanline): Removed `ptr_' from in + front of this function's name and replaced it with `image'. + Replaced instances of `img_header*' with `image_header*', if any. + + * main.h (ptr_open_input_file, ptr_close_input_file, ptr_get_header, + ptr_get_scanline): Removed `ptr_' from the front of all these + names and replaced it with `image'. Replaced `img_header_type' + with `image_header_type'. + + * main.c (ptr_open_input_file, ptr_close_input_file, ptr_get_header, + ptr_get_scanline): Moved and set all to NULL. + Removed `ptr_' from the front of all these names and replaced it + with `image'. + (read_command_line): Remove "img-input-format" from option + structure. + Removed variable need_resolutions, as don't need it. + Force them to specify the input format on the command line + rather than having a default. + +Wed May 29 16:19:57 1991 Kathy Hargreaves (kathy at hayley) + + * input-pbm.c (line_in_bytes): Deleted this global variable, as + don't need it. (pbm_readpbmrow reads right into line_in_bits in + get_pbm_scanline.) + + * pbm.h: Took out #include for types.h. + + * input-pbm.c (get_pbm_scanline): Check if at EOF before calling + pbm_readpbmrow. + + * libpbm2.c (pbm_readpbmrow): Restored to original; can test if at + EOF in the wrapper get_pbm_scanline. + Took out #include for types.h. + + * input-pbm.c (get_pbm_scanline): Hooked up to libpbm2.c routine. + + * main.c (read_command_line): Combined some options and changed + their names and their input. + Make input-format take an argument. + +Mon May 27 14:52:45 1991 Kathy Hargreaves (kathy at hayley) + + * main.c (read_commandline): If both resolutions are missing and + are required on the commandline, print that they both are, not + just that the horizontal one is. + + * bb-outline.c (is_outline_edge): Changed VALID_LOCATION to + BITMAP_VALID_PIXEL. + + * pbmplus.h: Commented out malloc, etc. declarations. + + * libpbm2.c (pbmreadpbmrow): Make it return a boolean instead of a + void, so will fit into our code. + Make it return false instead of an error message. + + * pbm.h (top): pbmplus.h is in the current directory, so take out + the `../' before it in the #include. + (pbmreadpbmrow): Make it return a boolean instead of a void, so + will fit into our code. + + * extract.c (top): Now #include input-pbm.h. + (some_black_to_all_white_row): Changed all instances of + get_img_scanline to get_scanline. + + * input-img.c (top): Now #include img-header.h. + (get_img_header): Got rid of variable format, as now put that in + the header. + + * main.c: (open_input_file, close_input_file, get_header, + get_scanline): Declared these pointers to functions so could set + them to a set of routines belonging to the type of input we're + using. Set them to .pbm input format routines as a default. + (font_name_extension): Added this static variable so could set + it when get read the input format on the command line. Set to + `.pbm' by default. + (main): Initialize img_header to all zeros so will know if the + user set them using the command line. + Changed call to open_img_input_file to open_input_file and + concat font_name_extension instead of ".img" for the argument. + Changed some comments. + Changed the call to get_img_header to get_header. + Changed the call to close_img_input_file to close_input_file. + (USAGE): Added horz-resolution, img-input-format, + pbm-input-format, and vert-resolution. + (read_command_line): Added boolean variable need_resolutions to + keep track of whether or not the user needs to input the + horizontal and vertical resolutions on the command line. + Added horz-resolution, img-input-format, pbm-input-format, and + vert-resolution to the option variable long_options. + If the argument is horz-resolution or vert-resolution, then set + the appropriate field in the header. + If the argument if img-input-format or pbm-input-format, the set + the input function pointers in main to the appropriate set of + functions that belong to the input format. If the argument is + the former, then set needs_resolution to false; if it's the latter, + set it to true. + If the user wants .pbm input format, then check that the header's + resolutions are set; if not, issue an error message and exit. + + * main.h (open_input_file, close_input_file, get_header, get_scanline): + Added these function pointer declarations so extract.c and strips.c + could use them. + + * strips.c (top): Now #include input-pbm.h. + (write_chars_as_strips): Changed the call to get_img_scanline to + a call to get_scanline. + +Sat Apr 13 17:13:51 1991 Karl Berry (karl at hayley) + + * main.c (get_image_info): use the libfile routines to read the + image info files. + + * main.c, input-img.c: new includes from the library + rearrangements. + +Mon Feb 25 16:32:45 1991 Karl Berry (karl at hayley) + + * main.c, strips.c: use `gf_...' instead of `..._gf_...'. + +Sun Feb 17 09:39:20 1991 Karl Berry (karl at hayley) + + * *.c: include config.h. + +Tue Jan 22 15:43:19 1991 Karl Berry (karl at hayley) + + * extract.[ch] (extract_subimage): move to kbase. + +Thu Jan 17 10:32:09 1991 Karl Berry (karl at hayley) + + * main.c (main): don't put the day of the week in the font comment. + +Tue Oct 9 09:07:02 1990 Karl Berry (karl at hayley) + + * main.c (scan_baseline_list): move to kbase. + (baseline_list): make a vector of ints, not unsigneds. + (main): test for the end of the baseline list being -1, not 0. + +Mon Oct 8 16:37:07 1990 Karl Berry (karl at hayley) + + * main.c: #include cmdline.h. + (read_command_line): call FINISH_COMMAND_LINE. + +Sun Sep 30 09:15:25 1990 Karl Berry (karl at hayley) + + * main.c (do_image_line): don't give a report when we read part of + the line, after all. + +Fri Sep 28 13:47:15 1990 Karl Berry (karl at hayley) + + * main.c (scan_integer_list): use strtok, instead of doing the + work ourselves. + +Sat Sep 22 06:16:49 1990 Karl Berry (karl at hayley) + + * main.c (output_chars): don't increment `current_char' if we've + already seen the box. + +Fri Sep 21 08:40:49 1990 Karl Berry (karl at hayley) + + * img-char.h (img_char_type): new element, `alternating'. + (IMG_CHAR_BB_ALTERNATING): macro to access it. + * main.c (get_image_info): if the bb count is negative, set + `alternating' (and make it positive). + (output_chars): handle the bounding boxes alternating. + + * main.c (do_image_line): give a progress report when we read part + of the line. + + * main.c (read_command_line): return NULL at the end; the POSIX + include files don't declare `exit' as volatile, more's the pity. + * bb-output.c (is_outline_edge): return false at the end, for the + same reason. + +Sun Sep 16 11:13:43 1990 Karl Berry (karl at hayley) + + * main.c: include "getopt.h" instead of <getopt.h>. + + * main.c (read_command_line): change call of PARSE_CHAR_CODE to + xparse_char_code. + + * main.c (main): make the default info filename `imginf.<name>', + not `imginfo.<name>'. + +Sat Sep 8 10:06:19 1990 Karl Berry (karl at hayley) + + * main.c (read_command_line): remove any suffix on the font name + before returning it. + + * main.c (read_command_line): use GET_RANGE. + + * main.c (get_image_info): use PARSE_CHAR_CODE to get the + character code from the file. + +Thu Sep 6 06:16:29 1990 Karl Berry (karl at hayley) + + * main.c (scan_integer_list): doc fix. + +Wed Sep 5 06:19:53 1990 Karl Berry (karl at hayley) + + * main.c (USAGE): doc fix in -range. + +Tue Sep 4 09:33:49 1990 Karl Berry (karl at hayley) + + * main.c (do_image_line): pass the current character to + output_chars, not the current box count. + + * extract.c (REPORT_SCANLINE): output to stderr instead of stdout. + + * main.c (get_image_info): always assign to the character code and + omit fields. + +Mon Sep 3 16:57:02 1990 Karl Berry (karl at hayley) + + * main.c (get_image_info): use NULL in subsequent calls to strtok. + + * main.c (get_encoding): replace with get_image_info; change + callers. + * img-char.[ch]: new files to support the data structure. + +Thu Aug 16 08:00:19 1990 Karl Berry (karl at hayley) + + * bb-outline.c (free_bounding_box_list): check if the list is + allocated before freeing it. + + * main.c (do_image_line): only say that we've read too many boxes + once. + +Wed Aug 8 08:06:53 1990 Karl Berry (karl at hayley) + + * main.c (read_command_line): change `encoding-file' to + `info-file'. + +Tue Aug 7 08:53:13 1990 Karl Berry (karl at hayley) + + * main.c (main): use the basename of the image filename to + construct the output name, instead of the full name. + + * main.c (USAGE): explain `-baselines' better. + +Thu Jul 26 06:54:56 1990 Karl Berry (karl at hayley) + + * extract.c (find_transitions): move to kbase. + +Tue Jul 24 13:09:38 1990 Karl Berry (karl at hayley) + + * main.c: don't include time.h. + +Thu Jul 19 15:22:29 1990 Karl Berry (karl at aten) + + * main.c (main): don't dereference baseline_list if it's null. + +Mon Jul 16 08:56:41 1990 Karl Berry (karl at hayley) + + * main.c (clean_bitmap): only print the `. ' if we're printing the + cleaning info. + +Sun Jul 15 08:27:52 1990 Karl Berry (karl at hayley) + + * bb-outline.c (append_bounding_box_list): don't change anything + if we're appending a list of length zero. + +Fri Jul 13 11:35:15 1990 Karl Berry (karl at hayley) + + * main.c (clean_bitmap): also potentially clean bounding boxes on + the bottom edge. + + * main.c (SET_EDGES): make coordinates relative to the bitmap of + the character. + + * main.c (clean_bitmap): only test the gray value for bounding + boxes that are on the edge. + + * main.c (output_chars): return the number of characters actually + output, omitting the ones out of range. + + * main.c (clean_bitmap): print gray values for the bounding boxes + if requested. + (read_command_line): new option, `print_clean_info'. + +Thu Jul 12 06:08:33 1990 Karl Berry (karl at hayley) + + * extract.c (some_black_to_all_white_row): don't output a newline + after reading the scanlines. + + * main.h: new file. + * extract.c: include it, remove declaration of verbose. + + * strips.[ch]: new files. + * main.c (main): cut the image into strips if requested. + (read_command_line): new option `strips'. + + * extract.c (find_transitions): new routine. + (some_black_to_all_white_row): call it, at the end, with a new + variable that is the logical or of all the rows we read. + (some_black_to_all_white_column, found_color_in_column): these + routines aren't needed any more. + * main.c (do_image_line): use the transition vector to set + `char_bitmap'. + + * main.c (scan_integer_list): increment length after checking the + exit condition. + + * main.c (do_image_line): new routine, consisting of a lot of the + main loop. + + * main.c (bitmap_to_gf_char): determine the baseline. + (read_command_line): new option `baselines' to set the baselines. + (scan_integer_list): new routine. + + * extract.c (found_color_in_column): start halfway down the + bitmap. + +Wed Jul 11 06:19:51 1990 Karl Berry (karl at hayley) + + * main.c (bitmap_to_gf_char): take another argument, the character + code, to consolidate where the GF char is set. + + * main.c (nchars_per_line): new static to say how many characters + we can report on per line; different for `print_guidelines' being + set and not set. + + * main.c (print_guidelines): new global. + (read_command_line): new option to set it. + (bitmap_to_gf_char): print the row numbers if it's set. + + * bb-outline.c (find_outline_bbs): take two additional arguments: + column numbers between which we don't look. + * bb-outline.h (find_outline_bbs): change the declaration. + * main.c (main), (clean_bitmap): change the calls. + + * bb-outline.c (append_bounding_box_list): reallocate based on the + element size, not the list size. + + * bb-outline.c (set_bounding_box_list_offset): replace by + `offset_bounding_box_list'. + (append_bb): don't offset the bounding boxes as they come in. + * bb-outline.h (set_bounding_box_list_offset): likewise. + * main.c (main): change call. + + * main.c (output_chars): set char_code to *next_code at the bottom + of the loop, and increment next_code. + +Tue Jul 10 06:10:05 1990 Karl Berry (karl at hayley) + + * bb-outline.c (set_bounding_box_list_offset): new routine. + (append_bb): move the bounding box to the right by the offset. + * bb-outline.h (set_bounding_box_list_offset): declare it. + + * main.c (get_char_code): rename to get_encoding, and read the + whole file. + + * bb-outline.h (init_bounding_box_list, append_bounding_box_list): + declare new routines. + bb-outline.c (same): define them. + +Mon Jul 9 08:10:20 1990 Karl Berry (karl at hayley) + + * main.c (main): don't split each line at white columns. + + * extract.c (clean_bitmap): set verbose to false before calling + find_outline_bbs. + + * main.c (get_char_code): make sure we actually find a character + code. + + * main.c (output_chars): don't extract or clean anything if the + character isn't within range. + + * extract.c (REPORT_SCANLINE): report every 100 scanlines. + + * main.c (output_chars): only give the status report if we + actually output the character. + +Sat Jul 7 10:43:18 1990 Karl Berry (karl at hayley) + + * bb-outline.c (append_bb): changed MAX_ROW, instead of MAX_COL. + + * main.c (clean_bitmap): new routine. + (output_gf_chars): call it. + * bb-outline.c (find_outline_bbs): take an additional parameter to + determine whether to look for inside outlines or not. + + * extract.c (REPORT_SCANLINE): report every 50 scanlines, instead + of every 10. + + * bb-outline.c (find_outline_bbs): look for outlines in + column-major order, instead of row-major. + diff --git a/imageto/GNUmakefile b/imageto/GNUmakefile new file mode 100644 index 0000000..2fcac49 --- /dev/null +++ b/imageto/GNUmakefile @@ -0,0 +1,43 @@ +# Makefile for image conversion program. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +program = imageto + +c_and_h = bitmap2 extract ifi input-img input-pbm main \ + out-chars out-epsf out-strips +h_only = image-header +c_only = version + +libraries = gf pbm tfm + +include ../data/defs.make +include ../data/defsprog.make + +check: + cd /w/ourfonts/dingbats ; gftopk -v g111236.1200gf + + +dist:: + ln strips.tex $(distdir) + +install:: + $(INSTALL_DATA) strips.tex $(texinputdir)/strips.tex + +include M.depend + + diff --git a/imageto/README b/imageto/README new file mode 100644 index 0000000..31f228f --- /dev/null +++ b/imageto/README @@ -0,0 +1,46 @@ +This program extracts the characters from a big image to a GF font file. +Information about the image is given in an ``image font information'' +(IFI) file; that file format is described in the documentation. + +Currently the program can read the IMG files output by the Scan7650 +software, which works with the fancy Xerox 9750 scanner. (I think IMG +output is used by other GEM applications as well.) These images are +used by the Interleaf desktop publishing program. The image format +isn't proprietary, though -- it doesn't have any novel features. The +message below describes the format. + +It can also read PBM files. + + +Date: Thu, 5 Jul 90 11:22:55 EDT +From: rgw@hq.ileaf.com (Bob Watkins x5545) +To: karl@cs.umb.edu + +The image file consists of an OPSHEADER followed by an IMGHEADER, followed +by raster data. The version field of the OPSHEADER determines which of the +IMGHEADER structures to use. Most likely this will be 2, but there is a +chance that it might be 1 -- it depends on how recently the software for +that scanner was written. + +When reading the headers structures, it is a good idea to read them a field +at a time rather than all at once, since not all compilers use the same +structure padding conventions. + +The resolution numbers are in pixels/inch. Their primary purpose is to +allow TPS to scale the image to the correct physical dimensions when it is +pasted into the document. Other than that, they aren't that useful. + +The flags field should be zero -- there is a stupid marketing reason why it +is there at all, but I won't go into that. + +The w and h fields are the width and height of the image in pixels; the d +field is the depth in bits/pixel. The depth is either 1 or 8, depending on +whether the image is a lineart image or a contone image. + +The format field specifies the encoding of the raster data. A format of 0 +means that the data is uncompressed. The data itself is stored in scanline- +major order. In the case of lineart image, 8 pixels are packed into each +byte, with most-to-least significant order within the byte representing left- +to-right order in the image. A 0 bit corresponds to a black pixel, and a 1 +bit corresponds to a white pixel. If necessary, the scanlines are padded out +to the next 16-bit boundary. diff --git a/imageto/bitmap2.c b/imageto/bitmap2.c new file mode 100644 index 0000000..67d3d09 --- /dev/null +++ b/imageto/bitmap2.c @@ -0,0 +1,83 @@ +/* bitmap2.c: extra bitmap manipulation routines. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bitmap.h" + +#include "bitmap2.h" + + + +/* Put B2 to the right of B1, changing B1. For example, if B1 looked + like `A' and B2 like `B', the result would look like `AB'. The two + bitmaps must have the same number of rows. */ + +void +bitmap_concat (bitmap_type *b1, bitmap_type b2) +{ + bitmap_type new; + dimensions_type new_dimens; + unsigned row; + + assert (BITMAP_HEIGHT (*b1) == BITMAP_HEIGHT (b2)); + + DIMENSIONS_WIDTH (new_dimens) = BITMAP_WIDTH (*b1) + BITMAP_WIDTH (b2); + DIMENSIONS_HEIGHT (new_dimens) = BITMAP_HEIGHT (b2); + new = new_bitmap (new_dimens); + + /* Choice of `b2' or `b1' here is arbitrary, of course. */ + for (row = 0; row < BITMAP_HEIGHT (b2); row++) + { + one_byte *target1 = BITMAP_ROW (new, row); + one_byte *target2 = target1 + BITMAP_WIDTH (*b1); + + memcpy (target1, BITMAP_ROW (*b1, row), BITMAP_WIDTH (*b1)); + memcpy (target2, BITMAP_ROW (b2, row), BITMAP_WIDTH (b2)); + } + + free_bitmap (b1); + *b1 = new; +} + + +/* Return a bitmap which consists of B1, one blank row, and B2. The two + bitmaps must have the same width. (The blank row is necessary + because one blank row is removed the first time we call + some_black_to_all_white; consider the row consisting of just an `!'.)*/ + +bitmap_type +bitmap_vconcat (bitmap_type b1, bitmap_type b2) +{ + bitmap_type new; + dimensions_type new_dimens; + unsigned width = BITMAP_WIDTH (b1); + unsigned size1 = width * BITMAP_HEIGHT (b1); + unsigned size2 = width * BITMAP_HEIGHT (b2); + + assert (width == BITMAP_WIDTH (b2)); + + DIMENSIONS_WIDTH (new_dimens) = width; + DIMENSIONS_HEIGHT (new_dimens) = BITMAP_HEIGHT (b1) + BITMAP_HEIGHT (b2) + 1; + new = new_bitmap (new_dimens); + + memcpy (BITMAP_BITS (new), BITMAP_BITS (b1), size1); + memcpy (BITMAP_BITS (new) + size1 + width, BITMAP_BITS (b2), size2); + + return new; +} diff --git a/imageto/bitmap2.h b/imageto/bitmap2.h new file mode 100644 index 0000000..d643117 --- /dev/null +++ b/imageto/bitmap2.h @@ -0,0 +1,34 @@ +/* bitmap2.h: declare extra bitmap manipulation routines. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef BITMAP2_H +#define BITMAP2_H + +#include "bitmap.h" + + +/* Put B2 to the right of B1, changing B2. The two bitmaps must have + the same number of rows. */ +extern void bitmap_concat (bitmap_type *b1, bitmap_type b2); + + +/* Put B2 below B1. The two bitmaps must have the same number of + columns. */ +extern bitmap_type bitmap_vconcat (bitmap_type b1, bitmap_type b2); + +#endif /* not BITMAP2_H */ diff --git a/imageto/extract.c b/imageto/extract.c new file mode 100644 index 0000000..2482646 --- /dev/null +++ b/imageto/extract.c @@ -0,0 +1,239 @@ +/* extract.c: operations on bitmaps. These could be put in + lib/bitmap.c, but since they are not particularly common + operations, we may as well define them separately for now. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bitmap.h" +#include "bounding-box.h" +#include "report.h" + +#include "bitmap2.h" +#include "extract.h" +#include "main.h" +#include "input-img.h" +#include "input-pbm.h" + +static bitmap_type *get_image_row (boolean, unsigned); +static unsigned *image_row_transitions (bitmap_type); + + + + +/* Combine the images in the bitmaps B1 and B2, returning the result in + B1. The relative position of the bitmaps is given by the bounding + boxes BB1 and BB2. We update the bounding box, also. */ + +void +combine_images (bitmap_type *b1, bitmap_type b2, + bounding_box_type *bb1, bounding_box_type bb2) +{ + int this_row, this_col; + bitmap_type whole_bitmap; + bounding_box_type whole_bb; + + /* If either of the bitmaps are nonexistent, we have nothing + significant to do. */ + if (BITMAP_BITS (b2) == NULL) + return; + if (BITMAP_BITS (*b1) == NULL) + { + *b1 = b2; + return; + } + + MIN_ROW (whole_bb) = MIN (MIN_ROW (*bb1), MIN_ROW (bb2)); + MAX_ROW (whole_bb) = MAX (MAX_ROW (*bb1), MAX_ROW (bb2)); + MIN_COL (whole_bb) = MIN (MIN_COL (*bb1), MIN_COL (bb2)); + MAX_COL (whole_bb) = MAX (MAX_COL (*bb1), MAX_COL (bb2)); + + whole_bitmap = new_bitmap (bb_to_dimensions (whole_bb)); + + /* First, copy the first image in. */ + for (this_row = MIN_ROW (*bb1); this_row <= MAX_ROW (*bb1); this_row++) + { + one_byte *target_row + = BITMAP_BITS (whole_bitmap) + + (this_row - MIN_ROW (whole_bb)) * BITMAP_WIDTH (whole_bitmap) + + MIN_COL (*bb1) - MIN_COL (whole_bb); + one_byte *source_row + = BITMAP_BITS (*b1) + + (this_row - MIN_ROW (*bb1)) * BITMAP_WIDTH (*b1); + + memcpy (target_row, source_row, BITMAP_WIDTH (*b1)); + } + + /* Put the second image in. */ + for (this_row = MIN_ROW (bb2); this_row <= MAX_ROW (bb2); this_row++) + for (this_col = MIN_COL (bb2); this_col < MAX_COL (bb2); this_col++) + { + if (BITMAP_PIXEL (b2, this_row - MIN_ROW (bb2), + this_col - MIN_COL (bb2)) == BLACK) + BITMAP_PIXEL (whole_bitmap, this_row - MIN_ROW (whole_bb), + this_col - MIN_COL (whole_bb)) + = BLACK; + } + + free_bitmap (b1); + *b1 = whole_bitmap; + *bb1 = whole_bb; +} + +/* Get the next image row of width WIDTH, ignoring leading white rows. + Return the columns at which there are black-to-white or white-black + transitions in TRANSITIONS. */ + +bitmap_type * +some_black_to_all_white_row (unsigned width, unsigned **transitions) +{ + bitmap_type *new = get_image_row (false, width); + if (new == NULL) + return NULL; + + *transitions = image_row_transitions (*new); + return new; +} + + +/* Get the next image row, including leading blank rows, concatenating + it below B with one blank row between. Otherwise like + `some_black_to_all_white_row'. */ + +bitmap_type * +append_next_image_row (bitmap_type b, unsigned width, unsigned **transitions) +{ + bitmap_type *new = XTALLOC1 (bitmap_type); + bitmap_type *next = get_image_row (true, width); + + if (next == NULL) + return NULL; + + *new = bitmap_vconcat (b, *next); + *transitions = image_row_transitions (*new); + return new; +} + +/* Because scanlines take a relatively long time to read, we will want + some kind of status report. */ + +#define REPORT_SCANLINE() if (++scanline_count % 100 == 0) REPORT (".") + +/* Read scanlines of width WIDTH from the image file until we get one + that has at least one black pixel in it (i.e., found part of a + character). Then read scanlines until we get one that is entirely + white. If KEEP_LEADING_WHITE_ROWS, then include the white rows we + found at the beginning in the returned bitmap; otherwise, it's just + the rows from the first-black to the one before the all-white. */ + +static bitmap_type * +get_image_row (boolean keep_leading_white_rows, unsigned width) +{ + static unsigned scanline_count = 0; + bitmap_type *bitmap; + boolean found_white_row; + one_byte *image; + unsigned rows_used, rows_allocated; + boolean found_black_row = false; + one_byte *scanline = xmalloc (width); + unsigned white_row_count = 0; + + while ((*image_get_scanline) (scanline)) + { + REPORT_SCANLINE (); + + found_black_row = memchr (scanline, BLACK, width) != NULL; + if (found_black_row) + break; + + white_row_count++; + } + + /* If reached end of the image before finding a black row, return NULL. */ + if (!found_black_row) + return NULL; + + /* Initialize the image to either the scanline with some black that we + just found, or to a bitmap with as many all-white rows as we've + seen, depending on `keep_leading_white_rows'. */ + rows_used = 1; + if (keep_leading_white_rows && white_row_count > 0) + { /* We clear the last row unnecessarily, since the next we do is + memcpy into it -- but that's better than realloc-ing. */ + image = xcalloc (white_row_count + 1, width); + rows_used += white_row_count; + memcpy (image + white_row_count * width, scanline, width); + free (scanline); + } + else + image = scanline; + + /* Found the row with a black pixel; now look for the all-white row. + When we start off here, we've allocated exactly as much space as + we've used so far. */ + rows_allocated = rows_used; + found_white_row = false; + while (!found_white_row) + { /* Since we only need one more row at a time, we don't need a + `while' loop here. */ + if (rows_used + 1 > rows_allocated) + { /* Perhaps doubling is the wrong thing to do here, as it may + waste quite a bit of memory. But it's simple. */ + rows_allocated += 100 /* ;<<= 1*/; + image = xrealloc (image, rows_allocated * width); + } + + scanline = image + rows_used * width; + if (!(*image_get_scanline) (scanline)) + break; + REPORT_SCANLINE (); + rows_used++; + found_white_row = memchr (scanline, BLACK, width) == NULL; + } + + bitmap = XTALLOC1 (bitmap_type); + BITMAP_WIDTH (*bitmap) = width; + BITMAP_HEIGHT (*bitmap) = rows_used; + BITMAP_BITS (*bitmap) = image; + + return bitmap; +} + + +/* Return a vector of the column numbers at which B changes from black + to white or white to black, terminated with an element which is B's + width + 1. */ + +static unsigned * +image_row_transitions (bitmap_type b) +{ + unsigned *transitions; + unsigned row, col; + unsigned width = BITMAP_WIDTH (b); + one_byte *or_of_all = xcalloc (width, 1); + + for (row = 0; row < BITMAP_HEIGHT (b); row++) + for (col = 0; col < width; col++) + or_of_all[col] |= BITMAP_PIXEL (b, row, col); + + /* We use `or_of_all' to find transitions: its ith column is 1 + if any row in the image had a black pixel at the ith column. */ + transitions = bitmap_find_transitions (or_of_all, width); + + return transitions; +} diff --git a/imageto/extract.h b/imageto/extract.h new file mode 100644 index 0000000..b1c29e3 --- /dev/null +++ b/imageto/extract.h @@ -0,0 +1,50 @@ +/* extract.h: declare operations on bitmaps. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef EXTRACT_H +#define EXTRACT_H + +#include "bitmap.h" +#include "bounding-box.h" + + +/* Return the segment in B starting after the column START that begins + with a column with at least one black pixel, to a column that is all + white (or the end of the bitmap). If no such segment is found, + return NULL. */ +extern bitmap_type *some_black_to_all_white_column (bitmap_type b); + +/* Read scanlines of width WIDTH (in pixels) from the input file until + we find a segment starting with a row with at least one black pixel, + and ending with a row that is all white (or the end of the file). If + no such segment is found, return NULL. In TRANSITIONS we return the + column numbers where white changes to black or black to white. The + first transition is black-to-white. */ +extern bitmap_type *some_black_to_all_white_row (unsigned width, + unsigned **transitions); + +/* Like `some_black_to_all_white_row', except appends both the white + rows and then the black ones to B. */ +extern bitmap_type *append_next_image_row + (bitmap_type b, unsigned width, unsigned **transitions); + +/* Combine the bitmaps B1 and B2 based on the bounding boxes, returning + the result in B1. Also combine the bounding boxes. */ +extern void combine_images (bitmap_type *b1, bitmap_type b2, + bounding_box_type *, bounding_box_type); +#endif /* not EXTRACT_H */ diff --git a/imageto/ifi.c b/imageto/ifi.c new file mode 100644 index 0000000..45d6b4c --- /dev/null +++ b/imageto/ifi.c @@ -0,0 +1,196 @@ +/* ifi.c: read an IFI file. */ + +#include "config.h" + +#include "encoding.h" +#include "libfile.h" + +#include "ifi.h" +#include "main.h" + + +/* The name of the encoding file specified by the user, and the + structure we parse it into. (-encoding) */ +string encoding_name = NULL; + +/* The name of the IFI file. (-ifi-file) */ +string ifi_filename = NULL; + + +static void append_image_char (image_char_list_type *l, image_char_type c); +static image_char_list_type new_image_char_list (void); + +/* Read the IFI file `ifi_filename' (or construct the IFI filename from + `input_name'), which gives us information about the image we are + going to read. + + See the documentation for full details and examples of IFI files. + Here we just sketch the bare bones. + + Each (non-blank, non-comment) line in this file represents a + ``character'' in the image, and has one to five entries, separated by + spaces and/or tabs. Comments start with `%' and continue to the end + of the line. + + The first entry represents the character code. See the documentation + for the various forms of charcodes. We also allow `.notdef', meaning + the ``character'' should not be output in the font. + + The second entry, if it exists, is an adjustment to the + baseline. We move the baseline down for negative numbers, and up + for positive ones. Default is zero. + + The third entry, if it exists, is the number of bounding boxes that + comprise this character. If it is negative, the bounding boxes + are not consecutive in the image; instead, they alternate with + bounding boxes for some other character. + + The fourth and fifth entries, if they exist, are the left and right + side bearings, respectively. */ + +image_char_list_type +read_ifi_file (unsigned *total_count) +{ + string line; + int bb_count; + encoding_info_type *encoding_info; + int n = 0; + image_char_list_type image_char_list = new_image_char_list (); + + if (encoding_name) + { + encoding_info = XTALLOC1 (encoding_info_type); + *encoding_info = read_encoding_file (encoding_name); + } + else + encoding_info = NULL; + + if (!ifi_filename) + ifi_filename = make_suffix (input_name, "ifi"); + + libfile_start (ifi_filename, "ifi"); + + *total_count = 0; + + while ((line = libfile_line ()) != NULL) + { + image_char_type c; + string baseline_adjust_str, bb_count_str, charname; + string lsb_str, rsb_str; + string save_line = line; /* So we can free it. */ + + /* The character name. */ + charname = strtok (line, " \t"); + + /* `libfile_line' should never return an empty line. */ + assert (charname != NULL); + + if (STREQ (charname, ".notdef")) + IMAGE_CHAR_OMIT (c) = true; + else + { + if (encoding_info) + n = encoding_number (*encoding_info, charname); + /* Otherwise, start n at 0. */ + + if (n == -1) + { + LIBFILE_WARN2 ("Character `%s' undefined in encoding `%s'", + charname, ENCODING_SCHEME_NAME (*encoding_info)); + IMAGE_CHAR_OMIT (c) = true; + } + else + { + IMAGE_CHARCODE (c) = n++; + IMAGE_CHARNAME (c) = xstrdup (charname); + IMAGE_CHAR_OMIT (c) = false; + } + } + + /* The baseline adjustment. */ + baseline_adjust_str = strtok (NULL, " \t"); + IMAGE_CHAR_BASELINE_ADJUST (c) + = baseline_adjust_str == NULL ? 0 : atoi (baseline_adjust_str); + + /* The bounding box count. */ + bb_count_str = strtok (NULL, " \t"); + bb_count = bb_count_str == NULL ? 1 : atoi (bb_count_str); + + if (bb_count < 0) + { + IMAGE_CHAR_BB_COUNT (c) = -bb_count; + IMAGE_CHAR_BB_ALTERNATING (c) = true; + } + else + { + IMAGE_CHAR_BB_COUNT (c) = bb_count; + IMAGE_CHAR_BB_ALTERNATING (c) = false; + } + + /* The left side bearing. */ + lsb_str = strtok (NULL, " \t"); + IMAGE_CHAR_LSB (c) = lsb_str == NULL ? 0 : atoi (lsb_str); + + /* The right side bearing. */ + rsb_str = strtok (NULL, " \t"); + IMAGE_CHAR_RSB (c) = rsb_str == NULL ? 0 : atoi (rsb_str); + + *total_count += IMAGE_CHAR_BB_COUNT (c); + append_image_char (&image_char_list, c); + free (save_line); + } + + libfile_close (); + if (encoding_info) + free (encoding_info); + + return image_char_list; +} + +/* Return an initialized, empty list. */ + +static image_char_list_type +new_image_char_list () +{ + image_char_list_type l; + + IMAGE_CHAR_LIST_LENGTH (l) = 0; + IMAGE_CHAR_LIST_DATA (l) = NULL; + + return l; +} + + +/* Append the character C to the list L. */ + +void +append_image_char (image_char_list_type *l, image_char_type c) +{ + IMAGE_CHAR_LIST_LENGTH (*l)++; + IMAGE_CHAR_LIST_DATA (*l) + = xrealloc (IMAGE_CHAR_LIST_DATA (*l), + IMAGE_CHAR_LIST_LENGTH (*l) * sizeof (image_char_type)); + IMAGE_CHAR (*l, IMAGE_CHAR_LIST_LENGTH (*l) - 1) = c; +} + + +/* Return false if the box BOX_COUNT boxes beyond FIRST_CHAR in LIST + is in the middle of a character, true otherwise. To do this, we + add up all the box counts for characters starting at FIRST_CHAR, + until we see where we land. */ + +boolean +box_at_char_boundary_p (image_char_list_type list, unsigned first_char, + unsigned box_count) +{ + unsigned count = 0; + + while (count < box_count && first_char < IMAGE_CHAR_LIST_LENGTH (list)) + { + image_char_type c = IMAGE_CHAR (list, first_char); + count += IMAGE_CHAR_BB_COUNT (c); + first_char++; + } + + return count == box_count; +} diff --git a/imageto/ifi.h b/imageto/ifi.h new file mode 100644 index 0000000..e013d26 --- /dev/null +++ b/imageto/ifi.h @@ -0,0 +1,91 @@ +/* ifi.h: information about the characters in the image. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef IFI_H +#define IFI_H + +#include <kpathsea/types.h> + + +/* See ifi.c. */ +extern string encoding_name, ifi_filename; + + +/* A single character in the image. */ +typedef struct +{ + charcode_type charcode; + string charname; + boolean omit; + int baseline_adjust; + unsigned bb_count; + boolean alternating; + int lsb, rsb; +} image_char_type; + +/* The character code. This is garbage if `omit' is true. */ +#define IMAGE_CHARCODE(c) ((c).charcode) + +/* The character name. */ +#define IMAGE_CHARNAME(c) ((c).charname) + +/* Says whether this character should be output. */ +#define IMAGE_CHAR_OMIT(c) ((c).omit) + +/* How far the baseline should be moved from the row's baseline. */ +#define IMAGE_CHAR_BASELINE_ADJUST(c) ((c).baseline_adjust) + +/* How many bounding boxes comprise this character. */ +#define IMAGE_CHAR_BB_COUNT(c) ((c).bb_count) + +/* Says whether the bounding boxes in this character are consecutive + (the usual case) or alternate. */ +#define IMAGE_CHAR_BB_ALTERNATING(c) ((c).alternating) + +/* The side bearings. */ +#define IMAGE_CHAR_LSB(c) ((c).lsb) +#define IMAGE_CHAR_RSB(c) ((c).rsb) + + +/* A list of the above. */ +typedef struct +{ + image_char_type *data; + unsigned length; +} image_char_list_type; + +/* The Nth element of the list L. */ +#define IMAGE_CHAR(l, n) ((l).data[n]) + +/* The list as a whole. */ +#define IMAGE_CHAR_LIST_DATA(l) ((l).data) + +/* The length of the list. */ +#define IMAGE_CHAR_LIST_LENGTH(l) ((l).length) + + +/* Read the IFI file IFI_FILENAME. Return the total number of characters + read in TOTAL_COUNT. */ +extern image_char_list_type read_ifi_file (unsigned *total_count); + +/* Return false if the box BOX_COUNT boxes beyond FIRST_CHAR in LIST + is in the middle of a character, true otherwise. */ +extern boolean box_at_char_boundary_p + (image_char_list_type list, unsigned first_char, unsigned box_count); + +#endif /* not IFI_H */ diff --git a/imageto/image-char.c b/imageto/image-char.c new file mode 100644 index 0000000..2f9fc56 --- /dev/null +++ b/imageto/image-char.c @@ -0,0 +1,69 @@ +/* image-char.c: manipulate information about the characters in the image. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "image-char.h" + + +/* Return an initialized, empty list. */ +image_char_list_type +new_image_char_list () +{ + image_char_list_type l; + + IMAGE_CHAR_LIST_LENGTH (l) = 0; + IMAGE_CHAR_LIST_DATA (l) = NULL; + + return l; +} + + +/* Append the character C to the list L. */ + +void +append_image_char (image_char_list_type *l, image_char_type c) +{ + IMAGE_CHAR_LIST_LENGTH (*l)++; + IMAGE_CHAR_LIST_DATA (*l) + = xrealloc (IMAGE_CHAR_LIST_DATA (*l), + IMAGE_CHAR_LIST_LENGTH (*l) * sizeof (image_char_type)); + IMAGE_CHAR (*l, IMAGE_CHAR_LIST_LENGTH (*l) - 1) = c; +} + + +/* Return false if the box BOX_COUNT boxes beyond CURRENT_CHAR in LIST + is in the middle of a character, true otherwise. To do this, we must + add up all the box counts for characters starting at FIRST_CHAR, + until we see where we land. */ + +boolean +box_at_char_boundary_p (image_char_list_type list, unsigned current_char, + unsigned box_count) +{ + unsigned count = 0; + + while (count < box_count && current_char < IMAGE_CHAR_LIST_LENGTH (list)) + { + image_char_type c = IMAGE_CHAR (list, current_char); + count += IMAGE_CHAR_BB_COUNT (c); + current_char++; + } + + return count == box_count; +} diff --git a/imageto/image-char.h b/imageto/image-char.h new file mode 100644 index 0000000..c1b2880 --- /dev/null +++ b/imageto/image-char.h @@ -0,0 +1,89 @@ +/* image-char.h: information about the characters in the image. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef IMAGE_CHAR_H +#define IMAGE_CHAR_H + +#include "types.h" + + +/* A single character in the image. */ +typedef struct +{ + charcode_type charcode; + string charname; + boolean omit; + int baseline_adjust; + unsigned bb_count; + boolean alternating; + int lsb, rsb; +} image_char_type; + +/* The character code. This is garbage if `omit' is true. */ +#define IMAGE_CHARCODE(c) ((c).charcode) + +/* The character name. */ +#define IMAGE_CHARNAME(c) ((c).charname) + +/* Says whether this character should be output. */ +#define IMAGE_CHAR_OMIT(c) ((c).omit) + +/* How far the baseline should be moved from the row's baseline. */ +#define IMAGE_CHAR_BASELINE_ADJUST(c) ((c).baseline_adjust) + +/* How many bounding boxes comprise this character. */ +#define IMAGE_CHAR_BB_COUNT(c) ((c).bb_count) + +/* Says whether the bounding boxes in this character are consecutive + (the usual case) or alternate. */ +#define IMAGE_CHAR_BB_ALTERNATING(c) ((c).alternating) + +/* The side bearings. */ +#define IMAGE_CHAR_LSB(c) ((c).lsb) +#define IMAGE_CHAR_RSB(c) ((c).rsb) + + +/* A list of the above. */ +typedef struct +{ + image_char_type *data; + unsigned length; +} image_char_list_type; + +/* The Nth element of the list L. */ +#define IMAGE_CHAR(l, n) ((l).data[n]) + +/* The list as a whole. */ +#define IMAGE_CHAR_LIST_DATA(l) ((l).data) + +/* The length of the list. */ +#define IMAGE_CHAR_LIST_LENGTH(l) ((l).length) + + +/* Return an empty list. */ +extern image_char_list_type new_image_char_list (void); + +/* Append the character C to the list L. */ +extern void append_image_char (image_char_list_type *l, image_char_type c); + +/* Return false if the box BOX_COUNT boxes beyond FIRST_CHAR in LIST + is in the middle of a character, true otherwise. */ +extern boolean box_at_char_boundary_p + (image_char_list_type list, unsigned first_char, unsigned box_count); + +#endif /* not IMAGE_CHAR_H */ diff --git a/imageto/image-header.h b/imageto/image-header.h new file mode 100644 index 0000000..9d48a60 --- /dev/null +++ b/imageto/image-header.h @@ -0,0 +1,35 @@ +/* image-header.h: declarations for a generic image header. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef IMAGE_HEADER_H +#define IMAGE_HEADER_H + +#include <kpathsea/types.h> + +/* The important general information about the image data. + See `get_{img,pbm}_header' for the full details of the headers for + the particular formats. */ +typedef struct +{ + two_bytes hres, vres; /* In pixels per inch. */ + two_bytes width, height; /* In bits. */ + two_bytes depth; + unsigned format; /* (for pbm) Whether packed or not. */ +} image_header_type; + +#endif /* not IMAGE_HEADER_H */ diff --git a/imageto/input-img.c b/imageto/input-img.c new file mode 100644 index 0000000..1930350 --- /dev/null +++ b/imageto/input-img.c @@ -0,0 +1,159 @@ +/* input-img.c: read Interleaf .img files. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" + +#include "main.h" +#include "image-header.h" +#include "input-img.h" + + +/* Where the input comes from. */ +static FILE *img_input_file; +static string img_input_filename; + +/* What we'll read the raw data for each scanline into. */ +static one_byte *line_in_bytes; + +/* How big `line_in_bytes' is, in both bytes and pixels. */ +static unsigned byte_width; +static unsigned pixel_width; +static unsigned pixel_depth; + +/* Macros for convenient input. The routines are defined in kbase. */ +#define IMG_MATCH_BYTE(v) match_byte (v, img_input_file, img_input_filename) + +#define IMG_GET_TWO() get_two (img_input_file, img_input_filename) +#define IMG_GET_FOUR() get_four (img_input_file, img_input_filename) + +/* Only one file can be open at a time. We do no path searching. If + FILENAME can't be opened, we quit. */ + +void +img_open_input_file (string filename) +{ + assert (img_input_file == NULL); + + img_input_file = xfopen (filename, "r"); + img_input_filename = filename; +} + + +/* Close the input file. If it hasn't been opened, we quit. */ + +void +img_close_input_file () +{ + assert (img_input_file != NULL); + + xfclose (img_input_file, img_input_filename); + img_input_file = NULL; +} + +/* Read the header information. + Modifies the global image_header in main.c. */ + +void +img_get_header () +{ + unsigned flags; + unsigned pixels_per_short; + unsigned short_width; + + /* The ``magic number''. */ + IMG_MATCH_BYTE (0211); + IMG_MATCH_BYTE ('O'); + IMG_MATCH_BYTE ('P'); + IMG_MATCH_BYTE ('S'); + + /* The version number. */ + IMG_MATCH_BYTE (0); + IMG_MATCH_BYTE (2); + + image_header.hres = IMG_GET_TWO (); + image_header.vres = IMG_GET_TWO (); + flags = IMG_GET_FOUR (); + if (flags != 0) + FATAL1 ("img_get_header: Expected flags to be zero, not %u", flags); + image_header.width = IMG_GET_TWO (); + image_header.height = IMG_GET_TWO (); + pixel_depth = image_header.depth = IMG_GET_TWO (); + image_header.format = IMG_GET_TWO (); + if (image_header.format != 0) + FATAL1 ("img_get_header: Expected format to be zero, not %u", + image_header.format); + + /* Allocate the space that we will read into (since that space is the + same from scanline to scanline). The width is derived from the + header information, which must already have been read. + Specifically, the width in the header is given in bits. Each + scanline is padded to a 16-bit boundary. For example, suppose the + header width = 1516, that is 94.75 shorts; we round up to 95, + thus getting a scanline width of 1520 bits, or 190 bytes. (For + monochrome images.) */ + pixel_width = image_header.width; + pixels_per_short = 16 / image_header.depth; + short_width = pixel_width / pixels_per_short + + (pixel_width % pixels_per_short != 0); + byte_width = short_width * 2; + line_in_bytes = xmalloc (byte_width); +} + +/* Read one scanline of the image, returning each bit of the scanline in + a separate byte. We may use the `line_in_bytes' variable, allocated in + `img_get_header' just above, to read into. */ + +boolean +img_get_scanline (one_byte *line_in_pixels) +{ + /* No point in using temp. buffer if pixels and bytes are the same. */ + if (fread (line_in_bytes, byte_width, 1, img_input_file) != 1) + { + if (feof (img_input_file)) + return false; + else + FATAL1 ("img_get_scanline: fread of %u bytes failed", byte_width); + } + + /* Don't handle cases other than depth 1 or 8. */ + if (pixel_depth == 1) + { + unsigned this_bit, this_byte, mask; + for (this_bit = 0, this_byte = 0, mask = 0x80; + this_bit < pixel_width; this_bit++) + { + /* Somewhere along the line, black and white got reversed. */ + line_in_pixels[this_bit] = (line_in_bytes[this_byte] & mask) == 0; + if (this_bit % 8 == 0) + { + this_byte = this_bit / 8; + mask = 0x80; + } + else + mask >>= 1; + } + } + else + memcpy (line_in_pixels, line_in_bytes, byte_width); + + print_scanline (line_in_pixels, pixel_width); + + return true; +} diff --git a/imageto/input-img.h b/imageto/input-img.h new file mode 100644 index 0000000..afbaaeb --- /dev/null +++ b/imageto/input-img.h @@ -0,0 +1,43 @@ +/* input-img.h: declarations for reading an IMG file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef INPUT_IMG_H +#define INPUT_IMG_H + +#include <kpathsea/types.h> +#include "image-header.h" + + +/* Prepare to read FILENAME. */ +extern void img_open_input_file (string filename); + +/* Close up gracefully. */ +extern void img_close_input_file (void); + + +/* Read the header. */ +extern void img_get_header (void); + + +/* Read a single scanline into P. P must point to a large-enough block + for one entire scanline (the width of the image is given in the + header). If at the end of the input file, returns false, else + returns true. */ +extern boolean img_get_scanline (one_byte *p); + +#endif /* not INPUT_IMG_H */ diff --git a/imageto/input-pbm.c b/imageto/input-pbm.c new file mode 100644 index 0000000..9fe47ba --- /dev/null +++ b/imageto/input-pbm.c @@ -0,0 +1,88 @@ +/* input-pbm.c: read PBM files. + +Copyright (C) 1990, 1991, 19 19ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" + +#include "main.h" +#include "image-header.h" +#include "input-pbm.h" + +#include "pbmplus.h" +#include "pbm.h" + + +/* Where the input comes from. */ +static FILE *pbm_input_file; +static string pbm_input_filename; + + + +/* Only one file can be open at a time. We do no path searching. If + FILENAME can't be opened, we quit. */ + +void +pbm_open_input_file (string filename) +{ + assert (pbm_input_file == NULL); + + pbm_input_file = xfopen (filename, "r"); + pbm_input_filename = filename; +} + + +/* Close the input file. If it hasn't been opened, we quit. */ + +void +pbm_close_input_file () +{ + assert (pbm_input_file != NULL); + + xfclose (pbm_input_file, pbm_input_filename); + pbm_input_file = NULL; +} + + + +/* Read the header information. + Modifies the global image_header in main.c. */ + +void +pbm_get_header () +{ + int width, height, format; + + pbm_readpbminit (pbm_input_file, &width, &height, &format); + image_header.width = (two_bytes) width; + image_header.height = (two_bytes) height; + image_header.depth = 0; + image_header.format = (two_bytes) format; +} + + + +/* Read one scanline of the image. */ + +boolean +pbm_get_scanline (one_byte *line_in_bits) +{ + int c = getc (pbm_input_file); + + if (c == EOF) + return false; + + ungetc (c, pbm_input_file); + pbm_readpbmrow (pbm_input_file, line_in_bits, image_header.width, + image_header.format); + + print_scanline (line_in_bits, image_header.width); + return true; +} diff --git a/imageto/input-pbm.h b/imageto/input-pbm.h new file mode 100644 index 0000000..522d2de --- /dev/null +++ b/imageto/input-pbm.h @@ -0,0 +1,44 @@ +/* input-pbm.h: declarations for reading an PBM file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef INPUT_PBM_H +#define INPUT_PBM_H + +#include <kpathsea/types.h> +#include "image-header.h" + + +/* Prepare to read FILENAME. */ +extern void pbm_open_input_file (string filename); + +/* Close up gracefully. */ +extern void pbm_close_input_file (void); + + +/* Read the header. */ +extern void pbm_get_header (void); + + +/* Read a single scanline into P. P must point to a large-enough block + for one entire scanline (the width of the image is given in the + header). If at the end of the input file, returns false, else + returns true. */ +extern boolean pbm_get_scanline (one_byte *p); + +#endif /* not INPUT_PBM_H */ + diff --git a/imageto/main.c b/imageto/main.c new file mode 100644 index 0000000..e3215c8 --- /dev/null +++ b/imageto/main.c @@ -0,0 +1,416 @@ +/* imageto -- convert a scanned image. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/concatn.h> + +#define CMDLINE_NO_DPI /* It's not in the input filename. */ +#include "cmdline.h" +#include "encoding.h" /* For `DEFAULT_ENCODING'. */ +#include "getopt.h" +#include "gf.h" +#include "report.h" + +#include "ifi.h" /* For `encoding_name'. */ +#include "image-header.h" +#include "input-img.h" +#include "input-pbm.h" +#include "main.h" +#include "out-chars.h" +#include "out-epsf.h" +#include "out-strips.h" + + +/* General information about the image. Set by the input routines. */ +image_header_type image_header; + +/* Pointers to functions based on input format. (-input-format) */ +void (*image_open_input_file) (string) = NULL; +void (*image_close_input_file) (void) = NULL; +void (*image_get_header) (void) = NULL; +boolean (*image_get_scanline) (one_byte *) = NULL; + +/* The filename for the input image. */ +string input_name; + +/* Show every scanline on the terminal as we read it? (-trace-scanlines) */ +boolean trace_scanlines = false; + +/* Private variables. */ + +/* The design size of the font we're creating. (-designsize) */ +static real design_size = 10.0; + +/* The suffix for the image file. */ +static string input_extension; + +/* If set, write an EPSF file. (-epsf) */ +static boolean output_epsf = false; + +/* The name of the file we're going to write. (-output-file) */ +string output_name; + +/* If set, make each ``character'' a (more or less) constant number of + scanlines. (-strips) */ +static boolean do_strips = false; + + +static string read_command_line (int, string[]); +static void set_img_input_format (void); +static void set_input_format (string); +static void set_pbm_input_format (void); + +/* We have three different strategies for processing the image: + 1) (normal) analyze the image and write out the ``true'' characters, + 2) (-strips) takes a constant number of scanlines as each character, + 3) (-epsf) write out the image as an Encapsulated PostScript file. + + The output name is, correspondingly, constructed differently: + 1) if `output_name' was supplied, and has a suffix, that's it. + 2) if `output_name' was supplied, but has no suffix, append `.eps' + if we're doing EPSF, else append `<suffix>.<dpi>gf', where + <suffix> is + a) `sp', if we are doing strips; + b) the design size, if not. + 3) if `output_name' was not supplied, use the basename of the input + filename extended as in #2. + */ + +int +main (int argc, string argv[]) +{ + boolean writing_gf; + + kpse_set_progname (argv[0]); + + input_name = read_command_line (argc, argv); + writing_gf = !output_epsf; + + set_input_format (input_name); + + /* If the input format is PBM, then they must also tell us the dpi. */ + if (image_open_input_file == pbm_open_input_file + && image_header.hres == 0) + { + fprintf (stderr, "If you use PBM format, you must supply the dpi.\n"); + fprintf (stderr, "For more information, use ``-help''.\n"); + exit (1); + } + + /* Open the main input file. */ + (*image_open_input_file) (extend_filename (input_name, input_extension)); + + /* We need the horizontal resolution before we can make the GF name, + so, at least for IMG input, have to read the header. */ + (*image_get_header) (); + + /* If the user didn't give an output name, use the input name. */ + if (output_name == NULL) + output_name = remove_suffix (basename (input_name)); + + /* If they didn't give an output name with a suffix, use ours. */ + if (find_suffix (output_name) == NULL) + { + if (writing_gf) + { + char dpi[MAX_INT_LENGTH + 1]; + string suffix = do_strips ? "sp" : itoa ((unsigned) design_size); + + sprintf (dpi, "%u", image_header.hres); + output_name = concatn (output_name, suffix, ".", dpi, "gf", NULL); + } + else if (output_epsf) + output_name = concat (output_name, ".eps"); + else + abort (); /* Should never happen. */ + } + + /* If necessary, open the GF file. */ + if (writing_gf) + { + if (!gf_open_output_file (output_name)) + FATAL_PERROR (output_name); + + /* Identify ourselves in the GF comment. */ + gf_put_preamble (concat ("imageto output ", now () + 4)); + } + + /* Do the real work, whichever the user wants. */ + if (do_strips) + { /* The design size is irrelevant when we're creating strips, + but it should be pretty large, lest the relative dimensions in + the TFM file get too big. */ + design_size = 100.0; + write_chars_as_strips (image_header, design_size); + } + else if (output_epsf) + write_epsf (output_name, image_header); + else + write_image_chars (image_header, design_size); + + /* Clean up. */ + if (verbose) + REPORT ("\n"); + + if (writing_gf) + { + /* We've read all the characters we're supposed to (or else the whole + image). Finish up the font. */ + gf_put_postamble (real_to_fix (design_size), + (real) image_header.hres, (real) image_header.vres); + gf_close_output_file (); + } + + (*image_close_input_file) (); + + return 0; +} + +/* We are semi-clever about printing this, for the sake of huge images. */ + +void +print_scanline (one_byte line[], unsigned width) +{ + static unsigned scanline_count = 0; + + if (trace_scanlines) + { + printf ("%7d:", scanline_count++); + + /* If the line is entirely white, don't print anything. */ + if (memchr (line, BLACK, width)) + { + unsigned c; + + for (c = 0; c < width; c++) + { /* Compress eight consecutive spaces to a tab, if we're at + the beginning of a tab mark. This handles the usual + case, although we could do still better. */ + if (c % 8 == 0 && c + 7 < width + && memchr (line + c, BLACK, 8) == NULL) + { + putchar ('\t'); + c += 7; + } + else + putchar (line[c] ? '*' : ' '); + } + } + + putchar ('\n'); + } +} + +/* Reading the options. */ + +/* This is defined in version.c. */ +extern string version_string; + +#define USAGE "Options: +<font_name> should be a base filename, e.g., `ggmr'. (More properly, it +is an <image_name>, not a <font_name>.)" \ + GETOPT_USAGE \ +"baselines <row1>,<row2>,...: define the baselines for each image row. + The baseline of the first image row is taken to be scanline <row1>, etc. +designsize <real>: set the designsize of the font to <real>; default is 10.0. +dpi <unsigned>: resolution (required for pbm input). +encoding <filename>: read ligature and other encoding information + from `<filename>.enc'; the default is to assign successive character codes. +epsf: write the image as an Encapsulated PostScript file, instead of a + bitmap font. +help: print this message. +ifi-file <filename>: use <filename>.ifi (if <filename doesn't have a + suffix; otherwise use <filename>) for the IFI filename; default is + `<font_name>.ifi'. +input-format <format>: specify format of input image; <format> must be + one of `pbm' or `img'. +nchars <unsigned>: only write the first <unsigned> (approximately) + characters to the font; default is infinity. +output-file <filename>: write to <filename> if <filename> has a suffix. + If <filename> doesn't have a suffix, then if writing strips, write to + <filename>sp.<dpi>gf and to <filename>.<dpi>gf if not. By default, + use <font_name> for <filename>. +print-clean-info: print gray values for the bounding boxes that are + considered for cleaning. This implies `-verbose'. +print-guidelines: print the numbers of the top and bottom rows (in that + order) of each character. This implies `-verbose'. +range <char1>-<char2>: only output characters between <char1> and + <char2>, inclusive. +strips: take a constant number of scanlines as each character, + instead of using an IFI file to analyze the image. +trace-scanlines: show every scanline as we read it. +verbose: output progress reports. +version: print the version number of this program. +" + +static string +read_command_line (int argc, string argv[]) +{ + int g; /* `getopt' return code. */ + int option_index; + boolean printed_version = false; + struct option long_options[] + = { { "baselines", 1, 0, 0 }, + { "designsize", 1, 0, 0 }, + { "encoding", 1, 0, 0 }, + { "epsf", 0, (int *) &output_epsf, 1 }, + { "help", 0, 0, 0 }, + { "dpi", 1, 0, 0 }, + { "ifi-file", 1, 0, 0 }, + { "nchars", 1, 0, 0 }, + { "input-format", 1, 0, 0 }, + { "output-file", 1, 0, 0 }, + { "print-clean-info", 0, (int *) &print_clean_info, 1 }, + { "print-guidelines", 0, (int *) &print_guidelines, 1 }, + { "range", 1, 0, 0 }, + { "strips", 0, (int *) &do_strips, 1 }, + { "trace-scanlines", 0, (int *) &trace_scanlines, 1 }, + { "verbose", 0, (int *) &verbose, 1 }, + { "version", 0, (int *) &printed_version, 1 }, + { 0, 0, 0, 0 } }; + + while (true) + { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') + exit (1); /* Unknown option. */ + + assert (g == 0); /* We have no short option names. */ + + if (ARGUMENT_IS ("baselines")) + baseline_list = scan_unsigned_list (optarg); + + else if (ARGUMENT_IS ("designsize")) + design_size = atof (optarg); + + else if (ARGUMENT_IS ("dpi")) + { + image_header.hres = (two_bytes) atou (optarg); + image_header.vres = image_header.hres; + } + + else if (ARGUMENT_IS ("encoding")) + encoding_name = optarg; + + else if (ARGUMENT_IS ("help")) + { + fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]); + fprintf (stderr, USAGE); + exit (0); + } + + else if (ARGUMENT_IS ("ifi-file")) + ifi_filename = optarg; + + else if (ARGUMENT_IS ("input-format")) + { + if (STREQ ("pbm", optarg)) + set_pbm_input_format (); + else if (STREQ ("img", optarg)) + set_img_input_format (); + else + FATAL1 ("imageto: Unknown input format `%s'; expected one of \ +`img' or `pbm'", optarg); + } + + else if (ARGUMENT_IS ("nchars")) + nchars_wanted = atou (optarg); + + else if (ARGUMENT_IS ("output-file")) + output_name = optarg; + + else if (ARGUMENT_IS ("print-clean-info") + || ARGUMENT_IS ("print-guidelines")) + verbose = true; + + else if (ARGUMENT_IS ("range")) + GET_RANGE (optarg, starting_char, ending_char); + + else if (ARGUMENT_IS ("version")) + printf ("%s.\n", version_string); + + /* Else it was a flag; getopt has already done the assignment. */ + } + + if (do_strips && output_epsf) + FATAL ("imageto: Sorry, -strips and -epsf are mutually exclusive"); + + FINISH_COMMAND_LINE (); +} + +/* If the input format wasn't explicitly set on the command line, + attempt to intuit it from FILENAME, and set the necessary variables. + If we can't tell what the format should be, quit. */ + +static void +set_input_format (string filename) +{ + string input_extension; + + /* If it's already set, just return. */ + if (image_open_input_file != NULL) + return; + + /* Try to guess based on FILENAME. */ + input_extension = find_suffix (filename) ? : ""; + + if (STREQ (input_extension, "img")) + set_img_input_format (); + + else if (STREQ (input_extension, "pbm")) + set_pbm_input_format (); + + else /* Can't guess it; quit. */ + { + fprintf (stderr, "You must supply an input format.\n"); + fprintf (stderr, "(I can't guess from the filename `%s'.)\n", filename); + fprintf (stderr, "For more information, use ``-help''.\n"); + exit (1); + } +} + + +/* Set up for reading a PBM file. */ + +static void +set_pbm_input_format () +{ + image_open_input_file = pbm_open_input_file; + image_close_input_file = pbm_close_input_file; + image_get_header = pbm_get_header; + image_get_scanline = pbm_get_scanline; + input_extension = "pbm"; +} + + +/* Set up for reading an IMG file. */ + +static void +set_img_input_format () +{ + image_open_input_file = img_open_input_file; + image_close_input_file = img_close_input_file; + image_get_header = img_get_header; + image_get_scanline = img_get_scanline; + input_extension = "img"; +} diff --git a/imageto/main.h b/imageto/main.h new file mode 100644 index 0000000..7d2f7c1 --- /dev/null +++ b/imageto/main.h @@ -0,0 +1,42 @@ +/* main.h: global variable declarations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef MAIN_H +#define MAIN_H + +#include <kpathsea/types.h> +#include "image-header.h" + + +/* See main.c for explanations of these globals. */ +extern boolean trace_scanlines; +extern image_header_type image_header; +extern string input_name; +extern string output_name; + +/* Generic routines to manipulate the image. */ +extern void (*image_open_input_file) (string filename); +extern void (*image_close_input_file) (void); +extern void (*image_get_header) (void); +extern boolean (*image_get_scanline) (one_byte *); + + +/* Print a scanline LINE of width WIDTH, if `trace_scanlines' is true.. */ +extern void print_scanline (one_byte line[], unsigned width); + +#endif /* not MAIN_H */ diff --git a/imageto/out-chars.c b/imageto/out-chars.c new file mode 100644 index 0000000..b0dc6f4 --- /dev/null +++ b/imageto/out-chars.c @@ -0,0 +1,750 @@ +/* out-chars.c: try to extract the real characters from the image. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/tex-file.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/paths.h> + +#include "bb-outline.h" +#include "gf.h" +#include "report.h" + +#include "bitmap2.h" +#include "extract.h" +#include "ifi.h" +#include "image-header.h" +#include "main.h" +#include "out-strips.h" + +/*xx*/ +FILE *testfileptr; +const char* whole_bitmap_filename = "test-whole-bitmap"; +const char* bb_whole_bitmap_filename = "test-bb-whole-bitmap"; +const char* subbitmap_filename = "test-subbitmap"; +const char* bb_subbitmap_filename = "test-bb-subbitmap"; +const char* line_subbitmap_filename = "test-line-subbitmap"; +const char* line_bb_subbitmap_filename = "test-line-bb-subbitmap"; +const char* gf_bitmap_filename = "test-gf-bitmap"; +const char* gf_bb_bitmap_filename = "test-gf-bb-bitmap"; + + + +/* A list of the image rows on which the baselines occur. The end of + the list is marked with an element -1. (-baselines) */ +int *baseline_list = NULL; + +/* Find about this many characters in the image, then stop. This is + useful only for testing, because converting the entire image takes a long + time. So we might in truth output a few more characters than + specified here. (-nchars) */ +unsigned nchars_wanted = MAX_CHARCODE + 1; + +/* If set, prints diagnostics about which boxes are and aren't cleaned. + (-print-clean-info) */ +boolean print_clean_info = false; + +/* Says whether to print the row numbers of each character as we go, + so that the user can decide how to adjust jumping baselines. + (-print-guidelines) */ +boolean print_guidelines = false; + +/* Says which characters to output. This is independent of the + ordering in the font file. (-range) */ +int starting_char = 0; +int ending_char = MAX_CHARCODE; + +/* The design size of the font we're creating. */ +static real design_size; + +/* Where the baseline of the current row is in the image. The first row + is #1, and so on. We start over at row 1 at each image row.*/ +static unsigned row_baseline; +static unsigned row_height; + +/* How many boxes total the characters take up. */ +static unsigned total_boxes_expected; + + +static boolean bb_equal_p (bounding_box_type, bounding_box_type); +static gf_char_type bitmap_to_gf_char + (bitmap_type, real, bounding_box_type, image_char_type); +static void clean_bitmap (bitmap_type *, bb_list_type); +static boolean do_image_line + (bitmap_type, unsigned *, unsigned *, real, image_char_list_type); +static void image_to_bitmap_bbs (bb_list_type *); +extern void offset_bb_list (bb_list_type *l, int offset); +static unsigned output_chars + (bb_list_type, bitmap_type, real, image_char_list_type, unsigned); + +/* Analyze the input image, outputting the characters we find. */ + +void +write_image_chars (image_header_type image_header, real ds) +{ + bitmap_type *image_line_bitmap; + unsigned nchars_done = 0; + + /* Read the image information. This tells us to which character + each bounding box belongs, among other things. */ + image_char_list_type image_char_list = read_ifi_file (&total_boxes_expected); + + /* Remember this so we don't need to pass it through all the + intervening routines to the low-level output. */ + design_size = ds; + + /* The main loop also (and more commonly) exits when we've read the + entire image. */ + while (nchars_done < nchars_wanted) + { + /* Vector of column numbers where the image column alternates + between some black to all white; used to get the bounding box + column min and max for each character. */ + unsigned *transitions; + + /* Read one line of characters, noting the transitions (see + above), in the image. After this, `image_line_bitmap' is, for + example, `a...z', with blank columns at the left and right. + Whatever is in the original image. */ + image_line_bitmap + = some_black_to_all_white_row (image_header.width, &transitions); + + if (image_line_bitmap == NULL) + break; /* We've read the whole image file. */ + + if (baseline_list == NULL || *baseline_list == -1) + { + if (baseline_list != NULL) + WARNING ("imageto: Not enough baselines specified"); + row_baseline = 0; + } + else + row_baseline = *baseline_list++; + + row_height = BITMAP_HEIGHT (*image_line_bitmap); + + /* Process one line of characters. If `do_image_line' fails, we + need to read the next row in the image, and put it directly + below the current line to complete a character. For example, + if a line has only an `!' on it, we will only get the stem on + the first call to `some_black_to_all_white_row'. We want to + get the dot in there, too. */ + while (!do_image_line (*image_line_bitmap, transitions, &nchars_done, + (real) image_header.hres, image_char_list)) + { + bitmap_type *revised + = append_next_image_row (*image_line_bitmap, image_header.width, + &transitions); + if (revised == NULL) + { + WARNING ("imageto: Image ended in the midst of a character"); + break; + } + + /* Tell the user the image row didn't end on a character. */ + REPORT ("+"); + + free_bitmap (image_line_bitmap); + image_line_bitmap = revised; + if (baseline_list == NULL) + row_baseline = 0; + + row_height = BITMAP_HEIGHT (*image_line_bitmap); + } + + free_bitmap (image_line_bitmap); + } +} + +/* Analyze and output all of the bitmap IMAGE, which is one line of type + in the original. The resolution of the image is H_RESOLUTION, and + we've read NCHARS characters (including .notdefs) so far. We use + IMAGE_CHAR_LIST, a list of character information from the IFI file, + and the transition vector TRANSITIONS, which has in it how IMAGE + breaks into characters or character groups. + + We return false if we need to be given another image row to complete + a character. */ + +#define NEXT_TRANSITION() ({ \ + if (*transitions == BITMAP_WIDTH (image) + 1) \ + { \ + WARNING ("imageto: Expected more transitions"); \ + break; \ + } \ + *transitions++; \ +}) + +static boolean +do_image_line (bitmap_type image, unsigned *transitions, unsigned *nchars, + real h_resolution, image_char_list_type image_char_list) +{ + static unsigned box_count = 0; + bounding_box_type bb; + + /* We always use the entire image line vertically. */ + MIN_ROW (bb) = 0; + MAX_ROW (bb) = BITMAP_HEIGHT (image) - 1; + + /* `nchars_wanted' is an option to the program, defined at the top. + Go through the whole line, unless we've found as many characters + as the user requested. */ + while (*nchars < nchars_wanted && *transitions != BITMAP_WIDTH (image) + 1) + { + int bb_offset = 0; + unsigned previous_box_count = box_count; + bb_list_type boxes = bb_list_init (); + bitmap_type *char_bitmap = XTALLOC1 (bitmap_type); + bitmap_type *temp_bitmap = XTALLOC1 (bitmap_type); + + /* The first element of TRANSITIONS is white-to-black. + Thereafter, they alternate. */ + MIN_COL (bb) = NEXT_TRANSITION (); + MAX_COL (bb) = NEXT_TRANSITION (); + + /* Get the bitmap of the first transition. `char_bitmap' is + either a single character (if the character didn't overlap with + a consecutive one in the font specimen) or more than one (if + the characters did overlap). For example, it might contain + just an `a' this time through the loop (with blank rows above + and below, because `a' has neither a descender nor an + ascender), then next time a `b', and so on. Or it might + contain `ij' (if they overlap in the specimen) instead of `i' + this time and `j' next time. */ + *char_bitmap = extract_subbitmap (image, bb); + *temp_bitmap = copy_bitmap (*char_bitmap); +/*xx*/ +if ((testfileptr = fopen(line_subbitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, *temp_bitmap); +else +printf("Bad file pointer for printing subbitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(line_bb_subbitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, *temp_bitmap, bb); +else +printf("Bad file pointer for printing bb-subbitmap.\n"); +fclose(testfileptr); + + /* Unless we've read enough boxes, find the ones in the current + character(s), and exit, either: 1) to output a character if the + boxes ``finish'' a character, or 2) to exit the routine with + false, if they don't. If don't find all the boxes needed to + finish a character (i.e., it has vertical white space in it, + loop around getting more ``transitions'' until we do. */ + while (true) + { + bb_list_type temp_boxes; + bounding_box_type previous_bb; + + /* If we've read all the bounding boxes specified (in the IFI + file), we're done. */ + if (box_count == total_boxes_expected) + break; + + /* If we've read more boxes than we expected to, trouble. */ + if (box_count > total_boxes_expected) + { + WARNING2 ("imageto: Read box #%u but expected only %u", + box_count, total_boxes_expected); + /* No point in giving this message more than once. */ + total_boxes_expected = INT_MAX; + } + + /* Find the bounding boxes around all the shapes in `temp_bitmap'. + (The first time through the loop, `temp_bitmap' is the same + as `char_bitmap.') Continuing the above `ij' example, this + would result in four bounding boxes (one for the ``dotless'' + part of the `i,' one for the ``dotless'' part of the `j' + and two for each of the dots). */ + temp_boxes = find_outline_bbs (*temp_bitmap, false, 0, 0); + + /* The subimages we've created all start at column zero. But + if there are overlapping characters (the `ij' example + above), we want to put the images (for, e.g., `i' and `j') + side-by-side instead of overlaying them. So we change the + bounding box numbers for `temp_boxes' by adding `bb_offset.' */ + offset_bb_list (&temp_boxes, bb_offset); + + box_count += BB_LIST_LENGTH (temp_boxes); + bb_list_splice (&boxes, temp_boxes); + + /* Break if the number of boxes indicated for the current + character(s) coincide with the end of a character. This + translates to: if the white column was at the end of some + character in the list, exit the loop to output what we've got. */ + if (box_at_char_boundary_p (image_char_list, *nchars, + box_count - previous_box_count)) + break; + + /* If we're at the end of the image row, return to our caller + that we had to quit in the middle of a character. */ + if (*transitions == BITMAP_WIDTH (image) + 1) + { /* Forget that we've seen these boxes. */ + box_count = previous_box_count; + return false; + } + /* If the character has white vertical space between its + parts, e.g., double quotes or ellipses, have to get the + rest of its bitmap. */ + previous_bb = bb; + MIN_COL (bb) = NEXT_TRANSITION (); + MAX_COL (bb) = NEXT_TRANSITION (); + + /* Leave in the white space between the character parts. */ + MIN_COL (bb) = MAX_COL (previous_bb); + + free_bitmap (temp_bitmap); + *temp_bitmap = extract_subbitmap (image, bb); +/*xx*/ +if ((testfileptr = fopen(line_subbitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, *temp_bitmap); +else +printf("Bad file pointer for printing subbitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(line_bb_subbitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, *temp_bitmap, bb); +else +printf("Bad file pointer for printing bb-subbitmap.\n"); +fclose(testfileptr); + if (temp_bitmap == NULL) + { + WARNING1 ("imageto: Expected more bounding boxes for `%d'", + IMAGE_CHARCODE (IMAGE_CHAR (image_char_list, *nchars))); + break; + } + + /* Next time through the loop, the boxes `temp_bitmap' should + be just to the right of the bitmap we've accumulated in + `char_bitmap'. This happens if the character has vertical + white space between its parts. */ + bb_offset = BITMAP_WIDTH (*char_bitmap); + + /* When this happens, it usually means that the IFI file + didn't specify enough bounding boxes for some character, + and so things are out of sync. */ + if (BITMAP_HEIGHT (*char_bitmap) != BITMAP_HEIGHT (*temp_bitmap)) + { + WARNING ("imageto: Line ended inside a character"); + break; + } + bitmap_concat (char_bitmap, *temp_bitmap); + } /* while (true) */ + + free_bitmap (temp_bitmap); + + /* Convert the bits inside those bounding boxes into one (if not + overlapping with another) or more (if overlapping) characters + in the GF font. */ + *nchars += output_chars (boxes, *char_bitmap, h_resolution, + image_char_list, *nchars); + free_bitmap (char_bitmap); + bb_list_free (&boxes); + } /* end while (*nchars < nchars_wanted + && *transitions != BITMAP_WIDTH (image) + 1) */ + + return true; +} + +/* Move all the elements in BB_LIST to the right by OFFSET. */ + +void +offset_bb_list (bb_list_type *bb_list, int offset) +{ + unsigned this_bb; + + for (this_bb = 0; this_bb < BB_LIST_LENGTH (*bb_list); this_bb++) + { + bounding_box_type *bb = &BB_LIST_ELT (*bb_list, this_bb); + MIN_COL (*bb) += offset; + MAX_COL (*bb) += offset; + } +} + + +/* Return true if BB1 and BB2 are equal. */ + +static boolean +bb_equal_p (bounding_box_type bb1, bounding_box_type bb2) +{ + return + MIN_COL (bb1) == MIN_COL (bb2) + && MIN_ROW (bb1) == MIN_ROW (bb2) + && MAX_COL (bb1) == MAX_COL (bb2) + && MAX_ROW (bb1) == MAX_ROW (bb2); +} + +/* For each bounding box in the list BOXES, extract from IMAGE_LINE_BITMAP + and turn the resulting bitmap into a single character in the font. + The information in IMAGE_CHAR_LIST maps bounding boxes to character codes; + consecutive bounding boxes may belong to the same character. For + example, `i' will appear twice, once for the dot and once for the + stem. We assume that all the bounding boxes for a given character + will appear in IMAGE_LINE_BITMAP. + + We return the number of characters (not bounding boxes) found, + including characters that were omitted. */ + +/* Predicate to tell us if we want to actually write the character. */ +#define OUTPUT_CHAR_P(code, image_char) \ + ((code) >= starting_char && (code) <= ending_char \ + && !IMAGE_CHAR_OMIT (image_char)) + +static unsigned +output_chars (bb_list_type boxes, bitmap_type image_line_bitmap, + real h_resolution, image_char_list_type image_char_list, + unsigned current_char) +{ + static unsigned char_count = 0; + int this_box; /* Because we might have to subtract when it's zero. */ + boolean done[BB_LIST_LENGTH (boxes)]; + + /* Since we report (a lot) more information when `print_guidelines' is + true, we can fit fewer characters per line. */ + unsigned nchars_per_line = print_guidelines ? 1 : 11; + + unsigned nchars_written = 0; + + for (this_box = 0; this_box < BB_LIST_LENGTH (boxes); this_box++) + done[this_box] = false; + + for (this_box = 0; this_box < BB_LIST_LENGTH (boxes); this_box++) + { + bounding_box_type bb; + bitmap_type bitmap; + image_char_type c; + charcode_type charcode; + bb_list_type bb_list = bb_list_init (); + + /* `done[this_box]' will be set if we get to a bounding box that + has already been combined with a previous one, because of + an alternating combination. Since we never go backwards, we + don't bother to set `done' for every box we look at. */ + if (done[this_box]) + continue; + + c = IMAGE_CHAR (image_char_list, current_char++); + charcode = IMAGE_CHARCODE (c); + + REPORT ("["); + + /* Only bother to collect the character image if we're going to + output it; otherwise, it just wastes a lot of time and space. */ + if (OUTPUT_CHAR_P (charcode, c)) + { /* A character consisting of zero bounding boxes is invisible; + e.g., a space. We don't want to read any of the bitmap for + such a thing. */ + if (IMAGE_CHAR_BB_COUNT (c) == 0) + { + BITMAP_HEIGHT (bitmap) = 0; + BITMAP_WIDTH (bitmap) = 0; + BITMAP_BITS (bitmap) = NULL; + bb = (bounding_box_type) { 0, 0, 0, 0 }; + + /* Since we're not eating up any bounding boxes, + reconsider the current one. */ + this_box--; + } + else + { + bb = BB_LIST_ELT (boxes, this_box); + bitmap = extract_subbitmap (image_line_bitmap, bb); +/*xx*/ +if ((testfileptr = fopen(subbitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, bitmap); +else +printf("Bad file pointer for printing subbitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(bb_subbitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, bitmap, bb); +else +printf("Bad file pointer for printing bb-subbitmap.\n"); +fclose(testfileptr); + bb_list_append (&bb_list, bb); + } + } + + while (IMAGE_CHAR_BB_COUNT (c)-- > 1) + { + unsigned combine_box; + + if (IMAGE_CHAR_BB_ALTERNATING (c)) + { + /* Don't increment `this_box', since it is incremented at + the end of the loop, and the next box is part of + another character. */ + combine_box = this_box + 2; + /* Don't look at the second box again in the outer loop. */ + done[combine_box] = true; + } + else + /* Increment `this_box' so can keep combining nonalternating + bounding boxes until they are used up or we hit an + alternating one. */ + combine_box = ++this_box; + + /* combine_box starts at 0 and BB_LIST_LENGTH starts at 1, so... */ + if (combine_box >= BB_LIST_LENGTH (boxes)) + { + WARNING1 ("imageto: Not enough outlines for char %u", + (unsigned) charcode); + break; + } + + if (OUTPUT_CHAR_P (charcode, c)) + { + /* Get the shape to combine with `bitmap'. */ + bounding_box_type next_bb = BB_LIST_ELT (boxes, combine_box); + bitmap_type next_bitmap + = extract_subbitmap (image_line_bitmap, next_bb); +/*xx*/ +if ((testfileptr = fopen(subbitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, next_bitmap); +else +printf("Bad file pointer for printing subbitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(bb_subbitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, next_bitmap, next_bb); +else +printf("Bad file pointer for printing bb-subbitmap.\n"); +fclose(testfileptr); + bb_list_append (&bb_list, next_bb); + combine_images (&bitmap, next_bitmap, &bb, next_bb); +/*xx*/ +if ((testfileptr = fopen(whole_bitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, bitmap); +else +printf("Bad file pointer for printing whole_bitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(bb_whole_bitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, bitmap, bb); +else +printf("Bad file pointer for printing bb_whole_bitmap.\n"); +fclose(testfileptr); + free_bitmap (&next_bitmap); + } + } /* while (IMAGE_CHAR_BB_COUNT (c)-- > 1) */ + + if (OUTPUT_CHAR_P (charcode, c)) + { + gf_char_type gf_char; + + if (BITMAP_BITS (bitmap) != NULL) + clean_bitmap (&bitmap, bb_list); + + gf_char = bitmap_to_gf_char (bitmap, h_resolution, bb, c); + gf_put_char (gf_char); + + /* This and the GF character's bitmap are the same, so we only + need to free one of the two. */ + if (BITMAP_BITS (bitmap) != NULL) + free_bitmap (&bitmap); + } + else + { + REPORT ("<ignored>"); /* We're ignoring this character. */ +/*xx this_box--;*//* Reconsider the bounding box. */ + } + REPORT1 ("]%c", ++char_count % nchars_per_line ? ' ' : '\n'); + nchars_written++; + + bb_list_free (&bb_list); + } /* for (this_box = 0; this_box < BB_LIST_LENGTH (boxes); this_box++) */ + + + return nchars_written; +} + +/* Remove bits of adjacent characters that may have crept into B because + of overlapping characters in the original image. KNOWN_BOXES lists + all the known parts of B; if we find other bounding boxes in B, we + remove them. */ + +static void +clean_bitmap (bitmap_type *b, bb_list_type known_boxes) +{ + unsigned test; + bb_list_type test_boxes = find_outline_bbs (*b, false, BITMAP_WIDTH (*b), 0); + + if (print_clean_info) + REPORT2 ("Cleaning %ux%u bitmap:\n", + BITMAP_WIDTH (*b), BITMAP_HEIGHT (*b)); + + /* Convert KNOWN_BOXES to the same coordinates as `test_boxes'. */ + image_to_bitmap_bbs (&known_boxes); + + for (test = 0; test < BB_LIST_LENGTH (test_boxes); test++) + { + unsigned known; + unsigned known_length = BB_LIST_LENGTH (known_boxes); + bounding_box_type test_bb = BB_LIST_ELT (test_boxes, test); + + if (print_clean_info) + REPORT4 (" checking (%d,%d)-(%d,%d) ... ", + MIN_COL (test_bb), MIN_ROW (test_bb), + MAX_COL (test_bb), MAX_ROW (test_bb)); + + /* If we want to keep `test_bb', it will be one of the elements of + BB_LIST. Otherwise, it is a piece of an adjacent character, + and we should erase it. */ + for (known = 0; known < known_length && !bb_equal_p (test_bb, + BB_LIST_ELT (known_boxes, known)); + known++) + ; + + if (known == known_length) + { + unsigned r; + int test_bb_width = BB_WIDTH (test_bb); + + assert (test_bb_width > 0); + + if (print_clean_info) + REPORT ("clearing.\n"); + + for (r = MIN_ROW (test_bb); r <= MAX_ROW (test_bb); r++) + { + one_byte *row = BITMAP_ROW (*b, r); + memset (row + MIN_COL (test_bb), 0, test_bb_width); + } + } + else if (print_clean_info) + REPORT ("keeping.\n"); + } +} + + +/* Translate the elements of BOXES to the origin, i.e., shift each down + by the minimum row and column. We use this in `clean_bitmap' to + change bounding boxes in the coordinates of the entire image to the + coordinates of the single character we are cleaning. */ + +static void +image_to_bitmap_bbs (bb_list_type *boxes) +{ + unsigned b; + unsigned min_col = UINT_MAX; + unsigned min_row = UINT_MAX; + + /* First find the minimum row and column of all the bb's in BOXES. */ + for (b = 0; b < BB_LIST_LENGTH (*boxes); b++) + { + bounding_box_type bb = BB_LIST_ELT (*boxes, b); + + assert (MIN_COL (bb) >= 0 && MIN_ROW (bb) >= 0); + + MIN_EQUALS (min_col, MIN_COL (bb)); + MIN_EQUALS (min_row, MIN_ROW (bb)); + } + + /* Now translate all the bb's by those minimums. */ + for (b = 0; b < BB_LIST_LENGTH (*boxes); b++) + { + bounding_box_type *bb = &BB_LIST_ELT (*boxes, b); + + MIN_COL (*bb) -= min_col; + MAX_COL (*bb) -= min_col; + MIN_ROW (*bb) -= min_row; + MAX_ROW (*bb) -= min_row; + } +} + +/* Derive the information necessary to output the font character from + the bitmap B, and return it. The resolution of the bitmap is given + in pixels per inch as H_RESOLUTION. The bounding box BB encloses the + character in the image coordinates. We use BB and the static + variables `row_baseline' and `row_height' to determine the + positioning of the GF character. */ + +#define BB_TO_CARTESIAN(x) \ + (row_height - 1 - (x) - row_baseline \ + - IMAGE_CHAR_BASELINE_ADJUST (image_char)) + +static gf_char_type +bitmap_to_gf_char (bitmap_type b, real h_resolution, + bounding_box_type bb, image_char_type image_char) +{ + static boolean first = true; + static boolean have_tfm_file = false; + gf_char_type gf_char; + bounding_box_type cartesian_bb; + charcode_type charcode = IMAGE_CHARCODE (image_char); + boolean have_tfm_width = false; + +/*xx*/ +if(b.bitmap){ +if ((testfileptr = fopen(gf_bitmap_filename, "w")) != NULL) +print_bitmap(testfileptr, b); +else +printf("Bad file pointer for printing gf_bitmap.\n"); +fclose(testfileptr); +if ((testfileptr = fopen(gf_bb_bitmap_filename, "w")) != NULL) +print_bounded_bitmap(testfileptr, b, bb); +else +printf("Bad file pointer for printing gf_bb_bitmap.\n"); +fclose(testfileptr); +} + MIN_ROW (cartesian_bb) = BB_TO_CARTESIAN (MAX_ROW (bb)); + MAX_ROW (cartesian_bb) = BB_TO_CARTESIAN (MIN_ROW (bb)); + + REPORT1 ("%u", charcode); + + GF_CHARCODE (gf_char) = charcode; + GF_BITMAP (gf_char) = b; + GF_CHAR_MIN_COL (gf_char) = IMAGE_CHAR_LSB (image_char); + GF_CHAR_MAX_COL (gf_char) = GF_CHAR_MIN_COL (gf_char) + BITMAP_WIDTH (b); + GF_CHAR_MIN_ROW (gf_char) = MIN_ROW (cartesian_bb); + GF_CHAR_MAX_ROW (gf_char) = MAX_ROW (cartesian_bb); + + GF_H_ESCAPEMENT (gf_char) = (GF_CHAR_MAX_COL (gf_char) + + IMAGE_CHAR_RSB (image_char)); + if (first) + { + string tfm_name = kpse_find_tfm (remove_suffix (output_name)); + + if (tfm_name) + have_tfm_file = tfm_open_input_file (tfm_name); + first = false; + } + + have_tfm_width = false; + if (have_tfm_file) + { + tfm_char_type *tfm_char = tfm_get_char (charcode); + if (tfm_char) + { + GF_TFM_WIDTH (gf_char) = TFM_FIX_WIDTH (*tfm_char); + have_tfm_width = true; + } + } + + /* If no TFM file, or the TFM file doesn't define this character, + use the pixel width for the TFM value. */ + if (!have_tfm_width) + { + real width_in_points + = GF_H_ESCAPEMENT (gf_char) * POINTS_PER_INCH / h_resolution; + GF_TFM_WIDTH (gf_char) = real_to_fix (width_in_points / design_size); + } + + if (print_guidelines) + REPORT3 (" (%s) %d/%d", IMAGE_CHARNAME (image_char), + MIN_ROW (cartesian_bb), MAX_ROW (cartesian_bb)); + + return gf_char; +} diff --git a/imageto/out-chars.h b/imageto/out-chars.h new file mode 100644 index 0000000..0b91ade --- /dev/null +++ b/imageto/out-chars.h @@ -0,0 +1,34 @@ +/* out-chars.h: extract the characters from the image. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUT_CHARS_H +#define OUT_CHARS_H + +#include "image-header.h" + + +/* See out-chars.c. */ +extern int *baseline_list; +extern boolean print_clean_info, print_guidelines; +extern unsigned nchars_wanted; +extern int starting_char, ending_char; + + +extern void write_image_chars (image_header_type, real design_size); + +#endif /* not OUT_CHARS_H */ diff --git a/imageto/out-epsf.c b/imageto/out-epsf.c new file mode 100644 index 0000000..564807c --- /dev/null +++ b/imageto/out-epsf.c @@ -0,0 +1,166 @@ +/* out-epsf.c: output the whole image as an EPS file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "hexify.h" +#include "report.h" + +#include "main.h" +#include "out-epsf.h" + +extern string version_string; + +static void pack_scanline (one_byte *, unsigned); + +/* Abbreviations for output to `eps_file'. */ +#define OUT_STRING(s) fprintf (eps_file, "%s", s) +#define OUT_SIMPLE(s) fprintf (eps_file, "%%%%%s\n", s) +#define OUT_COMMENT(s, v) fprintf (eps_file, "%%%%%s: %s\n", s, v) +#define OUT1(s, v1) fprintf (eps_file, s, v1) +#define OUT2(s, v1, v2) fprintf (eps_file, s, v1, v2) +#define OUT3(s, v1, v2, v3) fprintf (eps_file, s, v1, v2, v3) + +/* Write an Encapsulated PostScript file corresponding to the image. */ + +void +write_epsf (string output_name, image_header_type image_header) +{ + /* Just black & white, or do we have grayscale? */ + boolean monochrome_p = image_header.depth == 1; + + /* Just for convenience. */ + unsigned width = image_header.width; + unsigned height = image_header.height; + + /* We pack the image tightly if it's monochrome. */ + unsigned width_used = monochrome_p ? width / 8 + !!(width % 8) : width; + + /* Buffer into which we'll read the image data. */ + unsigned scanline_count = 0; + one_byte *scanline = xmalloc (width); + + /* Open the output file OUTPUT_NAME. */ + FILE *eps_file = xfopen (output_name, "w"); + + OUT_STRING ("%!PS-Adobe-3.0 EPSF-3.0\n"); + OUT2 ("%%%%BoundingBox: 0 0 %u %u\n", width, height); + OUT_COMMENT ("Creator", version_string); + OUT_COMMENT ("Title", output_name); + OUT_COMMENT ("CreationDate", now ()); + OUT_COMMENT ("DocumentData", "Clean7Bit"); + OUT_SIMPLE ("EndComments"); + + /* We map the image to the unit square for image(mask) and scale the + coordinate system to get back to the original size. I can't grasp + how to use the matrix argument to image(mask) to avoid the scaling, + but I'm sure it's possible. */ + OUT2 ("gsave\n %u %u scale\n", width, height); + + /* We need a buffer to hold the string chunks as we read them. It + can't be of arbitrary size: it must be an exact multiple of the + total number of data characters. Otherwise, we will read past the + end of the data. */ + OUT1 ("/image-buffer %u string def\n", width_used); + + /* If we are monochrome, we use the `imagemask' operator; else `image'. */ + OUT2 (" %u %u", width, height); + + if (monochrome_p) + OUT_STRING (" true"); /* The `invert' argument. */ + else + OUT1 (" %u", image_header.depth); /* bits/sample */ + + OUT3 (" [%u 0 0 -%u 0 %u]\n", width, height, height); + OUT_STRING ("{currentfile image-buffer readhexstring pop}\n"); + OUT1 ("%s\n", monochrome_p ? "imagemask" : "image"); + + /* Read the image. */ + while ((*image_get_scanline) (scanline)) + { + string h; + unsigned loc; + + scanline_count++; + if (scanline_count % 10 == 0) + REPORT1 (".%s", scanline_count % 790 == 0 ? "\n" : ""); + + /* Monochrome images are output with eight samples/byte; grayscale + images are output with one sample/byte. */ + if (monochrome_p) + pack_scanline (scanline, width); + + /* Convert binary to ASCII hexadecimal. */ + h = hexify (scanline, width_used); + + /* Adobe says lines in EPS files should be no more than 255 + characters. How silly. */ + for (loc = 1; loc <= 2 * width_used; loc++) + { + putc (h[loc - 1], eps_file); + if (loc % 255 == 0) + putc ('\n', eps_file); + } + + free (h); + putc ('\n', eps_file); + } + + /* Restore the ctm. */ + OUT_STRING ("grestore\n"); + + if (scanline_count != image_header.height) + WARNING2 ("Expected %u scanlines, read %u", image_header.height, + scanline_count); + + OUT_SIMPLE ("TRAILER"); + OUT_SIMPLE ("EOF"); +} + +/* Change the one bit/byte representation (call each byte a `cell') of + LENGTH bits in DATA to be eight bits/byte. Pad the last byte with + zero. We don't change those bytes beyond the end of packed portion, + thus assuming they are not looked at. */ + +static void +pack_scanline (one_byte *data, unsigned length) +{ + unsigned cell; /* Which bit in the original data we're on. */ + unsigned packing_loc = 0; /* Which byte we're currently packing. */ + unsigned packing_bit = 8; /* How much to shift. */ + + /* The very first cell has to be treated specially, because we must + initialize it with itself shifted left (if we're going to use data + in place, that is.) */ + data[0] <<= 7; + + for (cell = 0; cell < length; cell++) + { + packing_bit--; + data[packing_loc] |= data[cell] << packing_bit; + if (packing_bit == 0) + { + packing_bit = 8; + packing_loc++; + + /* After the first byte, we can just clear the byte at + `packing_loc', since `cell' has already moved beyond it. */ + data[packing_loc] = 0; + } + } +} diff --git a/imageto/out-epsf.h b/imageto/out-epsf.h new file mode 100644 index 0000000..c664772 --- /dev/null +++ b/imageto/out-epsf.h @@ -0,0 +1,28 @@ +/* out-epsf.h: output the whole image as an EPS file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUT_EPSF_H +#define OUT_EPSF_H + +#include "image-header.h" + + +/* Output an EPS file for the image with header H to OUTPUT_NAME. */ +extern void write_epsf (string output_name, image_header_type h); + +#endif /* not OUT_EPSF_H */ diff --git a/imageto/out-strips.c b/imageto/out-strips.c new file mode 100644 index 0000000..a43a411 --- /dev/null +++ b/imageto/out-strips.c @@ -0,0 +1,94 @@ +/* out-strips.c: cut the entire image into strips. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "gf.h" +#include "report.h" + +#include "main.h" +#include "out-strips.h" + +/* Output a ``font'' in which each ``character'' is a constant number of + scanlines from the image. This might use less than resources than + the giant PostScript file that -epsf outputs. + + We only output the GF characters here; we assume the postamble and + preamble are written by the caller. */ + +void +write_chars_as_strips (image_header_type image_header, real design_size) +{ + dimensions_type char_dimens; + gf_char_type gf_char; + unsigned gf_row; + unsigned lines_per_char; + one_byte *scanline; + real width_in_points; + boolean first_char = true; + unsigned scanline_count = 0; + + /* Set up for the first character. We divide the image into 256 parts, + each of which will turn into one ``character''. */ + lines_per_char = image_header.height / 256 + 1; + GF_CHARCODE (gf_char) = 0; + DIMENSIONS_WIDTH (char_dimens) = image_header.width; + DIMENSIONS_HEIGHT (char_dimens) = lines_per_char; + GF_BITMAP (gf_char) = new_bitmap (char_dimens); + GF_CHAR_MIN_COL (gf_char) = GF_CHAR_MIN_ROW (gf_char) = 0; + GF_CHAR_MAX_COL (gf_char) = DIMENSIONS_WIDTH (char_dimens); + GF_CHAR_MAX_ROW (gf_char) = DIMENSIONS_HEIGHT (char_dimens) - 1; + + /* We aren't going to have any side bearings. */ + GF_H_ESCAPEMENT (gf_char) = DIMENSIONS_WIDTH (char_dimens); + width_in_points = DIMENSIONS_WIDTH (char_dimens) * POINTS_PER_INCH + / (real) image_header.hres; + GF_TFM_WIDTH (gf_char) = real_to_fix (width_in_points / design_size); + + + /* Read the image. */ + while (true) + { + if (scanline_count % lines_per_char == 0) + { + /* We get here when scanline_count == 0, and we haven't read + anything, so we can't write anything. */ + if (!first_char) + { + gf_put_char (gf_char); + REPORT2 ("[%u]%c", GF_CHARCODE (gf_char), + (GF_CHARCODE (gf_char) + 1) % 13 ? ' ' : '\n'); + GF_CHARCODE (gf_char)++; + } + else + first_char = false; + gf_row = 0; + } + + scanline = BITMAP_BITS (GF_BITMAP (gf_char)) + + gf_row * DIMENSIONS_WIDTH (char_dimens); + if (!(*image_get_scanline) (scanline)) break; + + scanline_count++; + gf_row++; + } + + if (scanline_count != image_header.height) + WARNING2 ("Expected %u scanlines, read %u", image_header.height, + scanline_count); +} diff --git a/imageto/out-strips.h b/imageto/out-strips.h new file mode 100644 index 0000000..401c124 --- /dev/null +++ b/imageto/out-strips.h @@ -0,0 +1,27 @@ +/* out-strips.h: cut the image into strips. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef OUT_STRIPS_H +#define OUT_STRIPS_H + +#include "image-header.h" + + +extern void write_chars_as_strips (image_header_type, real design_size); + +#endif /* not OUT_STRIPS_H */ diff --git a/imageto/strips.tex b/imageto/strips.tex new file mode 100644 index 0000000..1b7a3ee --- /dev/null +++ b/imageto/strips.tex @@ -0,0 +1,85 @@ +% TeX file to display a ``font'' made from imagetofont's -strips option. + +% Set up our font. +\message{Fontname? } +\read -1 to \testfontname +\font\testfont = \testfontname\space +\testfont + +% \monthname produces the name of the month, abbreviated to three +% letters. The primitive \month should never be zero. +% +\def\monthname{% + \ifcase\month + \or Jan\or Feb\or Mar\or Apr\or May\or Jun% + \or Jul\or Aug\or Sep\or Oct\or Nov\or Dec% + \fi +}% + +% \timestring produces the current time, in a format like `1:14 p.m.'. +% +\def\timestring{\begingroup + \count0 = \time + \divide\count0 by 60 + \count2 = \count0 % The hour, from zero to 23. + % + \count4 = \time + \multiply\count0 by 60 + \advance\count4 by -\count0 % The minute, from zero to 59. + % But we need the minutes with a leading zero, if necessary. + \ifnum\count4<10 + \toks1 = {0}% + \else + \toks1 = {}% + \fi + % + % Convert the hour into `a.m.' or `p.m.', and make it mod 12. + \ifnum\count2<12 + \toks0 = {a.m.}% + \else + \toks0 = {p.m.}% + \advance\count2 by -12 + \fi + % + % If it's midnight, call it `12', not `0'. + \ifnum\count2=0 + \count2 = 12 + \fi + % + % Produce the output. + \number\count2:\the\toks1 \number\count4 \thinspace \the\toks0 +\endgroup}% +% +% +% \timestamp produces a text string for the whole thing like +% `23 Apr 1964 1:14 p.m.'. +% +\def\timestamp{\number\day\space\monthname\space\number\year\quad\timestring}% + +\nopagenumbers +\headline = {\hfil \tt \testfontname \quad \timestamp} + +% Use as much of the page as we dare. +\hoffset = -5pc \hsize = 49pc +\voffset = -5pc \vsize = 64pc + +% Don't worry if there's no good place to break pages. +\vbadness = 10000 + +% No leading between ``lines''. +\offinterlineskip + +% Don't worry if the font doesn't have exactly 256 characters, since +% roundoff error makes this likely. +\tracinglostchars = 0 + + +\count255 = 0 +\loop + %\setbox0 = \hbox{\char\count255} + \leftline{\char\count255} + \advance\count255 by 1 + \ifnum\count255<256 +\repeat + +\end diff --git a/imageto/version.c b/imageto/version.c new file mode 100644 index 0000000..b39f56a --- /dev/null +++ b/imageto/version.c @@ -0,0 +1 @@ +char *version_string = "imageto version REPLACE-WITH-VERSION"; diff --git a/lib/ChangeLog b/lib/ChangeLog new file mode 100644 index 0000000..0f3ff5d --- /dev/null +++ b/lib/ChangeLog @@ -0,0 +1,1414 @@ +Tue Dec 26 10:16:08 1995 Kathy Hargreaves <kathy@cs.umb.edu> + + * identity.c (get_identity): Added. + +Sun Nov 26 12:47:00 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * bb-outline.c: (find_outline_bbs): Doc fix. + + * edge.c: (next_unmarked_outline_edge): Doc fix. + +Fri Nov 24 05:48:20 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * concat*.c: made arguments const_string's to conform to .h files. + Call assert on the arguments, that they aren't NULL, because it + makes strlen blow up if they are. Set answer to NULL, and only + work on it if all the arguments are non-NULL. + +Thu Nov 23 09:08:00 1995 Kathy Hargreaves <karl@cs.umb.edu> + + * font.c: (get_font): replaced find_tfm_filename with kpse_find_tfm. + +Thu Aug 24 16:00:46 1995 Karl Berry <karl@cs.umb.edu> + + * GNUmakefile (c_only): strstr is now in kpathsea. + +Sat May 27 13:52:19 1995 Karl Berry <karl@cs.umb.edu> + + * GNUmakefile (c_only): atou is in kpathsea. + +Fri Apr 14 15:56:43 1995 Karl Berry <karl@cs.umb.edu> + + * GNUmakefile (c_only): Remove xfseek and xftell. + +Mon Oct 24 19:04:34 1994 Karl Berry <karl@cs.umb.edu> + + * GNUmakefile (c_only): basename is in kpathsea now. + +Sun May 1 15:31:10 1994 Karl Berry (karl@cs.umb.edu) + + * vector.c (Vangle): Declare const. + +Thu Sep 30 10:13:45 1993 Karl Berry (karl@cs.umb.edu) + + * str-to-bit.c (string_to_bitmap): Call close_font. + +Sun Aug 1 09:56:42 1993 Karl Berry (karl@cs.umb.edu) + + * Most *.c: Include files now in kpathsea. + + * GNUmakefile (c_only): Add statistics, remove many things now in + kpathsea. + +Tue Jul 27 09:24:08 1993 Karl Berry (karl@cs.umb.edu) + + * GNUmakefile (c_only): Remove dir-p and find-suffix (now in kpathsea). + +Fri May 21 13:45:30 1993 Karl Berry (karl@cs.umb.edu) + + * gmalloc.c (my_memmove): New routine, since ISC doesn't have a + real memmove. + +Thu May 20 19:11:05 1993 Karl Berry (karl@cs.umb.edu) + + * gmalloc.c: New file from the malloc distribution (plus a few + edits). + * GNUmakefile (malloc): Define to be gmalloc, and toss the old + malloc.c. + +Thu Apr 22 17:03:53 1993 Karl Berry (karl@cs.umb.edu) + + * remove-suffx.c (remove_suffix): If no suffix, return the string, + not NULL. + +Tue Apr 6 19:58:45 1993 Karl Berry (karl@cs.umb.edu) + + * malloc.c (getpagesize.h): Do not include. + (memalign, valloc): Remove, since we don't need them. + + * filename.c (find_tfm_filename): Call extend_filename to get the + `.tfm', instead of just concatenating. Not sure if this is a good + idea, but periods in font names are problematic all over, I think. + +Tue Mar 16 07:47:38 1993 Karl Berry (karl@cs.umb.edu) + + * fontmap.c (map_lookup): Don't extend the filename if there was + no suffix. + +Wed Mar 3 06:20:09 1993 Karl Berry (karl@cs.umb.edu) + + * xftell.c (xftell): Declare as unsigned long. + +Mon Jan 18 15:43:02 1993 Karl Berry (karl@cs.umb.edu) + + * xrealloc.c: Doc fix. + +Sun Jan 3 19:36:39 1993 Karl Berry (karl@cs.umb.edu) + + * pathsrch.c (R_OK): Defined in the config files now. + +Fri Dec 11 15:00:31 1992 Karl Berry (karl@cs.umb.edu) + + * font.c (print_char): Change ctype references to use uppercase macros. + * libfile.c (libfile_line), + * pathsrch.c (absolute_p), + * str-to-bit.c (string_to_bitmap), + * float-ok.c (float_ok), + * integer-ok.c (integer_ok), + * charspec.c (xparse_charspec): Likewise. + +Sun Nov 29 17:05:40 1992 Karl Berry (karl@cs.umb.edu) + + * xmessage.c [X_DISPLAY_MISSING]: Conditionalize whole file. + + * numtoa.c (xdtoa): Rename from `dtoa', to avoid Linux conflict. + (awasthi@cps.msu.edu) + +Tue Nov 17 09:25:58 1992 Karl Berry (karl@cs.umb.edu) + + * hexify.c: Doc fix. + +Mon Nov 16 16:08:39 1992 Karl Berry (karl@cs.umb.edu) + + * malloc.c (calloc): Complain if the malloc fails. + +Tue Oct 27 12:56:15 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Sun Oct 25 06:26:42 1992 Karl Berry (karl@cs.umb.edu) + + * getopt.c: New version. + +Thu Oct 22 17:58:12 1992 Karl Berry (karl@cs.umb.edu) + + * make-suffix.c: Doc fix. + +Tue Oct 20 11:57:57 1992 Karl Berry (karl@cs.umb.edu) + + * filename.c (find_{gf,pk,tfm}_filename): Just concatenate the + suffix onto the main font name, don't replace a suffix. + +Mon Oct 5 10:07:59 1992 Karl Berry (karl@cs.umb.edu) + + * report.c (report_file): New variable. + +Sun Oct 4 09:13:24 1992 Karl Berry (karl@cs.umb.edu) + + * bb-list.c: New file, from bb-outline.c. + * GNUmakefile (c_only): Add it. + * bb-outline.c: Change calls and decls for new improved names. + +Sat Oct 3 16:58:38 1992 Karl Berry (karl@cs.umb.edu) + + * bb-outline.c: Doc fix. + +Tue Sep 22 12:46:49 1992 Karl Berry (karl@cs.umb.edu) + + * malloc.c (realloc): abort if we can't malloc enough memory to do + the realloc. + + * bitmap.c (bb_ensure_bounds): new routine. + (extract_subbitmap): call it. + +Mon Sep 21 12:00:35 1992 Karl Berry (karl@cs.umb.edu) + + * malloc.c: define NO_NEW_HANDLER. + +Thu Sep 3 09:31:06 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Thu Aug 27 09:06:25 1992 Karl Berry (karl@hayley) + + * getopt.c: update from MIT. + +Mon Aug 24 15:50:03 1992 Karl Berry (karl@hayley) + + * rand.c (k_rand): use Ghostscript's algorithm exactly, to avoid + overflow problems. + + * rand.c (seed_rand): Our simplification was a loser if the + state ever became zero, so set the state to the seed + 1, and + subtract again before output. + +Wed Aug 19 07:10:12 1992 Karl Berry (karl@hayley) + + * charspec.c: doc fix. + +Mon Aug 17 15:43:42 1992 Karl Berry (karl@hayley) + + * encoding.c: doc fix. + +Mon Aug 10 11:11:52 1992 Karl Berry (karl@hayley) + + * rand.c (x): change the default seed to 1. + +Mon Jul 27 15:29:33 1992 Karl Berry (karl@hayley) + + * charspec.c (xparse_charspec): use an `int' while figuring out + the charcode. + +Sat Jul 25 14:38:23 1992 Karl Berry (karl@hayley) + + * getopt.c: new version. + + * pathsrch.c (expand_tilde): cast the result of getpwnam. + +Sat Jul 18 16:35:41 1992 Karl Berry (karl@hayley) + + * edge.c: add ^L's. + +Fri Jul 3 15:26:12 1992 Karl Berry (karl@hayley) + + * charspec.c (xparse_charspec): if arg is one character long, and + undefined in the encoding, use its value in C. + +Fri Jun 26 16:53:39 1992 Karl Berry (karl@hayley) + + * charspec.c: new file. + * GNUmakefile: add it. + +Thu Jun 25 07:04:49 1992 Karl Berry (karl@hayley) + + * pathsrch.c (readable) [ENAMETOOLONG]: conditionalize the test + for doing our own truncating, since it appears not all systems + have ENAMETOOLONG. + +Sun Jun 14 08:11:32 1992 Karl Berry (karl@hayley) + + * font.c (get_font): remove computation of NCHARS (and reading of + all the TFM chars). + + * str-lcase.c (str_to_lower): assert the arg is non-null. + +Sat Jun 13 16:28:08 1992 Karl Berry (karl@hayley) + + * libfile.c (libfile_start): return the FILE * we open. + +Sat Jun 13 13:52:30 1992 Kathy Hargreaves (kathy@hayley) + + * encoding.c (DEFAULT_ENCODING): moved to .h file. + +Sat Jun 13 09:24:12 1992 Karl Berry (karl@hayley) + + * encoding.c: include `str-lcase.h', not `str-casefold.h'. + + * xmessage.c (x_message): cast initializer in `popup_args' to + avoid warning. + + * str-to-bit.c (string_to_bitmap): `TFM_FONT_PARAMETER' is now + `TFM_FONTDIMEN'. + + * pathsrch.c (absolute_p): add parens to stop GCC 2's stupid warning. + + * encoding.c: change for new list fn names. + * font.c: likewise. + + * list.c (new_list): rename to `list_init', and rewrite to use + accessor macros. + (append_element): rename to `list_append', and likewise rewrite. + (list_free): new routine. + +Sun Jun 7 17:25:43 1992 Karl Berry (karl@hayley) + + * encoding.c (coding_scheme_to_filename): rewrite to avoid + sentinel boolean, lowercasing the passed codingscheme more than + once, etc. + + * str-casefold.c (str_to_lower): rewrite to use ? :. + (str_to_upper): remove this. + Rename to str-lcase.c. + * GNUmakefile (c_only): change str-casefold to str-lcase. + +Sun Jun 7 14:39:09 1992 Kathy Hargreaves (kathy@hayley) + + * bb-outline.c (find_outline_bbs): don't calculate edge if it's an + interior pixel. + + * bb-outline.c (find_outline_bbs): deleted avoiding finding a + bounding box which corresponds to a counterform by not looking + inside existing bounding boxes. + Added finding the bounding box for a counterform (i.e., marking + its edges) but not adding it to the list unless find_all is true. + Changed find_all to find_inner. + +Sun Jun 7 08:55:31 1992 Karl Berry (karl@hayley) + + * GNUmakefile (c_only): add `str-to-bit'. + * font.c (string_to_bitmap): extract the interword space out of + the TFM information, instead of expecting it in the main font + structure. Also, move this fn to its own file, `str-to-bit.c'. + + * float-ok.c (float_ok): don't accept the empty string, or just a + sign, or just a sign and a `.', etc. + * integer-ok.c (integer_ok): likewise. + +Thu Jun 4 08:11:36 1992 Karl Berry (karl@hayley) + + * pathsrch.c (absolute_p): `k./' should not be considered + explicitly relative. + +Tue Jun 2 11:40:32 1992 Karl Berry (karl@hayley) + + * encoding.c (encoding_number): don't crash if NAME is NULL. + +Mon Jun 1 15:16:15 1992 Karl Berry (karl@hayley) + + * GNUmakefile (c_only): add `integer-ok' and `float-ok'. + * {integer,float}-ok.c: new files. + + * libfile.c (libfile_start): use extend_filename. + + * encoding.c (read_encoding_file): initialize the return structure + after we know the file exists. + +Fri May 29 08:29:26 1992 Karl Berry (karl@hayley) + + * getopt*.c: new versions. + +Sat May 23 15:51:53 1992 Karl Berry (karl@hayley) + + * charcode.c (parse_charcode): ensure there are no extra + characters at the end of the charcode; change return type to + charcode_type. + (xparse_charcode): change return type. + +Sat May 23 12:33:32 1992 Kathy Hargreaves (kathy@hayley) + + * str-casefold.c (str_to_lower): added variable `length'; put 0 at + end of return string. + +Sat May 23 06:27:28 1992 Karl Berry (karl@hayley) + + * dir-p.c (leaf_dir_p): remove; `expand_subdir' now calls stat + itself, for efficiency. + + * pathsrch.c (expand_subdir): rewrite to always look for subdirs. + (initialize_path_list): check for the dir-ness of `foo' in + `foo//'. This change makes symlinks under `foo' be considered. + + * pathsrch.c (add_directory): don't check for the arg being a + directory. + (initialize_path_list): check here for the directory-ness of a + path element. + (expand_subdir): check here, too. + + * pathsrch.c (expand_subdir): call closedir after we read the + directory contents. + +Thu May 21 11:40:53 1992 Karl Berry (karl@hayley) + + * hexify.c (hexify): take a block of memory and a length, instead + of a varstring. + +Tue May 19 16:43:43 1992 Kathy Hargreaves (kathy@hayley) + + * line.c (read_line): return a string if not at EOF. + +Sat May 16 21:22:57 1992 Kathy Hargreaves (kathy@hayley) + + * varstring.c (vs_concat): added. + +Fri May 15 10:22:27 1992 Karl Berry (karl@hayley) + + * getopt.c: new version. + +Thu May 14 22:05:10 1992 Karl Berry (karl@claude.cs.umb.edu) + + * rand.c (srand): -> seed_rand, to avoid header conflicts. + (rand): -> k_rand, same reason. + +Sun May 10 10:05:36 1992 Karl Berry (karl@hayley) + + * encoding.c (coding_scheme_to_filename): don't xstrdup the return + value. + (DEFAULT_ENCODING): new macro. + +Fri May 8 15:38:38 1992 Karl Berry (karl@hayley) + + * pathshare from dvips. + +Thu May 7 16:44:14 1992 Karl Berry (karl@hayley) + + * GNUmakefile (c_only): add dlsym. + * dlsym.c: new file. + +Wed May 6 10:08:09 1992 Karl Berry (karl@hayley) + + * bitmap.c (bitmap_find_transitions): don't look outside the + current row when it's only one pixel long. + +Tue May 5 08:46:48 1992 Karl Berry (karl@hayley) + + * dir-p.c: doc fix. + +Sat May 2 07:51:53 1992 Karl Berry (karl@hayley) + + * pathsrch.c (add_directory): use ?:. + +Thu Apr 30 08:52:34 1992 Karl Berry (karl@hayley) + + * pathsrch.c (parse_envpath): expand the ~ here; + (add_directory): not here. + + * pathsrch.c (expand_tilde): free space for the login name. + + * dir-p.c (leaf_dir_p): use stat, not xlstat, so we don't bomb + out on missing directories in paths, and so we get info about + the (potential) dir, not the link. + +Tue Apr 21 07:44:52 1992 Karl Berry (karl@hayley) + + * bitmap.c (bitmap_find_transitions): use XTALLOC1. + * font.c (get_char): likewise. + +Mon Apr 20 08:35:23 1992 Karl Berry (karl@hayley) + + * pathsrch.c: doc fix. + + * malloc.c: don't include config.h. + (my_bzero, my_bcopy): new routines to simplify things. + +Sat Apr 18 12:22:29 1992 Kathy Hargreaves (kathy@hayley) + + * str-casefold.c: added. + + * encoding.c (coding_scheme_to_filename): compare case-folded + versions of the coding scheme and the mapped scheme. + +Wed Apr 15 15:23:20 1992 Karl Berry (karl@hayley) + + * make-output.c: rename to `extend-fname.c'; rename the fn to + `extend_filename'. + * GNUmakefile (c_only): analogously. + +Wed Apr 15 13:20:11 1992 Kathy Hargreaves (kathy@hayley) + + * encoding.c (coding_scheme_to_filename): changed some variable + names; added `mapped_coding' and set it to a second call to + strtok with `mapping'. + +Tue Apr 14 13:46:45 1992 Karl Berry (karl@hayley) + + * scaled-num.c (scaled_to_real): as below. + +Sun Apr 12 15:06:58 1992 Karl Berry (karl@hayley) + + * scaled-num.c (real_to_scaled): simplify to just multiply the + real by SCALED_UNITY. + +Fri Apr 10 16:36:33 1992 Karl Berry (karl@hayley) + + * concat.c: put concat[345] in separate files. + * GNUmakefile (c_only): update. + + * filename.c: remove prefix/suffix routines. + ({make-{output,prefix,suffix},remove-suffx,find-suffix}.c): new files. + * GNUmakefile (c_only): update. + + * pathsrch.c (initialize_path_list): remove cwd_first_p. + * filename.c (find_*_filename): change calls. + * libfile.c (libfile_start): change call. + +Mon Apr 6 13:46:36 1992 Kathy Hargreaves (kathy@fosse) + + * encoding.c (encoding_scheme_to_filename): added. + +Fri Apr 3 13:17:22 1992 Karl Berry (karl@hayley) + + * rand.c: new file. + * GNUmakefile (c_only): include it. + +Wed Apr 1 14:14:01 1992 Karl Berry (karl at hayley) + + * (pathshare from web2c) + + * filename.c (make_output_filename): don't duplicate the input + string, just return it. + + * filename.c (remove_suffix): remove. + + * edge.c: new file. + * GNUmakefile (c_only): add it. + * bb-outline.c: remove edge stuff in favor of this new file. + +Tue Mar 31 13:35:51 1992 Karl Berry (karl at hayley) + + * bitmap.c (bitmap_find_transitions): handle a row with a single + black pixel at the end correctly. + +Sun Mar 29 10:58:27 1992 Karl Berry (karl at hayley) + + * xrealloc.c (xrealloc): cast the ptr. + + * file-input.c (get_n_bytes): had args switched to fatal. + + * bb-outline.c (is_outline_edge): remove the assertion that we're + at a valid pixel, since it's half-implied by the types, anyway. + + * GNUmakefile (malloc.o): remove the special rule and vars. + * malloc.c [STDC_HEADERS | USG]: add the former for memset etc. + +Sat Mar 28 07:49:09 1992 Karl Berry (karl at hayley) + + * malloc.c: new version, from libg++ 2.0. + + * GNUmakefile (malloc_stats): don't define this. + + * Version 0.4. + + * Change copyright years to 1992 only. + +Wed Mar 25 08:37:28 1992 Karl Berry (karl at hayley) + + * GNUmakefile (c_only): add fmod. + * fmod.c: new file. + +Thu Mar 19 07:47:30 1992 Karl Berry (karl at hayley) + + * pathsearch.c, libfile.c, filename.c: include paths.h. + + * pathsearch.c: rename to pathsrch.c; new version. + +Wed Mar 11 10:03:12 1992 Karl Berry (karl at hayley) + + * bitmap.c (bitmap_find_transitions): handle the pixel at the end + of the row specially, unfortunately. + +Tue Mar 10 12:17:09 1992 Kathy Hargreaves (kathy at hayley) + + * libfile.c (libfile_start): use find_suffix instead of finding a + dot position. + +Mon Mar 9 16:42:49 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (make_stem_suffix): remove suffix from name before + adding stem_suffix and putting suffix back on. + + * filename.c (make_stem_suffix): don't add a dot if no suffix. + + * filename.c (make_stem_suffix): added. + +Sun Mar 8 17:08:06 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (make_output_filename): put dot between NAME and + DEFAULT_SUFFIX. + +Sun Mar 8 08:37:46 1992 Karl Berry (karl at fosse) + + * numtoa.c (dtoa): rename from ftoa. + + * strstr.c: new file. + GNUmakefile (c_only): add strstr. + +Sat Mar 7 17:00:44 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (sizeless_font_name): removed. + +Sat Mar 7 13:21:33 1992 Karl Berry (karl at fosse) + + * xmessage.c: include xmessage.h. + + * GNUmakefile (c_only): remove statistics; we never use it. + + * pathsearch.c: add prototypes for the subroutines. + + * line.c: include line.h. + + * bb-outline.c (find_outlines_bbs): rename parameters to avoid + shadow warnings. + +Sat Mar 7 09:14:00 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files, headers, sources): replace with `c_and_h', etc. + + * scaled-num.c (print_scaled): use putchar instead of printf where + possible. + +Wed Mar 4 10:40:02 1992 Karl Berry (karl at hayley) + + * filename.c (remove_suffix): don't include the `.' in what we + return. + +Tue Mar 3 16:28:38 1992 Karl Berry (karl at hayley) + + * filename.c (find_suffix): new routine. + (remove_suffix, make_output_filename, make_suffix): write in terms + of it. + +Sun Mar 1 16:33:49 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (make_output_file): use concat instead of make_suffix. + +Sun Mar 1 15:17:28 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files): add bb-outline. + +Sun Mar 1 14:48:41 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (make_output_file): added. + +Mon Feb 24 08:38:56 1992 Karl Berry (karl at hayley) + + * pathsearch.c (truncate_pathname): separate this out from `readable'. + + * concat.c dir-p.c file-p.c pathsearch.c xmalloc.c xopendir.c + xrealloc.c xstat.c xstrdup.c: redo with (un)prototype macros. + +Wed Feb 19 10:00:35 1992 Karl Berry (karl at hayley) + + * varstring.c (vs_set_char): set the allocated field after we + allocate more space. + + * hexify.c (hexify): add 'a' to each hex char to make it visible + ASCII; shift the upper nybble down before adding. + +Mon Feb 17 07:38:27 1992 Karl Berry (karl at hayley) + + * filename.c (sizeless_font_name): new routine. + + * line.c (read_line): use vs_append_char, and generally simplify. + + * varstring.c (vs_append_char): don't append a null afterwards. + + * GNUmakefile (files): add it. + * hexify.c: new file. + +Sun Feb 16 10:31:41 1992 Karl Berry (karl at hayley) + + * pathsearch.c (readable): keep track of the component lengths + properly; do the second test on the new name, not the old. + +Sat Feb 15 16:10:30 1992 Karl Berry (karl at hayley) + + * pathsearch.c (READABLE): redo the macro as a function, and + truncate the pathname if necessary. + +Fri Feb 14 07:26:35 1992 Karl Berry (karl at hayley) + + * varstring.c (vs_append_char): use VS_USED instead of strlen. + (vs_init): initialize VS_USED to zero. + (vs_set_char): set VS_USED. + All routines: rename `VS_LENGTH to `VS_ALLOCATED'. + + * varstring.c (vs_free): new routine. + + * math.c (acosd): clear errno before testing it. + +Thu Feb 13 13:32:54 1992 Karl Berry (karl at hayley) + + * pathsearch.c (READABLE): call it readable if the error is + ENAMETOOLONG; include <errno.h> and declare errno if that is + undefined. + +Sun Feb 2 16:08:44 1992 Karl Berry (karl at hayley) + + * filename.c (find_{gf,pk}_filename): allocate enough space for + the null sprintf writes. + +Sat Feb 1 14:53:39 1992 Karl Berry (karl at hayley) + + * filename.c (depath): remove. + + * pathsearch.c (initialize_path_list): subdirectories are now + indicated by // terminating a path element, instead of as + a separate envvar/path. + * filename.c (find*filename): remove subdirectory stuff. + * libfile.c (libfile_start): likewise. + +Mon Jan 20 11:09:10 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (depath): added this routine to take the path off the + front of a filename. + + * filename.c (make_prefix): added this routine to add a prefix to + a filename which may or may not be the full pathname. + +Wed Jan 15 16:57:36 1992 Kathy Hargreaves (kathy at hayley) + + * libfile.c (libfile_start): when FATAL, report `name', not it + concatenated with the default suffix. + +Wed Jan 15 13:01:30 1992 Karl Berry (karl at hayley) + + * GNUmakefile (c_only): remove xchdir and xgetcwd, as we don't + need them anymore. + * pathsearch.c: changes from TeX. + +Wed Jan 15 11:59:56 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (find_*_filename): only free `name' if it's not the + same string as `*_name'. + +Tue Jan 14 12:36:15 1992 Kathy Hargreaves (kathy at hayley) + + * bitmap.c (bitmap_find_transitions): make the last transition + always imply a black-to-white transition, even if ROW's last + pixel is black. + + * libfile.c (libfile_start): make FATAL2 report `name', not + `filename' as the library file not found. Also, only add suffix + to the library file name if it doesn't have one already. + +Sun Jan 12 16:29:11 1992 Kathy Hargreaves (kathy at hayley) + + * filename.c (make_suffix): copy suffix into new_s, not s. + +Sun Jan 12 14:57:24 1992 Karl Berry (karl at hayley) + + * pathsearch.c (check_subdir): add every existing subdirectory, + even if it's not a leaf. + +Sun Jan 12 12:47:57 1992 Kathy Hargreaves (kathy at hayley) + + * libfile.c (libfile_start): don't prepend a dot to the suffix. + + * dir-p.c (dir_p): call stat instead of xstat. + +Sat Jan 11 15:01:02 1992 Karl Berry (karl at hayley) + + * filename.c (find_*_filename): set cwd_first_p. + + * pathsearch.c (initialize_path_list): take an additional + argument, saying whether to search `.' first. + +Fri Jan 10 07:40:50 1992 Karl Berry (karl at hayley) + + * xgetcwd.c (xgetcwd) [GETWD_MISSING]: if it's not missing, use + it. + + * filename.c (find_*_filename): only initialize the path lists + once. + + * pathsearch.c (expand_colon): if env_path is null, return the + default path. + + * file-input.c (MOVE_BACK): use xfseek. + + * filename.c (*_suffix): use strrchr instead of rpos. + + * varstring.c: change names to start with `vs'. + + * memory.c: split into various files. + + * math.c (adjacent_points): rename to `points_adjacent_p'. + + * math.c (find_bounds): use MAXDOUBLE and MINDOUBLE instead of + MAXFLOAT and MINFLOAT. + + * filename.c (find_dpi): move to cmdline.c. + (basename): move to basename.c. + +Thu Jan 9 08:57:39 1992 Karl Berry (karl at hayley) + + * convert.c: split into various files. + * GNUmakefile: update. + + * cmdline.c (scan_integer_list): rename to `scan_unsigned_list'. + + * *.c: do not include global.h. + + * arith.c: split into `scaled-num.c' and `fix-num.c'. + * GNUmakefile: update. + +Wed Jan 8 09:14:45 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + + * list.c: doc fix. + +Tue Jan 7 17:28:07 1992 Karl Berry (karl at hayley) + + * filename.c (expand_colon): don't put the default value at the + end if we've already put it at the beginning. + +Thu Sep 12 11:06:58 1991 Karl Berry (karl at hayley) + + * malloc.c (malloc_sanity_check): new function. + + * bitmap.c (bitmap_find_transitions): rearrange logic for clarity. + + * malloc.c, getpagesize.h: new files. + * GNUmakefile (c_only): add Doug Lea's malloc. + (malloc_stats, malloc_inline): new variables. + (malloc.o): rule to explicitly use them. + +Tue Jul 30 13:18:12 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Wed Jul 24 06:34:11 1991 Karl Berry (karl at hayley) + + * bitmap.c (concat_bitmaps): remove; it's only used in one program. + + * bitmap.c (new_bitmap): call it. + + * memory.c (xcalloc): new routine. + +Tue Jul 16 08:24:08 1991 Karl Berry (karl at hayley) + + * memory.c (allocate): don't do assignment inside if. + + * bitmap.c (bitmap_find_transitions): we don't need to look at the + first black pixel twice. + +Fri Jun 28 09:09:59 1991 Karl Berry (karl at hayley) + + * font.c (close_font): only close the TFM file if the font is not + bitmap-only. + +Sat Jun 15 09:51:45 1991 Karl Berry (karl at hayley) + + * font.c (get_font): set the new `tfm_font' and `tfm_filename' + members. + + * {dirio,file-misc,file-open,filename,libfile}.c: change + `checked_' to `x'. + +Tue Jun 11 16:46:25 1991 Karl Berry (karl at hayley) + + * font.c (get_char): use XTALLOC. + + * font.c (close_font): close the TFM file here, instead of in + `get_font'. + +Sun Jun 9 13:23:59 1991 Karl Berry (karl at hayley) + + * font.c (string_to_bitmap): use `BITMAP_PIXEL (CHAR_BITMAP'... + instead of `CHAR_BITMAP_PIXEL'. + +Thu Jun 6 07:30:07 1991 Karl Berry (karl at hayley) + + * All files: change to version 2 of the GPL. + +Sat Jun 1 16:00:03 1991 Kathy Hargreaves (kathy at hayley) + + * libfile.c (libfile_start): Don't concat a `.' to suffix if it's + the empty string. + +Thu May 16 07:35:47 1991 Karl Berry (karl at hayley) + + * GNUmakefile (files): include `xmessage' (from xbce). + * xmessage.c: new file. + +Sun Apr 21 17:38:48 1991 Karl Berry (karl at hayley) + + * bitmap.c (bitmap_to_bb): declare the arg as const. + +Sun Apr 14 13:45:29 1991 Karl Berry (karl at hayley) + + * bitmap.c (print_bitmap): use `bitmap_to_bb' instead of + `dimensions_to_bb'. + +Fri Apr 12 15:12:32 1991 Karl Berry (karl at hayley) + + * math.c: doc fix. + + * GNUmakefile (files): add `report' and `logreport'. + * {log,}report.c: new files. + +Wed Apr 10 11:27:49 1991 Karl Berry (karl at hayley) + + * font.c (save_internal_font): omit needless casts. + +Mon Apr 8 07:57:20 1991 Karl Berry (karl at hayley) + + * font.c (ascender_part): move to ospace. + + * encoding.c (parse_encoding_line): make a copy of the character + name, since the line gets freed. + + * encoding.c (read_encoding_file): reinitialize the character + code, so we fill up the right array. + + * libfile.c (libfile_start): prepend the `.' to the suffix. + +Sun Apr 7 14:34:06 1991 Karl Berry (karl at hayley) + + * file-output.c (put_signed_four): declare this as a macro in the + .h file. + +Thu Apr 4 07:03:36 1991 Karl Berry (karl at hayley) + + * font.c (get_char): don't allocate any space unless the character + actually exists in the font. + +Mon Apr 1 07:57:58 1991 Karl Berry (karl at hayley) + + * {encoding,libfile}.c: new files. + GNUmakefile (files): add them to the list. + +Sat Mar 23 16:42:39 1991 Karl Berry (karl at hayley) + + * font.c (delete_internal_font): free the memory for the internal + font, and for the font name. + +Sat Mar 9 17:06:57 1991 Karl Berry (karl at hayley) + + * string.c: declare args to routines as const. + + * string.c (lowercasify): new routine. + +Thu Mar 7 07:33:05 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Mon Mar 4 15:06:59 1991 Karl Berry (karl at hayley) + + * font.c (delete_internal_font): new routine. + (close_font): call it, thus preventing us from finding a font that + has been closed. + +Mon Feb 25 15:58:21 1991 Karl Berry (karl at hayley) + + * font.c (get_font): use `tfm_...' instead of `..._tfm_...'; use + `pk_...' instead of `..._pk_...'; use `gf_...' instead of + `..._gf_...'. + +Sun Feb 24 15:34:36 1991 Karl Berry (karl at ra.cs.umb.edu) + + * math.c (int_distance): cast the arguments to `double'. + +Sun Feb 17 09:43:06 1991 Karl Berry (karl at hayley) + + * *.c: include config.h. + +Sat Feb 16 16:54:18 1991 Karl Berry (karl at hayley) + + * dirio.c (checked_lstat) [HAVE_SYMBOLIC_LINKS]: change + conditional from being on S_ISLNK and S_IFLNK. + +Tue Jan 22 15:44:43 1991 Karl Berry (karl at hayley) + + * bitmap.c (extract_subbitmap): new routine from imgtogf. + +Fri Jan 18 08:14:23 1991 Karl Berry (karl at hayley) + + * vector.c (all routines): declare args to be const. + + * vector.c (Vabs): new routine. + +Tue Jan 15 15:29:38 1991 Karl Berry (karl at hayley) + + * spline.c (append_spline): use LAST_SPLINE_LIST_ELT. + + * spline.c (new_spline_list_array, free_spline_list_array, + append_spline_list): new routines. + + * spline.c (append_spline_list): rename to concat_spline_lists. + +Sun Jan 13 09:48:56 1991 Karl Berry (karl at hayley) + + * font.c (bitmap_format_type): move to font.h. + + * file-output.c (put_n_bytes): give the arguments to fwrite in the + correct order. + +Sat Jan 12 16:46:44 1991 Karl Berry (karl at hayley) + + * file-output.c (put_n_bytes): use fwrite to do all the bytes at + one shot. + +Mon Jan 7 10:42:22 1991 Karl Berry (karl at hayley) + + * spline.c (evaluate_spline): no compiler bug anymore without + temporaries (as of gcc 1.38). + +Sat Dec 29 17:43:40 1990 Karl Berry (karl at hayley) + + * spline.c (print_spline): make the output lines shorter. + +Wed Dec 26 15:13:26 1990 Karl Berry (karl at hayley) + + * math.c (find_bounds): use MAXFLOAT and MINFLOAT, instead of + MAXDOUBLE and MINDOUBLE, since Sun's atof can't deal with + the latter. + +Sun Dec 9 11:02:20 1990 Karl Berry (karl at hayley) + + * spline.c: doc fix. + + * dirio.c (getwd): close each directory after we read it. + + * filename.c (find_subdir_path_filename): use getwd instead of + getcwd, and use checked_chdir. + + * dirio.c (checked_opendir, is_dir): make arguments be const strings. + + * dirio.c (checked_chdir, checked_stat, checked_lstat, getwd): new + routines. + +Sat Nov 17 11:09:56 1990 Karl Berry (karl at hayley) + + * file-*.c: include the appropriate file-....h file. + + * math.c (distance): put this back; it's too annoying to call + hypot with the x and y arguments. + +Thu Oct 18 15:00:32 1990 Karl Berry (karl at hayley) + + * filename.c (find_subdir_path_filename): initialize the list of + subdirectories to the empty string. + +Wed Oct 17 17:54:40 1990 Karl Berry (karl at aten) + + * filename.c (find_subdir_path_filename): do not do strlen when + the path is empty. + +Tue Oct 9 08:59:43 1990 Karl Berry (karl at hayley) + + * filename.c (find_dpi): don't crash if the argument doesn't have + a `.' at all. + + * cmdline.c: new file. + * GNUmakefile (files): add it. + +Mon Oct 8 09:08:30 1990 Karl Berry (karl at hayley) + + * filename.c (find_dpi): new routine. + +Wed Oct 3 07:33:07 1990 Karl Berry (karl at hayley) + + * filename.c (find_tfm_filename, find_pk_filename, + find_gf_filename): new routines. + +Sat Sep 29 08:34:52 1990 Karl Berry (karl at hayley) + + * bitmap.c (new_bitmap): don't use memset if the bitmap is null. + + * font.c (find_internal_font): use STREQ. + +Fri Sep 28 08:30:04 1990 Karl Berry (karl at hayley) + + * filename.c (next_component): return NULL after we've read all + the directories in the list. + + * filename.c (next_component): omit the path separator from the + returned directory. + +Thu Sep 27 11:45:36 1990 Karl Berry (karl at hayley) + + * font.c (DEFAULT_SUBDIR_PATH): new macro. + (get_bitmap_font): try to open the PK and GF files using + subdirectories if opening without them fails. + (get_font): likewise, for the TFM file. + * filename.c (get_subdir_path_filename): new routine. + (next_component): new routine, replaces `find_components'. + +Fri Sep 21 09:15:28 1990 Karl Berry (karl at hayley) + + * dirio.o (is_dir): use S_ISDIR. + +Thu Sep 13 10:38:32 1990 Karl Berry (karl at hayley) + + * convert.c (parse_char_code): new routine to replace the + PARSE_CHAR_CODE macro; return a status indicator. + (xparse_char_code): like the above, but gives a fatal error. + +Wed Sep 12 18:19:13 1990 Karl Berry (karl at aten) + + * font.c (get_font): set `bitmap_only' to false. + (save_internal_font): overwrite the old value if we're called with + the same key twice. + +Sun Sep 9 07:10:29 1990 Karl Berry (karl at hayley) + + * convert.c: new file for some numeric conversions. + * math.c: move atou to convert.c. + +Mon Sep 3 11:05:19 1990 Karl Berry (karl at hayley) + + * line.c (read_line): doc fix. + +Fri Aug 31 11:04:02 1990 Karl Berry (karl at hayley) + + * font.c (get_bitmap_font): new routine, taken from get_font. + +Thu Aug 30 16:32:25 1990 Karl Berry (karl at hayley) + + * file-misc.c (same_file_p): new function. + +Wed Aug 29 11:37:24 1990 Karl Berry (karl at hayley) + + * fileio.c: split up into several new files: file-open.c, + file-input.c, file-output.c, file-misc.c. + +Thu Aug 23 07:26:58 1990 Karl Berry (karl at hayley) + + * filename.c (remove_suffix): new routine. + (make_suffix): if the `.' is before a `/', it doesn't start the + extension. + +Thu Aug 16 07:10:48 1990 Karl Berry (karl at hayley) + + * memory.c (safe_free): use fprintf instead of FATAL, so the core dump + will happen. + +Thu Jul 26 06:53:33 1990 Karl Berry (karl at hayley) + + * bitmap.c (bitmap_find_transitions): new routine (from imgtogf). + +Wed Jul 25 08:20:12 1990 Karl Berry (karl at hayley) + + * string.c (concat5): new routine. + +Tue Jul 24 10:24:59 1990 Karl Berry (karl at hayley) + + * font.c (get_font): save the design size in points instead of + pixels. + + * filename.c: new file. + * fileio.c (find_path_filename): move there. + * string.c (make_suffix): ditto. + + * font.c (get_char): retrieve the TFM width also. + +Mon Jul 16 07:30:33 1990 Karl Berry (karl at hayley) + + * bitmap.c (bitmap_to_bb): new routine. + +Thu Jul 12 06:01:16 1990 Karl Berry (karl at hayley) + + * bitmap.c (copy_bitmap): don't use `new_bitmap', to avoid setting + all the bits twice. + +Tue Jul 10 06:23:54 1990 Karl Berry (karl at hayley) + + * bitmap.c (concat_bitmaps): new routine. + +Mon Jul 9 08:27:09 1990 Karl Berry (karl at hayley) + + * bitmap.c (get_bitmap_bounding_box): delete this. + (print_bitmap): use dimensions_to_bb. + + * bitmap.c (free_bitmap): don't free the bitmap if it's null. + + * bitmap.c (new_bitmap): use memset. + (copy_bitmap): use memcpy if the bitmap's size is greater than + zero. + +Sat Jul 7 18:22:55 1990 Karl Berry (karl at hayley) + + * memory.c (safe_free): dump core if we are freeing a null item. + +Fri Jul 6 14:21:07 1990 Karl Berry (karl at hayley) + + * bounding-box.c (bb_to_dimensions): ensure that the dimensions + are nonnegative. + +Wed Jul 4 12:06:49 1990 Karl Berry (karl at hayley) + + * memory.c (allocate): dump core if we run out of memory. + (reallocate): ditto. + + * bounding-box.c (dimensions_to_bb): don't subtract one from the + width, so it will work with the GF routines. + (bb_to_dimensions): use BB_WIDTH and BB_HEIGHT, instead of doing + the subtraction out here. + + * bounding-box.c (update_bounding_box): new routine. + +Sun Jul 1 15:11:56 1990 Karl Berry (karl at hayley) + + * font.c (ascender_part): new routine. + +Tue Jun 26 11:27:15 1990 Karl Berry (karl at hayley) + + * spline.c (evaluate_spline): use temporaries in the computation + to avoid a compiler bug. + + * vector.c (Padd, Pmult_scalar): remove definitions, since they + are defined as macros now. + +Sun Jun 24 15:31:34 1990 Karl Berry (karl at claude) + + * font.c (get_font): don't check the checksums if either one is + zero. + +Sat Jun 23 12:11:47 1990 Karl Berry (karl at hayley) + + * font.c (print_char): change precision for printing the row numbers. + +Tue Jun 19 11:50:52 1990 Karl Berry (karl at hayley) + + * fileio.c (move_to_byte): delete this. + + * fileio.c (cur_pos): rename to checked_ftell, and take a filename + argument for perror. + +Mon Jun 18 12:47:17 1990 Karl Berry (karl at hayley) + + * font.c (find_internal_font): return a pointer to an + internal_font_type, instead of a structure, and change callers. + (get_font): if we have already saved the font, return it, instead + of opening the files again. + +Mon Jun 4 16:20:32 1990 Karl Berry (karl at hayley) + + * math.c (find_bounds): use MAXDOUBLE and MINDOUBLE, instead of + MAXFLOAT and MINFLOAT. + + * spline.c (spline_bounding_box): remove this routine. + +Sun Jun 3 10:51:28 1990 Karl Berry (karl at hayley) + + * arith.c, math.c, vector.c: add const declarations. + + * fileio.c (get_two, get_four): don't bother to initialize the + variable before we read it. + + * fileio.c (get_n_bytes): improve the error message if the read + fails. + +Sat Jun 2 07:51:08 1990 Karl Berry (karl at hayley) + + * bounding-box.c (increase_int_bound): remove this. + + * spline.c (print_spline): print different things for lines and + splines. + +Wed May 30 16:02:26 1990 Karl Berry (karl at hayley) + + * bitmap.c (new_bitmap): if the bitmap is going to be zero bits, + don't try to allocate it. + + * font.c (get_font): figure out how many characters are in the + font by testing the `exists' member of the TFM structure. + + * font.c (get_font): don't try to open the GF file if we couldn't + find it. + +Tue May 22 09:51:20 1990 Karl Berry (karl at hayley) + + * fileio.c (find_path_filename): close the directories in the path. + +Sat May 19 10:30:39 1990 Karl Berry (karl at hayley) + + * fileio.c (find_path_filename): return NULL if we can't find the + file, instead of the original name. + * font.c (get_font): rewrite the file-opening code. + +Wed May 16 18:02:54 1990 Karl Berry (karl at aten) + + * font.c (string_to_bitmap): if the character doesn't exist in the + font, don't crash. + + * fileio.c (find_path_filename): don't get a fatal error when a + directory in the path doesn't exist. + +Sun May 13 13:45:12 1990 Karl Berry (karl at hayley) + + * dirio.c (is_dir): new routine. + + * fileio.c (find_path_filename): just return the name we're given + if the path is relative; move the suffix concatenation out of the + loop; search in subdirectories. + +Tue May 8 12:08:57 1990 Karl Berry (karl at hayley) + + * math.c: doc fix. + +Thu May 3 10:45:05 1990 Karl Berry (karl at hayley) + + * line.c (read_line): use VS_CHARS. + +Wed May 2 12:25:08 1990 Karl Berry (karl at claude) + + * font.c (string_to_bitmap): don't close the font when we're done. + +Wed Apr 25 13:16:28 1990 Karl Berry (karl at aten) + + * font.c (string_to_bitmap): don't asked for chars[x] when x is a + character that isn't there. + +Tue Apr 24 18:35:08 1990 Karl Berry (karl at hayley) + + * math.c (real_to_int_coord): new routine. + +Sun Apr 22 06:42:37 1990 Karl Berry (karl at hayley) + + * font.c (string_to_bitmap): initialize char_y properly. + [whoops, I mean test it properly, and initialize y.] + Pass the row and column to BITMAP_PIXEL in the right order. + Give the row and column to the constructor in the right order, + too. Use MAX to find the depth, not MIN. + + * font.c (print_char): print the bitmap here, so we can print out + the Cartesian row number, instead of calling `print_bitmap'. + +Sat Apr 21 09:49:42 1990 Karl Berry (karl at hayley) + + * fileio.c (get_n_bytes): use fread to read the whole block, + instead of getting them one byte at a time. + +Thu Apr 19 16:19:33 1990 Karl Berry (karl at hayley) + + * font.c (get_font): do checksum test before getting the + postamble. + +Tue Apr 17 16:53:31 1990 Karl Berry (karl at hayley) + + * font.c (print_char): new routine to print a text representation + of a character. + +Mon Apr 16 11:12:28 1990 Karl Berry (karl at hayley) + + * font.c (get_font): get the design size from the TFM file, + instead of the bitmap file. + +Sun Apr 15 07:34:19 1990 Karl Berry (karl at hayley) + + * font.c (get_font): do not set the font bounding box. + +Sat Apr 14 15:11:19 1990 Karl Berry (karl at hayley) + + * fileio.c (checked_fseek): make argument type be + seek_direction_type. + + * fileio.c (checked_fclose): new (trivial) routine. + +Thu Apr 12 12:06:17 1990 Karl Berry (karl at hayley) + + * GNUmakefile: do not define USG and USGr3. + + * time.c: include <sys/types.h> and declare time(2) and ctime(3) + using time_t. + + * fileio.c (find_path_filename): use access(2) instead of + fopen(3); pass the default path to find_components. + (find_components): use a default path if the environment variable + doesn't exist. + +Mon Apr 9 08:19:53 1990 Karl Berry (karl at hayley) + + * math.c (distance): remove this, I came across hypot(3). + + * all files: upcase macro names. + +Sun Mar 18 14:58:23 1990 Kathy Hargreaves (kathy at hayley) + + * bounding_box.[hc] (increase_int_bound): added this to increase a + bounding boxes bounds nicely, i.e., if the bound is negative, it + gets decreased, and increased otherwise. + +Tue Feb 27 21:01:24 1990 Kathy Hargreaves (kathy at hayley) + + * fileio.c (get_n_bytes): don't try to read zero bytes. + +Wed Feb 7 17:00:47 1990 Karl Berry (karl at hayley) + + * time.c (now): chop off the trailing space. + +Mon Jan 29 12:46:56 1990 Karl Berry (karl at hayley) + + * bounding-box.c (bb_to_dimensions): new routine. + + * math.c (atou): like atoi but < 0 is a fatal error. + +Sun Jan 21 09:55:14 1990 Karl Berry (karl at hayley) + + * Makefile: rename to GNUmakefile. + + * bounding_box.c (dimensions_to_bounding_box): rename to + dimensions_bb. Remove other conversion routines. And rename to + bounding-box.c. + +Tue Oct 31 07:24:05 1989 Karl Berry (karl at hayley) + + * math.c (int_to_real_coordinate): remove this. + +Mon Oct 30 14:03:57 1989 Karl Berry (karl at hayley) + + * all files: add the copyleft. + + * string.c (concat4): define this. + +Sun Oct 29 18:37:33 1989 Karl Berry (karl at claude) + + * math.c (undefined_real_coordinate): remove this. + +Sat Oct 28 15:55:59 1989 Karl Berry (karl at hayley) + + * arith.c (real_to_scaled, real_to_fix): multiply the integer part + by scaled_one and fix_one, respectively. + + * fileio.c (put_three): define this. + (put_three, put_four): had the mask wrong for the + low-order byte. + (put_two, put_three, put_four): a & b >> c is + a & (b >> c), not (a & b) >> c. + +Fri Oct 27 22:14:05 1989 Karl Berry (karl at hayley) + + * bitmap.c (new_bitmap): use the bitmap_dimensions macro. + +Sun Oct 8 15:41:01 1989 Karl Berry (karl at hayley) + + * math.c (epsilon_equal): new function to test if two values are + within epsilon of each other. + (acosd): changed to call that one. + + * bitmap.c (free_bitmap): new function to deallocate storage + used in a bitmap_type. + + * math.c (acosd): normalize to 1.0 or -1.0 if the argument is + within an epsilon of that anyway. + +Fri Oct 6 22:12:05 1989 Karl Berry (karl at hayley) + + * line.c (read_line): overwrite the newline at the end of the + string with a null. diff --git a/lib/GNUmakefile b/lib/GNUmakefile new file mode 100644 index 0000000..ed258fa --- /dev/null +++ b/lib/GNUmakefile @@ -0,0 +1,38 @@ +# Makefile for the fontutils library. +# +# Copyright (C) 1992, 93 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +library = lib + +# If this gives you trouble, just remove it. The system malloc will +# probably work well enough. +#malloc = gmalloc + +# The headers are in the `include' directory, so don't use `c_and_h'. + +c_only = $(malloc) bb-list bb-outline bitmap bounding-box \ +charcode charspec cmdline concat concat3 concat4 concat5 dlsym edge \ +encoding float-ok fmod file-input file-output filename fix-num font \ +getopt getopt1 hexify identity integer-ok libfile line list logreport \ +make-prefix math now numtoa pathsrch rand report safe-free scaled-num \ +spline statistics str-lcase str-to-bit substring varstring vector \ +xmessage xopendir xrename + +include ../data/defs.make +include ../data/defslib.make + +include M.depend diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..4d0c220 --- /dev/null +++ b/lib/README @@ -0,0 +1,73 @@ +This library contains many miscellanous functions that are used by the +other programs we have written. + +The declarations for the functions are in ../include. config.h must be +included first in a .c file; that includes global.h, which declares a +few of the most commonly used functions here. The rest have their own +include files, e.g., line.h. + +Some functions merely call a C library routine or make a system call, +check the return status, and abort if the function failed. (In the +programs this has been used for, that was all that we ever wanted.) + +Here is a brief description of what's here (aside from the files which +have just one function in them and other ``obvious'' ones): + +bb-outline find the outlines in a bitmap character. + +bitmap operations on bitmaps, with each pixel represented by a + byte in memory. + +bounding-box conversions to and from bounding boxes, both integer + and real. + +cmdline standard things for reading option lists. + +dirio directory operations. + +encoding read a font encoding specification in a .enc file. + +file-input read BigEndian values. + +file-open wrappers for fopen and fclose. + +file-output write BigEndian values. + +filename operations on filenames. + +fix-num conversions for the `fix_word' fixed-point fraction + type, used in TFM files et al. + +font read a bitmap font, or a bitmap font and its metrics. + +hexify convert a sequence of binary data to its hex representation. + +libfile read a `library', i.e., an auxiliary data, file. + +line read an arbitrarily long line from a file, returning a string. + +list generic list operations. It is a tossup as to whether + it is easier to repeat this code for the particular + lists you desire, or to use these, often with an extra + level of pointers. Unfortunately, C does not support + generic types. + +math distance, slope, etc., between two points; operations on + arrays as a collection of numeric data. + +now the current time as in date(1). + +pathsearch look up a filename along a path in an environment variable. + +report online progress reporting. + +scaled-num routines for the `scaled' fixed-point fraction + type, used in GF files et al. + +spline operations on Bezier splines. + +statistics find the mean/standard deviation of an array of numbers. + +varstring variable-length strings. + +vector operations on vectors and point/vector combinations. diff --git a/lib/atou.o b/lib/atou.o Binary files differnew file mode 100644 index 0000000..d15e642 --- /dev/null +++ b/lib/atou.o diff --git a/lib/basename.o b/lib/basename.o Binary files differnew file mode 100644 index 0000000..8242dd6 --- /dev/null +++ b/lib/basename.o diff --git a/lib/bb-list.c b/lib/bb-list.c new file mode 100644 index 0000000..e3df94e --- /dev/null +++ b/lib/bb-list.c @@ -0,0 +1,76 @@ +/* bb-list.c: operations on bounding box lists. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bb-list.h" + + +/* This routine returns an initialized empty list. */ + +bb_list_type +bb_list_init () +{ + bb_list_type bb_list; + + BB_LIST_LENGTH (bb_list) = 0; + BB_LIST_DATA (bb_list) = NULL; + + return bb_list; +} + +/* Append BB to BB_LIST. */ + +void +bb_list_append (bb_list_type *bb_list, bounding_box_type bb) +{ + BB_LIST_LENGTH (*bb_list)++; + XRETALLOC (BB_LIST_DATA (*bb_list), BB_LIST_LENGTH (*bb_list), + bounding_box_type); + + BB_LIST_ELT (*bb_list, BB_LIST_LENGTH (*bb_list) - 1) = bb; +} + +/* Append the elements in the list B2 onto the end of B1. */ + +void +bb_list_splice (bb_list_type *b1, bb_list_type b2) +{ + unsigned new_length; + unsigned this_bb; + + if (BB_LIST_LENGTH (b2) == 0) + return; + + assert (b1 != NULL); + + new_length = BB_LIST_LENGTH (*b1) + BB_LIST_LENGTH (b2); + XRETALLOC (BB_LIST_DATA (*b1), new_length, bounding_box_type); + + for (this_bb = 0; this_bb < BB_LIST_LENGTH (b2); this_bb++) + BB_LIST_ELT (*b1, BB_LIST_LENGTH (*b1)++) = BB_LIST_ELT (b2, this_bb); +} + +/* Free the memory in a list. */ + +void +bb_list_free (bb_list_type *bb_list) +{ + if (BB_LIST_DATA (*bb_list) != NULL) + safe_free ((address *) &BB_LIST_DATA (*bb_list)); +} diff --git a/lib/bb-outline.c b/lib/bb-outline.c new file mode 100644 index 0000000..1f0e3fa --- /dev/null +++ b/lib/bb-outline.c @@ -0,0 +1,114 @@ +/* bb-outline.c: find the bounding boxes enclosing outlines. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bb-outline.h" +#include "edge.h" + + +static bounding_box_type find_one_bb + (bitmap_type, edge_type, unsigned, unsigned, bitmap_type *); + +/* A character is made up of a list of one or more outlines. Here, we + go through a character's bitmap marking edges on pixels, top to + bottom, left to right, looking for the next pixel with an unmarked + edge that is also on the character's outline. Each one of these + pixels we find is the starting place for one outline. We then get the + bounding boxes of the outlines, and put them in a list to return. We + don't look at pixels that are at or after the column LEFT_MARK or + before RIGHT_MARK. If FIND_INNER is false, we return only outside + outlines; otherwise, we return both inside and outside. */ + +bb_list_type +find_outline_bbs (bitmap_type b, boolean find_inner, + int left_mark, int right_mark) +{ + unsigned row, col; + bb_list_type bb_list = bb_list_init (); + bitmap_type marked = new_bitmap (BITMAP_DIMENSIONS (b)); + + /* By looking through the bitmap in column-major order, we preserve + the original ordering of the characters in the image. Otherwise, + `b' would be found before `a' (for example), because of the + ascender. */ + for (col = 0; col < BITMAP_WIDTH (b); col++) + if (col < left_mark || col >= right_mark) + for (row = 0; row < BITMAP_HEIGHT (b); row++) + { + edge_type edge; + + if (BITMAP_PIXEL (b, row, col) == WHITE + || BITMAP_INTERIOR_PIXEL (b, row, col)) + continue; + + /* Get the next unmarked edge on this pixel, if there is one. */ + edge = next_unmarked_outline_edge (row, col, START_EDGE, b, marked); + + /* If there is an unmarked outline edge on this pixel... */ + if (edge != no_edge) + { + /* Want to mark edges in inner boxes, too. */ + bounding_box_type bb = find_one_bb (b, edge, row, col, &marked); + + /* If edge != START_EDGE, it's on an inner bounding box. */ + if (find_inner || edge == START_EDGE) + { + /* The numbers in BB, as it comes in, refer to pixels; + we have to change the maximum row so that it refers + to the edge beyond the last pixel. */ + MAX_COL (bb)++; + + bb_list_append (&bb_list, bb); + } + } + } + + free_bitmap (&marked); + return bb_list; +} + +/* Here we find one of a character's outlines. We're passed the + position (ORIGINAL_ROW and ORIGINAL_COL) of a starting pixel and one + of its unmarked edges, ORIGINAL_EDGE. We traverse the adjacent edges + of the outline pixels but keep the bounding box in pixel coordinates. + We keep track of the marked edges in MARKED, which should be + initialized to zeros before we get it. */ + +static bounding_box_type +find_one_bb (bitmap_type b, edge_type original_edge, + unsigned original_row, unsigned original_col, + bitmap_type *marked) +{ + bounding_box_type bb = { INT_MAX, INT_MIN, INT_MAX, INT_MIN }; + unsigned row = original_row, col = original_col; + edge_type edge = original_edge; + + do + { + coordinate_type p = { col, row }; + update_bounding_box (&bb, p); + + mark_edge (edge, row, col, marked); + next_outline_edge (b, &edge, &row, &col); + } + while (!(row == original_row && col == original_col + && edge == original_edge)); + + return bb; +} diff --git a/lib/bitmap.c b/lib/bitmap.c new file mode 100644 index 0000000..9223c66 --- /dev/null +++ b/lib/bitmap.c @@ -0,0 +1,258 @@ +/* bitmap.c: operations on bitmaps. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bitmap.h" +#include "bounding-box.h" + +static void bb_ensure_bounds (bounding_box_type *, bitmap_type, string); + +/* Make sure the bitmap is entirely white to begin with. */ + +bitmap_type +new_bitmap (dimensions_type d) +{ + bitmap_type answer; + unsigned size = DIMENSIONS_WIDTH (d) * DIMENSIONS_HEIGHT (d); + + BITMAP_DIMENSIONS (answer) = d; + BITMAP_BITS (answer) = size > 0 ? xcalloc (size, 1) : NULL; + + return answer; +} + + +/* Free the storage that is allocated for a bitmap. On the other hand, + the bitmap might not have any storage allocated for it if it is zero + in either dimension; in that case, don't free it. */ + +void +free_bitmap (bitmap_type *b) +{ + if (BITMAP_BITS (*b) != NULL) + safe_free ((address *) &BITMAP_BITS (*b)); +} + + +/* Copy an existing bitmap into new memory. We don't want to use + `new_bitmap' here, since that routine clears the bitmap's bits, and + we are going to set all the bits ourselves, anyway. */ + +bitmap_type +copy_bitmap (bitmap_type bitmap) +{ + bitmap_type answer; + unsigned size = BITMAP_WIDTH (bitmap) * BITMAP_HEIGHT (bitmap); + + BITMAP_DIMENSIONS (answer) = BITMAP_DIMENSIONS (bitmap); + BITMAP_BITS (answer) = size > 0 ? xmalloc (size) : NULL; + + if (size > 0) + memcpy (BITMAP_BITS (answer), BITMAP_BITS (bitmap), size); + + return answer; +} + + +/* Return the part of the bitmap SOURCE enclosed by the bounding box BB. + BB is interpreted in bitmap coordinates, with y increasing downwards; + for example, if MIN_ROW (BB) == 10, the subimage will start in the + tenth row from the top of SOURCE. */ + +bitmap_type +extract_subbitmap (bitmap_type source, bounding_box_type bb) +{ + unsigned this_row; + bitmap_type sub = new_bitmap (bb_to_dimensions (bb)); + + /* Move to the bit at which we want to start copying. */ + BITMAP_BITS (source) += MIN_ROW (bb) * BITMAP_WIDTH (source) + MIN_COL (bb); + + bb_ensure_bounds (&bb, source, "extract_subbitmap"); + + for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++) + { + one_byte *target = BITMAP_ROW (sub, this_row - MIN_ROW (bb)); + + memcpy (target, BITMAP_BITS (source), BITMAP_WIDTH (sub)); + BITMAP_BITS (source) += BITMAP_WIDTH (source); + } + + return sub; +} + + +/* If any of the elements of BB (taken to be in bitmap coordinates) are + outside the bounds of the bitmap SOURCE, give a warning (using NAME) + and update them. */ + +static void +bb_ensure_bounds (bounding_box_type *bb, bitmap_type source, string name) +{ + if (MIN_COL (*bb) < 0) + { + WARNING2 ("%s: min col=%d outside source image", name, MIN_COL (*bb)); + MIN_COL (*bb) = 0; + } + + if (MIN_ROW (*bb) < 0) + { + WARNING2 ("%s: min row=%d outside source image", name, MIN_ROW (*bb)); + MIN_COL (*bb) = 0; + } + + /* See comments at `get_character_bitmap' in gf_input.c for why the + width and height are treated asymetrically. */ + if (MAX_COL (*bb) > BITMAP_WIDTH (source)) + { + WARNING2 ("%s: max col=%d outside source image", name, MAX_COL (*bb)); + MAX_COL (*bb) = BITMAP_WIDTH (source) - 1; + } + + if (MAX_ROW (*bb) >= BITMAP_HEIGHT (source)) + { + WARNING2 ("%s: max row=%d outside source image", name, MAX_ROW (*bb)); + MAX_COL (*bb) = BITMAP_HEIGHT (source) - 1; + } +} + +/* The bounding boxes that we make in this routine are unlike the + bounding boxes used elsewhere. These are in bitmap coordinates, not + Cartesian, and they refer to pixels, not edges. So we have to adjust + the maximum column by one. */ + +const bounding_box_type +bitmap_to_bb (const bitmap_type b) +{ + bounding_box_type bb = dimensions_to_bb (BITMAP_DIMENSIONS (b)); + if (MAX_COL (bb) != 0) MAX_COL (bb)--; + + return bb; +} + +/* Return the (zero-based) column numbers in which ROW changes from + black to white or white to black. The first element marks a + white-to-black transition, and the last element marks a + black-to-white transition, imagining that ROW is surrounded by white. + (In other words, there is always an even number of transitions.) We + mark the end of the vector with an element WIDTH + 1. */ + +/* We use `length - 2' because we need to save one element at the end + for our sentinel. */ +#define INSERT_TRANSITION(e) \ + do { \ + XRETALLOC (vector, ++length, unsigned); \ + vector[length - 2] = e; \ + } while (0) + +unsigned * +bitmap_find_transitions (const one_byte *row, unsigned width) +{ + unsigned col; + unsigned start; + one_byte color = BLACK; + unsigned length = 1; + + /* We want to make sure we start at a column with some black. */ + char *start_ptr = memchr (row, BLACK, width); + + /* Save the last element for the sentinel. */ + unsigned *vector = XTALLOC1 (unsigned); + + if (start_ptr == NULL) + start = width; /* Don't go through the loop. */ + else + { + INSERT_TRANSITION (start_ptr - (char *) row); + start = vector[0] + 1; /* Don't look at this pixel again. */ + } + + for (col = start; col < width - 1; col++) + { + if (row[col] != color) + { + INSERT_TRANSITION (col); + color = row[col]; + } + } + + /* We have to treat the last pixel in ROW specially. There are + several cases: + 1) if it's white, and the previous pixel is white, or the row is + one pixel long, do nothing; + 2) if it's white, and the previous pixel is black, + insert one element in `vector' (marking the end of a run); + 3) if it's black, and either the previous pixel is black or this was the + first black pixel in the row, insert one element (marking the + end of a run because we're at the end of the row); + 4) if it's black, and the previous pixel is white and there was a + previous black pixel, or the row was one pixel long, insert + two elements (marking the start and end of this one-pixel run). + */ + if (row[width - 1] == WHITE) + { + if (width > 1 && row[width - 2] == BLACK) + INSERT_TRANSITION (width - 1); + } + else + { /* Last pixel is black. If previous pixel was also black, just + finish off the run. */ + if (width > 1 && row[width - 2] == BLACK) + INSERT_TRANSITION (width); + else + { /* Last pixel is black, previous pixel was white. If this was + the only black pixel in the row, we've already inserted the + start of the run via `start' above, so just insert the end of + the run. Otherwise, insert both the start and end of this + one-pixel run. */ + if (start != width) + INSERT_TRANSITION (width - 1); + INSERT_TRANSITION (width); + } + } + + vector[length - 1] = width + 1; /* Sentinel for the end of the vector. */ + return vector; +} + +/* Print a part of the bitmap in human-readable form. */ + +void +print_bounded_bitmap (FILE *f, bitmap_type bitmap, bounding_box_type bb) +{ + unsigned this_row, this_col; + + fprintf (f, "Printing bitmap between (%u,%u) and (%u,%u):\n", + MIN_COL (bb), MIN_ROW (bb), + MAX_COL (bb), MAX_ROW (bb)); + for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++) + { + for (this_col = MIN_COL (bb); this_col <= MAX_COL (bb); this_col++) + putc (BITMAP_PIXEL (bitmap, this_row, this_col) ? '*' : ' ', f); + + fprintf (f, "%u\n", this_row); + } +} + + +void +print_bitmap (FILE *f, bitmap_type b) +{ + print_bounded_bitmap (f, b, bitmap_to_bb (b)); +} diff --git a/lib/bounding-box.c b/lib/bounding-box.c new file mode 100644 index 0000000..25f0b74 --- /dev/null +++ b/lib/bounding-box.c @@ -0,0 +1,78 @@ +/* bounding-box.c: definitions for bounding box operations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bounding-box.h" + + +/* See the comments at `get_character_bitmap' in gf_input.c for why the + width and height are treated asymmetrically. */ + +const bounding_box_type +dimensions_to_bb (dimensions_type dimensions) +{ + bounding_box_type answer; + + MIN_ROW (answer) = 0; + MIN_COL (answer) = 0; + MAX_ROW (answer) = MAX ((int) DIMENSIONS_HEIGHT (dimensions) - 1, 0); + MAX_COL (answer) = MAX (DIMENSIONS_WIDTH (dimensions), 0); + + return answer; +} + + +/* Dimensions can't be negative, even though bounding boxes can, so we + have to check. */ + +const dimensions_type +bb_to_dimensions (bounding_box_type bb) +{ + dimensions_type d; + + DIMENSIONS_WIDTH (d) = MAX (BB_WIDTH (bb), 0); + DIMENSIONS_HEIGHT (d) = MAX (BB_HEIGHT (bb), 0); + + return d; +} + + +/* If the point P lies outside of any of the current bounds in BB, + update BB. */ + +void +update_real_bounding_box (real_bounding_box_type *bb, real_coordinate_type p) +{ + if (p.x < MIN_COL (*bb)) MIN_COL (*bb) = p.x; + if (p.x > MAX_COL (*bb)) MAX_COL (*bb) = p.x; + if (p.y < MIN_ROW (*bb)) MIN_ROW (*bb) = p.y; + if (p.y > MAX_ROW (*bb)) MAX_ROW (*bb) = p.y; + +} + + +void +update_bounding_box (bounding_box_type *bb, coordinate_type p) +{ + if (p.x < MIN_COL (*bb)) MIN_COL (*bb) = p.x; + if (p.x > MAX_COL (*bb)) MAX_COL (*bb) = p.x; + if (p.y < MIN_ROW (*bb)) MIN_ROW (*bb) = p.y; + if (p.y > MAX_ROW (*bb)) MAX_ROW (*bb) = p.y; + +} diff --git a/lib/charcode.c b/lib/charcode.c new file mode 100644 index 0000000..931928f --- /dev/null +++ b/lib/charcode.c @@ -0,0 +1,85 @@ +/* charcode.c: parse character code strings into their values. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* This routine parses the string CHARCODE as a character code (see the + .h file). If CHARCODE cannot be parsed, *VALID is set to false and + the value returned is unpredictable; otherwise, it is set to true and + the value returned is the character code. */ + +charcode_type +parse_charcode (string charcode, boolean *valid) +{ + int code = 75; /* OK, it's not *really* unpredictable. */ + unsigned length = strlen (charcode); + + if (charcode == NULL || length == 0) + *valid = false; + else + { /* We need this to ensure that there are no extra characters after + the character code. */ + char dummy; + + /* If a single character, return its value. */ + if (length == 1) + { + *valid = true; + code = *charcode; + } + + else if (*charcode == '0') + { /* Either octal or hex. */ + if (*(charcode + 1) == 'x' || *(charcode + 1) == 'X') + /* It seems not all scanf's ignore a leading `0x'. */ + *valid = sscanf (charcode + 2, "%x%c", &code, &dummy) == 1; + else + /* octal */ + *valid = sscanf (charcode, "%o%c", &code, &dummy) == 1; + } + + else + /* decimal */ + *valid = sscanf (charcode, "%d%c", &code, &dummy) == 1; + + /* Since our return type can only hold numbers up to 255 (typically), + we are justified in using the numeric constant here, instead of + `MAX_CHARCODE'. */ + if (*valid) + *valid = 0 <= code && code <= 255; + } + + return code; +} + + +/* This routine calls `parse_charcode', and, if the character code is + invalid, gives a fatal error. */ + +charcode_type +xparse_charcode (string charcode) +{ + boolean valid; + charcode_type code = parse_charcode (charcode, &valid); + + if (!valid) + FATAL1 ("xparse_charcode: Invalid character code `%s'", charcode); + + return code; +} diff --git a/lib/charspec.c b/lib/charspec.c new file mode 100644 index 0000000..cf7c407 --- /dev/null +++ b/lib/charspec.c @@ -0,0 +1,63 @@ +/* charspec.c: parse a character code or name. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> +#include "charspec.h" +#include "encoding.h" + + +charcode_type +xparse_charspec (string spec, encoding_info_type *enc) +{ + int code; + + /* It's an error to call this with SPEC == NULL or the empty string. */ + assert (spec != NULL && *spec); + + if (ISDIGIT (*spec)) + code = xparse_charcode (spec); + + else if (enc == NULL) + { + /* If ENC is null, and SPEC is longer than a single character, we + don't know what to do. */ + if (spec[1] != 0) + FATAL1 ("%s: Unparseable character specification", spec); + else + code = *spec; + } + + else + { + int code = encoding_number (*enc, spec); + + /* If SPEC is not in the encoding, and it's one character long, + just use its value as a C integer. */ + if (code == -1) + { + if (spec[1] == 0) + code = spec[0]; + else + FATAL1 ("%s: Undefined character name", spec); + } + } + + return (charcode_type) code; +} diff --git a/lib/cmdline.c b/lib/cmdline.c new file mode 100644 index 0000000..3552fae --- /dev/null +++ b/lib/cmdline.c @@ -0,0 +1,63 @@ +/* cmdline.c: routines to help in parsing command lines. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "cmdline.h" + + +/* This routine takes a string L consisting of unsigned integers + separated by commas and returns a vector of the integers, as numbers. + A element is appended to the vector. */ + +int * +scan_unsigned_list (string l) +{ + string map; + unsigned length = 1; + int *vector = xmalloc (sizeof (int)); + + for (map = strtok (l, ","); map != NULL; map = strtok (NULL, ",")) + { + length++; + vector = xrealloc (vector, length * sizeof (int)); + vector[length - 2] = atou (map); + if (vector[length - 2] < 0) + WARNING1 ("Unsigned number %u is too large", vector[length - 2]); + } + + vector[length - 1] = -1; + return vector; +} + + +/* Return the <number> substring in `<name>.<number><stuff>', if S has + that form. If it doesn't, return NULL. */ + +string +find_dpi (string s) +{ + unsigned dpi_number; + string extension = strrchr (s, '.'); + + if (extension != NULL) + if (sscanf (extension + 1, "%u", &dpi_number) == 1) + return utoa (dpi_number); + + return NULL; +} diff --git a/lib/concat.c b/lib/concat.c new file mode 100644 index 0000000..946ed19 --- /dev/null +++ b/lib/concat.c @@ -0,0 +1,41 @@ +/* concat.c: dynamic string concatenation. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +/* Return the concatenation of S1 and S2. This would be a prime place + to use varargs. */ + +string +concat P2C(const_string, s1, const_string, s2) +{ + string answer = NULL; + + assert (s1 != NULL); + assert (s2 != NULL); + + if (s1 != NULL && s2 != NULL) + { + answer = (string) xmalloc (strlen (s1) + strlen (s2) + 1); + + strcpy (answer, s1); + strcat (answer, s2); + } + + return answer; +} diff --git a/lib/concat3.c b/lib/concat3.c new file mode 100644 index 0000000..383a54c --- /dev/null +++ b/lib/concat3.c @@ -0,0 +1,40 @@ +/* concat3.c: concatenate three strings. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +string +concat3 P3C(const_string, s1, const_string, s2, const_string, s3) +{ + string answer = NULL; + + assert (s1 != NULL); + assert (s2 != NULL); + assert (s3 != NULL); + + if (s1 != NULL && s2 != NULL && s3 != NULL) + { + answer = (string) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1); + + strcpy (answer, s1); + strcat (answer, s2); + strcat (answer, s3); + } + + return answer; +} diff --git a/lib/concat4.c b/lib/concat4.c new file mode 100644 index 0000000..f8b3d06 --- /dev/null +++ b/lib/concat4.c @@ -0,0 +1,43 @@ +/* concat4.c: concatenate four strings. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +string +concat4 P4C(const_string, s1, const_string, s2, const_string, s3, + const_string, s4) +{ + string answer = NULL; + + assert (s1 != NULL); + assert (s2 != NULL); + assert (s3 != NULL); + assert (s4 != NULL); + + if (s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL) + { + answer = (string) xmalloc (strlen (s1) + strlen (s2) + + strlen (s3) + strlen (s4) + 1); + strcpy (answer, s1); + strcat (answer, s2); + strcat (answer, s3); + strcat (answer, s4); + } + + return answer; +} diff --git a/lib/concat5.c b/lib/concat5.c new file mode 100644 index 0000000..fbf9601 --- /dev/null +++ b/lib/concat5.c @@ -0,0 +1,45 @@ +/* concat5.c: concatenate five strings. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +string +concat5 P5C(const_string, s1, const_string, s2, const_string, s3, + const_string, s4, const_string, s5) +{ + string answer = NULL; + + assert (s1 != NULL); + assert (s2 != NULL); + assert (s3 != NULL); + assert (s4 != NULL); + assert (s5 != NULL); + + if (s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL && s5 != NULL) + { + answer = (string) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + + strlen (s4) + strlen (s5) + 1); + strcpy (answer, s1); + strcat (answer, s2); + strcat (answer, s3); + strcat (answer, s4); + strcat (answer, s5); + } + + return answer; +} diff --git a/lib/dlsym.c b/lib/dlsym.c new file mode 100644 index 0000000..c14ffdd --- /dev/null +++ b/lib/dlsym.c @@ -0,0 +1,28 @@ +/* + * Stub interface to dynamic linker routines + * that SunOS uses but didn't ship with 4.1. + * + * The C library routine wcstombs in SunOS 4.1 tries to dynamically + * load some routines using the dlsym interface, described in dlsym(3x). + * Unfortunately SunOS 4.1 does not include the necessary library, libdl. + * + * The R5 Xlib uses wcstombs. If you link dynamcally, your program can + * run even with the unresolved reference to dlsym. However, if you + * link statically, you will encounter this bug. One workaround + * is to include these stub routines when you link. + */ + +void *dlopen() +{ + return 0; +} + +void *dlsym() +{ + return 0; +} + +int dlclose() +{ + return -1; +} diff --git a/lib/edge.c b/lib/edge.c new file mode 100644 index 0000000..7bec506 --- /dev/null +++ b/lib/edge.c @@ -0,0 +1,265 @@ +/* edge.c: operations on edges in bitmaps. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "edge.h" + + +/* We can move in any of eight directions as we are traversing + the outline. These numbers are not arbitrary; TRY_PIXEL depends on + them. */ + +typedef enum +{ + north = 0, northwest = 1, west = 2, southwest = 3, south = 4, + southeast = 5, east = 6, northeast = 7 +} direction_type; + + +static boolean is_marked_edge (edge_type, unsigned, unsigned, bitmap_type); +static boolean is_outline_edge (edge_type, bitmap_type, unsigned, unsigned); +static edge_type next_edge (edge_type); + +/* The following macros are used (directly or indirectly) by the + `next_outline_edge' routine. */ + +/* Given the direction DIR of the pixel to test, decide which edge on + that pixel we are supposed to test. Because we've chosen the mapping + from directions to numbers carefully, we don't have to do much. */ + +#define FIND_TEST_EDGE(dir) ((dir) / 2) + + +/* Find how to move in direction DIR on the axis AXIS (either `ROW' or + `COL'). We are in the ``display'' coordinate system, with y + increasing downward and x increasing to the right. Therefore, we are + implementing the following table: + + direction row delta col delta + north -1 0 + south +1 0 + east 0 +1 + west 0 +1 + + with the other four directions (e.g., northwest) being the sum of + their components (e.g., north + west). + + The first macro, `COMPUTE_DELTA', handles splitting up the latter + cases, all of which have been assigned odd numbers. */ + +#define COMPUTE_DELTA(axis, dir) \ + ((dir) % 2 != 0 \ + ? COMPUTE_##axis##_DELTA ((dir) - 1) \ + + COMPUTE_##axis##_DELTA (((dir) + 1) % 8) \ + : COMPUTE_##axis##_DELTA (dir) \ + ) + +/* Now it is trivial to implement the four cardinal directions. */ +#define COMPUTE_ROW_DELTA(dir) \ + ((dir) == north ? -1 : (dir) == south ? +1 : 0) + +#define COMPUTE_COL_DELTA(dir) \ + ((dir) == west ? -1 : (dir) == east ? +1 : 0) + + +/* See if the appropriate edge on the pixel from (row,col) in direction + DIR is on the outline. If so, update `row', `col', and `edge', and + break. We also use the variable `character' as the bitmap in which + to look. */ + +#define TRY_PIXEL(dir) \ + { \ + int delta_r = COMPUTE_DELTA (ROW, dir); \ + int delta_c = COMPUTE_DELTA (COL, dir); \ + int test_row = *row + delta_r; \ + int test_col = *col + delta_c; \ + edge_type test_edge = FIND_TEST_EDGE (dir); \ + \ + if (BITMAP_VALID_PIXEL (character, test_row, test_col) \ + && is_outline_edge (test_edge, character, test_row, test_col)) \ + { \ + *row = test_row; \ + *col = test_col; \ + *edge = test_edge; \ + break; \ + } \ + } + +/* Finally, we are ready to implement the routine that finds the next + edge on the outline. We look first for an adjacent edge that is not + on the current pixel. We want to go around outside outlines + counterclockwise, and inside outlines clockwise (because that is how + both Metafont and Adobe Type 1 format want their curves to be drawn). + + The very first outline (an outside one) on each character starts on a + top edge (STARTING_EDGE in edge.h defines this); so, if we're at a + top edge, we want to go only to the left (on the pixel to the west) + or down (on the same pixel), to begin with. Then, when we're on a + left edge, we want to go to the top edge (on the southwest pixel) or + to the left edge (on the south pixel). + + All well and good. But if you draw a rasterized circle (or whatever), + eventually we have to come back around to the beginning; at that + point, we'll be on a top edge, and we'll have to go to the right edge + on the northwest pixel. Draw pictures. + + The upshot is, if we find an edge on another pixel, we return (in ROW + and COL) the position of the new pixel, and (in EDGE) the kind of + edge it is. If we don't find such an edge, we return (in EDGE) the + next (in a counterclockwise direction) edge on the current pixel. */ + +void +next_outline_edge (bitmap_type character, edge_type *edge, + unsigned *row, unsigned *col) +{ + unsigned original_row = *row; + unsigned original_col = *col; + + switch (*edge) + { + case right: + TRY_PIXEL (north); + TRY_PIXEL (northeast); + break; + + case top: + TRY_PIXEL (west); + TRY_PIXEL (northwest); + break; + + case left: + TRY_PIXEL (south); + TRY_PIXEL (southwest); + break; + + case bottom: + TRY_PIXEL (east); + TRY_PIXEL (southeast); + break; + + default: + FATAL1 ("next_outline_edge: Bad edge value (%d)", *edge); + + } + + /* If we didn't find an adjacent edge on another pixel, return the + next edge on the current pixel. */ + if (*row == original_row && *col == original_col) + *edge = next_edge (*edge); +} + +/* We return the next edge on the pixel at position ROW and COL which is + an unmarked outline edge. By ``next'' we mean either the one sent in + in STARTING_EDGE, if it qualifies, or the next such returned by + `next_edge'. Otherwise, it returns NO_EDGE. */ + +edge_type +next_unmarked_outline_edge (unsigned row, unsigned col, + edge_type starting_edge, bitmap_type character, + bitmap_type marked) +{ + edge_type edge = starting_edge; + + assert (edge != no_edge); + + while (is_marked_edge (edge, row, col, marked) + || !is_outline_edge (edge, character, row, col)) + { + edge = next_edge (edge); + if (edge == starting_edge) + return no_edge; + } + + return edge; +} + + +/* We check to see if the edge EDGE of the pixel at position ROW and COL + is an outline edge; i.e., that it is a black pixel which shares that + edge with a white pixel. The position ROW and COL should be inside + the bitmap CHARACTER. */ + +boolean +is_outline_edge (edge_type edge, bitmap_type character, + unsigned row, unsigned col) +{ + /* If this pixel isn't black, it's not part of the outline. */ + if (BITMAP_PIXEL (character, row, col) == WHITE) + return false; + + switch (edge) + { + case left: + return col == 0 || BITMAP_PIXEL (character, row, col - 1) == WHITE; + + case top: + return row == 0 || BITMAP_PIXEL (character, row - 1, col) == WHITE; + + case right: + return col == BITMAP_WIDTH (character) - 1 + || BITMAP_PIXEL (character, row, col + 1) == WHITE; + + case bottom: + return row == BITMAP_HEIGHT (character) - 1 + || BITMAP_PIXEL (character, row + 1, col) == WHITE; + + case no_edge: + default: + FATAL1 ("is_outline_edge: Bad edge value(%d)", edge); + } + + return 0; /* NOTREACHED */ +} + +/* If EDGE is not already marked, we mark it; otherwise, it's a fatal error. + The position ROW and COL should be inside the bitmap MARKED. EDGE can + be `no_edge'; we just return false. */ + +void +mark_edge (edge_type edge, unsigned row, unsigned col, bitmap_type *marked) +{ + assert (!is_marked_edge (edge, row, col, *marked)); + + if (edge != no_edge) + BITMAP_PIXEL (*marked, row, col) |= 1 << edge; +} + + +/* Test if the edge EDGE at ROW/COL in MARKED is marked. */ + +static boolean +is_marked_edge (edge_type edge, unsigned row, unsigned col, bitmap_type marked) +{ + return + edge == no_edge ? false : BITMAP_PIXEL (marked, row, col) & (1 << edge); +} + + +/* Return the edge which is counterclockwise-adjacent to EDGE. This + code makes use of the ``numericness'' of C enumeration constants; + sorry about that. */ + +#define NUM_EDGES no_edge + +static edge_type +next_edge (edge_type edge) +{ + return edge == no_edge ? edge : (edge + 1) % NUM_EDGES; +} + diff --git a/lib/encoding.c b/lib/encoding.c new file mode 100644 index 0000000..a40d281 --- /dev/null +++ b/lib/encoding.c @@ -0,0 +1,191 @@ +/* encoding.c: read a font encoding (.enc) file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "encoding.h" +#include "libfile.h" +#include "str-lcase.h" +#include "tfm.h" + + +static encoding_char_type parse_encoding_line (string); +static tfm_ligature_type parse_ligature (void); + +/* Look through INFO for NAME. */ + +int +encoding_number (encoding_info_type info, string name) +{ + unsigned code; + + if (name == NULL) + return -1; + + for (code = 0; code <= MAX_CHARCODE; code++) + if (ENCODING_CHAR_NAME (info, code) != NULL + && STREQ (ENCODING_CHAR_NAME (info, code), name)) + return code; + + return -1; +} + +/* Return the basename for the encoding file in which the encoding + CODING_SCHEME can be found. If we can't find CODING_SCHEME, return + DEFAULT_ENCODING. */ + +string +coding_scheme_to_filename (string coding_scheme) +{ + string mapping_line, enc_name; + string lc_coding_scheme = str_to_lower (coding_scheme); + + libfile_start ("encoding", "map"); + + while ((mapping_line = libfile_line ()) != NULL) + { + string test_coding_scheme, lc_test_coding_scheme; + + enc_name = strtok (mapping_line, " \t"); + test_coding_scheme = strtok (NULL, "\t"); + lc_test_coding_scheme = str_to_lower (test_coding_scheme); + + if (STREQ (lc_coding_scheme, lc_test_coding_scheme)) + break; + + free (lc_test_coding_scheme); + free (mapping_line); + } + + libfile_close (); + + if (mapping_line == NULL) + { + WARNING3 ("%s: unknown encoding `%s'; using default `%s'", + "encoding.map", coding_scheme, DEFAULT_ENCODING); + enc_name = DEFAULT_ENCODING; + } + + free (lc_coding_scheme); + + return enc_name; +} + +/* Parse the encoding file `FILENAME.enc' and return a structure + describing what we read. If the file doesn't exist, give a fatal + error. */ + +encoding_info_type +read_encoding_file (string filename) +{ + encoding_info_type info; + string line; + unsigned code; + + /* Prepare to read from FILENAME. */ + libfile_start (filename, "enc"); + + /* Start with an empty encoding. */ + for (code = 0; code <= MAX_CHARCODE; code++) + ENCODING_CHAR_NAME (info, code) = NULL; + + /* The entire first line is the TFM `CODINGSCHEME'. */ + ENCODING_SCHEME_NAME (info) = libfile_line (); + + /* Each remaining line defines one character. */ + code = 0; + while ((line = libfile_line ()) != NULL) + { + ENCODING_CHAR_ELT (info, code) = parse_encoding_line (line); + code++; + free (line); + } + + return info; +} + +/* Parse one line of the encoding file; this specifies one character. + The BNF is: + + <line> ::= <word> <ligatures> + + <ligatures> ::= <ligature> [<ligature>]? + | <empty> + + <ligature> ::= lig <charcode> =: <charcode> + + Whitespace must be between all elements. + + If the line is malformed, we give a fatal error. */ + +#define WORD_SEPARATOR " \t" +#define GET_WORD() strtok (NULL, WORD_SEPARATOR) + +static encoding_char_type +parse_encoding_line (string line) +{ + encoding_char_type c; + + c.name = xstrdup (strtok (line, WORD_SEPARATOR)); + c.ligature = list_init (); + + do + { + tfm_ligature_type *lig; + string t = GET_WORD (); + + if (t == NULL) /* Do we have more ligature specs? */ + break; + + if (!STREQ (t, "lig")) + LIBFILE_ERROR1 ("Expected `lig', found `%s'", t); + + lig = LIST_TAPPEND (&c.ligature, tfm_ligature_type); + *lig = parse_ligature (); + } + while (true); + + return c; +} + + +/* Parse a single ligature: <charcode> =: <charcode>. */ + +static tfm_ligature_type +parse_ligature () +{ + tfm_ligature_type lig; + boolean valid; + string t = GET_WORD (); + + lig.character = parse_charcode (t, &valid); + + if (!valid) + LIBFILE_ERROR1 ("Invalid right character code `%s'", t); + + t = GET_WORD (); + if (!STREQ (t, "=:")) + LIBFILE_ERROR1 ("Expected `=:', found `%s'", t); + + t = GET_WORD (); + lig.ligature = parse_charcode (t, &valid); + if (!valid) + LIBFILE_ERROR1 ("Invalid ligature character code `%s'", t); + + return lig; +} diff --git a/lib/file-input.c b/lib/file-input.c new file mode 100644 index 0000000..1bc138b --- /dev/null +++ b/lib/file-input.c @@ -0,0 +1,158 @@ +/* file-input.c: file reading routines for binary files in BigEndian + order, 2's complement representation. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" + + +one_byte +get_byte (FILE *f, string filename) +{ + one_byte b; + + if (fread (&b, 1, 1, f) != 1) + FATAL_PERROR (concat3 ("get_byte (", filename, ")")); + + return b; +} + + +two_bytes +get_two (FILE *f, string filename) +{ + two_bytes b; + + b = get_byte (f, filename) << 8; + b |= get_byte (f, filename); + + return b; +} + + +four_bytes +get_four (FILE *f, string filename) +{ + four_bytes b; + + b = get_byte (f, filename) << 24; + b |= get_byte (f, filename) << 16; + b |= get_byte (f, filename) << 8; + b |= get_byte (f, filename); + + return b; +} + + +/* In order to get a signed value, we merely read an unsigned value and + cast it; the value in the file is assumed to be 2's complement. */ + +signed_4_bytes +get_signed_four (FILE *f, string filename) +{ + return (signed_4_bytes) get_four (f, filename); +} + + +/* Return the next N bytes in the file F as an array. */ + +address +get_n_bytes (unsigned n, FILE *f, string filename) +{ + one_byte *b; + + if (n == 0) + FATAL1 ("get_n_bytes (%s): can't get zero bytes", filename); + + b = xmalloc (n); + + if (fread (b, n, 1, f) != 1) + FATAL2 ("get_n_bytes (%s): fread of %u bytes failed", filename, n); + + return b; +} + + + +/* Reading backwards. This macro is shared among all the routines by assuming + the name `f' for the file pointer. */ + +#define MOVE_BACK(size) xfseek (f, (long) -size, SEEK_CUR, filename) + +one_byte +get_previous_byte (FILE *f, string filename) +{ + one_byte b; + + MOVE_BACK (1); + b = get_byte (f, filename); + MOVE_BACK (1); + return b; +} + + +two_bytes +get_previous_two (FILE *f, string filename) +{ + two_bytes b; + + MOVE_BACK (2); + b = get_two (f, filename); + MOVE_BACK (2); + + return b; +} + + + +four_bytes +get_previous_four (FILE *f, string filename) +{ + four_bytes b; + + MOVE_BACK (4); + b = get_four (f, filename); + MOVE_BACK (4); + + return b; +} + + + +/* Looking for specific values in the input. */ + +void +match_byte (one_byte expected, FILE *f, string filename) +{ + one_byte b = get_byte (f, filename); + + if (b != expected) + FATAL3 ("%s: Expected byte value %u, found %u", filename, expected, b); +} + + +void +match_previous_byte (one_byte expected, FILE *f, string filename) +{ + one_byte b = get_previous_byte (f, filename); + + if (b != expected) + FATAL3 ("%s: Expected previous byte value %u, found %u", filename, + expected, b); +} diff --git a/lib/file-output.c b/lib/file-output.c new file mode 100644 index 0000000..94559ec --- /dev/null +++ b/lib/file-output.c @@ -0,0 +1,73 @@ +/* file-output.c: file writing routines for binary files in BigEndian + order, 2's complement representation. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-output.h" + + +/* Output in BigEndian order. We could do these more efficiently by + checking if the hardware already uses BigEndian order, but it's not + worth it. These routines are never the bottleneck (in the ways + they've been used so far, anyway). We assume that we write negative + numbers in 2's complement, also. */ + +void +put_byte (one_byte b, FILE *f, string filename) +{ + if (fwrite (&b, 1, 1, f) != 1) + FATAL2 ("%s: Could not write byte %u", filename, b); +} + + +void +put_two (two_bytes b, FILE *f, string filename) +{ + put_byte ((b & 0xff00) >> 8, f, filename); /* High-order byte. */ + put_byte (b & 0x00ff, f, filename); /* And low-order. */ +} + + +void +put_three (four_bytes b, FILE *f, string filename) +{ + put_byte ((b & 0x00ff0000) >> 16, f, filename); + put_byte ((b & 0x0000ff00) >> 8, f, filename); + put_byte (b & 0x000000ff, f, filename); +} + + +void +put_four (four_bytes b, FILE *f, string filename) +{ + put_byte ((b & 0xff000000) >> 24, f, filename); + put_byte ((b & 0x00ff0000) >> 16, f, filename); + put_byte ((b & 0x0000ff00) >> 8, f, filename); + put_byte (b & 0x000000ff, f, filename); +} + + +void +put_n_bytes (unsigned n, address b, FILE *f, string filename) +{ + one_byte *data_b = b; /* We can't dereference a pure `address'. */ + + if (fwrite (data_b, n, 1, f) != 1) + FATAL2 ("%s: Could not write %u-byte block", filename, n); +} diff --git a/lib/filename.c b/lib/filename.c new file mode 100644 index 0000000..b85d095 --- /dev/null +++ b/lib/filename.c @@ -0,0 +1,99 @@ +/* filename.c: routines to manipulate filenames. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "paths.h" + +#include "filename.h" +#include "pathsrch.h" + + +/* Try to find the PK font FONT_NAME at resolution DPI, using various + paths (see `filename.h'). The filename must have the resolution as + part of the extension, e.g., `cmr10.300pk', for it to be found. */ + +string +find_pk_filename (string font_name, unsigned dpi) +{ + static string *dirs = NULL; + string pk_var, pk_name, name; + char suffix[MAX_INT_LENGTH + sizeof ".pk"]; + + sprintf (suffix, ".%dpk", dpi); + + pk_var = getenv ("PKFONTS") ? "PKFONTS" + : getenv ("TEXPKS") ? "TEXPKS" : "TEXFONTS"; + + if (dirs == NULL) + dirs = initialize_path_list (pk_var, DEFAULT_PK_PATH); + + name = concat (font_name, suffix); + pk_name = find_path_filename (name, dirs); + + if (name != pk_name) + free (name); + + return pk_name; +} + + +/* Like `find_pk_filename', but search for a font in GF format. */ + +string +find_gf_filename (string font_name, unsigned dpi) +{ + static string *dirs = NULL; + string gf_var, gf_name, name; + char suffix[MAX_INT_LENGTH + sizeof ".pk"]; + + sprintf (suffix, ".%dgf", dpi); + + gf_var = getenv ("GFFONTS") ? "GFFONTS" : "TEXFONTS"; + + if (dirs == NULL) + dirs = initialize_path_list (gf_var, DEFAULT_GF_PATH); + + name = concat (font_name, suffix); + gf_name = find_path_filename (name, dirs); + + if (name != gf_name) + free (name); + + return gf_name; +} + + +/* Like `find_pk_filename', except search for a TFM file. */ + +string +find_tfm_filename (string font_name) +{ + static string *dirs = NULL; + string tfm_name, name; + + if (dirs == NULL) + dirs = initialize_path_list ("TEXFONTS", DEFAULT_TFM_PATH); + + name = extend_filename (font_name, "tfm"); + tfm_name = find_path_filename (name, dirs); + + if (name != tfm_name) + free (name); + + return tfm_name; +} diff --git a/lib/fix-num.c b/lib/fix-num.c new file mode 100644 index 0000000..2827d2c --- /dev/null +++ b/lib/fix-num.c @@ -0,0 +1,43 @@ +/* fix-num.c: conversions on ``fixnums'', which are a 32-bit + word with 20 bits of fraction. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "fix-num.h" + + +#define FIX_UNITY (1 << 20) + + +const real +fix_to_real (fix_word f) +{ + real r = f / FIX_UNITY + ((real) (f % FIX_UNITY) / (real) FIX_UNITY); + + return r; +} + + +const fix_word +real_to_fix (real r) +{ + fix_word f = floor (r) * FIX_UNITY + (r - floor (r)) * FIX_UNITY; + + return f; +} diff --git a/lib/float-ok.c b/lib/float-ok.c new file mode 100644 index 0000000..b3e81d6 --- /dev/null +++ b/lib/float-ok.c @@ -0,0 +1,60 @@ +/* float-ok.c: test if a string is a valid floating-point number. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> + + +/* Actually, we don't worry about a trailing exponent. */ + +boolean +float_ok (string str) +{ + boolean found_digit = false; + + if (str == NULL) + return false; + + /* Allow leading `-' or `+' sign (but digits must follow). */ + if (*str == '-' || *str == '+') + { + str++; + } + + /* Skip decimal digits. */ + while (ISDIGIT (*str)) + { + str++; + found_digit = true; + } + + /* If a `.' follows, can have more digits. */ + if (*str == '.') + { + str++; + while (ISDIGIT (*str)) + { + str++; + found_digit = true; + } + } + + return *str == 0 && found_digit; +} + diff --git a/lib/fmod.c b/lib/fmod.c new file mode 100644 index 0000000..0c78f52 --- /dev/null +++ b/lib/fmod.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by the University of California, Berkeley and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)fmod.c 5.2 (Berkeley) 6/1/90"; +#endif /* not lint */ + +/* fmod.c + * + * SYNOPSIS + * + * #include <math.h> + * double fmod(double x, double y) + * + * DESCRIPTION + * + * The fmod function computes the floating-point remainder of x/y. + * + * RETURNS + * + * The fmod function returns the value x-i*y, for some integer i + * such that, if y is nonzero, the result has the same sign as x and + * magnitude less than the magnitude of y. + * + * On a VAX or CCI, + * + * fmod(x,0) traps/faults on floating-point divided-by-zero. + * + * On IEEE-754 conforming machines with "isnan()" primitive, + * + * fmod(x,0), fmod(INF,y) are invalid operations and NaN is returned. + * + */ +#include <math.h> /* changed from "mathimpl.h" --karl */ + +#if !defined(vax) && !defined(tahoe) +extern int isnan(),finite(); +#endif /* !defined(vax) && !defined(tahoe) */ +extern double frexp(),ldexp(),fabs(); + +#ifdef TEST_FMOD +static double +_fmod(x,y) +#else /* TEST_FMOD */ +double +fmod(x,y) +#endif /* TEST_FMOD */ +double x,y; +{ + int ir,iy; + double r,w; + + if (y == (double)0 +#if 0 /* removed this --karl */ +#if !defined(vax) && !defined(tahoe) /* per "fmod" manual entry, SunOS 4.0 */ + || isnan(y) || !finite(x) +#endif /* !defined(vax) && !defined(tahoe) */ +#endif + ) + return (x*y)/(x*y); + + r = fabs(x); + y = fabs(y); + (void)frexp(y,&iy); + while (r >= y) { + (void)frexp(r,&ir); + w = ldexp(y,ir-iy); + r -= w <= r ? w : w*(double)0.5; + } + return x >= (double)0 ? r : -r; +} + +#ifdef TEST_FMOD +extern long random(); +extern double fmod(); + +#define NTEST 10000 +#define NCASES 3 + +static int nfail = 0; + +static void +doit(x,y) +double x,y; +{ + double ro = fmod(x,y),rn = _fmod(x,y); + if (ro != rn) { + (void)printf(" x = 0x%08.8x %08.8x (%24.16e)\n",x,x); + (void)printf(" y = 0x%08.8x %08.8x (%24.16e)\n",y,y); + (void)printf(" fmod = 0x%08.8x %08.8x (%24.16e)\n",ro,ro); + (void)printf("_fmod = 0x%08.8x %08.8x (%24.16e)\n",rn,rn); + (void)printf("\n"); + } +} + +main() +{ + register int i,cases; + double x,y; + + srandom(12345); + for (i = 0; i < NTEST; i++) { + x = (double)random(); + y = (double)random(); + for (cases = 0; cases < NCASES; cases++) { + switch (cases) { + case 0: + break; + case 1: + y = (double)1/y; break; + case 2: + x = (double)1/x; break; + default: + abort(); break; + } + doit(x,y); + doit(x,-y); + doit(-x,y); + doit(-x,-y); + } + } + if (nfail) + (void)printf("Number of failures: %d (out of a total of %d)\n", + nfail,NTEST*NCASES*4); + else + (void)printf("No discrepancies were found\n"); + exit(0); +} +#endif /* TEST_FMOD */ diff --git a/lib/font.c b/lib/font.c new file mode 100644 index 0000000..e2b9a71 --- /dev/null +++ b/lib/font.c @@ -0,0 +1,466 @@ +/* font.c: define (more or less) format-independent font operations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/tex-file.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/paths.h> +#include <kpathsea/c-ctype.h> + +#include "filename.h" +#include "font.h" +#include "gf.h" +#include "list.h" +#include "pk.h" +#include "tfm.h" + + +/* We want to allow reading of multiple fonts, so we keep some + information around for each font we read. */ + +typedef struct +{ + bitmap_format_type bitmap_format; + boolean bitmap_only; + font_info_type info; +} internal_font_type; + +/* The format of the bitmap file for this font. */ +#define INTERNAL_BITMAP_FORMAT(i) ((i).bitmap_format) + +/* If the font was opened with `get_bitmap_font', this field is true; + if with `get_font', false. */ +#define INTERNAL_BITMAP_ONLY(i) ((i).bitmap_only) + +/* The filename for the bitmap font. */ +#define INTERNAL_BITMAP_NAME(i) ((i).bitmap_name) + +/* The fontwide information. The parts of this that are found in the + TFM file are garbage if INTERNAL_BITMAP_ONLY (I) is true. */ +#define INTERNAL_FONT_INFO(i) ((i).info) + + +static void delete_internal_font (string filename); +static internal_font_type *find_internal_font (string font_name); +static void save_internal_font (string font_name, internal_font_type); + +/* Starting with FONT_NAME as the base filename, e.g., `cmr10', we try + various extensions to find a PK or GF file at resolution DPI. This + bitmap font defines the shapes of the characters. */ + +bitmap_font_type +get_bitmap_font (string font_name, unsigned dpi) +{ + bitmap_font_type font; + internal_font_type internal_f; + internal_font_type *internal_font_ptr; + string pk_name, gf_name; + boolean found_pk = false, found_gf = false; + + /* If we are passed a null pointer or the empty string, it's got to be + a mistake. */ + assert (font_name && *font_name); + + /* If we already have the font saved, we just return it, thus (1) saving + going out to the file system, and (2) causing multiple calls with + the same FONT_NAME not to open more and more bitmap files. */ + internal_font_ptr = find_internal_font (font_name); + if (internal_font_ptr != NULL) + return FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*internal_font_ptr)); + + pk_name = find_pk_filename (font_name, dpi); + if (pk_name != NULL) + { /* Found the PK file, so unless something strange is happening + (like the file being removed between the `find_path_filename' + call and the `pk_open_input_file' call), we will be able to + open it. */ + found_pk = pk_open_input_file (pk_name); + if (!found_pk) + FATAL_PERROR (pk_name); + } + else if ((gf_name = find_gf_filename (font_name, dpi)) != NULL) + { + found_gf = gf_open_input_file (gf_name); + if (!found_gf) + { + perror (gf_name); + FATAL1 ("(I couldn't find the PK file `%s', either.)", pk_name); + } + } + else + FATAL2 ("%s.%d{gf,pk}: Nowhere in path", font_name, dpi); + + + /* We've opened the files; get the information we need to return. */ + if (found_pk) + { + pk_preamble_type preamble = pk_get_preamble (pk_name); + + BITMAP_FONT_DESIGN_SIZE (font) + = fix_to_real (PK_DESIGN_SIZE (preamble)); + BITMAP_FONT_COMMENT (font) = PK_COMMENT (preamble); + BITMAP_FONT_CHECKSUM (font) = PK_CHECKSUM (preamble); + BITMAP_FONT_FILENAME (font) = pk_name; + + INTERNAL_BITMAP_FORMAT (internal_f) = pk_format; + } + else if (found_gf) + { + gf_postamble_type postamble = gf_get_postamble (); + + BITMAP_FONT_DESIGN_SIZE (font) + = fix_to_real (GF_DESIGN_SIZE (postamble)); + BITMAP_FONT_COMMENT (font) = gf_get_preamble (); + BITMAP_FONT_CHECKSUM (font) = GF_CHECKSUM (postamble); + BITMAP_FONT_FILENAME (font) = gf_name; + + INTERNAL_BITMAP_FORMAT (internal_f) = gf_format; + } + else + FATAL ("No bitmap file found, but I must have found one"); + + FONT_BITMAP_FONT (INTERNAL_FONT_INFO (internal_f)) = font; + INTERNAL_BITMAP_ONLY (internal_f) = true; + + save_internal_font (font_name, internal_f); + + return font; +} + + +/* Look for both a bitmap font named FONT_NAME, and for the TFM file + FONT_NAME.tfm. We call `get_bitmap_font' to find the bitmap font. + For the TFM file, we use the path in the environment variable + TEXFONTS; if TEXFONTS isn't set, we use the default defined above. + + If FONT_NAME was previously opened with `get_bitmap_font', we give a + fatal error. */ + +font_info_type +get_font (string font_name, unsigned dpi) +{ + unsigned bitmap_checksum; + font_info_type font; + internal_font_type internal_f; + internal_font_type *internal_font_ptr; + unsigned tfm_checksum; + string tfm_name; + + /* If we are passed a null pointer or the empty string, it's got to be + a mistake. */ + assert (font_name != NULL && *font_name); + + /* If we already have the font saved, we just return it, thus (1) saving + going out to the file system, and (2) causing multiple calls with + the same FONT_NAME not to open more and more bitmap files. */ + internal_font_ptr = find_internal_font (font_name); + if (internal_font_ptr != NULL) + if (INTERNAL_BITMAP_ONLY (*internal_font_ptr)) + FATAL1 ("get_font: `%s' was opened with get_bitmap_font", font_name); + else + return INTERNAL_FONT_INFO (*internal_font_ptr); + + /* If we don't have the font saved, we have to look for the TFM file. */ + tfm_name = kpse_find_tfm (font_name); + + if (tfm_name == NULL) + FATAL1 ("%s.tfm: Nowhere in path", font_name); + + if (!tfm_open_input_file (tfm_name)) + FATAL_PERROR (tfm_name); + + + /* The TFM file is opened. Save some global information. */ + FONT_TFM_FONT (font) = tfm_get_global_info (); + FONT_TFM_FILENAME (font) = tfm_name; + + /* Read the (we hope) corresponding bitmap file. */ + FONT_BITMAP_FONT (font) = get_bitmap_font (font_name, dpi); + + /* We have found the bitmap font on the filesystem, so it should be in + our internal list now. We will overwrite it below. */ + internal_font_ptr = find_internal_font (font_name); + assert (internal_font_ptr != NULL); + + /* We've opened the files; now get the information we're supposed to + return. */ + + /* Let's check the checksums. */ + tfm_checksum = tfm_get_checksum (); + bitmap_checksum = BITMAP_FONT_CHECKSUM (FONT_BITMAP_FONT (font)); + + if (tfm_checksum != 0 && bitmap_checksum != 0 + && tfm_checksum != bitmap_checksum) + WARNING1 ("%s: TFM and bitmap checksums don't match", font_name); + + INTERNAL_FONT_INFO (internal_f) = font; + INTERNAL_BITMAP_ONLY (internal_f) = false; + INTERNAL_BITMAP_FORMAT (internal_f) + = INTERNAL_BITMAP_FORMAT (*internal_font_ptr); + save_internal_font (font_name, internal_f); + + return font; +} + +/* Close the files we have opened, for tidiness. */ + +void +close_font (string font_name) +{ + internal_font_type *f = find_internal_font (font_name); + + if (f == NULL) + FATAL1 ("close_font: Font `%s' not open", font_name); + + switch (INTERNAL_BITMAP_FORMAT (*f)) + { + case pk_format: + { + string pk_name + = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f))); + pk_close_input_file (pk_name); + } + break; + + case gf_format: + gf_close_input_file (); + break; + + default: + FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f)); + } + + if (!INTERNAL_BITMAP_ONLY (*f)) + tfm_close_input_file (); + + delete_internal_font (font_name); +} + +/* Look for the character numbered CODE in the font FONT_NAME. If it + doesn't exist, return NULL. Otherwise, fill in a `char_info_type' + structure and return a pointer to it. + + This merely calls the get-a-character routine in the appropriate + library. */ + +char_info_type * +get_char (string font_name, one_byte code) +{ + char_info_type *c; + internal_font_type *f = find_internal_font (font_name); + + if (f == NULL) + FATAL1 ("get_char: Font `%s' not open", font_name); + + switch (INTERNAL_BITMAP_FORMAT (*f)) + { + case pk_format: + { + string pk_name + = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f))); + pk_char_type *pk_char = pk_get_char (code, pk_name); + if (pk_char == NULL) return NULL; + + c = XTALLOC1 (char_info_type); + CHARCODE (*c) = PK_CHARCODE (*pk_char); + CHAR_SET_WIDTH (*c) = PK_H_ESCAPEMENT (*pk_char); + CHAR_TFM_WIDTH (*c) = PK_TFM_WIDTH (*pk_char); + CHAR_BB (*c) = PK_CHAR_BB (*pk_char); + CHAR_BITMAP (*c) = PK_BITMAP (*pk_char); + } + break; + + case gf_format: + { + gf_char_type *gf_char = gf_get_char (code); + if (gf_char == NULL) return NULL; + + c = XTALLOC1 (char_info_type); + CHARCODE (*c) = GF_CHARCODE (*gf_char); + CHAR_SET_WIDTH (*c) = GF_H_ESCAPEMENT (*gf_char); + CHAR_TFM_WIDTH (*c) = GF_TFM_WIDTH (*gf_char); + CHAR_BB (*c) = GF_CHAR_BB (*gf_char); + CHAR_BITMAP (*c) = GF_BITMAP (*gf_char); + } + break; + + default: + FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f)); + } + + return c; +} + +/* Look for the character numbered CODE in the font FONT_NAME. If it + doesn't exist, return NULL. Otherwise, fill in a `raw_char_type' + structure and return a pointer to it. + + This merely calls the corresponding routine in the appropriate + library. */ + +raw_char_type * +get_raw_char (string font_name, one_byte code) +{ + raw_char_type *c; + internal_font_type *f = find_internal_font (font_name); + + if (f == NULL) + FATAL1 ("get_raw_char: Font `%s' not open", font_name); + + switch (INTERNAL_BITMAP_FORMAT (*f)) + { + case pk_format: + c = NULL; + break; + + case gf_format: + c = gf_get_raw_char (code); + break; + + default: + FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f)); + } + + if (c != NULL) + RAW_CHAR_BITMAP_FORMAT (*c) = INTERNAL_BITMAP_FORMAT (*f); + return c; +} + + +/* Free the information in the raw character RAW_CHAR, including the + character itself. */ + +void +free_raw_char (raw_char_type *raw_char) +{ + free (RAW_CHAR_BYTES (*raw_char)); + free (raw_char); +} + +/* Print the character C to the file F, using ordinary characters. */ + +void +print_char (FILE *f, char_info_type c) +{ + unsigned this_row, this_col; + bitmap_type b = CHAR_BITMAP (c); + + fprintf (f, "Character 0x%x=%u", CHARCODE (c), CHARCODE (c)); + if (ISPRINT (CHARCODE (c))) + fprintf (f, " (%c)", CHARCODE (c)); + + fprintf (f, ":\n"); + + fprintf (f, " min/max col %d/%d, min/max row %d/%d, set width %d.\n", + CHAR_MIN_COL (c), CHAR_MAX_COL (c), + CHAR_MIN_ROW (c), CHAR_MAX_ROW (c), CHAR_SET_WIDTH (c)); + + /* We don't call `print_bitmap' because we want to print the Cartesian + row number, as well as the bitmap row number. */ + + for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++) + { + for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++) + putc (BITMAP_PIXEL (b, this_row, this_col) ? '*' : ' ', f); + + fprintf (f, "%3d\t%u\n", CHAR_MAX_ROW (c) - this_row, this_row); + } +} + +/* We want to implement a typical key/value setup: here we are given the + key (FONT_NAME) and the value (F). We assign an index number to + FONT_NAME, and store it and F in parallel lists. If we are passed a + FONT_NAME that is already in the list, we overwrite the old value. */ + +static list_type font_name_list, internal_font_list; + +static void +save_internal_font (string font_name, internal_font_type f) +{ + string *new_name; + internal_font_type *new_font; + static boolean first_call = true; + + if (first_call) + { /* Have to construct our lists. */ + font_name_list = list_init (); + internal_font_list = list_init (); + first_call = false; + } + + new_font = find_internal_font (font_name); + if (new_font == NULL) + { + /* Add another pointer to the end of the lists. */ + new_name = LIST_TAPPEND (&font_name_list, string); + new_font = LIST_TAPPEND (&internal_font_list, internal_font_type); + + /* Save the information. */ + *new_name = xstrdup (font_name); + } + + /* Either update the existing font, or save the new one. */ + *new_font = f; +} + + +/* This routine returns the font information previously stored with + FONT_NAME. If FONT_NAME hasn't been saved, we return NULL. */ + +static internal_font_type * +find_internal_font (string font_name) +{ + unsigned e; + + for (e = 0; e < LIST_SIZE (font_name_list); e++) + if (STREQ (*(string *) LIST_ELT (font_name_list, e), font_name)) + return (internal_font_type *) LIST_ELT (internal_font_list, e); + + return NULL; +} + + +/* Remove FILENAME from `font_name_list', by setting the name in + `font_name_list' to the empty string, so that the element is useless. + (We don't have any actual memory to free.) What a kludge. */ + +static void +delete_internal_font (string filename) +{ + unsigned e; + + /* We can't use `find_internal_font', since we need to know the list + element index, not just the internal font information. */ + for (e = 0; e < LIST_SIZE (font_name_list); e++) + if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename)) + { + string *name = LIST_ELT (font_name_list, e); + internal_font_type *i + = (internal_font_type *) LIST_ELT (internal_font_list, e); + + free (*name); + *name = ""; + + free (i); + + return; + } + + FATAL1 ("The font `%s' hasn't been saved", filename); +} diff --git a/lib/fontmap.c b/lib/fontmap.c new file mode 100644 index 0000000..2b4f0b7 --- /dev/null +++ b/lib/fontmap.c @@ -0,0 +1,210 @@ +/* fontmap.c: read a file for additional font names. + +Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "c-pathmx.h" +#include "fontmap.h" + + + +/* Fontname mapping. We use a straightforward hash table. */ + +#define MAP_SIZE 199 + + +/* The hash function. We go for simplicity here. */ + +static unsigned +map_hash (key) + char *key; +{ + unsigned n = 0; + + /* There are very few font names which are anagrams of each other (I + think), so no point in weighting the characters. */ + while (*key != 0) + n += *key++; + + n %= MAP_SIZE; + + return n; +} + +/* Look up STR in MAP. Return the corresponding `value' or NULL. */ + +static char * +map_lookup_str (map, key) + map_type map; + char *key; +{ + map_element_type *p; + unsigned n = map_hash (key); + + for (p = map[n]; p != NULL; p = p->next) + if (STREQ (key, p->key)) + return p->value; + + return NULL; +} + + +/* Look up KEY in MAP; if it's not found, remove any suffix from KEY and + try again. */ + +char * +map_lookup (map, key) + map_type map; + char *key; +{ + extern string extend_filename (); + string suffix = find_suffix (key); + string ret = map_lookup_str (map, key); + + if (!ret) + { + /* OK, the original KEY didn't work. Let's check for the KEY without + an extension -- perhaps they gave foobar.tfm, but the mapping only + defines `foobar'. */ + if (suffix) + { + string base_key = remove_suffix (key); + + ret = map_lookup_str (map, base_key); + + free (base_key); + } + } + + /* Append the same suffix we took off, if necessary. */ + if (ret && suffix) + ret = extend_filename (ret, suffix); + + return ret; +} + +/* If KEY is not already in MAP, insert it and VALUE. */ + +static void +map_insert (map, key, value) + map_type map; + char *key; + char *value; +{ + unsigned n = map_hash (key); + map_element_type **p = &map[n]; + map_element_type ***trailer = &p; + + while (*p != NULL && !STREQ (key, (*p)->key)) + { + *p = (*p)->next; + trailer = &p; + } + + if (*p == NULL) + { + **trailer = XTALLOC (MAP_SIZE, map_element_type); + (**trailer)->key = xstrdup (key); + (**trailer)->value = xstrdup (value); + (**trailer)->next = NULL; + } +} + +/* Open and read the mapping file FILENAME, putting its entries into + MAP. Comments begin with % and continue to the end of the line. Each + line of the file defines an entry: the first word is the real + filename (e.g., `ptmr'), the second word is the alias (e.g., + `Times-Roman'), and any subsequent words are ignored. .tfm is added + if either the filename or the alias have no extension. This is the + same order as in Dvips' psfonts.map; unfortunately, we can't have TeX + read that same file, since most of the real filenames start with an + `r', because of the virtual fonts Dvips uses. */ + +static void +map_file_parse (map, map_filename) + map_type map; + char *map_filename; +{ + extern FILE *xfopen (); /* In xfopen.c. */ + extern char *read_line (); /* In line.c. */ + char *l; + unsigned map_lineno = 0; + FILE *f = xfopen (map_filename, FOPEN_R_MODE); + + while ((l = read_line (f)) != NULL) + { + string filename; + string comment_loc = strrchr (l, '%'); + + map_lineno++; + + /* Ignore anything after a %. */ + if (comment_loc) + *comment_loc = 0; + + /* If we don't have any filename, that's ok, the line is blank. */ + filename = strtok (l, " \t"); + if (filename) + { + string alias = strtok (NULL, " \t"); + + /* But if we have a filename and no alias, something's wrong. */ + if (alias == NULL || *alias == 0) + fprintf (stderr, "%s:%u: Alias missing for filename `%s'.\n", + map_filename, map_lineno, filename); + else + { + /* We've got everything. Insert the new entry. */ + map_insert (map, alias, filename); + } + } + + free (l); + } + + xfclose (f, map_filename); +} + + +/* Look for the file `texfonts.map' in each of the directories in + DIR_LIST. Entries in earlier files override later files. */ + +map_type +map_create (dir_list) + string *dir_list; +{ + map_type map = (map_type) xcalloc (MAP_SIZE, sizeof (map_element_type *)); + + while (*dir_list) + { + char filename[PATH_MAX]; + + /* We don't bother with the filename truncation that `readable' in + `pathsrch.c' does, since we ourselves are giving the filename, + and I don't think it's worth worrying about too-long + intermediate directory names in the path. */ + strcpy (filename, *dir_list); + strcat (filename, "texfonts.map"); + + if (access (filename, R_OK) == 0) + map_file_parse (map, filename); + + dir_list++; + } + return map; +} diff --git a/lib/gmalloc.c b/lib/gmalloc.c new file mode 100644 index 0000000..bf4c70f --- /dev/null +++ b/lib/gmalloc.c @@ -0,0 +1,1172 @@ +/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ + +#define _MALLOC_INTERNAL + +/* The malloc headers and source files from the C library follow here. */ + +/* Declarations for `malloc' and friends. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) +#include <string.h> +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#ifndef memmove +#define memmove(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + +#if defined(__GNU_LIBRARY__) || defined(__STDC__) +#include <limits.h> +#else +#define CHAR_BIT 8 +#endif + +#endif /* _MALLOC_INTERNAL. */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#ifdef __STDC__ +#include <stddef.h> +#else +#undef size_t +#define size_t unsigned int +#undef ptrdiff_t +#define ptrdiff_t int +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((size_t __nmemb, size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +extern __ptr_t memalign __P ((size_t __alignment, size_t __size)); + +/* Allocate SIZE bytes on a page boundary. */ +extern __ptr_t valloc __P ((size_t __size)); + + +#ifdef _MALLOC_INTERNAL + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large block, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + size_t nfree; /* Free fragments in a fragmented block. */ + size_t first; /* First free fragment of the block. */ + } frag; + /* Size (in blocks) of a large cluster. */ + size_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + size_t size; /* Size (in blocks) of a free cluster. */ + size_t next; /* Index of next free cluster. */ + size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern size_t _heapindex; + +/* Limit of valid info table indices. */ +extern size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern size_t _chunks_used; +extern size_t _bytes_used; +extern size_t _chunks_free; +extern size_t _bytes_free; + +/* Internal version of `free' used in `morecore' (malloc.c). */ +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; + +/* Hooks for debugging versions. */ +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); + +/* Activate a standard collection of debugging hooks. */ +extern int mcheck __P ((void (*__func) __P ((void)))); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + size_t bytes_total; /* Total size of the heap. */ + size_t chunks_used; /* Chunks allocated by the user. */ + size_t bytes_used; /* Byte total of user-allocated chunks. */ + size_t chunks_free; /* Chunks in the free list. */ + size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((__const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* How to really get more memory. */ +__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +__ptr_t (*__malloc_hook) __P ((size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static size_t heapsize; + +/* Search index in the info table. */ +size_t _heapindex; + +/* Limit of valid info table indices. */ +size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +size_t _chunks_used; +size_t _bytes_used; +size_t _chunks_free; +size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +void (*__after_morecore_hook) __P ((void)); + +/* Aligned allocation. */ +static __ptr_t align __P ((size_t)); +static __ptr_t +align (size) + size_t size; +{ + __ptr_t result; + unsigned long int adj; + + result = (*__morecore) (size); + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % BLOCKSIZE; + if (adj != 0) + { + adj = BLOCKSIZE - adj; + (void) (*__morecore) (adj); + result = (char *) result + adj; + } + + if (__after_morecore_hook) + (*__after_morecore_hook) (); + + return result; +} + +/* Set everything up and remember that we have. */ +static int initialize __P ((void)); +static int +initialize () +{ + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); + if (_heapinfo == NULL) + return 0; + memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + __malloc_initialized = 1; + return 1; +} + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static __ptr_t morecore __P ((size_t)); +static __ptr_t +morecore (size) + size_t size; +{ + __ptr_t result; + malloc_info *newinfo, *oldinfo; + size_t newsize; + + result = align (size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if ((size_t) BLOCK ((char *) result + size) > heapsize) + { + newsize = heapsize; + while ((size_t) BLOCK ((char *) result + size) > newsize) + newsize *= 2; + newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); + if (newinfo == NULL) + { + (*__morecore) (-size); + return NULL; + } + memset (newinfo, 0, newsize * sizeof (malloc_info)); + memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); + oldinfo = _heapinfo; + newinfo[BLOCK (oldinfo)].busy.type = 0; + newinfo[BLOCK (oldinfo)].busy.info.size + = BLOCKIFY (heapsize * sizeof (malloc_info)); + _heapinfo = newinfo; + _free_internal (oldinfo); + heapsize = newsize; + } + + _heaplimit = BLOCK ((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +__ptr_t +malloc (size) + size_t size; +{ + __ptr_t result; + size_t block, blocks, lastblocks, start; + register size_t i; + struct list *next; + + /* ANSI C allows `malloc (0)' to either return NULL, or to return a + valid address you can realloc and free (though not dereference). + + It turns out that some extant code (sunrpc, at least Ultrix's version) + expects `malloc (0)' to return non-NULL and breaks otherwise. + Be compatible. */ + +#if 0 + if (size == 0) + return NULL; +#endif + + if (__malloc_hook != NULL) + return (*__malloc_hook) (size); + + if (!__malloc_initialized) + if (!initialize ()) + return NULL; + + if (size < sizeof (struct list)) + size = sizeof (struct list); + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (__ptr_t) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK (result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc (BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + if (next->next != NULL) + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + _bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY (size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Check to see if + the new core will be contiguous with the final free + block; if so we don't need to get as much. */ + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + (*__morecore) (0) == ADDRESS (block + lastblocks) && + (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL) + { + _heapinfo[block].free.size = blocks; + _bytes_free += (blocks - lastblocks) * BLOCKSIZE; + continue; + } + result = morecore (blocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK (result); + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + return result; + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS (block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + } + + return result; +} +/* Free a block of memory allocated by `malloc'. + Copyright 1990, 1991, 1992 Free Software Foundation + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* Debugging hook for free. */ +void (*__free_hook) __P ((__ptr_t __ptr)); + +/* List of blocks allocated by memalign. */ +struct alignlist *_aligned_blocks = NULL; + +/* Return memory to the heap. + Like `free' but don't call a __free_hook if there is one. */ +void +_free_internal (ptr) + __ptr_t ptr; +{ + int type; + size_t block, blocks; + register size_t i; + struct list *prev, *next; + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* Now see if we can return stuff to the system. */ + blocks = _heapinfo[block].free.size; + if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit + && (*__morecore) (0) == ADDRESS (block + blocks)) + { + register size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore) (-bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS (block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free (ADDRESS (block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) ptr - (char *) NULL) + % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +free (ptr) + __ptr_t ptr; +{ + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + + if (__free_hook != NULL) + (*__free_hook) (ptr); + else + _free_internal (ptr); +} +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#undef cfree + +#ifdef _LIBC + +#include <ansidecl.h> +#include <gnu-stabs.h> + +function_alias(cfree, free, void, (ptr), + DEFUN(cfree, (ptr), PTR ptr)) + +#else + +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +#endif +/* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#define min(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +__ptr_t +realloc (ptr, size) + __ptr_t ptr; + size_t size; +{ + __ptr_t result; + int type; + size_t block, blocks, oldlimit; + + if (size == 0) + { + free (ptr); + return malloc (0); + } + else if (ptr == NULL) + return malloc (size); + + if (__realloc_hook != NULL) + return (*__realloc_hook) (ptr, size); + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = malloc (size); + if (result != NULL) + { + memcpy (result, ptr, size); + free (ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + free (ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + free (ptr); + _heaplimit = oldlimit; + result = malloc (size); + if (result == NULL) + { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + (void) malloc (blocks * BLOCKSIZE); + else + { + __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE); + (void) malloc (blocks * BLOCKSIZE); + free (previous); + } + return NULL; + } + if (ptr != result) + memmove (result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = malloc (size); + if (result == NULL) + return NULL; + memcpy (result, ptr, min (size, (size_t) 1 << type)); + free (ptr); + } + break; + } + + return result; +} +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ +__ptr_t +calloc (nmemb, size) + register size_t nmemb; + register size_t size; +{ + register __ptr_t result = malloc (nmemb * size); + + if (result != NULL) + (void) memset (result, 0, nmemb * size); + + return result; +} +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU C Library 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 the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#ifndef __GNU_LIBRARY__ +#define __sbrk sbrk +#endif + +extern __ptr_t __sbrk __P ((int increment)); + +#ifndef NULL +#define NULL 0 +#endif + +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +__ptr_t +__default_morecore (increment) + ptrdiff_t increment; +{ + __ptr_t result = __sbrk ((int) increment); + if (result == (__ptr_t) -1) + return NULL; + return result; +} +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +__ptr_t +memalign (alignment, size) + size_t alignment; + size_t size; +{ + __ptr_t result; + unsigned long int adj; + + size = ((size + alignment - 1) / alignment) * alignment; + + result = malloc (size); + if (result == NULL) + return NULL; + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % alignment; + if (adj != 0) + { + struct alignlist *l; + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == NULL) + /* This slot is free. Use it. */ + break; + if (l == NULL) + { + l = (struct alignlist *) malloc (sizeof (struct alignlist)); + if (l == NULL) + { + free (result); + return NULL; + } + } + l->exact = result; + result = l->aligned = (char *) result + alignment - adj; + l->next = _aligned_blocks; + _aligned_blocks = l; + } + + return result; +} +/* Allocate memory on a page boundary. + Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#ifdef __GNU_LIBRARY__ +extern size_t __getpagesize __P ((void)); +#else +#include "getpagesize.h" +#define __getpagesize() getpagesize() +#endif + +static size_t pagesize; + +__ptr_t +valloc (size) + size_t size; +{ + if (pagesize == 0) + pagesize = __getpagesize (); + + return memalign (pagesize, size); +} diff --git a/lib/hexify.c b/lib/hexify.c new file mode 100644 index 0000000..e3941b2 --- /dev/null +++ b/lib/hexify.c @@ -0,0 +1,46 @@ +/* hexify.c: change a binary string to ASCII hex characters. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "hexify.h" + + +/* Convert the number N (assumed to be small enough) to a lowercase hex + character. */ +#define HEX_DIGIT(n) ((n) < 10 ? (n) + '0' : (n) - 10 + 'a') + +string +hexify (one_byte *data, unsigned length) +{ + unsigned i; + /* Each byte in S turns into two hex chars, plus the terminating null. */ + string h = xmalloc (length * 2 + 1); + + for (i = 0; i < length; i++) + { + unsigned char n = (data[i] & 0xf0) >> 4; + h[i * 2] = HEX_DIGIT (n); + + n = data[i] & 0x0f; + h[i * 2 + 1] = HEX_DIGIT (n); + } + h[i * 2] = 0; + + return h; +} diff --git a/lib/identity.c b/lib/identity.c new file mode 100644 index 0000000..ffe0e1d --- /dev/null +++ b/lib/identity.c @@ -0,0 +1,38 @@ +/* identity.c. + +Copyright (C) 1995 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/lib.h> +#include <kpathsea/progname.h> + +/* Return `hostname:pid' as a string. */ + +string +get_identity () +{ + char s[1024]; + int i; + + i = XmuGetHostname (s, sizeof (s)); + if (i == 0) + FATAL ("limn: Could not get hostname"); + + sprintf (&s[i], ":%d", getpid ()); + return (string)xstrdup (s); +} diff --git a/lib/integer-ok.c b/lib/integer-ok.c new file mode 100644 index 0000000..5af9214 --- /dev/null +++ b/lib/integer-ok.c @@ -0,0 +1,44 @@ +/* integer-ok.c: test if a string is a valid integer. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> + + +boolean +integer_ok (string str) +{ + boolean found_digit = false; + + if (str == NULL) + return false; + + /* Allow leading `-' or `+' sign. */ + if (*str == '-' || *str == '+') + str++; + + /* Skip decimal digits. */ + while (ISDIGIT (*str)) + { + str++; + found_digit = true; + } + + return *str == 0 && found_digit; +} diff --git a/lib/libfile.c b/lib/libfile.c new file mode 100644 index 0000000..7ce3633 --- /dev/null +++ b/lib/libfile.c @@ -0,0 +1,130 @@ +/* libfile.c: open and read a single auxiliary data file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "paths.h" + +#include <kpathsea/c-ctype.h> +#include <kpathsea/line.h> +#include "libfile.h" +#include "pathsrch.h" + + +/* Private variables to hold the auxiliary file we're reading from, and + its name. */ +static FILE *lib_file = NULL; +static string lib_filename; +static unsigned lib_file_line_number; + + +/* Prepare to read the ``library file'' FILENAME.DEFAULT_SUFFIX (if + FILENAME has no suffix), or just FILENAME (if it has). Give a fatal + error if it cannot be opened. Return the resulting FILE * (although + usually this will just be ignored by the caller). */ + +FILE * +libfile_start (string filename, string default_suffix) +{ + string *lib_dirs = initialize_path_list (LIB_ENVVAR, DEFAULT_LIB_PATH); + string name = extend_filename (filename, default_suffix); + + lib_filename = find_path_filename (name, lib_dirs); + + if (lib_filename == NULL) + FATAL1 ("%s: Cannot find library file in path", name); + + lib_file = xfopen (lib_filename, "r"); + lib_file_line_number = 1; + + return lib_file; +} + + +/* Close our current open file. If we don't have any file open, give a + fatal error. */ + +void +libfile_close () +{ + assert (lib_file != NULL); + + fclose (lib_file); + lib_file = NULL; +} + +/* Return the name of the currently open file, or NULL if none. */ + +string +libfilename () +{ + return lib_file == NULL ? NULL : lib_filename; +} + + +/* Analogously, for the current line number. */ + +unsigned +libfile_linenumber () +{ + return lib_file == NULL ? 0 : lib_file_line_number; +} + +/* Return the next nonblank non-comment line from `lib_file', or NULL if + we are at EOF. Also remove any trailing comment on the line. */ + +string +libfile_line () +{ + string s; + string line; + boolean skip = true; + + assert (lib_file != NULL); + + do + { + line = read_line (lib_file); + lib_file_line_number++; + + /* If at EOF, quit the loop. */ + if (line == NULL) + break; + + s = line; + + /* Move ahead to the first nonblank character. */ + while (*s != 0 && ISSPACE (*s)) + s++; + + /* Keep going if the line was blank or a comment. */ + if (*s == 0 || *s == '%') + free (line); + else + skip = false; + } + while (skip); + + if (line != NULL) + { + s = strrchr (line, '%'); + if (s != NULL) + *s = 0; + } + + return line; +} diff --git a/lib/line.c b/lib/line.c new file mode 100644 index 0000000..6c2e16e --- /dev/null +++ b/lib/line.c @@ -0,0 +1,63 @@ +/* line.c: return the next line from a file, or NULL. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +#define BLOCK_SIZE 40 + +char * +read_line (f) + FILE *f; +{ + int c; + unsigned limit = BLOCK_SIZE; + unsigned loc = 0; + char *line = (char *) xmalloc (limit); + + while ((c = getc (f)) != EOF && c != '\n') + { + line[loc] = c; + loc++; + + /* By testing after the assignment, we guarantee that we'll always + have space for the null we append below. We know we always + have room for the first char, since we start with BLOCK_SIZE. */ + if (loc == limit) + { + limit += BLOCK_SIZE; + line = (char *) xrealloc (line, limit); + } + } + + /* If we read anything, return it. This can't represent a last + ``line'' which doesn't end in a newline, but so what. */ + if (c != EOF) + { + /* Terminate the string. We can't represent nulls in the file, + either. Again, it doesn't matter. */ + line[loc] = 0; + } + else /* At end of file. */ + { + free (line); + line = NULL; + } + + return line; +} diff --git a/lib/list.c b/lib/list.c new file mode 100644 index 0000000..8dcca72 --- /dev/null +++ b/lib/list.c @@ -0,0 +1,64 @@ +/* list.c: simple list (represented as arrays) manipulation. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "list.h" + + +list_type +list_init () +{ + list_type answer; + + LIST_DATA (answer) = NULL; + LIST_SIZE (answer) = 0; + + return answer; +} + + +/* Free the memory for both the elements and the list itself. */ + +void +list_free (list_type *list) +{ + if (list != NULL && LIST_DATA (*list) != NULL) + { + unsigned e; + + for (e = 0; e < LIST_SIZE (*list); e++) + free (LIST_ELT (*list, e)); + + free (LIST_DATA (*list)); + } +} + +/* The list consists entirely of pointers to objects. We allocate the + space for the objects pointed to here, though, and return a pointer to + the newly-created final element in the list. */ + +address +list_append (list_type *list, unsigned element_size) +{ + LIST_SIZE (*list)++; + XRETALLOC (LIST_DATA (*list), LIST_SIZE (*list), address); + LIST_LAST_ELT (*list) = xmalloc (element_size); + + return LIST_LAST_ELT (*list); +} diff --git a/lib/logreport.c b/lib/logreport.c new file mode 100644 index 0000000..93d2dff --- /dev/null +++ b/lib/logreport.c @@ -0,0 +1,36 @@ +/* logreport.c: showing information to the user. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "logreport.h" + + +/* Says whether to output detailed progress reports, i.e., all the data + on the fitting, as we run. (-log) */ +boolean logging = false; + +FILE *log_file = NULL; + + +void +flush_log_output () +{ + if (logging) + fflush (log_file); +} diff --git a/lib/make-prefix.c b/lib/make-prefix.c new file mode 100644 index 0000000..fe4fcd4 --- /dev/null +++ b/lib/make-prefix.c @@ -0,0 +1,41 @@ +/* make-prefix.c: construct a pathname prefix. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/concatn.h> + + +string +make_prefix (string prefix, string pathname) +{ + string slash_pos = strrchr (pathname, '/'); + + if (slash_pos == NULL) + return concat (prefix, pathname); + else + { + string answer = NULL; + string path_only = xstrdup (pathname); + path_only[slash_pos - pathname] = 0; + answer = concatn (path_only, "/", prefix, slash_pos + 1, NULL); + free (path_only); + + return answer; + } +} diff --git a/lib/math.c b/lib/math.c new file mode 100644 index 0000000..0939d8e --- /dev/null +++ b/lib/math.c @@ -0,0 +1,173 @@ +/* math.c: define some simple array operations, and other functions. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Numerical errors sometimes make a floating point number just slightly + larger or smaller than its true value. When it matters, we need to + compare with some tolerance, REAL_EPSILON, defined in kbase.h. */ + +const boolean +epsilon_equal (real v1, real v2) +{ + return + v1 == v2 /* Usually they'll be exactly equal, anyway. */ + || fabs (v1 - v2) <= REAL_EPSILON; +} + + +/* Return the Euclidean distance between P1 and P2. */ + +const real +distance (real_coordinate_type p1, real_coordinate_type p2) +{ + return hypot (p1.x - p2.x, p1.y - p2.y); +} + + +/* Same thing, for integer points. */ +const real +int_distance (coordinate_type p1, coordinate_type p2) +{ + return hypot ((double) p1.x - p2.x, (double) p1.y - p2.y); +} + + +/* Return the arc cosine of V, in degrees in the range zero to 180. V + is taken to be in radians. */ + +const real +acosd (real v) +{ + real a; + + if (epsilon_equal (v, 1.0)) + v = 1.0; + else if (epsilon_equal (v, -1.0)) + v = -1.0; + + errno = 0; + a = acos (v); + if (errno == ERANGE || errno == EDOM) + FATAL_PERROR ("acosd"); + + return a * 180.0 / M_PI; +} + + +/* The slope of the line defined by COORD1 and COORD2. */ + +const real +slope (real_coordinate_type coord1, real_coordinate_type coord2) +{ + assert (coord2.x - coord1.x != 0); + + return (coord2.y - coord1.y) / (coord2.x - coord1.x); +} + + +/* Turn an integer point into a real one, and vice versa. */ + +const real_coordinate_type +int_to_real_coord (coordinate_type int_coord) +{ + real_coordinate_type real_coord; + + real_coord.x = int_coord.x; + real_coord.y = int_coord.y; + + return real_coord; +} + + +const coordinate_type +real_to_int_coord (real_coordinate_type real_coord) +{ + coordinate_type int_coord; + + int_coord.x = ROUND (real_coord.x); + int_coord.y = ROUND (real_coord.y); + + return int_coord; +} + + +/* See if two points (described by their row and column) are adjacent. */ + +const boolean +points_adjacent_p (int row1, int col1, int row2, int col2) +{ + int row_diff = abs (row1 - row2); + int col_diff = abs (col1 - col2); + + return + (row_diff == 1 && col_diff == 1) + || (row_diff == 0 && col_diff == 1) + || (row_diff == 1 && col_diff == 0); +} + + + + +/* Find the largest and smallest elements in an array of reals. */ + +void +find_bounds (real *values, unsigned value_count, real *min, real *max) +{ + unsigned this_value; + + /* We must use FLT_MAX and FLT_MIN, instead of the corresponding + values for double, because gcc uses the native atof to parse + floating point constants, and many atof's choke on the extremes. */ + *min = FLT_MAX; + *max = FLT_MIN; + + for (this_value = 0; this_value < value_count; this_value++) + { + if (values[this_value] < *min) + *min = values[this_value]; + + if (values[this_value] > *max) + *max = values[this_value]; + } +} + + + +/* Map a range of numbers, some positive and some negative, into all + positive, with the greatest being at one and the least at zero. + + This allocates new memory. */ + +real * +map_to_unit (real *values, unsigned value_count) +{ + real smallest, largest; + int this_value; + real *mapped_values = xmalloc (sizeof (real) * value_count); + + find_bounds (values, value_count, &smallest, &largest); + + largest -= smallest; /* We never care about largest itself. */ + + for (this_value = 0; this_value < value_count; this_value++) + mapped_values[this_value] = (values[this_value] - smallest) / largest; + + return mapped_values; +} diff --git a/lib/now.c b/lib/now.c new file mode 100644 index 0000000..aabf718 --- /dev/null +++ b/lib/now.c @@ -0,0 +1,38 @@ +/* time.c: the current date and time. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Get the current date and time as a string. The 26 here is defined in + the manual page for ctime(3). */ + +string +now () +{ + extern time_t time (long *); + extern string ctime (time_t *); + + string time_string = xmalloc (26); + time_t t = time (0); + + strcpy (time_string, ctime (&t)); + time_string[24] = 0; /* No newline. */ + + return time_string; +} diff --git a/lib/numtoa.c b/lib/numtoa.c new file mode 100644 index 0000000..53c1a7d --- /dev/null +++ b/lib/numtoa.c @@ -0,0 +1,50 @@ +/* numtoa.c: change numbers back to strings. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +/* Declarations for these are in global.h. */ + +string +itoa (int i) +{ + char a[MAX_INT_LENGTH]; + + sprintf (a, "%d", i); + return xstrdup (a); +} + +string +utoa (unsigned u) +{ + char a[MAX_INT_LENGTH]; + + sprintf (a, "%u", u); + return xstrdup (a); +} + +string +xdtoa (double d) +{ + /* I'm not sure if this is really enough, but I also don't know how to + compute what *would* be enough. */ + char a[500]; + + sprintf (a, "%f", d); + return xstrdup (a); +} diff --git a/lib/pathsrch.c b/lib/pathsrch.c new file mode 100644 index 0000000..e513df5 --- /dev/null +++ b/lib/pathsrch.c @@ -0,0 +1,509 @@ +/* pathsrch.c: look for files based on paths, i.e., colon-separated + lists of directories. + + We should allow % specifiers in the paths for the resolution, mode + name, etc. + +Copyright (C) 1992, 93 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-stat.h> +#include "c-pathch.h" +#include "c-namemx.h" +#include "c-pathmx.h" +#include "paths.h" + +#include <kpathsea/c-ctype.h> +#if !defined (DOS) && !defined (VMS) && !defined (VMCMS) +#include <pwd.h> +#endif +#include "dirio.h" +#include "pathsrch.h" + +static boolean absolute_p P1H(string filename); +static void add_directory P3H(string **, unsigned *, string); +static void expand_subdir P3H(string **, unsigned *, string); +static string *find_dir_list P1H(string); +static string readable P1H(string); +static void save_dir_list P2H(string, string *); +static string truncate_pathname P1H(string); + +/* If FILENAME is absolute or explicitly relative (i.e., starts with + `/', `./', or `../'), or if DIR_LIST is null, we return whether + FILENAME is readable as-is. Otherwise, we test if FILENAME is in any of + the directories listed in DIR_LIST. (The last entry of DIR_LIST must + be null.) We return the complete path if found, NULL else. + + In the interests of doing minimal work here, we assume that each + element of DIR_LIST already ends with a `/'. + + DIR_LIST is most conveniently made by calling `initialize_path_list'. + This is a separate routine because we allow recursive searching, and + it may take some time to discover the list of directories. + We do not want to incur that overhead every time we want to look for + a file. + + (Actually, `/' is not hardwired into this routine; we use PATH_SEP, + defined above.) */ + +string +find_path_filename P2C(string, filename, string *, dir_list) +{ + string found_name = NULL; + + /* Do this before testing for absolute-ness, as a leading ~ will be an + absolute pathname. */ + filename = expand_tilde (filename); + + /* If FILENAME is absolute or explicitly relative, or if DIR_LIST is + null, only check if FILENAME is readable. */ + if (absolute_p (filename) || dir_list == NULL) + found_name = readable (filename); + else + { /* Test if FILENAME is in any of the directories in DIR_LIST. */ + string save_filename = filename; + + while (*dir_list != NULL) + { + filename = concat (*dir_list, save_filename); + found_name = readable (filename); + if (found_name == NULL) + { + free (filename); + dir_list++; + } + else + { + if (found_name != filename) + free (filename); + break; + } + } + } + + return found_name; +} + + +/* If NAME is readable, return it. If the error is ENAMETOOLONG, + truncate any too-long path components and return the result (unless + there were no too-long components, i.e., a overall too-long name + caused the error, in which case return NULL). On any other error, + return NULL. + + POSIX invented this brain-damage of not necessarily truncating + pathname components; the system's behavior is defined by the value of + the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! */ + +static string +readable (name) + string name; +{ + string ret; + + if (access (name, R_OK) == 0 && !dir_p (name)) + ret = name; +#ifdef ENAMETOOLONG + else if (errno == ENAMETOOLONG) + { + ret = truncate_pathname (name); + + /* Perhaps some other error will occur with the truncated name, so + let's call access again. */ + if (!(access (ret, R_OK) == 0 && !dir_p (ret))) + { /* Failed. */ + free (ret); + ret = NULL; + } + } +#endif + else + ret = NULL; /* Some other error. */ + + return ret; +} + + + +/* Truncate any too-long path components in NAME, returning the result. */ + +static string +truncate_pathname (name) + string name; +{ + unsigned c_len = 0; /* Length of current component. */ + unsigned ret_len = 0; /* Length of constructed result. */ + string ret = (string) xmalloc (PATH_MAX + 1); + + for (; *name; name++) + { + if (IS_PATH_SEP (*name)) + { /* At a directory delimiter, reset component length. */ + c_len = 0; + } + else if (c_len > NAME_MAX) + { /* If past the max for a component, ignore this character. */ + continue; + } + + /* If we've already copied the max, give up. */ + if (ret_len == PATH_MAX) + { + free (ret); + return NULL; + } + + /* Copy this character. */ + ret[ret_len++] = *name; + c_len++; + } + ret[ret_len] = 0; + + return ret; +} + + +/* Return true if FILENAME is absolute or explicitly relative, else false. */ + +static boolean +absolute_p P1C(string, filename) +{ + boolean absolute = IS_PATH_SEP (*filename) +#ifdef DOS + || ISALPHA (*filename) && filename[1] == ':' +#endif + ; + boolean explicit_relative + = (*filename == '.' + && (IS_PATH_SEP (filename[1]) + || (filename[1] == '.' && IS_PATH_SEP (filename[2])))); + + return absolute || explicit_relative; +} + +/* Return a NULL-terminated array of directory names, each name ending + with PATH_SEP, created by parsing the PATH_DELIMITER-separated list + in the value of the environment variable ENV_NAME, or DEFAULT_PATH if + the envvar is not set. + + A leading or trailing colon in the value of ENV_NAME is replaced by + DEFAULT_PATH. + + Any element of the path that ends with double PATH_SEP characters + (e.g., `foo//') is replaced by all its subdirectories. + + If ENV_NAME is null, only parse DEFAULT_PATH. If both are null, do + nothing and return NULL. */ + +string * +initialize_path_list P2C(string, env_name, string, default_path) +{ + string dir, path; + string *dir_list; + unsigned dir_count = 0; + string env_value = env_name ? getenv (env_name) : NULL; + string orig_path = expand_default (env_value, default_path); + + if (orig_path == NULL || *orig_path == 0) + return NULL; + + /* If we've already seen this colon-separated list, then just get it + back instead of going back to the filesystem. */ + dir_list = find_dir_list (orig_path); + if (dir_list != NULL) + return dir_list; + + /* Be sure `path' is in writable memory. */ + path = (orig_path == env_value || orig_path == default_path + ? xstrdup (orig_path) : orig_path); + + /* Find each element in the path in turn. */ + for (dir = strtok (path, PATH_DELIMITER_STRING); dir != NULL; + dir = strtok (NULL, PATH_DELIMITER_STRING)) + { + int len; + /* If the path starts with ~ or ~user, expand it. Do this + before calling `expand_subdir' or `add_directory', so that + 1) we don't expand the same ~ for every subdirectory; and + 2) pathnames in `expand_subdir' don't have a `~' in them + (since the system won't grok `~/foo' as a directory). */ + dir = expand_tilde (dir); + len = strlen (dir); + + /* If `dir' is the empty string, ignore it. */ + if (len == 0) + continue; + + /* If `dir' ends in double slashes, do subdirectories (and remove + the second slash, so the final pathnames we return don't look + like foo//bar). Because we obviously want to do subdirectories + of `dir', we don't check if it is a leaf. This means that if + `dir' is `foo//', and `foo' contains only symlinks (so our leaf + test below would be true), the symlinks are chased. */ + if (len > 2 && IS_PATH_SEP (dir[len - 1]) && IS_PATH_SEP (dir[len - 2])) + { + dir[len - 1] = 0; + if (dir_p (dir)) + { + add_directory (&dir_list, &dir_count, dir); + expand_subdir (&dir_list, &dir_count, dir); + } + } + else + { /* Don't bother to add the directory if it doesn't exist. */ + if (dir_p (dir)) + add_directory (&dir_list, &dir_count, dir); + } + } + + /* Add the terminating null entry to `dir_list'. */ + dir_count++; + XRETALLOC (dir_list, dir_count, string); + dir_list[dir_count - 1] = NULL; + + /* Save the directory list we just found. */ + save_dir_list (orig_path, dir_list); + + return dir_list; +} + +/* Subroutines for `initialize_path_list'. */ + +/* Add a newly-allocated copy of DIR to the end of the array pointed to + by DIR_LIST_PTR. Increment DIR_COUNT_PTR. Append a `/' to DIR if + necessary. We assume DIR is a directory, to avoid unnecessary an + unnecessary call to `stat'. */ + +static void +add_directory (dir_list_ptr, dir_count_ptr, dir) + string **dir_list_ptr; + unsigned *dir_count_ptr; + string dir; +{ + /* If `dir' does not end with a `/', add it. We can't just + write it in place, since that would overwrite the null that + strtok may have put in. So we always make a copy of DIR. */ + dir = (IS_PATH_SEP (dir[strlen (dir) - 1]) ? xstrdup (dir) + : concat (dir, PATH_SEP_STRING)); + + /* Add `dir' to the list of the directories. */ + (*dir_count_ptr)++; + XRETALLOC (*dir_list_ptr, *dir_count_ptr, string); + (*dir_list_ptr)[*dir_count_ptr - 1] = dir; +} + + +/* Add DIRNAME to DIR_LIST and look for subdirectories, recursively. We + assume DIRNAME is the name of a directory. */ + +static void +expand_subdir (dir_list_ptr, dir_count_ptr, dirname) + string **dir_list_ptr; + unsigned *dir_count_ptr; + string dirname; +{ + DIR *dir; + struct dirent *e; + unsigned length; + char potential[PATH_MAX]; + struct stat st; + + /* We will be looking at its contents. */ + dir = opendir (dirname); + if (dir == NULL) + return; + + /* Compute the length of DIRNAME, since it's loop-invariant. */ + length = strlen (dirname); + + /* Construct the part of the pathname that doesn't change. */ + strcpy (potential, dirname); + if (!IS_PATH_SEP (potential[length - 1])) + { + potential[length] = PATH_SEP; + potential[length + 1] = 0; + length++; + } + + while ((e = readdir (dir)) != NULL) + { /* If it's . or .., never mind. */ + if (!(e->d_name[0] == '.' + && (e->d_name[1] == 0 + || (e->d_name[1] == '.' && e->d_name[2] == 0)))) + { /* If it's not a directory, we will skip it on the + recursive call. */ + strcat (potential, e->d_name); + + /* If we can't stat it, or if it isn't a directory, continue. */ + if (stat (potential, &st) == 0 && S_ISDIR (st.st_mode)) + { /* It's a subdirectory; add `potential' to the list. */ + add_directory (dir_list_ptr, dir_count_ptr, potential); + + /* If it's not a leaf, quit. Assume that leaf + directories have two links (one for . and one for ..). + This means that symbolic links to directories do not affect + the leaf-ness. This is arguably wrong, but the only + alternative I know of is to stat every entry in the + directory, and that is unacceptably slow. + + The #ifdef here at least makes this configurable at + compile-time, so that if we're using VMS directories or + some such, we can still find subdirectories, even if it + is much slower. */ +#ifdef UNIX_ST_NLINK + if (st.st_nlink > 2) +#endif + { /* All criteria are met; find subdirectories. */ + expand_subdir (dir_list_ptr, dir_count_ptr, potential); + } + } + + /* ``Remove'' the directory entry name. */ + potential[length] = 0; + } + } + + closedir (dir); +} + +/* These routines, while not strictly needed to be exported, are + plausibly useful to be called by outsiders. */ + +/* Replace a leading or trailing `:' in ENV_PATH with DEFAULT_PATH. If + neither is present, return ENV_PATH if that is non-null, else + DEFAULT_PATH. */ + +string +expand_default (env_path, default_path) + string env_path; + string default_path; +{ + string expansion; + + if (env_path == NULL) + expansion = default_path; + else if (*env_path == PATH_DELIMITER) + expansion = concat (default_path, env_path); + else if (env_path[strlen (env_path) - 1] == PATH_DELIMITER) + expansion = concat (env_path, default_path); + else + expansion = env_path; + + return expansion; +} + + +/* Expand a leading ~ or ~user, Unix-style, unless we are some weirdo + operating system. */ + +string +expand_tilde P1C(string, name) +{ +#if defined (DOS) || defined (VMS) || defined (VMCMS) + return name; +#else + string expansion; + string home; + + /* If no leading tilde, do nothing. */ + if (*name != '~') + expansion = name; + + /* If `~' or `~/', use $HOME if it exists, or `.' if it doesn't. */ + else if (IS_PATH_SEP (name[1]) || name[1] == 0) + { + home = getenv ("HOME"); + if (home == NULL) + home = "."; + + expansion + = name[1] == 0 ? home : concat3 (home, PATH_SEP_STRING, name + 2); + } + + /* If `~user' or `~user/', look up user in the passwd database. */ + else + { + struct passwd *p; + string user; + unsigned c = 2; + while (!IS_PATH_SEP (name[c]) && name[c] != 0) + c++; + + user = (string) xmalloc (c); + strncpy (user, name + 1, c - 1); + user[c - 1] = 0; + + /* We only need the cast here for those (old deficient) systems + which do not declare `getpwnam' in <pwd.h>. */ + p = (struct passwd *) getpwnam (user); + free (user); + /* If no such user, just use `.'. */ + home = p == NULL ? "." : p->pw_dir; + + expansion = name[c] == 0 ? home : concat (home, name + c); + } + + return expansion; +#endif /* not (DOS or VMS or VM/CMS) */ +} + +/* Routines to save and retrieve a directory list keyed by the original + colon-separated path. This is useful because 1) it can take a + significant amount of time to discover all the subdirectories of a + given directory, and 2) many paths all have the same basic default, + and thus would recompute the directory list. */ + +typedef struct +{ + string path; + string *dir_list; +} saved_path_entry; + +static saved_path_entry *saved_paths = NULL; +static unsigned saved_paths_length = 0; + + +/* We implement the data structure as a simple linear list, since it's + unlikely to ever be more than a dozen or so elements long. We don't + bother to check here if PATH has already been saved; we always add it + to our list. */ + +static void +save_dir_list P2C(string, path, string *, dir_list) +{ + saved_paths_length++; + XRETALLOC (saved_paths, saved_paths_length, saved_path_entry); + saved_paths[saved_paths_length - 1].path = path; + saved_paths[saved_paths_length - 1].dir_list = dir_list; +} + +/* When we retrieve, just check the list in order. */ + +static string * +find_dir_list P1C(string, path) +{ + unsigned p; + + for (p = 0; p < saved_paths_length; p++) + { + if (strcmp (saved_paths[p].path, path) == 0) + return saved_paths[p].dir_list; + } + + return NULL; +} diff --git a/lib/rand.c b/lib/rand.c new file mode 100644 index 0000000..78cc7fa --- /dev/null +++ b/lib/rand.c @@ -0,0 +1,70 @@ +/* rand.c: a simple pseudo-random number generator. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "rand.h" + + +/* Current state of the random number generator. ANSI C says that the + default should be as if `srand' was called with the value 1. At all + times this will be a random number between 1 and RAND_MAX+1. */ +static long rand_state = 2; + + +/* Set the state. It's ok if `seed' doesn't fit in a long, since we + check for negative values before we return anything. On the other + hand, we cannot allow our state to become zero, since then we will + produce zero forever. */ + +void +seed_rand (unsigned seed) +{ + rand_state = seed + 1; +} + + +/* Return a pseudo-random number based on `x' in the range [0, RAND_MAX]. + We use the Ghostscript computation (from the function `zrand' in the + file `zmath.c'). */ + +int +k_rand () +{ + /* We use an algorithm from CACM 31(10), pp. 1192-1201, October 1988. + According to a posting by Ed Taft on comp.lang.postscript, Level 2 + (Adobe) PostScript interpreters use this algorithm too: + + x[n+1] = (16807 * x[n]) mod (2^31 - 1) + + The complication ensues from the fact that the multiplication may + lead to a 46-bit number. */ + +#define A 16807 +#define M 0x7fffffff +#define Q 127773 /* M / A */ +#define R 2836 /* M % A */ + rand_state = A * (rand_state % Q) - R * (rand_state / Q); + while ( rand_state <= 0 ) rand_state += M; + + /* OK, `rand_state' is our new random number between 1 and 2^31 - 1. + Now we have to subtract one, so that we return a number in the + range zero to RAND_MAX (inclusive). We obviously must define our + RAND_MAX to be 2^31 - 2, which we do (in `rand.h'). */ + return rand_state - 1; +} diff --git a/lib/report.c b/lib/report.c new file mode 100644 index 0000000..fc732b2 --- /dev/null +++ b/lib/report.c @@ -0,0 +1,27 @@ +/* report.c: showing information to the user online. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Says whether to output short progress reports as we run. (-verbose) */ +boolean verbose = false; + +/* Where to output the reports. If a particular program uses standard + output for real output, this gets changed to `stderr'. */ +FILE *report_file = stdout; diff --git a/lib/safe-free.c b/lib/safe-free.c new file mode 100644 index 0000000..7c56d0a --- /dev/null +++ b/lib/safe-free.c @@ -0,0 +1,37 @@ +/* safe-free.c: free with error checking. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* `free' itself does not return an error status. So all we can do here + is check for nulls. */ + +void +safe_free (address *item) +{ + if (item == NULL || *item == NULL) + { + fprintf (stderr, "safe_free: Attempt to free a null item.\n"); + abort (); + } + + free (*item); + + *item = NULL; +} diff --git a/lib/scaled-num.c b/lib/scaled-num.c new file mode 100644 index 0000000..cf4a18f --- /dev/null +++ b/lib/scaled-num.c @@ -0,0 +1,75 @@ +/* scaled-num.c: conversions on ``scaled'' numbers, which are a 32-bit + word with 16 bits of fraction. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "scaled-num.h" + + +#define SCALED_UNITY (1 << 16) /* 2^16, represents 1.00000. */ + + +/* This prints a scaled number, rounded to five digits. */ + +void +print_scaled (scaled s) +{ + scaled delta; + + if (s < 0) + { /* Print sign, if negative. */ + putchar ('-'); + s = -s; + } + + printf ("%u", s / SCALED_UNITY); /* Print integer part. */ + putchar ('.'); + + s = 10 * (s % SCALED_UNITY) + 5; + delta = 10; + + do + { + if (delta > SCALED_UNITY) + s += 0100000 - (delta / 2); /* Round the last digit. */ + + printf ("%c", '0' + (s / SCALED_UNITY)); + s = 10 * (s % SCALED_UNITY); + delta *= 10; + } + while (s > delta); +} + + +const real +scaled_to_real (scaled s) +{ + real r = (real) s / SCALED_UNITY; + + return r; +} + + +const scaled +real_to_scaled (real r) +{ + scaled s = r * SCALED_UNITY; + + return s; +} diff --git a/lib/spline.c b/lib/spline.c new file mode 100644 index 0000000..cdfc25f --- /dev/null +++ b/lib/spline.c @@ -0,0 +1,216 @@ +/* spline.c: spline and spline list (represented as arrays) manipulation. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "bounding-box.h" +#include "spline.h" +#include "vector.h" + + +/* Return a new spline structure, initialized with (recognizable) + garbage. */ + +spline_type +new_spline () +{ + spline_type spline; + + START_POINT (spline) + = CONTROL1 (spline) + = CONTROL2 (spline) + = END_POINT (spline) + = (real_coordinate_type) { -100.0, -100.0 }; + SPLINE_DEGREE (spline) = -1; + + return spline; +} + + +/* Print a spline in human-readable form. */ + +void +print_spline (FILE *f, spline_type s) +{ + if (SPLINE_DEGREE (s) == LINEAR) + fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n", + START_POINT (s).x, START_POINT (s).y, + END_POINT (s).x, END_POINT (s).y); + + else if (SPLINE_DEGREE (s) == CUBIC) + fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n", + START_POINT (s).x, START_POINT (s).y, + CONTROL1 (s).x, CONTROL1 (s).y, + CONTROL2 (s).x, CONTROL2 (s).y, + END_POINT (s).x, END_POINT (s).y); + + else + FATAL1 ("print_spline: strange degree (%d)", SPLINE_DEGREE (s)); +} + + + + +/* Evaluate the spline S at a given T value. This is an implementation + of de Casteljau's algorithm. See Schneider's thesis (reference in + ../limn/README), p.37. The variable names are taken from there. */ + +real_coordinate_type +evaluate_spline (spline_type s, real t) +{ + spline_type V[4]; /* We need degree+1 splines, but assert degree <= 3. */ + unsigned i, j; + real one_minus_t = 1.0 - t; + polynomial_degree degree = SPLINE_DEGREE (s); + + for (i = 0; i <= degree; i++) + V[0].v[i] = s.v[i]; + + for (j = 1; j <= degree; j++) + for (i = 0; i <= degree - j; i++) + { + real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t); + real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t); + V[j].v[i] = Padd (t1, t2); + } + + return V[degree].v[0]; +} + + + + +/* Return a new, empty, spline list. */ + +spline_list_type * +new_spline_list () +{ + spline_list_type *answer = xmalloc (sizeof (spline_list_type)); + + SPLINE_LIST_DATA (*answer) = NULL; + SPLINE_LIST_LENGTH (*answer) = 0; + + return answer; +} + + +/* Return a new spline list with SPLINE as the first element. */ + +spline_list_type * +init_spline_list (spline_type spline) +{ + spline_list_type *answer = xmalloc (sizeof (spline_list_type)); + + SPLINE_LIST_DATA (*answer) = xmalloc (sizeof (spline_type)); + SPLINE_LIST_ELT (*answer, 0) = spline; + SPLINE_LIST_LENGTH (*answer) = 1; + + return answer; +} + + +/* Free the storage in a spline list. We don't have to free the + elements, since they are arrays in automatic storage. And we don't + want to free the list if it was empty. */ + +void +free_spline_list (spline_list_type *spline_list) +{ + if (SPLINE_LIST_DATA (*spline_list) != NULL) + safe_free ((address *) &(SPLINE_LIST_DATA (*spline_list))); +} + + +/* Append the spline S to the list SPLINE_LIST. */ + +void +append_spline (spline_list_type *l, spline_type s) +{ + assert (l != NULL); + + SPLINE_LIST_LENGTH (*l)++; + SPLINE_LIST_DATA (*l) = xrealloc (SPLINE_LIST_DATA (*l), + SPLINE_LIST_LENGTH (*l) * sizeof (spline_type)); + LAST_SPLINE_LIST_ELT (*l) = s; +} + + +/* Tack the elements in the list S2 onto the end of S1. + S2 is not changed. */ + +void +concat_spline_lists (spline_list_type *s1, spline_list_type s2) +{ + unsigned this_spline; + unsigned new_length; + + assert (s1 != NULL); + + new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2); + + XRETALLOC (SPLINE_LIST_DATA (*s1), new_length, spline_type); + + for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++) + SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++) + = SPLINE_LIST_ELT (s2, this_spline); +} + + + +/* Return a new, empty, spline list array. */ + +spline_list_array_type +new_spline_list_array () +{ + spline_list_array_type answer; + + SPLINE_LIST_ARRAY_DATA (answer) = NULL; + SPLINE_LIST_ARRAY_LENGTH (answer) = 0; + + return answer; +} + + +/* Free the storage in a spline list array. We don't + want to free the list if it is empty. */ + +void +free_spline_list_array (spline_list_array_type *spline_list_array) +{ + unsigned this_list; + + for (this_list = 0; + this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array); + this_list++) + free_spline_list (&SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list)); + + if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL) + safe_free ((address *) &(SPLINE_LIST_ARRAY_DATA (*spline_list_array))); +} + + +/* Append the spline S to the list SPLINE_LIST_ARRAY. */ + +void +append_spline_list (spline_list_array_type *l, spline_list_type s) +{ + SPLINE_LIST_ARRAY_LENGTH (*l)++; + XRETALLOC (SPLINE_LIST_ARRAY_DATA (*l), + SPLINE_LIST_ARRAY_LENGTH (*l), spline_list_type); + LAST_SPLINE_LIST_ARRAY_ELT (*l) = s; +} diff --git a/lib/statistics.c b/lib/statistics.c new file mode 100644 index 0000000..c786ce9 --- /dev/null +++ b/lib/statistics.c @@ -0,0 +1,79 @@ +/* statistics.c: find various statistics. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "statistics.h" + + +/* The mean. The array A might have been filtered (for example), in + which case it will have many zeros in it that shouldn't be counted + when computing the statistics. PERTINENT is the number of elements + that are actually valid. COUNT, on the other hand, is the number of + elements in the array. */ + +real +mean (real *a, unsigned count, unsigned pertinent) +{ + unsigned this_variable; + real sum = 0.0; + + assert (pertinent > 0); + + for (this_variable = 0; this_variable < count; this_variable++) + sum += a[this_variable]; + + return sum / pertinent; +} + + +/* The standard deviation. We have to subtract one from the number of + samples, because we lost a degree of freedom because of the mean. */ + +real +standard_deviation (real *a, real mean, unsigned count, unsigned pertinent) +{ + real sum = 0.0; + int this_variable; + + assert (pertinent > 0); + + for (this_variable = 0; this_variable < count; this_variable++) + { + real x = a[this_variable] - mean; + sum += x * x; + } + + return sqrt (sum / (pertinent > 1 ? (pertinent - 1) : 1)); +} + + +/* Here's a routine to fill up the statistics structure. */ + +statistics_type +statistics (real *data, unsigned data_length, unsigned pertinent) +{ + statistics_type s; + + s.mean = mean (data, data_length, pertinent); + + s.variance = standard_deviation (data, s.mean, data_length, pertinent); + s.variance *= s.variance; + + return s; +} diff --git a/lib/str-lcase.c b/lib/str-lcase.c new file mode 100644 index 0000000..0c21a4c --- /dev/null +++ b/lib/str-lcase.c @@ -0,0 +1,49 @@ +/* str-casefold.c: make a string either all uppercase or all lowercase. + +Copyright (C) 1992 Free Software Foundation, Inc. +This file was part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> +#include "str-lcase.h" + + +/* Return a malloced copy of S with all its uppercase letters replaced + with their lowercase counterparts. S must not be NULL. */ + +string +str_to_lower (string s) +{ + unsigned c; + string lc; + unsigned length; + + assert (s != NULL); + + length = strlen (s); + lc = xmalloc (length + 1); + + for (c = 0; c < length; c++) + lc[c] = ISUPPER (s[c]) ? TOLOWER (s[c]) : s[c]; + + lc[length] = 0; + + return lc; + +} diff --git a/lib/str-to-bit.c b/lib/str-to-bit.c new file mode 100644 index 0000000..83ffa42 --- /dev/null +++ b/lib/str-to-bit.c @@ -0,0 +1,111 @@ +/* str-to-bit.c: typeset a text string in some font, producing a bitmap. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include <kpathsea/c-ctype.h> +#include "font.h" + + +/* Turn the C string TEXT into a bitmap, taking the characters from the + font FONT_NAME at resolution DPI. Any space characters in TEXT turn + into the natural interword space for this font. No escapes are + recognized in TEXT. */ + +bitmap_type +string_to_bitmap (string text, string font_name, unsigned dpi) +{ + bitmap_type b; + unsigned this_char; + char_info_type *chars[strlen (text)]; + font_info_type font = get_font (font_name, dpi); + int width = 0, height = 0, depth = 0; + int x = 0, y = 0; /* Our current position. */ + real tfm_space + = TFM_SAFE_FONTDIMEN (FONT_TFM_FONT (font), TFM_SPACE_PARAMETER, 0); + int font_space = POINTS_TO_PIXELS (tfm_space, dpi); + + for (this_char = 0; this_char < strlen (text); this_char++) + { + /* Turn any kind of space character into a normal interword space. */ + if (ISSPACE (text[this_char])) + width += font_space; + else + { + chars[this_char] = get_char (font_name, text[this_char]); + + /* If the character doesn't exist in this font, just keep + going. */ + if (chars[this_char] == NULL) + continue; + + /* The set width should be equal to the left side bearing plus + the bitmap width plus the right side bearing. */ + width += CHAR_SET_WIDTH (*chars[this_char]); + height = MAX (height, CHAR_HEIGHT (*chars[this_char])); + depth = MAX (depth, CHAR_DEPTH (*chars[this_char])); + } + } + + /* Unless the image is nonnegative both horizontally and vertically, + it is invisible. */ + if (width <= 0 || (height + depth + 1 <= 0)) + { + BITMAP_WIDTH (b) = 0; + BITMAP_HEIGHT (b) = 0; + BITMAP_BITS (b) = NULL; + return b; + } + + /* The image is going to be visible. */ + b = new_bitmap ((dimensions_type) { height + depth + 1, width }); + + for (this_char = 0; this_char < strlen (text); this_char++) + { + if (ISSPACE (text[this_char])) + x += font_space; + else + { + int char_x, char_y; + char_info_type c; + + if (chars[this_char] == NULL) + continue; + + c = *chars[this_char]; + + x += CHAR_LSB (c); + x = MAX (x, 0); /* In case the lsb was negative. */ + + /* Copy the character image to the bitmap we are building, one + column at a time, from top to bottom. */ + for (char_x = 0; char_x < CHAR_BITMAP_WIDTH (c); char_x++, x++) + for (char_y = 0, y = height - CHAR_HEIGHT (c); + char_y < CHAR_BITMAP_HEIGHT (c); + char_y++, y++) + BITMAP_PIXEL (b, y, x) + = BITMAP_PIXEL (CHAR_BITMAP (c), char_y, char_x); + + x += CHAR_RSB (c); + } + } + + close_font (font_name); + + return b; +} diff --git a/lib/strstr.o b/lib/strstr.o Binary files differnew file mode 100644 index 0000000..a882b08 --- /dev/null +++ b/lib/strstr.o diff --git a/lib/substring.c b/lib/substring.c new file mode 100644 index 0000000..8ef7174 --- /dev/null +++ b/lib/substring.c @@ -0,0 +1,50 @@ +/* substring.c: copy a chunk from a string. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Return a fresh copy of SOURCE[START..LIMIT], or NULL if LIMIT<START. + If LIMIT>strlen(START), it is reassigned. */ + +string +substring (string source, const unsigned start, const unsigned limit) +{ + string result; + unsigned this_char; + unsigned length = strlen (source); + unsigned lim = limit; + + /* Upper bound out of range? */ + if (lim >= length) + lim = length - 1; + + /* Null substring? */ + if (start > limit) + return ""; + + /* The `2' here is one for the null and one for limit - start inclusive. */ + result = xmalloc (limit - start + 2); + + for (this_char = start; this_char <= limit; this_char++) + result[this_char - start] = source[this_char]; + + result[this_char - start] = 0; + + return result; +} diff --git a/lib/varstring.c b/lib/varstring.c new file mode 100644 index 0000000..0107abd --- /dev/null +++ b/lib/varstring.c @@ -0,0 +1,97 @@ +/* varstring.c: variable-length strings. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "varstring.h" + + +/* You use variable-length stringsd by calling `init_string' first, then + assigning to particular elements via `set_string_element'. The string + will initially be `INITIAL_SIZE' characters, and be incremented in + blocks of size `INCREMENT_SIZE'. */ + +#define INITIAL_SIZE 16 +#define INCREMENT_SIZE 64 + +variable_string +vs_init () +{ + variable_string vs; + + VS_CHARS (vs) = xmalloc (INITIAL_SIZE); + *VS_CHARS (vs) = 0; + VS_ALLOCATED (vs) = INITIAL_SIZE; + VS_USED (vs) = 0; + + return vs; +} + + +/* Free the data we've allocated for VS. */ + +void +vs_free (variable_string *vs) +{ + free (VS_CHARS (*vs)); + VS_CHARS (*vs) = NULL; +} + + +/* We do not put a NULL after we insert NEW_CHAR at the (zero-based) + index LOC. The caller is responsible for that. */ + +void +vs_set_char (variable_string *vs, unsigned loc, char new_char) +{ + /* Do we need more space? */ + if (loc >= VS_ALLOCATED (*vs)) + { /* Yes. Make sure to allocate enough. */ + unsigned extra = MAX (INCREMENT_SIZE, loc - VS_ALLOCATED (*vs) + 1); + VS_CHARS (*vs) = xrealloc (VS_CHARS (*vs), VS_ALLOCATED (*vs) + extra); + VS_ALLOCATED (*vs) += extra; + } + + VS_CHARS (*vs)[loc] = new_char; + VS_USED (*vs) = loc + 1; +} + + +/* Append NEW_CHAR to VS. */ + +void +vs_append_char (variable_string *vs, char new_char) +{ + vs_set_char (vs, VS_USED (*vs), new_char); +} + + +variable_string +vs_concat (variable_string vs1, variable_string vs2) +{ + variable_string vs; + unsigned used = VS_USED (vs1) + VS_USED (vs2); + + VS_CHARS (vs) = xmalloc (used + 1); + memcpy (VS_CHARS (vs), VS_CHARS (vs1), VS_USED (vs1)); + memcpy (VS_CHARS (vs) + VS_USED (vs1), VS_CHARS (vs2), VS_USED (vs2)); + VS_ALLOCATED (vs) = used + 1; + VS_USED (vs) = used; + + return vs; +} diff --git a/lib/vector.c b/lib/vector.c new file mode 100644 index 0000000..354af2d --- /dev/null +++ b/lib/vector.c @@ -0,0 +1,272 @@ +/* vector.c: vector/point operations. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "vector.h" + + +/* Given the point COORD, return the corresponding vector. */ + +const vector_type +make_vector (const real_coordinate_type c) +{ + vector_type v; + + v.dx = c.x; + v.dy = c.y; + + return v; +} + + +/* And the converse: given a vector, return the corresponding point. */ + +const real_coordinate_type +vector_to_point (const vector_type v) +{ + real_coordinate_type coord; + + coord.x = v.dx; + coord.y = v.dy; + + return coord; +} + + + +const real +magnitude (const vector_type v) +{ + return hypot (v.dx, v.dy); +} + + +const vector_type +normalize (const vector_type v) +{ + vector_type new_v; + real m = magnitude (v); + + assert (m > 0.0); + + new_v.dx = v.dx / m; + new_v.dy = v.dy / m; + + return new_v; +} + + +const vector_type +Vadd (const vector_type v1, const vector_type v2) +{ + vector_type new_v; + + new_v.dx = v1.dx + v2.dx; + new_v.dy = v1.dy + v2.dy; + + return new_v; +} + + +const real +Vdot (const vector_type v1, const vector_type v2) +{ + return v1.dx * v2.dx + v1.dy * v2.dy; +} + + +const vector_type +Vmult_scalar (const vector_type v, const real r) +{ + vector_type new_v; + + new_v.dx = v.dx * r; + new_v.dy = v.dy * r; + + return new_v; +} + + +/* Given the IN_VECTOR and OUT_VECTOR, return the angle between them in + degrees, in the range zero to 180. */ + +const real +Vangle (const vector_type in_vector, const vector_type out_vector) +{ + vector_type v1 = normalize (in_vector); + vector_type v2 = normalize (out_vector); + + return acosd (Vdot (v2, v1)); +} + + +const real_coordinate_type +Vadd_point (const real_coordinate_type c, const vector_type v) +{ + real_coordinate_type new_c; + + new_c.x = c.x + v.dx; + new_c.y = c.y + v.dy; + return new_c; +} + + +const real_coordinate_type +Vsubtract_point (const real_coordinate_type c, const vector_type v) +{ + real_coordinate_type new_c; + + new_c.x = c.x - v.dx; + new_c.y = c.y - v.dy; + return new_c; +} + + +const coordinate_type +Vadd_int_point (const coordinate_type c, const vector_type v) +{ + coordinate_type a; + + a.x = ROUND ((real) c.x + v.dx); + a.y = ROUND ((real) c.y + v.dy); + return a; +} + + +const vector_type +Vabs (const vector_type v) +{ + vector_type new_v; + + new_v.dx = fabs (v.dx); + new_v.dy = fabs (v.dy); + return new_v; +} + + + +/* Operations on points. */ + +/* This is a macro now. */ +#if 0 +const real_coordinate_type +Padd (real_coordinate_type coord1, real_coordinate_type coord2) +{ + real_coordinate_type sum; + + sum.x = coord1.x + coord2.x; + sum.y = coord1.y + coord2.y; + + return sum; +} + + +const real_coordinate_type +Pmult_scalar (const real_coordinate_type coord, const real r) +{ + real_coordinate_type answer; + + answer.x = coord.x * r; + answer.y = coord.y * r; + + return answer; +} +#endif /* 0 */ + + +const vector_type +Psubtract (const real_coordinate_type c1, const real_coordinate_type c2) +{ + vector_type v; + + v.dx = c1.x - c2.x; + v.dy = c1.y - c2.y; + + return v; +} + + + +/* Operations on integer points. */ + +const vector_type +IPsubtract (const coordinate_type coord1, const coordinate_type coord2) +{ + vector_type v; + + v.dx = coord1.x - coord2.x; + v.dy = coord1.y - coord2.y; + + return v; +} + + +const coordinate_type +IPsubtractP (const coordinate_type c1, const coordinate_type c2) +{ + coordinate_type c; + + c.x = c1.x - c2.x; + c.y = c1.y - c2.y; + + return c; +} + + +const coordinate_type +IPadd (const coordinate_type c1, const coordinate_type c2) +{ + coordinate_type c; + + c.x = c1.x + c2.x; + c.y = c1.y + c2.y; + + return c; +} + + +const coordinate_type +IPmult_scalar (const coordinate_type c, const int i) +{ + coordinate_type a; + + a.x = c.x * i; + a.y = c.y * i; + + return a; +} + + +const real_coordinate_type +IPmult_real (const coordinate_type c, const real r) +{ + real_coordinate_type a; + + a.x = c.x * r; + a.y = c.y * r; + + return a; +} + + +const boolean +IPequal (const coordinate_type c1, const coordinate_type c2) +{ + return c1.x == c2.x && c1.y == c2.y; +} diff --git a/lib/xchdir.c b/lib/xchdir.c new file mode 100644 index 0000000..9831663 --- /dev/null +++ b/lib/xchdir.c @@ -0,0 +1,29 @@ +/* xchdir.c: chdir with error checking. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "dirio.h" + + +void +xchdir (string dirname) +{ + if (chdir (dirname) != 0) + FATAL_PERROR (dirname); +} diff --git a/lib/xfseek.o b/lib/xfseek.o Binary files differnew file mode 100644 index 0000000..fc2e725 --- /dev/null +++ b/lib/xfseek.o diff --git a/lib/xftell.o b/lib/xftell.o Binary files differnew file mode 100644 index 0000000..0dfe6f8 --- /dev/null +++ b/lib/xftell.o diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c new file mode 100644 index 0000000..8f3e4a9 --- /dev/null +++ b/lib/xgetcwd.c @@ -0,0 +1,104 @@ +/* xgetcwd.c: a from-scratch version of getwd. Based on the tcsh 5.20 + source, apparently uncopyrighted. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "c-pathmx.h" + +#include "dirio.h" +#include "xstat.h" + +/* Return the pathname of the current directory, or give a fatal error. */ + +string +xgetcwd () +{ + /* If the system provides getwd, use it. But don't use getcwd; + forking a process is even more expensive than all the stat calls we + make figuring out the cwd. */ +#ifdef GETWD_MISSING /* whole function */ + struct stat root_stat, cwd_stat; + string cwd_path = xmalloc (1); + + *cwd_path = 0; + + /* Find the inodes of the root and current directories. */ + root_stat = xstat ("/"); + cwd_stat = xstat ("."); + + /* Go up the directory hierarchy until we get to root, prepending each + directory we pass through to `cwd_path'. */ + while (!SAME_FILE_P (root_stat, cwd_stat)) + { + struct dirent *e; + DIR *parent_dir; + boolean found = false; + + xchdir (".."); + parent_dir = xopendir ("."); + + /* Look through the parent directory for the entry with the same + inode, so we can get its name. */ + while ((e = readdir (parent_dir)) != NULL && !found) + { + struct stat test_stat = xlstat (e->d_name); + + if (SAME_FILE_P (test_stat, cwd_stat)) + { + /* We've found it. Prepend the pathname. */ + string temp = cwd_path; + cwd_path = concat3 ("/", e->d_name, cwd_path); + free (temp); + + /* Set up to test the next parent. */ + cwd_stat = xstat ("."); + + /* Stop reading this directory. */ + found = true; + } + } + if (!found) + FATAL2 ("No inode %d/device %d in parent directory", + cwd_stat.st_ino, cwd_stat.st_dev); + + xclosedir (parent_dir); + } + + /* If the current directory is the root, cwd_path will be the empty + string, and we will have not gone through the loop. */ + if (*cwd_path == 0) + cwd_path = "/"; + else + /* Go back to where we were. */ + xchdir (cwd_path); + + return cwd_path; + +#else /* not GETWD_MISSING */ + + string path = xmalloc (PATH_MAX + 1); + + if (getwd (path) == 0) + { + fprintf (stderr, "getwd: %s", path); + exit (1); + } + + return path; +#endif /* not GETWD_MISSING */ +} diff --git a/lib/xmessage.c b/lib/xmessage.c new file mode 100644 index 0000000..1b8331a --- /dev/null +++ b/lib/xmessage.c @@ -0,0 +1,101 @@ +/* xmessage.c: pop up a message for five seconds and then go away. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef X_DISPLAY_MISSING /* whole file */ + +#include "config.h" + +#include "xt-common.h" +#include <X11/Shell.h> +#include <X11/Xaw/Label.h> + +#include "xmessage.h" + +static void message_over (XtPointer, XtIntervalId *); + + + +/* Make a popup child of the widget PARENT displaying the string S. We + pass the ARGS and N_ARGS parameters to the creation routine. */ + +void +x_message (Widget parent, string s, ArgList args, Cardinal n_args) +{ + Dimension parent_height; + Position popup_x, popup_y; + Widget popup; + + XtAppContext app_con = XtWidgetToApplicationContext (parent); + Arg parent_args[] + = { { XtNheight, (XtArgVal) &parent_height }, + }; + Arg popup_args[] + = { { XtNx, 0 }, /* We assign to the position below. */ + { XtNy, 0 }, + { XtNgeometry, (XtArgVal) NULL }, /* Don't use parent's geometry. */ + }; + + Arg default_args[] = { { XtNlabel, (XtArgVal) s } }; + ArgList all_args + = XtMergeArgLists (args, n_args, default_args, XtNumber (default_args)); + + /* Put the message at the left edge of and about halfway down PARENT's + window. We pass the address of true Position variables rather + than the address of the Arg values; in the latter case, the + endianness of the computer determines which half of the word the + answers get stored in, which is clearly bad. */ + XtGetValues (parent, parent_args, XtNumber (parent_args)); + XtTranslateCoords (parent, 0, parent_height / 2, &popup_x, &popup_y); + popup_args[0].value = popup_x; + popup_args[1].value = popup_y; + + popup = XtCreatePopupShell ("message shell", transientShellWidgetClass, + parent, popup_args, XtNumber (popup_args)); + + /* We can't use XtNumber on `all_args', since it's a pointer. */ + (void) + XtCreateManagedWidget ("message", labelWidgetClass, popup, all_args, + n_args + XtNumber (default_args)); + + /* XtPopup realizes the window, etc. */ + XtPopup (popup, XtGrabNone); + + /* Leave the message there for five seconds. */ + (void) XtAppAddTimeOut (app_con, 5000, message_over, popup); +} + + +/* Just a convenient interface to the above. */ + +void +x_warning (Widget parent, string s) +{ + x_message (parent, concat (s, "."), NULL, 0); +} + + + +static void +message_over (XtPointer client_data, XtIntervalId *interval_id) +{ + Widget popup = (Widget) client_data; + + XtPopdown (popup); +} + +#endif /* not X_DISPLAY_MISSING */ diff --git a/lib/xopendir.c b/lib/xopendir.c new file mode 100644 index 0000000..02709ac --- /dev/null +++ b/lib/xopendir.c @@ -0,0 +1,47 @@ +/* xopendir.c: opendir and closedir with error checking. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "dirio.h" + + +DIR * +xopendir P1C(string, dirname) +{ + DIR *d = opendir (dirname); + + if (d == NULL) + FATAL_PERROR (dirname); + + return d; +} + + +void +xclosedir P1C(DIR *, d) +{ +#ifdef VOID_CLOSEDIR + closedir (d); +#else + int ret = closedir (d); + + if (ret != 0) + FATAL ("closedir failed"); +#endif +} diff --git a/lib/xrename.c b/lib/xrename.c new file mode 100644 index 0000000..c840805 --- /dev/null +++ b/lib/xrename.c @@ -0,0 +1,44 @@ +/* xrename.c: conceptually rename with error checking. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Copy FROM to TO, then unlink FROM. It would probably be faster to + read and write buffers, but the files we use this for aren't big + enough for it to make a substantial difference. */ + +void +xrename (string from, string to) +{ + int c; + FILE *input = xfopen (from, "r"); + FILE *output = xfopen (to, "w"); + + while ((c = getc (input)) != EOF || !feof (input)) + putc (c, output); + + xfclose (input, from); + xfclose (output, to); + + if (unlink (from) != 0) + { + fprintf (stderr, "warning: Could not unlink "); + perror (from); + } +} diff --git a/lib/xstrdup.c b/lib/xstrdup.c new file mode 100644 index 0000000..3ce69e9 --- /dev/null +++ b/lib/xstrdup.c @@ -0,0 +1,29 @@ +/* xstrdup.c: strdup with error checking. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + + +/* Return a copy of S in new storage. */ + +string +xstrdup P1C(string, s) +{ + string new_string = (string) xmalloc (strlen (s) + 1); + return strcpy (new_string, s); +} diff --git a/pbm/ChangeLog b/pbm/ChangeLog new file mode 100644 index 0000000..65afe89 --- /dev/null +++ b/pbm/ChangeLog @@ -0,0 +1,41 @@ +Sat Aug 7 11:51:41 1993 Karl Berry (karl@cs.umb.edu) + + * libpbm1.c: c-ctype.h now in kpathsea. + +Fri Dec 11 15:06:54 1992 Karl Berry (karl@cs.umb.edu) + + * libpbm1.c (pm_keymatch): Change ctype references to use + uppercase macros. + +Tue Oct 27 12:56:21 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Tue Sep 15 08:39:17 1992 Karl Berry (karl@hayley) + + * libpbm1.c (malloc, free, exit): don't declare these, rely on + config.h. + +Thu Sep 3 09:31:14 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Wed Apr 15 09:01:07 1992 Karl Berry (karl@hayley) + + * pbmascii.c: new file for debugging. + +Sat Mar 28 07:49:22 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Sat Mar 7 10:00:47 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files, headers, sources): replace with `c_and_h', etc. + + * libpbm1.c: use #if __STDC__, not #ifdef. + +Thu Mar 5 07:53:37 1992 Karl Berry (karl at hayley) + + * Created. diff --git a/pbm/GNUmakefile b/pbm/GNUmakefile new file mode 100644 index 0000000..3d970e5 --- /dev/null +++ b/pbm/GNUmakefile @@ -0,0 +1,27 @@ +# Makefile for (part of) Jef Poskanzer's PBM library. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +library = pbm + +h_only = libpbm +c_only = libpbm1 libpbm2 libpbm4 + +include ../data/defs.make +include ../data/defslib.make + +include M.depend diff --git a/pbm/README b/pbm/README new file mode 100644 index 0000000..f7e0f64 --- /dev/null +++ b/pbm/README @@ -0,0 +1,2 @@ +These are some of the files from Jef Poskanzer's PBM library. They are +essentially unmodified. diff --git a/pbm/libpbm.h b/pbm/libpbm.h new file mode 100644 index 0000000..7b80f2f --- /dev/null +++ b/pbm/libpbm.h @@ -0,0 +1,18 @@ +/* libpbm.h - internal header file for libpbm portable bitmap library +*/ + +#ifndef _LIBPBM_H_ +#define _LIBPBM_H_ + +/* Here are some routines internal to the pbm library. */ + +char pbm_getc ARGS(( FILE* file )); +unsigned char pbm_getrawbyte ARGS(( FILE* file )); +int pbm_getint ARGS(( FILE* file )); + +int pbm_readmagicnumber ARGS(( FILE* file )); + +void pbm_readpbminitrest ARGS(( FILE* file, int* colsP, int* rowsP )); + +#endif /*_LIBPBM_H_*/ + diff --git a/pbm/libpbm1.c b/pbm/libpbm1.c new file mode 100644 index 0000000..5b8258a --- /dev/null +++ b/pbm/libpbm1.c @@ -0,0 +1,449 @@ +/* libpbm1.c - pbm utility library part 1 +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +** Minor configuration changes for GNU --karl. +*/ + +#include "pbm.h" +#include "libpbm.h" + +#include <kpathsea/c-ctype.h> +#include <varargs.h> + +#if 0 /* karl */ +extern char *malloc (); +extern void free (); +extern void exit (); +#endif + +/* Variable-sized arrays. */ + +char* +pm_allocrow( cols, size ) + int cols, size; + { + register char* itrow; + + itrow = (char*) malloc( cols * size ); + if ( itrow == (char*) 0 ) + pm_error( "out of memory allocating a row", 0,0,0,0,0 ); + return itrow; + } + +void +pm_freerow( itrow ) + char* itrow; + { + free( itrow ); + } + + +char** +pm_allocarray( cols, rows, size ) + int cols, rows; + int size; + { + char** its; + int i; + + its = (char**) malloc( rows * sizeof(char*) ); + if ( its == (char**) 0 ) + pm_error( "out of memory allocating an array", 0,0,0,0,0 ); + its[0] = (char*) malloc( rows * cols * size ); + if ( its[0] == (char*) 0 ) + pm_error( "out of memory allocating an array", 0,0,0,0,0 ); + for ( i = 1; i < rows; ++i ) + its[i] = &(its[0][i * cols * size]); + return its; + } + +void +pm_freearray( its, rows ) + char** its; + int rows; + { + free( its[0] ); + free( its ); + } + + +/* Case-insensitive keyword matcher. */ + +int +pm_keymatch( str, keyword, minchars ) + char* str; + char* keyword; + int minchars; + { + register int len; + + len = strlen( str ); + if ( len < minchars ) + return 0; + while ( --len >= 0 ) + { + register char c1, c2; + + c1 = *str++; + c2 = *keyword++; + if ( c2 == '\0' ) + return 0; + if ( ISUPPER( c1 ) ) + c1 = TOLOWER( c1 ); + if ( ISUPPER( c2 ) ) + c1 = TOLOWER( c2 ); + if ( c1 != c2 ) + return 0; + } + return 1; + } + + +/* Log base two hacks. */ + +int +pm_maxvaltobits( maxval ) + int maxval; + { + if ( maxval <= 1 ) + return 1; + else if ( maxval <= 3 ) + return 2; + else if ( maxval <= 7 ) + return 3; + else if ( maxval <= 15 ) + return 4; + else if ( maxval <= 31 ) + return 5; + else if ( maxval <= 63 ) + return 6; + else if ( maxval <= 127 ) + return 7; + else if ( maxval <= 255 ) + return 8; + else if ( maxval <= 511 ) + return 9; + else if ( maxval <= 1023 ) + return 10; + else if ( maxval <= 2047 ) + return 11; + else if ( maxval <= 4095 ) + return 12; + else if ( maxval <= 8191 ) + return 13; + else if ( maxval <= 16383 ) + return 14; + else if ( maxval <= 32767 ) + return 15; + else if ( maxval <= 65535 ) + return 16; + else + pm_error( "maxval of %d is too large!", maxval, 0,0,0,0 ); + return 0; /* Avoid dumb warning. */ + } + +int +pm_bitstomaxval( bits ) + int bits; + { + return ( 1 << bits ) - 1; + } + + +/* Initialization. */ + +static char* pm_progname; + +void +pm_init( argcP, argv ) + int* argcP; + char* argv[]; + { + pm_progname = rindex( argv[0], '/'); + if ( pm_progname == NULL ) + pm_progname = argv[0]; + else + ++pm_progname; + } + +void +pbm_init( argcP, argv ) + int* argcP; + char* argv[]; + { + pm_init( argcP, argv ); + } + +/* Error handling. */ + +/* I'd use varargs here, but it can't be done portably, because (a) vfprintf() +** is not very widespread, and (b) varargs itself is not powerful enough to +** allow me to include a portable vfprintf(). +** +** So instead, we have the gross hack of a fixed number of args. It's not +** even clear how portable this hack is, but it does seem to work everywhere +** I've tried it. +*/ + +void +pm_message( fmt, v1, v2, v3, v4, v5 ) + char* fmt; + char *v1, *v2, *v3, *v4, *v5; + { + fprintf( stderr, "%s: ", pm_progname ); + fprintf( stderr, fmt, v1, v2, v3, v4, v5 ); + fputc( '\n', stderr ); + } + +void +pm_error( fmt, v1, v2, v3, v4, v5 ) + char* fmt; + char *v1, *v2, *v3, *v4, *v5; + { + pm_message( fmt, v1, v2, v3, v4, v5 ); + exit( 1 ); + } + +void +pm_perror( reason ) + char* reason; + { + extern char* sys_errlist[]; + extern int errno; + char* e; + + e = sys_errlist[errno]; + + if ( reason != 0 && reason[0] != '\0' ) + pm_error( "%s - %s", reason, e, 0,0,0 ); + else + pm_error( "%s", e, 0,0,0,0 ); + } + +void +pm_usage( usage ) + char* usage; + { + fprintf( stderr, "usage: %s %s\n", pm_progname, usage ); + exit( 1 ); + } + + +/* File open/close that handles "-" as stdin and checks errors. */ + +FILE* +pm_openr( name ) + char* name; + { + FILE* f; + + if ( strcmp( name, "-" ) == 0 ) + f = stdin; + else + { +#ifdef MSDOS + f = fopen( name, "rb" ); +#else /*MSDOS*/ + f = fopen( name, "r" ); +#endif /*MSDOS*/ + if ( f == NULL ) + { + pm_perror( name ); + exit( 1 ); + } + } + return f; + } + +FILE* +pm_openw( name ) + char* name; + { + FILE* f; + +#ifdef MSDOS + f = fopen( name, "wb" ); +#else /*MSDOS*/ + f = fopen( name, "w" ); +#endif /*MSDOS*/ + if ( f == NULL ) + { + pm_perror( name ); + exit( 1 ); + } + return f; + } + +void +pm_close( f ) + FILE* f; + { + if ( f != stdin ) + if ( fclose( f ) != 0 ) + pm_perror( "fclose" ); + } + +/* Broken putc() fix. */ + +#ifdef PBMPLUS_BROKENPUTC2 +int +putc( c, stream ) + char c; + FILE* stream; + { + return fwrite( &c, 1, 1, stream ) == 1 ? c : EOF; + } +#endif /*PBMPLUS_BROKENPUTC2*/ + +/* Endian I/O. +*/ + +int +pm_readbigshort( in, sP ) + FILE* in; + short* sP; + { + int c; + + if ( (c = getc( in )) == EOF ) + return -1; + *sP = ( c & 0xff ) << 8; + if ( (c = getc( in )) == EOF ) + return -1; + *sP |= c & 0xff; + return 0; + } + +#if __STDC__ +int +pm_writebigshort( FILE* out, short s ) +#else /*not __STDC__*/ +int +pm_writebigshort( out, s ) + FILE* out; + short s; +#endif /*not __STDC__*/ + { + if ( putc( ( s >> 8 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( s & 0xff, out ) == EOF ) + return -1; + return 0; + } + +int +pm_readbiglong( in, lP ) + FILE* in; + long* lP; + { + int c; + + if ( (c = getc( in )) == EOF ) + return -1; + *lP = ( c & 0xff ) << 24; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= ( c & 0xff ) << 16; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= ( c & 0xff ) << 8; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= c & 0xff; + return 0; + } + +int +pm_writebiglong( out, l ) + FILE* out; + long l; + { + if ( putc( ( l >> 24 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( ( l >> 16 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( ( l >> 8 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( l & 0xff, out ) == EOF ) + return -1; + return 0; + } + +int +pm_readlittleshort( in, sP ) + FILE* in; + short* sP; + { + int c; + + if ( (c = getc( in )) == EOF ) + return -1; + *sP = c & 0xff; + if ( (c = getc( in )) == EOF ) + return -1; + *sP |= ( c & 0xff ) << 8; + return 0; + } + +#if __STDC__ +int +pm_writelittleshort( FILE* out, short s ) +#else /*not __STDC__*/ +int +pm_writelittleshort( out, s ) + FILE* out; + short s; +#endif /*not __STDC__*/ + { + if ( putc( s & 0xff, out ) == EOF ) + return -1; + if ( putc( ( s >> 8 ) & 0xff, out ) == EOF ) + return -1; + return 0; + } + +int +pm_readlittlelong( in, lP ) + FILE* in; + long* lP; + { + int c; + + if ( (c = getc( in )) == EOF ) + return -1; + *lP = c & 0xff; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= ( c & 0xff ) << 8; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= ( c & 0xff ) << 16; + if ( (c = getc( in )) == EOF ) + return -1; + *lP |= ( c & 0xff ) << 24; + return 0; + } + +int +pm_writelittlelong( out, l ) + FILE* out; + long l; + { + if ( putc( l & 0xff, out ) == EOF ) + return -1; + if ( putc( ( l >> 8 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( ( l >> 16 ) & 0xff, out ) == EOF ) + return -1; + if ( putc( ( l >> 24 ) & 0xff, out ) == EOF ) + return -1; + return 0; + } diff --git a/pbm/libpbm2.c b/pbm/libpbm2.c new file mode 100644 index 0000000..afae0dc --- /dev/null +++ b/pbm/libpbm2.c @@ -0,0 +1,134 @@ +/* libpbm2.c - pbm utility library part 2 +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include "pbmplus.h" +#include "pbm.h" +#include "libpbm.h" + +static bit +pbm_getbit( file ) + FILE* file; + { + register char ch; + + do + { + ch = pbm_getc( file ); + } + while ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' ); + + if ( ch != '0' && ch != '1' ) + pm_error( "junk in file where bits should be", 0,0,0,0,0 ); + + return ( ch == '1' ) ? 1 : 0; + } + +int +pbm_readmagicnumber( file ) + FILE* file; + { + int ich1, ich2; + + ich1 = getc( file ); + if ( ich1 == EOF ) + pm_error( "EOF / read error reading magic number", 0,0,0,0,0 ); + ich2 = getc( file ); + if ( ich2 == EOF ) + pm_error( "EOF / read error reading magic number", 0,0,0,0,0 ); + return ich1 * 256 + ich2; + } + +void +pbm_readpbminitrest( file, colsP, rowsP ) + FILE* file; + int* colsP; + int* rowsP; + { + /* Read size. */ + *colsP = pbm_getint( file ); + *rowsP = pbm_getint( file ); + } + +void +pbm_readpbminit( file, colsP, rowsP, formatP ) + FILE* file; + int* colsP; + int* rowsP; + int* formatP; + { + /* Check magic number. */ + *formatP = pbm_readmagicnumber( file ); + switch ( PBM_FORMAT_TYPE(*formatP) ) + { + case PBM_TYPE: + pbm_readpbminitrest( file, colsP, rowsP ); + break; + + default: + pm_error( "bad magic number - not a pbm file", 0,0,0,0,0 ); + } + } + +void +pbm_readpbmrow( file, bitrow, cols, format ) + FILE* file; + bit* bitrow; + int cols, format; + { + register int col, bitshift; + register unsigned char item; + register bit* bP; + + switch ( format ) + { + case PBM_FORMAT: + for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) + *bP = pbm_getbit( file ); + break; + + case RPBM_FORMAT: + bitshift = -1; + for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) + { + if ( bitshift == -1 ) + { + item = pbm_getrawbyte( file ); + bitshift = 7; + } + *bP = ( item >> bitshift ) & 1; + --bitshift; + } + break; + + default: + pm_error( "can't happen", 0,0,0,0,0 ); + } + } + +bit** +pbm_readpbm( file, colsP, rowsP ) + FILE* file; + int* colsP; + int* rowsP; + { + register bit** bits; + int format, row; + + pbm_readpbminit( file, colsP, rowsP, &format ); + + bits = pbm_allocarray( *colsP, *rowsP ); + + for ( row = 0; row < *rowsP; ++row ) + pbm_readpbmrow( file, bits[row], *colsP, format ); + + return bits; + } diff --git a/pbm/libpbm4.c b/pbm/libpbm4.c new file mode 100644 index 0000000..7a74424 --- /dev/null +++ b/pbm/libpbm4.c @@ -0,0 +1,80 @@ +/* libpbm4.c - pbm utility library part 4 +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include "pbm.h" +#include "libpbm.h" + +char +pbm_getc( file ) + FILE* file; + { + register int ich; + register char ch; + + ich = getc( file ); + if ( ich == EOF ) + pm_error( "EOF / read error", 0,0,0,0,0 ); + ch = (char) ich; + + if ( ch == '#' ) + { + do + { + ich = getc( file ); + if ( ich == EOF ) + pm_error( "EOF / read error", 0,0,0,0,0 ); + ch = (char) ich; + } + while ( ch != '\n' ); + } + + return ch; + } + +unsigned char +pbm_getrawbyte( file ) + FILE* file; + { + register int iby; + + iby = getc( file ); + if ( iby == EOF ) + pm_error( "EOF / read error", 0,0,0,0,0 ); + return (unsigned char) iby; + } + +int +pbm_getint( file ) + FILE* file; + { + register char ch; + register int i; + + do + { + ch = pbm_getc( file ); + } + while ( ch == ' ' || ch == '\t' || ch == '\n' ); + + if ( ch < '0' || ch > '9' ) + pm_error( "junk in file where an integer should be", 0,0,0,0,0 ); + + i = 0; + do + { + i = i * 10 + ch - '0'; + ch = pbm_getc( file ); + } + while ( ch >= '0' && ch <= '9' ); + + return i; + } diff --git a/pbm/pbmascii b/pbm/pbmascii Binary files differnew file mode 100755 index 0000000..ffa329c --- /dev/null +++ b/pbm/pbmascii diff --git a/pbm/pbmascii.c b/pbm/pbmascii.c new file mode 100644 index 0000000..945190e --- /dev/null +++ b/pbm/pbmascii.c @@ -0,0 +1,37 @@ +/* pbmascii -- dump a PBM file (from stdin) on stdout. */ + +#include <stdio.h> +#include <stdlib.h> + +int +main (int argc, char *argv[]) +{ + int width, height, format; + unsigned row; + unsigned char *image_row; + + pbm_readpbminit (stdin, &width, &height, &format); + + image_row = malloc (width); + + for (row = 0; row < height; row++) + { + int c; + + pbm_readpbmrow (stdin, image_row, width, format); + + printf ("%5d:", row); + for (c = 0; c < width; c++) + putchar (image_row[c] ? '*' : ' '); + putchar ('\n'); + } + + return 0; +} + + +/* +Local variables: +compile-command: "gcc -g -posix -o pbmascii pbmascii.c pbm.a" +End: +*/ diff --git a/pk/ChangeLog b/pk/ChangeLog new file mode 100644 index 0000000..9ee8f4d --- /dev/null +++ b/pk/ChangeLog @@ -0,0 +1,138 @@ +Tue Oct 27 12:56:27 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Thu Sep 3 09:31:18 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Sat Jun 13 11:45:30 1992 Karl Berry (karl@hayley) + + * pk_input.c: change for new names of list fns. + +Sat Mar 28 07:49:27 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Sat Mar 7 14:07:52 1992 Karl Berry (karl at fosse) + + * pk_input.c: complete prototypes for static fns. + +Sat Mar 7 11:16:20 1992 Karl Berry (karl at hayley) + + * GNUmakefile (files, headers, sources): replace with `c_and_h', etc. + +Thu Jan 9 08:29:21 1992 Karl Berry (karl at hayley) + + * *.c: do not include global.h. + + * *.h: remove #pragma once. + +Wed Jan 8 15:05:33 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + +Tue Jul 30 13:19:47 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Sat Jun 15 09:53:33 1991 Karl Berry (karl at hayley) + + * all files: change `checked_' to `x'. + +Thu Jun 6 07:31:28 1991 Karl Berry (karl at hayley) + + * All files: change to version 2 of the GPL. + +Thu Mar 7 07:33:24 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Mon Mar 4 15:00:02 1991 Karl Berry (karl at hayley) + + * pk_input.c: doc fix. + +Mon Feb 25 16:04:52 1991 Karl Berry (karl at hayley) + + * pk_input.c: use `pk_...' instead of `..._pk_...'. + +Sun Feb 17 09:48:32 1991 Karl Berry (karl at hayley) + + * pk_input.c: include config.h. + +Sat Nov 17 12:52:59 1990 Karl Berry (karl at hayley) + + * pk_input.c: include appropriate file-...h files. + +Sat Sep 29 09:01:25 1990 Karl Berry (karl at hayley) + + * pk_input.c (find_internal_font): return null at the end. + +Sun Sep 9 12:37:53 1990 Karl Berry (karl at hayley) + + * pk_input.c (pk_get_string): append a trailing null to the + string. + +Wed Aug 29 14:23:26 1990 Karl Berry (karl at hayley) + + * pk_input.c (pk_get_byte, ...): add the filename argument, and + rewrite as macros. + +Sat Aug 25 13:42:42 1990 Karl Berry (karl at hayley) + + * pk_input.c (get_bitmap): ignore bits remaining in the last byte. + +Wed May 30 15:32:37 1990 Karl Berry (karl at hayley) + + * pk_input.c (get_one_pk_char): give a better error message if the + character code is out of range; allow for it to be negative. + +Wed May 2 12:14:57 1990 Karl Berry (karl at claude) + + * pk_input.c (delete_internal_font): new routine. + (close_pk_input_file): call it, instead of doing the work here. + +Sun Apr 22 07:04:07 1990 Karl Berry (karl at hayley) + + * pk_input.c (unpack): off by one in calculation of the minimum row. + +Tue Apr 17 07:17:33 1990 Karl Berry (karl at hayley) + + * pk_input.c (pk_get_two): new routine. + (get_one_pk_char): call it to get the packet length in the + extended short format. + + * pk_input.c (unpack): get the h and v_offset values as signed + numbers. + + * pk_input.c: make `do_upper_nybble' visible to the file, so that + we can set it to true before reading each character. + +Mon Apr 16 16:53:36 1990 Karl Berry (karl at hayley) + + * pk_input.c (get_packed_bitmap): don't overwrite the repeat count + for a row on a subsequent run count. + + * pk_input.c (get_run_count): forgot to initialize *repeat_count + to zero, and to only look for it once. + + * pk_input.c (data_get_nybble): returned the upper nybble when we + wanted the lower, and vice versa. + + * pk_input.c (get_one_pk_char): tested wrong bit to see which + preamble format we were supposed to read. + + * pk_input.c (get_one_pk_char): allocate the space for each packed + character before we fill it in. + + * pk_input.c (get_one_pk_char): the flag byte has already been + read; get it as a parameter, not by reading it from the file. + + * pk_input.c (get_all_pk_chars): test for a non-command first, + since that is so common. And give a fatal error if we hit a + command that isn't undefined. diff --git a/pk/GNUmakefile b/pk/GNUmakefile new file mode 100644 index 0000000..2845c19 --- /dev/null +++ b/pk/GNUmakefile @@ -0,0 +1,26 @@ +# Makefile for the PK library. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +library = pk + +c_only = pk_input + +include ../data/defs.make +include ../data/defslib.make + +include M.depend diff --git a/pk/README b/pk/README new file mode 100644 index 0000000..6677bca --- /dev/null +++ b/pk/README @@ -0,0 +1,13 @@ +This library provides for reading of packed font (PK) bitmap files. An +arbitrary number of fonts may be read simultaneously. Routines to write +a PK file have not been written; instead, use the TeX utility routine +gftopk. + +None of the code that processes the PK commands actually explains what +the precise definition of those commands are. For that, you should look +at the definition of the PK format in the TeX utility programs that +convert to and from PK format. + +The header file is ../include/pk.h. It explains the basics of how to +use the routines. The source files in this directory do not repeat that +explanation. diff --git a/pk/pk_input.c b/pk/pk_input.c new file mode 100644 index 0000000..de5599e --- /dev/null +++ b/pk/pk_input.c @@ -0,0 +1,729 @@ +/* pk_input.c: read from any number of PK files. The basic idea is to + read the entire file into memory the first time the client asks for a + character. Since PK files tend to be quite small, this does not use + an enormous amount of memory. But we only bother to unpack a + character's bitmap when the client asks for that particular + character. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" +#include "list.h" +#include "pk.h" +#include "pk_opcodes.h" + + +/* The `packed_char_type' structure holds the character description, + taken directly from the input file, before it is unpacked into a + bitmap. This type is only used as part of the `internal_font_type' + structure, above. (In contrast, the `pk_char_type' structure holds + the unpacked information, in the form convenient for clients.) */ + +typedef struct +{ + unsigned dyn_f : 4; + unsigned black_first : 1; + unsigned parameter_length : 3; + unsigned packet_length; + one_byte *data; +} packed_char_type; + +/* This is the number of one-nybble run counts. It is at most 14. */ +#define PACKED_DYN_F(c) ((c).dyn_f) + +/* This says whether the first run count is black or white. */ +#define PACKED_BLACK_FIRST(c) ((c).black_first) + +/* This says how long the size parameters in the character preamble are. + It is either 1, 2, or 4. Either 1 or 2 means we're using a ``short + format''; 4 means we're using the ``long format''. */ +#define PACKED_PARAM_LENGTH(c) ((c).parameter_length) +#define LONG_FORMAT(c) (PACKED_PARAM_LENGTH (c) == 4) + +/* This is the length of the packed character data, in bytes. */ +#define PACKED_DATA_LENGTH(c) ((c).packet_length) + +/* And the packed data, as an array of `packet_length' bytes. */ +#define PACKED_DATA(c) ((c).data) + + +/* We save an instance of this structure for each font we are asked to + open. */ + +typedef struct +{ + FILE *file; + pk_char_type *chars[MAX_CHARCODE + 1]; + packed_char_type *packed_chars[MAX_CHARCODE + 1]; + boolean chars_read; +} internal_font_type; + +/* The file pointer for the font F. */ +#define INTERNAL_FILE(f) ((f).file) + +/* This pointer is null if the character C in the internal font F has + not yet been unpacked. */ +#define INTERNAL_PK_CHAR(f, c) ((f).chars[c]) + +/* This pointer is null if the character C does not exist in F. */ +#define INTERNAL_PACKED_CHAR(f, c) ((f).packed_chars[c]) + +/* This remembers whether we have read the character info from the file. */ +#define INTERNAL_CHARS_READ(f) ((f).chars_read) + + +/* These macros get at the members of the packed character numbered C, + in the internal font F. */ + +#define INTERNAL_PACKED_DYN_F(f, c) \ + PACKED_DYN_F (*INTERNAL_PACKED_CHAR (f, c)) +#define INTERNAL_PACKED_BLACK_FIRST(f, c) \ + PACKED_BLACK_FIRST (*INTERNAL_PACKED_CHAR (f, c)) +#define INTERNAL_PACKED_PARAM_LENGTH(f, c) \ + PACKED_PARAM_LENGTH (*INTERNAL_PACKED_CHAR (f, c)) +#define INTERNAL_PACKED_DATA_LENGTH(f, c) \ + PACKED_DATA_LENGTH (*INTERNAL_PACKED_CHAR (f, c)) +#define INTERNAL_PACKED_DATA(f, c) \ + PACKED_DATA (*INTERNAL_PACKED_CHAR (f, c)) + +/* File I/O. */ +static FILE *pk_input_file; /* The file we're currently reading. */ +static string current_filename; /* Its pathname. */ + +/* Low-level input. These macros call the corresponding routines in + kbase, using the static variables for the input file and filename. */ + +#define PK_MATCH_BYTE(expected) \ + match_byte (expected, pk_input_file, current_filename) +#define PK_GET_BYTE() get_byte (pk_input_file, current_filename) +#define PK_GET_TWO() get_two (pk_input_file, current_filename) +#define PK_GET_FOUR() get_four (pk_input_file, current_filename) +#define PK_GET_N_BYTES(n) get_n_bytes (n, pk_input_file, current_filename) + +static four_bytes pk_get_n_byte_value (unsigned); +static string pk_get_string (unsigned); + +static void get_all_pk_chars (internal_font_type *); +static void get_one_pk_char (internal_font_type *, one_byte); + +/* Memory ``I/O''. */ +static pk_char_type *unpack (packed_char_type); +static void get_bitmap (pk_char_type *); +static void get_packed_bitmap (pk_char_type *, packed_char_type); +static unsigned get_run_count (one_byte, unsigned *); + +static one_byte *pk_input_data = NULL; /* Where we are reading from. */ +static boolean do_upper_nybble = true; /* Which nybble we're reading. */ + +static one_byte data_get_bit (void); +static one_byte data_get_nybble (void); +static four_bytes data_get_three (void); +static four_bytes data_get_four (void); +static four_bytes data_get_n_byte_value (one_byte); +static signed_4_bytes data_get_signed_n_byte_value (one_byte); + + +/* Handle multiple fonts. */ +static internal_font_type *find_internal_font (string); +static void save_internal_font (string, FILE *); +static void delete_internal_font (string); + +/* Prepare for reading FILENAME. Return false if it can't be opened. + We allow the same file to be opened twice; I'm not sure if that's a + good idea or not, but it doesn't seem to matter much. */ + +boolean +pk_open_input_file (string filename) +{ + FILE *f = fopen (filename, "r"); + + if (f == NULL) return false; + + save_internal_font (filename, f); + return true; +} + + +/* Close the file associated with FILENAME, if we have it open. If it's + not open, the caller must have made a mistake, so + `delete_internal_font' gives a fatal error. */ + +void +pk_close_input_file (string filename) +{ + delete_internal_font (filename); +} + +/* The PK preamble contains the fontwide information we are supposed to + return. If FONT_NAME isn't open for reading, we give a fatal error. */ + +pk_preamble_type +pk_get_preamble (string filename) +{ + pk_preamble_type p; + unsigned comment_length; + internal_font_type *f = find_internal_font (filename); + + assert (INTERNAL_FILE (*f) != NULL); + pk_input_file = INTERNAL_FILE (*f); + current_filename = filename; + + /* The preamble is at the beginning of the file, so move there. */ + xfseek (pk_input_file, 0, SEEK_SET, filename); + + PK_MATCH_BYTE (PK_PRE); + PK_MATCH_BYTE (PK_ID); + comment_length = PK_GET_BYTE (); + PK_COMMENT (p) = pk_get_string (comment_length); + PK_DESIGN_SIZE (p) = PK_GET_FOUR (); + PK_CHECKSUM (p) = PK_GET_FOUR (); + PK_H_RESOLUTION (p) = PK_GET_FOUR (); + PK_V_RESOLUTION (p) = PK_GET_FOUR (); + + /* We read (but not unpack) the entire file. */ + get_all_pk_chars (f); + + return p; +} + +/* Return the information for the character CODE in the font FILENAME, + or null if the character doesn't exist in that font. */ + +pk_char_type * +pk_get_char (one_byte code, string filename) +{ + internal_font_type *f = find_internal_font (filename); + + assert (INTERNAL_FILE (*f) != NULL); + pk_input_file = INTERNAL_FILE (*f); + current_filename = filename; + + if (!INTERNAL_CHARS_READ (*f)) + /* This routine sets the character info in F (among other things). */ + get_all_pk_chars (f); + + /* The PK_CHAR is null until we unpack the bitmap. If the character + is not in the font at all, then the PACKED_CHAR is null. */ + if (INTERNAL_PK_CHAR (*f, code) != NULL) + /* We've already unpacked this character. */ + return INTERNAL_PK_CHAR (*f, code); + + else if (INTERNAL_PACKED_CHAR (*f, code) == NULL) + /* The character is not in the font. */ + return NULL; + + else + { /* We need to unpack the character. */ + INTERNAL_PK_CHAR (*f, code) = unpack (*INTERNAL_PACKED_CHAR (*f, code)); + PK_CHARCODE (*INTERNAL_PK_CHAR (*f, code)) = code; + return INTERNAL_PK_CHAR (*f, code); + } +} + + +/* This routine reads the contents of the entire `pk_input_file' (which + should be set before calling it). The results go into F. */ + +static void +get_all_pk_chars (internal_font_type *f) +{ + while (true) /* The loop exits when we see PK_POST. */ + { + one_byte command = PK_GET_BYTE (); + + if (command < PK_XXX1) + get_one_pk_char (f, command); + + else if (PK_XXX1 <= command && command <= PK_XXX4) + /* The length of the string is given by the next 1--4 bytes, + according to the opcode. We just ignore all specials. */ + (void) PK_GET_N_BYTES (pk_get_n_byte_value (command - PK_XXX1 + 1)); + + else if (command == PK_YYY) + (void) PK_GET_FOUR (); + + else if (command == PK_POST) + break; + + else if (command == PK_NO_OP) + /* do nothing */; + + else + FATAL1 ("Undefined command byte %u in PK file", command); + } + + INTERNAL_CHARS_READ (*f) = true; +} + + +/* Read a single character, starting at the current position of + `pk_input_file'. The results go into F. */ + +static void +get_one_pk_char (internal_font_type *f, one_byte flag) +{ + unsigned parameter_length, packet_length; + int charcode; + one_byte dyn_f = flag >> 4; + + if (dyn_f == 15) + FATAL1 ("Unrecognized command %u", flag); + + if (!(flag & 4)) + { /* Short format. */ + parameter_length = 1; + packet_length = ((flag & 3) << 8) + PK_GET_BYTE (); + charcode = PK_GET_BYTE (); + } + else if (!(flag & 1)) + { /* Extended short format. */ + parameter_length = 2; + packet_length = ((flag & 3) << 16) + PK_GET_TWO (); + charcode = PK_GET_BYTE (); + } + else + { /* Long format. */ + parameter_length = 4; + packet_length = PK_GET_FOUR (); + charcode = PK_GET_FOUR (); + if (charcode > MAX_CHARCODE || charcode < 0) + /* Someone is trying to use a font with character codes that are + out of our range. */ + FATAL1 ("Character code %d out of range 0..255 in PK file (sorry)", + charcode); + } + + INTERNAL_PACKED_CHAR (*f, charcode) = xmalloc (sizeof (packed_char_type)); + INTERNAL_PACKED_DYN_F (*f, charcode) = dyn_f; + INTERNAL_PACKED_BLACK_FIRST (*f, charcode) = (flag & 8) != 0; + INTERNAL_PACKED_PARAM_LENGTH (*f, charcode) = parameter_length; + INTERNAL_PACKED_DATA_LENGTH (*f, charcode) = packet_length; + INTERNAL_PACKED_DATA (*f, charcode) + = (one_byte *) PK_GET_N_BYTES (packet_length); +} + + +/* This routine unpacks a character C into the raster image. All the + fields but one in the `pk_char_type' structure are filled in. The + exception is the character code, which our caller does. */ + +static pk_char_type * +unpack (packed_char_type c) +{ + dimensions_type d; + signed_4_bytes h_offset, v_offset; + pk_char_type *pk_char = xmalloc (sizeof (pk_char_type)); + + /* So it doesn't have to be a parameter to all the routines. */ + pk_input_data = PACKED_DATA (c); + do_upper_nybble = true; /* The data always starts on a byte boundary. */ + + /* The TFM width is three bytes in the short formats, four in the + long format. */ + PK_TFM_WIDTH (*pk_char) + = LONG_FORMAT (c) ? data_get_four () : data_get_three (); + + /* The horizontal escapement is the next PARAMETER_LENGTH bytes. In + addition, if we're using the long format, it is in pixels + multiplied by 2^16, and we want to unscale it. */ + PK_H_ESCAPEMENT (*pk_char) + = data_get_n_byte_value (PACKED_PARAM_LENGTH (c)); + if (LONG_FORMAT (c)) + { + PK_H_ESCAPEMENT (*pk_char) >>= 16;/* Don't bother to round. */ + (void) data_get_four (); /* Ignore the vertical escapement. */ + } + + /* Next comes the size of the bitmap. */ + DIMENSIONS_WIDTH (d) = data_get_n_byte_value (PACKED_PARAM_LENGTH (c)); + DIMENSIONS_HEIGHT (d) = data_get_n_byte_value (PACKED_PARAM_LENGTH (c)); + PK_BITMAP (*pk_char) = new_bitmap (d); + + /* The last two values in the character preamble are the offsets from + the upper left pixel to the reference pixel. */ + h_offset = data_get_signed_n_byte_value (PACKED_PARAM_LENGTH (c)); + v_offset = data_get_signed_n_byte_value (PACKED_PARAM_LENGTH (c)); + MIN_COL (PK_CHAR_BB (*pk_char)) = -h_offset; + MAX_COL (PK_CHAR_BB (*pk_char)) = -h_offset + DIMENSIONS_WIDTH (d); + MIN_ROW (PK_CHAR_BB (*pk_char)) = v_offset + 1 - DIMENSIONS_HEIGHT (d); + MAX_ROW (PK_CHAR_BB (*pk_char)) = v_offset; + + if (PACKED_DYN_F (c) == PK_BITMAP_FLAG) + get_bitmap (pk_char); + else + get_packed_bitmap (pk_char, c); + + return pk_char; +} + + +/* Turn the packed bitmap in the character C into a real bitmap, in + PK_CHAR. The bitmap storage and sizes in PK_CHAR must already be + set. The packed data should encode exactly as many bits as are in + the bitmap. */ + +static void +get_packed_bitmap (pk_char_type *pk_char, packed_char_type c) +{ + bitmap_type b = PK_BITMAP (*pk_char); + unsigned row = 0; + unsigned col = 0; + unsigned row_repeat_count = 0; + one_byte color = PACKED_BLACK_FIRST (c); + + while (row < BITMAP_HEIGHT (b)) + { + unsigned i; + unsigned cmd_repeat_count; + unsigned run_count = get_run_count (PACKED_DYN_F (c), &cmd_repeat_count); + + if (cmd_repeat_count != 0) + { + if (row_repeat_count != 0) + FATAL2 ("Two repeat counts (%u and %u) in PK row", + row_repeat_count, cmd_repeat_count); + row_repeat_count = cmd_repeat_count; + } + + /* Start painting pixels. */ + for (i = 0; i < run_count; i++) + { + BITMAP_PIXEL (b, row, col) = color; + col++; + + /* It is inefficient to test this here. Sorry. */ + if (col == BITMAP_WIDTH (b)) + { /* We've finished a row. If we saw a repeat count + somewhere within it, we should duplicate it. + If the PK file is correct, `row' will not increase past + the height of the bitmap from repeat counts, but we may + as well be safe. */ + for (row++; + row_repeat_count > 0 && row < BITMAP_HEIGHT (b); + row_repeat_count--, row++) + for (col = 0; col < BITMAP_WIDTH (b); col++) + BITMAP_PIXEL (b, row, col) = BITMAP_PIXEL (b, row - 1, col); + + /* Start painting pixels from the run count at the + beginning of the next row. */ + col = 0; + } + } + + color = !color; + } + + if (col != 0) + FATAL ("The PK bitmap ended in a strange place"); +} + + +/* This routine is called `pk_packed_num' in the PK documentation, but + as far as the caller is concerned, it doesn't return a packed number, + it returns a run count. Due to the definition of packed data, it is + impractical to return repeat counts in any other way except together + with a run count. */ + +static unsigned +get_run_count (one_byte dyn_f, unsigned *repeat_count) +{ + unsigned n = data_get_nybble (); + + *repeat_count = 0; + + if (n == LONG_RUN_COUNT_FLAG) + { /* Get a three nybble (or more) value, represented as some number + of zeros, followed by that many hexadecimal values. The + largest such number that we'll be asked to find will fit in + 32 bits. */ + unsigned zero_count = 0; + do + { + n = data_get_nybble (); + zero_count++; + } + while (n == 0); + + for ( ; zero_count > 0; zero_count --) + n = (n << 4) + data_get_nybble (); + + /* The smallest three-nybble value is one more than the largest + two nybble value. */ + return n - 15 + ((13 - dyn_f) << 4) + dyn_f; + } + + else if (n <= dyn_f) + /* The value we just read is itself the number. */ + return n; + + else if (n < REPEAT_COUNT_FLAG) + /* Get a two-nybble value. */ + return ((n - dyn_f - 1) << 4) + data_get_nybble () + dyn_f + 1; + + else if (n == REPEAT_COUNT_FLAG) + /* If the PK file is valid, this recursion will go only one level + deep, because a repeat count should never be followed by another + repeat count. In other words, the next nybble must be a ``run + count'' in some form. (This is why this routine is called + `pk_packed_num' in other programs.) */ + *repeat_count = get_run_count (dyn_f, &n); + + else + *repeat_count = 1; + + /* We only get here if we saw a repeat count. Now we have to get the + run count which should be next; there won't be any repeat count. */ + return get_run_count (dyn_f, &n); +} + + +/* The PK format also allows for a straight bitmap representation in the + file, one pixel per bit. Here we put each pixel into a byte. */ + +static void +get_bitmap (pk_char_type *pk_char) +{ + unsigned row; + unsigned col; + one_byte extra_bits; + bitmap_type b = PK_BITMAP (*pk_char); + + for (row = 0; row < BITMAP_HEIGHT (b); row++) + for (col = 0; col < BITMAP_WIDTH (b); col++) + BITMAP_PIXEL (b, row, col) = data_get_bit (); + + /* If the bitmap did not completely fill the last byte, we should read + and ignore the remaining bits. */ + extra_bits = 8 - (row * col) % 8; + while (extra_bits-- > 0) + (void) data_get_bit (); +} + +/* Low-level routines that read from the disk file. */ + +static string +pk_get_string (unsigned length) +{ + string s; + + if (length == 0) return ""; + + s = PK_GET_N_BYTES (length); + s = xrealloc (s, length + 1); + s[length] = 0; + return s; +} + + +/* N must be <= 4. */ + +static four_bytes +pk_get_n_byte_value (unsigned n) +{ + four_bytes v = 0; + + for ( ; n > 0; n--) + v |= PK_GET_BYTE () << ((n - 1) * 8); + + return v; +} + +/* These routines do not read from a disk file. Instead, they read from + memory (where we have put each character's definition, directly from + the file.) They use the semi-global `pk_input_data'. */ + + +/* This routine is used when the character is defined as a bitmap, + instead of run-encoded. */ + +static one_byte +data_get_bit () +{ + static one_byte mask = 0; + static one_byte n; + one_byte value; + + if (mask == 0) + { + n = data_get_nybble (); + mask = 0x8; + } + + value = (n & mask) != 0; + mask >>= 1; + + return value; +} + + +/* Since the PK format is based on nybbles, this routine is by far the + most frequently called. */ + +static one_byte +data_get_nybble () +{ + do_upper_nybble = !do_upper_nybble; + + /* Double inversion gets us back the original value. After we have + done the lower nybble, we advance to the next byte. */ + return !do_upper_nybble ? *pk_input_data >> 4 : *pk_input_data++ & 0xf; +} + + +/* We assume (correctly) that we are not in the middle of a byte + when any of the following routines are called. */ + +static four_bytes +data_get_three () +{ + return data_get_n_byte_value (3); +} + + +static four_bytes +data_get_four () +{ + return data_get_n_byte_value (4); +} + + +static four_bytes +data_get_n_byte_value (one_byte n) +{ + four_bytes v = 0; + + for ( ; n > 0; n--) + v |= *pk_input_data++ << ((n - 1) * 8); + + return v; +} + + +static signed_4_bytes +data_get_signed_n_byte_value (one_byte passed_n) +{ + signed_4_bytes v = 0; + unsigned n = passed_n; + + assert (n <= 4); + + for ( ; n > 0; n--) + v |= (*pk_input_data++ << ((n - 1) * 8)); + + if (passed_n == 1) + return (signed_byte) (v & 0xff); + else if (passed_n == 2) + return (signed_2_bytes) (v & 0xffff); + else if (passed_n == 3) + return (signed_4_bytes) (v & 0xffffff); + else + return (signed_4_bytes) v; + + return v; +} + +/* We assign an index number to NAME, and store both NAME and the + `internal_font_type' that we construct in parallel lists. The file F + goes into the `internal_font_list'. */ + +static list_type font_name_list, internal_font_list; + +static void +save_internal_font (string name, FILE *f) +{ + unsigned c; + string *new_name; + internal_font_type *new_font; + static boolean first_call = true; + + if (first_call) + { /* We have to construct our lists. */ + font_name_list = list_init (); + internal_font_list = list_init (); + first_call = false; + } + + new_name = (string *) LIST_TAPPEND (&font_name_list, string); + new_font = (internal_font_type *) + LIST_TAPPEND (&internal_font_list, internal_font_type); + + /* Save the information. */ + *new_name = xstrdup (name); + INTERNAL_FILE (*new_font) = f; + + /* We also have to initialize other parts of `new_font'. */ + for (c = 0; c <= MAX_CHARCODE; c++) + { + INTERNAL_PK_CHAR (*new_font, c) = NULL; + INTERNAL_PACKED_CHAR (*new_font, c) = NULL; + } + INTERNAL_CHARS_READ (*new_font) = false; +} + + +/* Here we return the `internal_font_type' previously stored along with + NAME. If NAME hasn't been saved, we give a fatal error. */ + +static internal_font_type * +find_internal_font (string name) +{ + unsigned e; + + for (e = 0; e < LIST_SIZE (font_name_list); e++) + if (STREQ (*(string *) LIST_ELT (font_name_list, e), name)) + return (internal_font_type *) LIST_ELT (internal_font_list, e); + + FATAL1 ("The PK font `%s' hasn't been saved", name); + return NULL; /* NOTREACHED */ +} + + +/* Free the memory and file pointer used by the font FILENAME. We don't + delete the list element for now, since removing elements from the + middle of an array is painful. Instead, we simply set the name in + `font_name_list' to the empty string, so that the element is useless. + Yes, this is disgusting. */ + +static void +delete_internal_font (string filename) +{ + unsigned e; + + /* We can't use `find_internal_font', since we need to know the list + element index, not just the internal font information. */ + for (e = 0; e < LIST_SIZE (font_name_list); e++) + if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename)) + { + unsigned c; + internal_font_type *f = LIST_ELT (internal_font_list, e); + + assert (INTERNAL_FILE (*f) != NULL); + xfclose (INTERNAL_FILE (*f), filename); + INTERNAL_FILE (*f) = NULL; + + if (INTERNAL_CHARS_READ (*f)) + for (c = 0; c <= MAX_CHARCODE; c++) + if (INTERNAL_PK_CHAR (*f, c) != NULL) + free (INTERNAL_PK_CHAR (*f, c)); + + *(string *) LIST_ELT (font_name_list, e) = ""; + return; + } + FATAL1 ("The PK font `%s' hasn't been saved", filename); +} diff --git a/pk/pk_opcodes.h b/pk/pk_opcodes.h new file mode 100644 index 0000000..854ed52 --- /dev/null +++ b/pk/pk_opcodes.h @@ -0,0 +1,41 @@ +/* pk_opcodes.h: symbolic names for some of the GF commands and special + values. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef PK_OPCODES_H +#define PK_OPCODES_H + +/* Some of the command bytes. */ +#define PK_PRE 247 +#define PK_ID 89 +#define PK_XXX1 240 +#define PK_XXX4 243 +#define PK_YYY 244 +#define PK_POST 245 +#define PK_NO_OP 246 + +/* If the `dyn_f' value for a character is this, the bitmap is + represented as a bitmap, instead of being packed. */ +#define PK_BITMAP_FLAG 14 + +/* These values are for the first nybble in packed numbers. */ +#define LONG_RUN_COUNT_FLAG 0 +#define REPEAT_COUNT_FLAG 14 +#define REPEAT_ONE 15 + +#endif /* not PK_OPCODES_H */ diff --git a/tfm/ChangeLog b/tfm/ChangeLog new file mode 100644 index 0000000..044da8f --- /dev/null +++ b/tfm/ChangeLog @@ -0,0 +1,371 @@ +Fri May 13 16:57:15 1994 Karl Berry (karl@cs.umb.edu) + + * tfm_output.c (tfm_convert_pl): Add NULL to the concatn. + +Sun May 1 15:32:11 1994 Karl Berry (karl@cs.umb.edu) + + * tfm_output.c: Use concatn instead of the no-longer-existing concat5. + +Tue Oct 27 12:56:39 1992 Karl Berry (karl@cs.umb.edu) + + * Version 0.6. + +Mon Oct 19 08:11:44 1992 Karl Berry (karl@cs.umb.edu) + + * tfm_input.c (tfm_get_chars): Return the newly malloced array, + not the static variable. + +Thu Sep 3 09:31:23 1992 Karl Berry (karl@hayley) + + * Version 0.5. + +Tue Jul 7 16:42:47 1992 Karl Berry (karl@hayley) + + * tfm_input.c (tfm_input_filename): new routine. + (tfm_input_filename): change var name to just `tfm_input_name'. + +Sat Jun 13 07:55:29 1992 Karl Berry (karl@hayley) + + * all files: change `font_param{,eter}' to `fontdimen', globally. + + * tfm_fontdim.c: rename from `fontdimen.c'. + * GNUmakefile (c_only): change here. + +Fri Jun 12 09:45:31 1992 Karl Berry (karl@hayley) + + * fontdimen.c (tfm_set_fontdimen): rename from + `tfm_set_font_parameter', and rearrange args. + + * tfm_ligature.c (tfm_set_ligature): take a lig list as the + parameter instead of a TFM char. + +Tue Jun 9 13:57:18 1992 Karl Berry (karl@hayley) + + * fontdimen.c (tfm_set_fontdimens): call `float_ok' on the + potential fontdimen value. + + * fontdimen.c: new file with all the fontdimen stuff. + * tfm_kern.c: new file with the kern stuff. + * tfm_ligature.c: and the ligature stuff. + * tfm_char.c: rename from tfm_util, since that's all that's left. + +Mon Jun 8 15:27:59 1992 Karl Berry (karl@hayley) + + * tfm_util.c (tfm_set_kern): take a kern list as the parameter instead + of the whole TFM character. + +Sun May 31 10:56:10 1992 Karl Berry (karl@hayley) + + * tfm_output.c (tfm_put_char): use `epsilon_equal'. + +Sat May 30 14:58:33 1992 Karl Berry (karl@hayley) + + * tfm_output.c (tfm_convert_pl): allow for passing in the TFM name. + + * tfm_output.c (tfm_convert_pl): free `cmd'. + +Thu May 14 22:20:14 1992 Karl Berry (karl@claude.cs.umb.edu) + + * tfm_util.c (tfm_set_fontsize): make non-static. + +Wed May 13 09:16:19 1992 Karl Berry (karl@hayley) + + * tfm_input.c (get_tfm_header): initialize the parameter count in + global_info here. + (get_tfm_params): not here. + +Tue Apr 21 07:45:29 1992 Karl Berry (karl@hayley) + + * tfm_input.c (tfm_get_global_info): use XTALLOC1. + +Sun Mar 29 19:02:25 1992 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_params): forgot arg to printf. + +Sat Mar 28 07:49:38 1992 Karl Berry (karl at hayley) + + * Version 0.4. + + * Change copyright years to 1992 only. + +Sat Mar 21 10:59:51 1992 Kathy Hargreaves (kathy at hayley) + + * tfm_util.c (tfm_set_design_size): set design size unconditionally. + + * tfm_util.c (tfm_set_design_size): added. + + * tfm_util.c (tfm_set_header): deleted DEFAULT_DESIGN_SIZE. + + * tfm_util.c (tfm_set_fontsize): made extern. + + * tfm_util.c [TFM_CHECK_DESIGNSIZE]: changed name from + CHECK_DESIGNSIZE. + + * tfm_util.c (tfm_set_font_parameter, tfm_set_fontsize): added. + (tfm_set_fontdimens): use tfm_set_font_parameter. + +Thu Mar 19 13:24:14 1992 Kathy Hargreaves (kathy at hayley) + + * tfm_util.c (tfm_set_header): use CHECK_DESIGN_SIZE. + Don't range of check default design size; expect it to be valid. + + * tfm_util.h [CHECK_DESIGN_SIZE]: added. + + * tfm_util.c (tfm_set_header): took `design_size' out of + `designsize' else clause. Added DEFAULT_DESIGN_SIZE. If either + variable is set, then arrange to set fontsize. + Set tfm_info's design size to DEFAULT_DESIGN_SIZE if it's not + set by the tfm-header design-size option. + + * tfm_util.c (set_fontsize): changed name from set_fontsize_if_unset. + (tfm_set_header): if -design-size tfm-header option is used, set + the font parameter count so will change the fontsize. + +Wed Mar 18 12:27:44 1992 Kathy Hargreaves (kathy at hayley) + + * tfm_util.c (tfm_set_ligature): added. + + * tfm_util.c (tfm_set_header): dox fix. + +Mon Mar 16 12:22:42 1992 Kathy Hargreaves (kathy at hayley) + + * tfm_util.c (tfm_set_header): set design size correctly. + + * tfm_util.c (set_fontsize_if_unset): added. + (tfm_set_header, tfm_set_fontdimens): call set_fontsize_if_unset. + + * tfm_util.c (tfm_set_header): added. + +Thu Jan 9 11:22:04 1992 Karl Berry (karl at hayley) + + * *.c: do not include global.h. + +Wed Jan 8 15:25:17 1992 Karl Berry (karl at hayley) + + * update copyright messages. + + * change `allocate to `xmalloc', `reallocate' to `xrealloc', and + `string_copy' to `strdup'. + +Tue Sep 17 16:54:26 1991 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_get_bcpl_string): append a null to the data. + +Tue Jul 30 13:20:02 1991 Karl Berry (karl at ra.cs.umb.edu) + + * Version 0.3. + +Tue Jul 16 17:21:19 1991 Karl Berry (karl at hayley) + + * tfm_util.c (tfm_get_kern): move from tfm_input.c, and take a tfm + char as an arg, instead of using the tfm_char_table from the font. + +Sun Jun 16 07:47:49 1991 Karl Berry (karl at hayley) + + * tfm_output.c (put_lig_kern_info): output a `stop' after each + character, since it isn't implied by a `label'. + + * tfm_output.c (tfm_put_global_info): don't output a checksum + property if the checksum is zero. + +Sat Jun 15 09:54:19 1991 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_get_chars, tfm_get_char): set the `code' member + of the TFM character structure. + + * tfm_output.c (put_pl_lig_kern_table): rename to + `put_lig_kern_info' and rewrite to take a single character. + (tfm_put_char): new routine to output only one character. + (tfm_put_chars): call `tfm_put_char'. + + * all files: change `checked_' to `x'. + +Tue Jun 11 15:17:51 1991 Karl Berry (karl at hayley) + + * tfm_util.c (tfm_new_chars): use XTALLOC. + + * tfm_input.c (tfm_get_char): new routine. + + * tfm_input.c (tfm_get_kern): check if the character exists before + looking at its kern list. Also, use LIST_... macros instead of + doing direct selection. Also, use `charcode_type' instead of + `one_byte'. + * tfm_util.c (tfm_set_kern): likewise. + + * tfm_input.c (tfm_get_global_info, tfm_get_chars): don't save and + restore the file position. + + * tfm_input.c (get_tfm_char): rename to `get_char'. + +Thu Jun 6 07:31:49 1991 Karl Berry (karl at hayley) + + * All files: change to version 2 of the GPL. + +Thu Apr 4 05:48:15 1991 Karl Berry (karl at hayley) + + * tfm_util.c (tfm_new_chars): call `tfm_new_char'. + + * tfm_output.c (put_pl_lig_kern_table): test different characters + as we go through the loop! How did this one get past? Ohh, now + I see -- I was incrementing the pointer. + + * tfm_output.c (put_pl_lig_kern_table): test >0 instead of !=0 on + the (unsigned) count variables. + +Wed Apr 3 11:43:28 1991 Karl Berry (karl at hayley) + + * tfm_output.c (tfm_init_global_info): initialize the number of + parameters to zero. + + * tfm_output.c (put_pl_lig_kern_table): don't output a lig/kern + program for a character that doesn't exist -- either the left or + the right. + +Tue Apr 2 06:48:27 1991 Karl Berry (karl at hayley) + + * tfm_util.c (tfm_set_fontdimens): assign zero to all the + intervening fontdimens when we set the fontsize; reset the + parameter count. + + * tfm_output.c (tfm_put_global_info): output the number of + parameters we have, instead of trying to find the last nonzero + one. + + * tfm_output.c (put_string_prop): don't output a space if there is + no value to the string property. + +Sun Mar 10 13:12:51 1991 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_params): save the number of parameters we + read. + + * tfm_output.c (tfm_put_global_info): output as many parameters as + we have, instead of just the first six. + * tfm_input.c (get_tfm_params): likewise, for reading. + + * tfm_output.c (tfm_init_global_info): new routine. + +Sat Mar 9 17:23:42 1991 Karl Berry (karl at hayley) + + * tfm_util.c (tfm_set_fontdimens): new routine. + +Thu Mar 7 07:33:33 1991 Karl Berry (karl at hayley) + + * Version 0.2. + +Tue Mar 5 15:34:26 1991 Karl Berry (karl at hayley) + + * tfm_output.c (tfm_convert_pl): use output redirection instead of + -v to make tftopl be quiet. + +Mon Feb 25 15:42:09 1991 Karl Berry (karl at hayley) + + * tfm_output.c (tfm_convert_pl): take a new parameter which says + whether to operate silently. + + * tfm_output.c (INDENT_INCR): define as 2. + + * tfm_input.c (tfm_open_filename): give an error if the caller + tries to open more than one file. + + * tfm_{input,output,util}.c: rename external routines to start with + `tfm'; change error messages, etc. + +Sun Feb 17 09:51:50 1991 Karl Berry (karl at hayley) + + * *.c: include config.h. + +Sun Dec 9 15:08:57 1990 Karl Berry (karl at hayley) + + * tfm_input.c, tfm_output.c: doc fix. + +Sat Nov 17 12:54:02 1990 Karl Berry (karl at hayley) + + * tfm_input.c, tfm_output.c: include appropriate file-...h files. + +Thu Aug 30 16:29:51 1990 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_get_byte, ...): pass the input filename, and + rewrite as macros. + +Tue Jul 24 11:09:46 1990 Karl Berry (karl at hayley) + + * tfm_output.c: include filename.h. + +Fri Jul 13 16:48:56 1990 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_chars): declare `this_char' as unsigned, + not one_byte, since it might have to become 256. + +Wed Jul 4 08:39:28 1990 Karl Berry (karl at hayley) + + * tfm_output.c (put_tfm_chars): look at the `exists' member of the + character structure, instead of checking for the width being zero. + +Wed Jun 20 07:32:49 1990 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_cur_pos): rename to tfm_ftell, and use + checked_ftell. + (tfm_set_pos): rename to tfm_fseek. + +Fri Jun 1 15:36:38 1990 Karl Berry (karl at hayley) + + * tfm_input.c (close_tfm_input_file): use checked_fclose. + * tfm_output.c (close_pl_output_file): likewise. + +Wed May 30 16:21:43 1990 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_char): set the `exists' member of the + character structure. + * tfm_util.c (new_tfm_char): initialize the `exists' member. + +Thu Apr 12 14:58:24 1990 Karl Berry (karl at hayley) + + * tfm_input.c (get_interword_space): rename to + `tfm_get_interword_space'. + +Mon Apr 9 12:10:26 1990 Karl Berry (karl at hayley) + + * (all files): upcase macro names. + +Sun Apr 8 11:42:53 1990 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_global_info): if we've already read the + global info, just return the structure, instead of reading it + again. + +Fri Feb 23 08:43:02 1990 Karl Berry (karl at hayley) + + * tfm_input.c (get_tfm_char): remember the dimensions in their + original fix_word units, as well as in points. + +Wed Feb 7 17:22:27 1990 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_get_design_size): new routine. + (tfm_get_coding_scheme): rename `get_coding_scheme'. + +Sun Jan 28 14:48:35 1990 Karl Berry (karl at hayley) + + * tfm_util.c (set_kern): move this routine from tfm_input.c. + + * tfm_output.c (change_pl_to_tfm): check that pl_output_filename + is non-NULL. + +Fri Dec 22 17:33:30 1989 Karl Berry (karl at hayley) + + * tfm_input.c (tfm_get_x_height): new routine. + +Mon Oct 30 12:37:02 1989 Karl Berry (karl at hayley) + + * all files: add the copyleft. + + * tfm_util.c: define new_tfm_chars. + + * tfm_output.c (put_tfm_global_info): take a structure as input, + not a pointer. + (new_tfm_char): move to tfm_util.c. + +Sun Oct 29 08:13:05 1989 Karl Berry (karl at hayley) + + * tfm_output.c (put_pl_file): remove this, and add put_tfm_chars + and put_tfm_global_info in its place. diff --git a/tfm/GNUmakefile b/tfm/GNUmakefile new file mode 100644 index 0000000..7b0201a --- /dev/null +++ b/tfm/GNUmakefile @@ -0,0 +1,27 @@ +# Makefile for the TFM library. +# +# Copyright (C) 1992 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +library = tfm + +c_only = tfm_char tfm_fontdim tfm_header tfm_input tfm_kern tfm_ligature \ +tfm_output + +include ../data/defs.make +include ../data/defslib.make + +include M.depend diff --git a/tfm/README b/tfm/README new file mode 100644 index 0000000..cbbdf5e --- /dev/null +++ b/tfm/README @@ -0,0 +1,17 @@ +This library provides for reading and writing of TeX font metric (TFM) +files. Only a single file may be read or written at a time. + +None of the code that processes the TFM commands actually explains what +the precise definition of those commands are. For that, you should look +at the definition of the TFM format in Metafont: The Program, by Don +Knuth, chapter 46. It is also in the TeXware program tftopl, +TeX: The Program, and other places. + +The header file is ../include/tfm.h. It explains the basics of how to +use these routines. The source files in this directory do not repeat +that explanation. + +TFM format was extended in 1990 to allow for complicated ligatures. +We do not recognize all the distinctions; all ligatures are simply +collapsed into the pre-1990 form, character A followed by character B +leads to character C. diff --git a/tfm/fontdimen.c b/tfm/fontdimen.c new file mode 100644 index 0000000..dadd516 --- /dev/null +++ b/tfm/fontdimen.c @@ -0,0 +1,183 @@ +/* fontdimen.c: handle TFM fontdimens a.k.a. font parameters. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "tfm.h" + + +/* This structure maps font parameter names to numbers. */ +typedef struct +{ + string name; + unsigned number; +} font_param_type; + +/* The list of fontdimen names and their corresponding numbers. I wish + I could figure out a good way to give this list only once (in tfm.h), + instead of three times. */ + +static font_param_type font_param[] = { + { "slant", TFM_SLANT_PARAMETER }, + { "space", TFM_SPACE_PARAMETER }, + { "stretch", TFM_STRETCH_PARAMETER }, + { "shrink", TFM_SHRINK_PARAMETER }, + { "xheight", TFM_XHEIGHT_PARAMETER }, + { "quad", TFM_QUAD_PARAMETER }, + { "extraspace", TFM_EXTRASPACE_PARAMETER }, + { "num1", TFM_NUM1_PARAMETER }, + { "num2", TFM_NUM2_PARAMETER }, + { "num3", TFM_NUM3_PARAMETER }, + { "denom1", TFM_DENOM1_PARAMETER }, + { "denom2", TFM_DENOM2_PARAMETER }, + { "sup1", TFM_SUP1_PARAMETER }, + { "sup2", TFM_SUP2_PARAMETER }, + { "sup3", TFM_SUP3_PARAMETER }, + { "sub1", TFM_SUB1_PARAMETER }, + { "sub2", TFM_SUB2_PARAMETER }, + { "supdrop", TFM_SUPDROP_PARAMETER }, + { "subdrop", TFM_SUBDROP_PARAMETER }, + { "delim1", TFM_DELIM1_PARAMETER }, + { "delim2", TFM_DELIM2_PARAMETER }, + { "axisheight", TFM_AXISHEIGHT_PARAMETER }, + { "defaultrulethickness", TFM_DEFAULTRULETHICKNESS_PARAMETER }, + { "bigopspacing1", TFM_BIGOPSPACING1_PARAMETER }, + { "bigopspacing2", TFM_BIGOPSPACING2_PARAMETER }, + { "bigopspacing3", TFM_BIGOPSPACING3_PARAMETER }, + { "bigopspacing4", TFM_BIGOPSPACING4_PARAMETER }, + { "bigopspacing5", TFM_BIGOPSPACING5_PARAMETER }, + { "leadingheight", TFM_LEADINGHEIGHT_PARAMETER }, + { "leadingdepth", TFM_LEADINGDEPTH_PARAMETER }, + { "fontsize", TFM_FONTSIZE_PARAMETER }, + { "version", TFM_VERSION_PARAMETER }, +}; + +/* Set the font parameter entries in TFM_INFO according to the string S. + If S is non-null and non-empty, it should look like + <fontdimen>:<real>,<fontdimen>:<real>,..., where each <fontdimen> is + either a standard name or a number between 1 and 30 (the 30 comes + from the default value in PLtoTF, it's not critical). + + Also, if the `design_size' member of TFM_INFO is nonzero, we set the + `FONTSIZE' parameter to 1.0 (meaning it's equal to the design size), + unless the `FONTSIZE' parameter is already set. */ + +void +tfm_set_fontdimens (string s, tfm_global_info_type *tfm_info) +{ + string spec; + + /* If S is empty, we have nothing more to do. */ + if (s == NULL || *s == 0) + return; + + /* Parse the specification string. */ + for (spec = strtok (s, ","); spec != NULL; spec = strtok (NULL, ",")) + { + string fontdimen; + real value; + unsigned param_number = 0; + string value_string = strchr (spec, ':'); + + if (value_string == NULL || !float_ok (value_string)) + FATAL1 ("Fontdimens look like `<fontdimen>:<real>', not `%s'", + spec); + + value = atof (value_string + 1); + fontdimen = substring (spec, 0, value_string - spec - 1); + + /* If `fontdimen' is all numerals, we'll take it to be an integer. */ + if (strspn (fontdimen, "0123456789") == strlen (fontdimen)) + { + param_number = atou (fontdimen); + + if (param_number == 0 || param_number > TFM_MAX_FONT_PARAMETERS) + FATAL2 ("Font parameter %u is not between 1 and the maximum (%u)", + param_number, TFM_MAX_FONT_PARAMETERS); + } + else + { /* It wasn't a number; see if it's a valid name. */ + param_number = tfm_fontdimen_number (fontdimen); + + if (param_number == 0) + FATAL1 ("I don't know the font parameter name `%s'", fontdimen); + } + + /* If we got here, `param_number' is the number of the font + parameter we are supposed to assign to. */ + tfm_set_font_parameter (param_number, value, tfm_info); + + /* If `param_number' is past the last fontdimen previously + assigned, we have to assign zero to all the intervening ones. + But this can never happen, because we always assign the + `fontsize' parameter, which happens to be the last one. */ + assert (param_number <= TFM_FONT_PARAMETER_COUNT (*tfm_info)); + } +} + +/* Return zero if we do not recognize S as the name of a fontdimen, else + its corresponding number. We just do a linear search through the + structure, since it's so small. */ + +unsigned +tfm_fontdimen_number (string s) +{ + unsigned this_param; + unsigned param_number = 0; + + for (this_param = 0; + this_param < TFM_MAX_FONT_PARAMETERS && param_number == 0; + this_param++) + if (STREQ (s, font_param[this_param].name)) + param_number = font_param[this_param].number; + + return param_number; +} + +/* Set the PARAMETER-th font parameter of TFM_INFO to VALUE. If + PARAMETER is beyond the current last parameter of TFM_INFO, set + all the intervening parameters to zero. */ + +void +tfm_set_fontdimen (tfm_global_info_type *tfm_info, + unsigned parameter, real value, +{ + if (TFM_FONT_PARAMETER_COUNT (*tfm_info) < parameter) + { + unsigned p; + + for (p = TFM_FONT_PARAMETER_COUNT (*tfm_info) + 1; p < parameter; p++) + TFM_FONT_PARAMETER (*tfm_info, p) = 0.0; + + /* Now we have more parameters. */ + TFM_FONT_PARAMETER_COUNT (*tfm_info) = parameter; + } + + TFM_FONT_PARAMETER (*tfm_info, parameter) = value; +} + + +/* Set the `FONTSIZE' parameter of TFM_INFO, if the design size is set. */ + +void +tfm_set_fontsize (tfm_global_info_type *tfm_info) +{ + if (TFM_DESIGN_SIZE (*tfm_info) != 0.0) + tfm_set_font_parameter (TFM_FONTSIZE_PARAMETER, + TFM_DESIGN_SIZE (*tfm_info), tfm_info); +} diff --git a/tfm/tfm_char.c b/tfm/tfm_char.c new file mode 100644 index 0000000..dad8a02 --- /dev/null +++ b/tfm/tfm_char.c @@ -0,0 +1,56 @@ +/* tfm_util.c: routines independent of reading or writing a particular font. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "tfm.h" + + +/* A constructor for the TFM character type. */ + +tfm_char_type +tfm_new_char () +{ + tfm_char_type ch; + + ch.code = 0; + ch.width = ch.height = ch.depth = ch.italic_correction = 0.0; + ch.fix_width = ch.fix_height = ch.fix_depth = ch.fix_italic_correction = 0; + + ch.ligature = list_init (); + ch.kern = list_init (); + + ch.exists = false; + + return ch; +} + + +/* Return an initialized array of `tfm_char_type's. */ + +tfm_char_type * +tfm_new_chars () +{ + unsigned i; + tfm_char_type *chars = XTALLOC (TFM_SIZE, tfm_char_type); + + for (i = 0; i < TFM_SIZE; i++) + chars[i] = tfm_new_char (); + + return chars; +} diff --git a/tfm/tfm_fontdim.c b/tfm/tfm_fontdim.c new file mode 100644 index 0000000..454b12e --- /dev/null +++ b/tfm/tfm_fontdim.c @@ -0,0 +1,194 @@ +/* fontdimen.c: handle TFM fontdimens a.k.a. font parameters. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "tfm.h" + + +/* This structure maps fontdimen names to numbers (and vice versa). */ +typedef struct +{ + string name; + unsigned number; +} fontdimen_type; + +/* The list of fontdimen names and their corresponding numbers. I wish + I could figure out a good way to give this list only once (in tfm.h), + instead of three times. */ + +static fontdimen_type fontdimen[] = { + { "slant", TFM_SLANT_PARAMETER }, + { "space", TFM_SPACE_PARAMETER }, + { "stretch", TFM_STRETCH_PARAMETER }, + { "shrink", TFM_SHRINK_PARAMETER }, + { "xheight", TFM_XHEIGHT_PARAMETER }, + { "quad", TFM_QUAD_PARAMETER }, + { "extraspace", TFM_EXTRASPACE_PARAMETER }, + { "num1", TFM_NUM1_PARAMETER }, + { "num2", TFM_NUM2_PARAMETER }, + { "num3", TFM_NUM3_PARAMETER }, + { "denom1", TFM_DENOM1_PARAMETER }, + { "denom2", TFM_DENOM2_PARAMETER }, + { "sup1", TFM_SUP1_PARAMETER }, + { "sup2", TFM_SUP2_PARAMETER }, + { "sup3", TFM_SUP3_PARAMETER }, + { "sub1", TFM_SUB1_PARAMETER }, + { "sub2", TFM_SUB2_PARAMETER }, + { "supdrop", TFM_SUPDROP_PARAMETER }, + { "subdrop", TFM_SUBDROP_PARAMETER }, + { "delim1", TFM_DELIM1_PARAMETER }, + { "delim2", TFM_DELIM2_PARAMETER }, + { "axisheight", TFM_AXISHEIGHT_PARAMETER }, + { "defaultrulethickness", TFM_DEFAULTRULETHICKNESS_PARAMETER }, + { "bigopspacing1", TFM_BIGOPSPACING1_PARAMETER }, + { "bigopspacing2", TFM_BIGOPSPACING2_PARAMETER }, + { "bigopspacing3", TFM_BIGOPSPACING3_PARAMETER }, + { "bigopspacing4", TFM_BIGOPSPACING4_PARAMETER }, + { "bigopspacing5", TFM_BIGOPSPACING5_PARAMETER }, + { "leadingheight", TFM_LEADINGHEIGHT_PARAMETER }, + { "leadingdepth", TFM_LEADINGDEPTH_PARAMETER }, + { "fontsize", TFM_FONTSIZE_PARAMETER }, + { "version", TFM_VERSION_PARAMETER }, +}; + +/* How many entries we have in the `fontdimen' array. */ +static unsigned fontdimen_array_size + = sizeof (fontdimen) / sizeof (fontdimen_type); + +/* Set the font parameter entries in TFM_INFO according to the string S. + If S is non-null and non-empty, it should look like + <fontdimen>:<real>,<fontdimen>:<real>,..., where each <fontdimen> is + either a standard name (in the list above) or a number between 1 and + TFM_MAX_FONTDIMENS (which is currently 30, the default value in + PLtoTF). */ + +void +tfm_set_fontdimens (string s, tfm_global_info_type *tfm_info) +{ + string spec; + + /* If S is empty, we have nothing more to do. */ + if (s == NULL || *s == 0) + return; + + /* Parse the specification string. */ + for (spec = strtok (s, ","); spec != NULL; spec = strtok (NULL, ",")) + { + string fontdimen; + real value; + unsigned param_number = 0; + string value_string = strchr (spec, ':'); + + if (value_string == NULL || !float_ok (value_string)) + FATAL1 ("Fontdimens look like `<fontdimen>:<real>', not `%s'", + spec); + + value = atof (value_string + 1); + fontdimen = substring (spec, 0, value_string - spec - 1); + + /* If `fontdimen' is all numerals, we'll take it to be an integer. */ + if (strspn (fontdimen, "0123456789") == strlen (fontdimen)) + { + param_number = atou (fontdimen); + + if (param_number == 0 || param_number > TFM_MAX_FONTDIMENS) + FATAL2 ("Font parameter %u is not between 1 and the maximum (%u)", + param_number, TFM_MAX_FONTDIMENS); + } + else + { /* It wasn't a number; see if it's a valid name. */ + param_number = tfm_fontdimen_number (fontdimen); + + if (param_number == 0) + FATAL1 ("I don't know the font parameter name `%s'", fontdimen); + } + + /* If we got here, `param_number' is the number of the font + parameter we are supposed to assign to. */ + tfm_set_fontdimen (tfm_info, param_number, value); + } +} + +/* Return zero if we do not recognize S as the name of a fontdimen, else + its corresponding number. We just do a linear search through the + structure, since it's so small. */ + +unsigned +tfm_fontdimen_number (string s) +{ + unsigned i; /* Index into the `fontdimen' array. */ + unsigned param_number = 0; + + for (i = 0; i < fontdimen_array_size && param_number == 0; i++) + if (STREQ (s, fontdimen[i].name)) + param_number = fontdimen[i].number; + + return param_number; +} + + +/* Return the name in `fontdimens' corresponding to the number N. */ + +string +tfm_fontdimen_name (unsigned n) +{ + unsigned i; + string name = NULL; + + for (i = 0; i < fontdimen_array_size && name == NULL; i++) + { + if (fontdimen[i].number == n) + name = fontdimen[i].name; + } + + return name; +} + +/* Set the PARAMETER-th font parameter of TFM_INFO to VALUE. If + PARAMETER is beyond the current last parameter of TFM_INFO, set + all the intervening parameters to zero. */ + +void +tfm_set_fontdimen (tfm_global_info_type *tfm_info, + unsigned parameter, real value) +{ + if (TFM_FONTDIMEN_COUNT (*tfm_info) < parameter) + { + unsigned p; + + for (p = TFM_FONTDIMEN_COUNT (*tfm_info) + 1; p < parameter; p++) + TFM_FONTDIMEN (*tfm_info, p) = 0.0; + + /* Now we have more parameters. */ + TFM_FONTDIMEN_COUNT (*tfm_info) = parameter; + } + + TFM_FONTDIMEN (*tfm_info, parameter) = value; +} + + +/* Set the `FONTSIZE' parameter of TFM_INFO, if the design size is set. */ + +void +tfm_set_fontsize (tfm_global_info_type *tfm_info) +{ + if (TFM_DESIGN_SIZE (*tfm_info) != 0.0) + tfm_set_fontdimen (tfm_info, + TFM_FONTSIZE_PARAMETER, TFM_DESIGN_SIZE (*tfm_info)); +} diff --git a/tfm/tfm_header.c b/tfm/tfm_header.c new file mode 100644 index 0000000..33ecd1d --- /dev/null +++ b/tfm/tfm_header.c @@ -0,0 +1,92 @@ +/* tfm_header.c: deal with the TFM header bytes. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "tfm.h" + + +/* Set the header in TFM_INFO according to the string S. */ + +void +tfm_set_header (string s, tfm_global_info_type *tfm_info) +{ + string spec; + + /* If S is empty, we have nothing more to do. */ + if (s == NULL || *s == 0) + return; + + /* Parse the specification string. */ + for (spec = strtok (s, ","); spec != NULL; spec = strtok (NULL, ",")) + { + string header_item; + string value_string = strchr (spec, ':'); + + if (value_string == NULL) + FATAL1 ("TFM headers look like `<header-item>:<value>', not `%s'", + spec); + + header_item = substring (spec, 0, value_string - spec - 1); + + /* Advance past the `:'. */ + value_string++; + + if (STREQ (header_item, "checksum")) + { + if (!integer_ok (value_string)) + FATAL1 ("%s: Invalid integer constant (for checksum)", + value_string); + TFM_CHECKSUM (*tfm_info) = atoi (value_string); + } + + else if (STREQ (header_item, "designsize")) + { + if (!float_ok (value_string)) + FATAL1 ("%s: Invalid floating-point constant (for designsize)", + value_string); + tfm_set_design_size (atof (value_string), tfm_info); + } + + else if (STREQ (header_item, "codingscheme")) + { + unsigned length = strlen (value_string); + + if (strchr (value_string, '(') != NULL + || strchr (value_string, ')') != NULL) + FATAL1 ("Your coding scheme `%s' may not contain parentheses", + value_string); + + if (length > TFM_MAX_CODINGSCHEME_LENGTH) + WARNING3 ("Your coding scheme `%s' of length %d will be \ +truncated to %d", value_string, length, TFM_MAX_CODINGSCHEME_LENGTH); + + TFM_CODING_SCHEME (*tfm_info) = xstrdup (value_string); + } + } +} + +/* Set the design and font size of TFM_INFO to DESIGN_SIZE. */ + +void +tfm_set_design_size (real design_size, tfm_global_info_type *tfm_info) +{ + TFM_CHECK_DESIGN_SIZE (design_size); + TFM_DESIGN_SIZE (*tfm_info) = design_size; + tfm_set_fontsize (tfm_info); +} diff --git a/tfm/tfm_input.c b/tfm/tfm_input.c new file mode 100644 index 0000000..5e2c8e1 --- /dev/null +++ b/tfm/tfm_input.c @@ -0,0 +1,506 @@ +/* tfm_input.c: read a TFM file. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "file-input.h" +#include "tfm.h" + + +/* If true, print out what we read. */ +static boolean tracing_tfm_input = false; + +/* These identify the file we're reading. */ +static FILE *tfm_input_file; +static string tfm_input_name; + + +/* A copy of the character information. We rely on the `exists' member + of all these characters being initialized to zero (i.e., `false') by + virtue of the variable being static. */ +static tfm_char_type tfm_char_table[TFM_SIZE]; + +/* A copy of the global information. */ +static tfm_global_info_type *global_info = NULL; + +/* Global information which is only useful to us, not the user. The + `..._pos' members record the location of the various components of + the file. The member `param_word_count' says how many words of + header information are present in this TFM file. */ +typedef struct +{ + byte_count_type char_info_pos; + byte_count_type width_pos; + byte_count_type height_pos; + byte_count_type depth_pos; + byte_count_type italic_correction_pos; + byte_count_type lig_kern_pos; + byte_count_type kern_pos; + unsigned param_word_count; +} tfm_header_type; + +static tfm_header_type tfm_header; + + +/* Low-level input. These macros call the corresponding routines in + kbase, using the static variables for the input file and filename. */ +#define TFM_FTELL() xftell (tfm_input_file, tfm_input_name) +#define TFM_FSEEK(offset, from_where) \ + xfseek (tfm_input_file, offset, from_where, tfm_input_name) +#define TFM_GET_BYTE() get_byte (tfm_input_file, tfm_input_name) +#define TFM_GET_TWO() get_two (tfm_input_file, tfm_input_name) +#define TFM_GET_FOUR() get_four (tfm_input_file, tfm_input_name) + + +static tfm_char_type get_char (); +static string tfm_get_bcpl_string (void); +static real tfm_get_fix_word (void); +static void get_lig_kern_program (list_type *, list_type *); +static real tfm_get_scaled_fix (void); +static void get_tfm_header (void); +static void get_tfm_params (void); + +/* Routines to start and finish reading a file. (For the user to call.) */ + +boolean +tfm_open_input_file (string filename) +{ + if (tfm_input_file != NULL) + FATAL2 ("tfm_open_input_file: Attempt to open `%s', but `%s' is +already open", filename, tfm_input_name); + + tfm_input_name = filename; + tfm_input_file = fopen (filename, "r"); + + return tfm_input_file != NULL; +} + + +void +tfm_close_input_file () +{ + assert (tfm_input_file != NULL); + + xfclose (tfm_input_file, tfm_input_name); + + tfm_input_file = NULL; + tfm_input_name = NULL; + global_info = NULL; +} + + +/* This is just avoids all callers having to keep a global around with + the TFM name they used. */ + +string +tfm_input_filename () +{ + if (tfm_input_file == NULL) + return NULL; + + return tfm_input_name; +} + +/* Some of the global information comes from the beginning of the file, + and some from the end. If we've already read the information from + the file, we don't do it again. */ + +tfm_global_info_type +tfm_get_global_info () +{ + assert (tfm_input_file != NULL); + + /* Only read the file once. */ + if (global_info != NULL) return *global_info; + + global_info = XTALLOC1 (tfm_global_info_type); + get_tfm_header (); + get_tfm_params (); + + return *global_info; +} + + +/* Now comes convenience routines to get particular parts of the global + info. */ + +unsigned +tfm_get_checksum () +{ + (void) tfm_get_global_info (); + return TFM_CHECKSUM (*global_info); +} + + +double +tfm_get_design_size () +{ + (void) tfm_get_global_info (); + return TFM_DESIGN_SIZE (*global_info); +} + + +string +tfm_get_coding_scheme () +{ + (void) tfm_get_global_info (); + return TFM_CODING_SCHEME (*global_info); +} + + +double +tfm_get_interword_space () +{ + (void) tfm_get_global_info (); + return TFM_FONTDIMEN (*global_info, TFM_SPACE_PARAMETER); +} + + +double +tfm_get_x_height () +{ + (void) tfm_get_global_info (); + return TFM_FONTDIMEN (*global_info, TFM_XHEIGHT_PARAMETER); +} + + +/* Here we read the information at the beginning of the file. We store + the result into the static variables `global_info' and + `tfm_header'. */ + +static void +get_tfm_header () +{ + two_bytes file_length, header_length; + two_bytes width_word_count, height_word_count, depth_word_count; + two_bytes italic_correction_word_count, lig_kern_word_count; + two_bytes kern_word_count, extensible_word_count; + + /* The header is at the beginning of the file, naturally. */ + TFM_FSEEK (0, SEEK_SET); + + file_length = TFM_GET_TWO (); + header_length = TFM_GET_TWO (); + + global_info->first_charcode = TFM_GET_TWO (); + global_info->last_charcode = TFM_GET_TWO (); + width_word_count = TFM_GET_TWO (); + height_word_count = TFM_GET_TWO (); + depth_word_count = TFM_GET_TWO (); + italic_correction_word_count = TFM_GET_TWO (); + lig_kern_word_count = TFM_GET_TWO (); + kern_word_count = TFM_GET_TWO (); + extensible_word_count = TFM_GET_TWO (); + tfm_header.param_word_count = TFM_GET_TWO (); + TFM_FONTDIMEN_COUNT (*global_info) = tfm_header.param_word_count; + + tfm_header.char_info_pos = (6 + header_length) * 4; + tfm_header.width_pos = tfm_header.char_info_pos + + (global_info->last_charcode + - global_info->first_charcode + 1) * 4; + tfm_header.height_pos = tfm_header.width_pos + width_word_count * 4; + tfm_header.depth_pos = tfm_header.height_pos + height_word_count * 4; + tfm_header.italic_correction_pos = tfm_header.depth_pos + + depth_word_count * 4; + tfm_header.lig_kern_pos = tfm_header.italic_correction_pos + + italic_correction_word_count * 4; + tfm_header.kern_pos = tfm_header.lig_kern_pos + lig_kern_word_count * 4; + /* We don't care about the extensible table. */ + + if (header_length < 2) + FATAL2 ("TFM header of `%s' has only %u word(s)", tfm_input_name, + header_length); + + TFM_CHECKSUM (*global_info) = TFM_GET_FOUR (); + TFM_DESIGN_SIZE (*global_info) = tfm_get_fix_word (); + + /* Although the coding scheme might be interesting to the caller, the + font family and face byte probably aren't. So we don't read them. */ + TFM_CODING_SCHEME (*global_info) + = header_length > 2 ? tfm_get_bcpl_string () : "unspecified"; + + if (tracing_tfm_input) + printf ("TFM checksum = %u, design_size = %fpt, coding scheme = `%s'.\n", + TFM_CHECKSUM (*global_info), + TFM_DESIGN_SIZE (*global_info), + TFM_CODING_SCHEME (*global_info)); +} + + +/* Although TFM files are only usable by TeX if they have at least seven + parameters, that is not a requirement of the file format itself, so + we don't impose it. And they can have many more than seven, of + course. We do impose a limit of TFM_MAX_FONT_PARAMETERS. We assume + that `tfm_header' has already been filled in. */ + +static void +get_tfm_params () +{ + unsigned this_param; + + /* If we have no font parameters at all, we're done. */ + if (tfm_header.param_word_count == 0) + return; + + /* Move to the beginning of the parameter table in the file. */ + TFM_FSEEK (-4 * tfm_header.param_word_count, SEEK_END); + + /* It's unlikely but possible that this TFM file has more fontdimens + than we can deal with. */ + if (tfm_header.param_word_count > TFM_MAX_FONTDIMENS) + { + WARNING3 ("%s: TFM file has %u parameters, which is more than the +%u I can handle", + tfm_input_name, tfm_header.param_word_count, + TFM_MAX_FONTDIMENS); + tfm_header.param_word_count = TFM_MAX_FONTDIMENS; + } + + /* The first parameter is different than all the rest, because it + isn't scaled by the design size. */ + TFM_FONTDIMEN (*global_info, TFM_SLANT_PARAMETER) = tfm_get_fix_word (); + + for (this_param = 2; this_param <= tfm_header.param_word_count; + this_param++) + TFM_FONTDIMEN (*global_info, this_param) = tfm_get_scaled_fix (); + + if (tracing_tfm_input) + { + for (this_param = 1; this_param <= tfm_header.param_word_count; + this_param++) + printf ("TFM parameter %d: %.3f", this_param, + TFM_FONTDIMEN (*global_info, this_param)); + } +} + +/* Read every character in the TFM file, storing the result in the + static `tfm_char_table'. We return a copy of that variable. */ + +tfm_char_type * +tfm_get_chars () +{ + tfm_char_type *tfm_chars; + unsigned this_char; + + assert (tfm_input_file != NULL); + + tfm_get_global_info (); + + for (this_char = global_info->first_charcode; + this_char <= global_info->last_charcode; + this_char++) + /* This fills in the `tfm_char_table' global. */ + (void) tfm_get_char (this_char); + + /* Return a copy, so our information can't get corrupted. */ + tfm_chars = XTALLOC (TFM_SIZE, tfm_char_type); + memcpy (tfm_chars, tfm_char_table, sizeof (tfm_char_table)); + return tfm_chars; +} + + +/* Read the character CODE. If the character doesn't exist, return + NULL. If it does, save the information in `tfm_char_table', as well + as returning it. */ + +tfm_char_type * +tfm_get_char (charcode_type code) +{ + assert (tfm_input_file != NULL); + + tfm_get_global_info (); + + /* If the character is outside the declared bounds in the file, don't + try to read it. Just return NULL. */ + if (code < global_info->first_charcode + || code > global_info->last_charcode) + return NULL; + + /* Move to the appropriate place in the `char_info' array. */ + TFM_FSEEK (tfm_header.char_info_pos + + (code - global_info->first_charcode) * 4, + SEEK_SET); + + /* Read the character. */ + tfm_char_table[code] = get_char (); + + /* If it exists, return a pointer to it. We return a copy, so our + information can't get corrupted. */ + if (!TFM_CHAR_EXISTS (tfm_char_table[code])) + return NULL; + else + { + tfm_char_type *c = XTALLOC1 (tfm_char_type); + + TFM_CHARCODE (tfm_char_table[code]) = code; + *c = tfm_char_table[code]; + return c; + } +} + + +/* We assume we are positioned at the beginning of a `char_info' word. + We read that word to get the indexes into the dimension tables; then + we go read the tables to get the values (if the character exists). */ + +static tfm_char_type +get_char () +{ + one_byte width_index, height_index, depth_index, italic_correction_index; + one_byte packed; + one_byte tag, remainder; + tfm_char_type tfm_char; + + /* Read the char_info word. */ + width_index = TFM_GET_BYTE (); + + packed = TFM_GET_BYTE (); + height_index = (packed & 0xf0) >> 4; + depth_index = packed & 0x0f; + + packed = TFM_GET_BYTE (); + italic_correction_index = (packed & 0xfc) >> 6; + tag = packed & 0x3; + + remainder = TFM_GET_BYTE (); + + tfm_char = tfm_new_char (); + +#define GET_CHAR_DIMEN(d) \ + if (d##_index != 0) \ + { \ + TFM_FSEEK (tfm_header.##d##_pos + d##_index*4, SEEK_SET); \ + tfm_char.fix_##d = TFM_GET_FOUR (); \ + tfm_char.##d = fix_to_real (tfm_char.fix_##d) \ + * global_info->design_size; \ + } + + GET_CHAR_DIMEN (width); + GET_CHAR_DIMEN (height); + GET_CHAR_DIMEN (depth); + GET_CHAR_DIMEN (italic_correction); + + /* The other condition for a character existing is that it be between + the first and last character codes given in the header. We've + already assumed that's true (or we couldn't be positioned at a + `char_info_word'). */ + TFM_CHAR_EXISTS (tfm_char) = width_index != 0; + + if (tracing_tfm_input) + { + printf (" width = %f, height = %f, ", tfm_char.width, tfm_char.height); + printf ("depth = %f, ic = %f.\n", tfm_char.depth, + tfm_char.italic_correction); + } + + if (tag == 1) + { + TFM_FSEEK (tfm_header.lig_kern_pos + remainder * 4, SEEK_SET); + get_lig_kern_program (&(tfm_char.ligature), &(tfm_char.kern)); + } + + /* We don't handle the other tags. */ + return tfm_char; +} + +/* Read a ligature/kern program at the current position, storing the + result into *LIGATURE and *KERN. We don't distinguish all the kinds + of ligatures that Metafont can output. */ + +#define STOP_FLAG 128 +#define KERN_FLAG 128 + +static void +get_lig_kern_program (list_type *ligature, list_type *kern) +{ + boolean end_of_program; + + assert (ligature != NULL && kern != NULL); + + do + { + one_byte next_char; + boolean kern_step; + one_byte remainder; + + end_of_program = TFM_GET_BYTE () >= STOP_FLAG; + + next_char = TFM_GET_BYTE (); + kern_step = TFM_GET_BYTE () >= KERN_FLAG; + remainder = TFM_GET_BYTE (); + + if (tracing_tfm_input) + printf (" if next = %u (%c), ", next_char, next_char); + + if (kern_step) + { + byte_count_type old_pos = TFM_FTELL (); + tfm_kern_type *kern_element = LIST_TAPPEND (kern, tfm_kern_type); + + kern_element->character = next_char; + + TFM_FSEEK (tfm_header.kern_pos + remainder * 4, SEEK_SET); + kern_element->kern = tfm_get_scaled_fix (); + TFM_FSEEK (old_pos, SEEK_SET); + + if (tracing_tfm_input) + printf ("kern %f.\n", kern_element->kern); + } + else + { + tfm_ligature_type *ligature_element + = LIST_TAPPEND (ligature, tfm_ligature_type); + + ligature_element->character = next_char; + ligature_element->ligature = remainder; + + if (tracing_tfm_input) + printf ("ligature %d (hex %x).\n", + ligature_element->ligature, ligature_element->ligature); + } + } while (!end_of_program); +} + +/* Most quantities are fixed-point fractions. */ + +static real +tfm_get_fix_word () +{ + return fix_to_real (TFM_GET_FOUR ()); +} + + +/* Dimensions are a `fix_word' scaled by the design size. */ + +static real +tfm_get_scaled_fix () +{ + return tfm_get_fix_word () * global_info->design_size; +} + + +static string +tfm_get_bcpl_string () +{ + unsigned string_length = TFM_GET_BYTE (); + string s = get_n_bytes (string_length, tfm_input_file, tfm_input_name); + s = xrealloc (s, string_length + 1); + s[string_length] = 0; + + return s; +} diff --git a/tfm/tfm_kern.c b/tfm/tfm_kern.c new file mode 100644 index 0000000..414c892 --- /dev/null +++ b/tfm/tfm_kern.c @@ -0,0 +1,75 @@ +/* tfm_kern.c: deal with TFM kern lists. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "list.h" +#include "tfm.h" + + +/* The character RIGHT may or may not be in the list of kerns already. */ + +void +tfm_set_kern (list_type *kern_table, charcode_type right, real k) +{ + unsigned this_right; + tfm_kern_type *new_kern; + + assert (kern_table != NULL); + + for (this_right = 0; this_right < LIST_SIZE (*kern_table); this_right++) + { + tfm_kern_type *kern = LIST_ELT (*kern_table, this_right); + + if (kern->character == right) + { /* Already there, just replace the value. */ + kern->kern = k; + return; + } + } + + /* RIGHT wasn't in the existing list. Add it to the end. */ + new_kern = LIST_TAPPEND (kern_table, tfm_kern_type); + new_kern->character = right; + new_kern->kern = k; +} + +/* Find the kern between the characters LEFT and RIGHT. (Return zero if + none such.) */ + +real +tfm_get_kern (tfm_char_type left, charcode_type right) +{ + list_type kern_table; + unsigned r; + + if (!TFM_CHAR_EXISTS (left)) + return 0.0; + + kern_table = left.kern; + + for (r = 0; r < LIST_SIZE (kern_table); r++) + { + tfm_kern_type *kern = LIST_ELT (kern_table, r); + + if (kern->character == right) + return kern->kern; + } + + return 0.0; +} diff --git a/tfm/tfm_ligature.c b/tfm/tfm_ligature.c new file mode 100644 index 0000000..4e3db36 --- /dev/null +++ b/tfm/tfm_ligature.c @@ -0,0 +1,48 @@ +/* tfm_ligature.c: deal with TFM ligature lists. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" + +#include "tfm.h" + + +/* The character RIGHT may or may not be in LIG_LIST already. + Update it if so, otherwise add it. */ + +void +tfm_set_ligature (list_type *lig_list, charcode_type right, charcode_type l) +{ + unsigned this_right; + tfm_ligature_type *new_ligature; + + for (this_right = 0; this_right < LIST_SIZE (*lig_list); this_right++) + { + tfm_ligature_type *ligature = LIST_ELT (*lig_list, this_right); + + if (ligature->character == right) + { + ligature->ligature = l; + return; + } + } + + /* RIGHT wasn't in the existing list. Add it to the end. */ + new_ligature = LIST_TAPPEND (lig_list, tfm_ligature_type); + new_ligature->character = right; + new_ligature->ligature = l; +} diff --git a/tfm/tfm_output.c b/tfm/tfm_output.c new file mode 100644 index 0000000..2ff7cb4 --- /dev/null +++ b/tfm/tfm_output.c @@ -0,0 +1,371 @@ +/* tfm_output.c: write property list files (a human-readable equivalent + of TFM files), and convert them to TFM format. PL format is + described in the source code to the TeX utility PLtoTF, by Donald + Knuth. + +Copyright (C) 1992 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include <kpathsea/concatn.h> + +#include "file-output.h" +#include "report.h" +#include "tfm.h" + + +/* These identify the output file. (Only one may be open at a time.) */ +static FILE *pl_output_file; +static string pl_output_filename; + +/* The design size for the font is used to scale almost all numbers in + the file. It is in units of printer's points. */ +static real design_size; + + +/* Subroutines for output. */ +static void put_lig_kern_info (tfm_char_type); + + +/* Routines to actually write the properties. */ +static void start_prop_list (string); +static void finish_prop_list (void); +static void start_integer_prop_list (string, unsigned); +static void put_integer_prop (string, unsigned); +static void put_octal_prop (string, unsigned); +static void put_real_prop (string, real); +static void put_scaled_prop (string, real); +static void put_string_prop (string, string); +static void put_indentation (void); + +static void put_lig_prop (tfm_ligature_type *); +static void put_kern_prop (tfm_kern_type *); + +/* Routines to start and finish reading a file. (For the user to call.) */ + +boolean +tfm_open_pl_output_file (string filename) +{ + assert (pl_output_file == NULL); + + pl_output_filename = filename; + pl_output_file = fopen (filename, "w"); + + return pl_output_file != NULL; +} + + +void +tfm_close_pl_output_file () +{ + assert (pl_output_file != NULL); + + xfclose (pl_output_file, pl_output_filename); + + pl_output_file = NULL; + pl_output_filename = NULL; +} + + +/* An argument to allow the PL file to be deleted might be in order + here, and maybe returning the exit status. If TFM_NAME is NULL, we + replace any suffix on `pl_output_filename' with `tfm' and use that. + Otherwise, we use exactly TFM_NAME. */ + +void +tfm_convert_pl (string tfm_name, boolean verbose) +{ + string cmd; + int status; + string arg = verbose ? "" : " >/dev/null 2>&1"; + + if (pl_output_filename == NULL) + { + fprintf (stderr, "No PL output file to convert to TFM format.\n"); + fprintf (stderr, "(Perhaps you called tfm_close_pl_output_file?)\n"); + return; + } + + if (tfm_name == NULL) + tfm_name = make_suffix (pl_output_filename, "tfm"); + + cmd = concatn ("pltotf ", pl_output_filename, " ", tfm_name, arg, NULL); + + /* Make sure that all data we have written will be read. */ + if (fflush (pl_output_file) == EOF) + FATAL1 ("%s: could not flush", pl_output_filename); + + /* Convert to TFM. */ + if (verbose) + printf ("Executing `%s'.\n", cmd); + status = system (cmd); + + free (cmd); + + if (verbose && status != 0) + printf ("Exit status = %d.\n", status); +} + +/* Return an initialized structure. */ + +tfm_global_info_type +tfm_init_global_info () +{ + tfm_global_info_type info; + unsigned this_param; + + TFM_CHECKSUM (info) = 0; + TFM_DESIGN_SIZE (info) = 0.0; + TFM_CODING_SCHEME (info) = "unspecified"; + TFM_FONTDIMEN_COUNT (info) = 0; + for (this_param = 1; this_param <= TFM_MAX_FONTDIMENS; this_param++) + TFM_FONTDIMEN (info, this_param) = 0.0; + + return info; +} + + +/* Output the fontwide information in INFO. */ + +void +tfm_put_global_info (tfm_global_info_type info) +{ + unsigned this_param; + + /* Save the design size so we can scale the other reals. */ + design_size = TFM_DESIGN_SIZE (info); + + put_string_prop ("comment", now ()); + put_real_prop ("designsize", design_size); + put_string_prop ("codingscheme", TFM_CODING_SCHEME (info)); + + /* If the checksum is zero, don't output it; then PLtoTF will compute + one for us. */ + if (TFM_CHECKSUM (info) != 0) + put_octal_prop ("checksum", TFM_CHECKSUM (info)); + + start_prop_list ("fontdimen"); + + for (this_param = 1; this_param <= TFM_FONTDIMEN_COUNT (info); + this_param++) + { + real param_value = TFM_FONTDIMEN (info, this_param); + + /* Parameter #1 (the font slant) is different than all the + rest, because it's not scaled by the design size. */ + if (this_param == 1) + put_real_prop ("slant", param_value); + else + put_scaled_prop (concat ("parameter d ", utoa (this_param)), + param_value); + } + + finish_prop_list (); +} + + +/* We don't bother to keep track of the `nextlarger' and `varchar' + properties, which are used in TeX's math mode. + + TFM_CHAR should be an array of (exactly) `TFM_SIZE' elements. */ + +void +tfm_put_chars (tfm_char_type *tfm_char) +{ + unsigned this_char; + + for (this_char = 0; this_char < TFM_SIZE; this_char++, tfm_char++) + { + if (TFM_CHAR_EXISTS (*tfm_char)) + tfm_put_char (*tfm_char); + } +} + + +/* Output the single character C to the PL file. Although the width and + height are not zero often enough to matter, the depth and italic + correction are often zero, so we may as well check first. */ + +void +tfm_put_char (tfm_char_type c) +{ + /* If we're being called, the character should exist. */ + assert (TFM_CHAR_EXISTS (c)); + + start_integer_prop_list ("character", TFM_CHARCODE (c)); + + put_scaled_prop ("charwd", TFM_WIDTH (c)); + put_scaled_prop ("charht", TFM_HEIGHT (c)); + + if (!epsilon_equal (TFM_DEPTH (c), 0.0)) + put_scaled_prop ("chardp", TFM_DEPTH (c)); + + if (!epsilon_equal (TFM_ITALIC_CORRECTION (c), 0.0)) + put_scaled_prop ("charic", TFM_ITALIC_CORRECTION (c)); + + finish_prop_list (); + + put_lig_kern_info (c); +} + +/* Output any ligature/kern information in the tfm character C. */ + +static void +put_lig_kern_info (tfm_char_type c) +{ + unsigned ligature_count = LIST_SIZE (c.ligature); + unsigned kern_count = LIST_SIZE (c.kern); + + assert (TFM_CHAR_EXISTS (c)); + + /* Do nothing if there's neither ligatures nor kerns. */ + if (ligature_count > 0 || kern_count > 0) + { + unsigned step; + + start_prop_list ("ligtable"); + put_integer_prop ("label", TFM_CHARCODE (c)); + + /* We shouldn't output a lig/kern step unless all the characters + involved exist. But we don't know which characters exist until + the end, when we convert to PL. So for now, we just output + everything we get, instead of saving the information away. It + doesn't actually affect the validity of the results -- it's + just that PLtoTF might give some warnings. */ + for (step = 0; step < ligature_count; step++) + { + tfm_ligature_type *lig = LIST_ELT (c.ligature, step); +#if 0 + if (TFM_CHAR_EXISTS (tfm_char[lig->character]) + && TFM_CHAR_EXISTS (tfm_char[lig->ligature])) +#endif + put_lig_prop (lig); + } + + for (step = 0; step < kern_count; step++) + { + tfm_kern_type *k = LIST_ELT (c.kern, step); +#if 0 + if (TFM_CHAR_EXISTS (tfm_char[k->character])) +#endif + put_kern_prop (k); + } + + put_string_prop ("stop", ""); + finish_prop_list (); + } +} + +/* It makes the output more readable to make the property lists + indented. */ + +static unsigned indentation = 0; +#define INDENT_INCR 2 + + +static void +start_prop_list (string prop_list_name) +{ + put_indentation (); + fprintf (pl_output_file, "(%s\n", prop_list_name); + indentation += INDENT_INCR; +} + + +static void +start_integer_prop_list (string prop, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s d %u\n", prop, v); + indentation += INDENT_INCR; +} + + +static void +finish_prop_list () +{ + put_indentation (); + fprintf (pl_output_file, ")\n"); + indentation -= INDENT_INCR; +} + + +static void +put_lig_prop (tfm_ligature_type *lig) +{ + put_indentation (); + fprintf (pl_output_file, "(lig d %u d %u)\n", + lig->character, lig->ligature); +} + + +static void +put_kern_prop (tfm_kern_type *kern) +{ + put_indentation (); + fprintf (pl_output_file, "(krn d %u r %f)\n", + kern->character, kern->kern / design_size); +} + + +static void +put_integer_prop (string prop_name, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s d %u)\n", prop_name, v); +} + + +static void +put_octal_prop (string prop_name, unsigned v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s o %o)\n", prop_name, v); +} + + +static void +put_scaled_prop (string prop_name, real v) +{ + put_real_prop (prop_name, v / design_size); +} + + +static void +put_real_prop (string prop_name, real v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s r %f)\n", prop_name, v); +} + + +static void +put_string_prop (string prop_name, string v) +{ + put_indentation (); + fprintf (pl_output_file, "(%s%s%s)\n", + prop_name, strlen (v) > 0 ? " " : "", v); +} + + +static void +put_indentation () +{ + unsigned this_space; + + for (this_space = 0; this_space < indentation; this_space++) + fprintf (pl_output_file, " "); +} |