[Pkg-cups-devel] r817 - in cupsys/trunk/debian: . local/filters/pdf-filters local/filters/pdf-filters/conf local/filters/pdf-filters/data local/filters/pdf-filters/filter local/filters/pdf-filters/filter/fontembed
Till Kamppeter
till-guest at alioth.debian.org
Thu Aug 14 17:18:53 UTC 2008
Author: till-guest
Date: Thu Aug 14 17:18:52 2008
New Revision: 817
Log:
Added texttopdf filter.
Added:
cupsys/trunk/debian/local/filters/pdf-filters/conf/texttopdf.convs
cupsys/trunk/debian/local/filters/pdf-filters/data/
cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.heavy
cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.simple
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/Makefile
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/README
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/bitset.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed_sfnt.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/main.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt_int.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_analyze.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_pdf.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.h
cupsys/trunk/debian/local/filters/pdf-filters/filter/test.sh (contents, props changed)
cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf1.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf2.c
cupsys/trunk/debian/local/filters/pdf-filters/filter/texttopdf.c
Modified:
cupsys/trunk/debian/changelog
cupsys/trunk/debian/control
cupsys/trunk/debian/local/filters/pdf-filters/AUTHORS
cupsys/trunk/debian/local/filters/pdf-filters/README
cupsys/trunk/debian/local/filters/pdf-filters/addtocups
cupsys/trunk/debian/local/filters/pdf-filters/removefromcups
cupsys/trunk/debian/rules
Modified: cupsys/trunk/debian/changelog
==============================================================================
--- cupsys/trunk/debian/changelog (original)
+++ cupsys/trunk/debian/changelog Thu Aug 14 17:18:52 2008
@@ -1,3 +1,27 @@
+cups (1.3.8-4) UNRELEASED; urgency=low
+
+ [ Till Kamppeter ]
+ * debian/control, debian/rules,
+ debian/local/filters/pdf-filters/filter/pdfutils.h,
+ debian/local/filters/pdf-filters/filter/texttopdf.c,
+ debian/local/filters/pdf-filters/filter/fontembed,
+ debian/local/filters/pdf-filters/filter/test.sh,
+ debian/local/filters/pdf-filters/filter/test_pdf1.c,
+ debian/local/filters/pdf-filters/filter/test_pdf2.c,
+ debian/local/filters/pdf-filters/filter/pdfutils.c,
+ debian/local/filters/pdf-filters/conf/texttopdf.convs,
+ debian/local/filters/pdf-filters/AUTHORS,
+ debian/local/filters/pdf-filters/addtocups,
+ debian/local/filters/pdf-filters/data,
+ debian/local/filters/pdf-filters/data/pdf.utf-8.simple,
+ debian/local/filters/pdf-filters/data/pdf.utf-8.heavy,
+ debian/local/filters/pdf-filters/removefromcups,
+ debian/local/filters/pdf-filters/README: Added texttopdf filter.
+ Added "Depends: ttf-freefont" for the cups package, as the
+ texttopdf filter needs these fonts.
+
+ -- Martin Pitt <mpitt at debian.org> Thu, 14 Aug 2008 17:40:59 +0200
+
cups (1.3.8-3) experimental; urgency=low
[ Till Kamppeter ]
Modified: cupsys/trunk/debian/control
==============================================================================
--- cupsys/trunk/debian/control (original)
+++ cupsys/trunk/debian/control Thu Aug 14 17:18:52 2008
@@ -8,7 +8,8 @@
debhelper (>= 5.0), po-debconf, cdbs (>= 0.4.27), sharutils,
dpatch (>= 1.11), libdbus-1-dev, libkrb5-dev | heimdal-dev,
libavahi-compat-libdnssd-dev, libpoppler-dev, poppler-utils | xpdf-utils,
- lsb-release, po4a (>= 0.31), autotools-dev, autoconf, automake, libtool
+ lsb-release, po4a (>= 0.31), autotools-dev, autoconf, automake, libtool,
+ ttf-freefont
Uploaders: Kenshi Muto <kmuto at debian.org>,
Martin Pitt <mpitt at debian.org>, Roger Leigh <rleigh at debian.org>,
Martin-Éric Racine <q-funk at iki.fi>, Masayuki Hatta (mhatta) <mhatta at debian.org>,
@@ -62,7 +63,7 @@
Depends: ${shlibs:Depends}, debconf (>= 1.2.9) | debconf-2.0,
poppler-utils | xpdf-utils, perl-modules, procps,
ghostscript, lsb-base (>= 3), cups-common,
- ssl-cert (>= 1.0.11), adduser
+ ssl-cert (>= 1.0.11), adduser, ttf-freefont
Recommends: cups-client, smbclient (>= 3.0.9), foomatic-filters, avahi-utils
Suggests: cups-bsd, cups-driver-gutenprint, foomatic-db-engine, foomatic-db,
hplip, xpdf-korean | xpdf-japanese | xpdf-chinese-traditional | xpdf-chinese-simplified,
Modified: cupsys/trunk/debian/local/filters/pdf-filters/AUTHORS
==============================================================================
--- cupsys/trunk/debian/local/filters/pdf-filters/AUTHORS (original)
+++ cupsys/trunk/debian/local/filters/pdf-filters/AUTHORS Thu Aug 14 17:18:52 2008
@@ -1 +1,2 @@
Koji Otani
+Tobias Hoffmann
Modified: cupsys/trunk/debian/local/filters/pdf-filters/README
==============================================================================
--- cupsys/trunk/debian/local/filters/pdf-filters/README (original)
+++ cupsys/trunk/debian/local/filters/pdf-filters/README Thu Aug 14 17:18:52 2008
@@ -26,8 +26,7 @@
Below you find the original documentation of the three filters, from
the original README files.
-The COPYING and AUTHORS files of all the three filters are the same.
-They are also included in the root directory of this tarball.
+The COPYING and AUTHORS files are merged from the original packages
===========================================================================
@@ -715,3 +714,48 @@
"pdftoraster" creates temporally files if needed. Temporary files are created
in the location specified by TMPDIR environment variable. Default location
is "/tmp".
+
+===========================================================================
+
+TEXTTOPDF
+
+This implements a texttopdf filter, and is derived from cups' texttops.
+
+To configure:
+-------------
+
+- texttopdf uses a CUPS_DATADIR/charset/pdf.* (e.g. pdf.utf-8) for
+ font configuration. All the fonts named here MUST also be present
+ under CUPS_DATADIR/fonts/ as TrueType fonts for texttopdf to work.
+ For TrueType Collections (.TTC) you'll have to append '/' and the
+ number of the font in the collection to the filename charsets/pdf.utf-8
+ (resp. charsets/pdf.* ), for example to use the second font of uming.ttc
+ use the filename uming.ttc/1
+
+- There are examples of pdf.utf-8 in the cups/data directory,
+ you may use one of these (don't forget to copy / symlink the fonts).
+
+To use:
+-------
+
+The filter is called just like any other cups filter. Have a
+look at test.sh for example.
+
+Known Issues
+------------
+(Release 0.0.1)
+
+ - text extraction does not work (at least for pdftotext from xpdf)
+ for the resulting pdfs.
+
+ - text wrapping in pretty-printing mode does not respect double-wide
+ characters (CJK), and thus produce wrong results (wrap too late)
+ for lines where they occur. The fix is not trivial, since all the
+ pretty-printing processing is done without knowledge of / prior to
+ the font configuration (which is where single or double width
+ code-ranges are specified).
+
+ - The hebrew example in test5.pdf shows one of our limitations:
+ Compose glyphs are not composed with the primary glyph but printed
+ as separate glyphs.
+
Modified: cupsys/trunk/debian/local/filters/pdf-filters/addtocups
==============================================================================
--- cupsys/trunk/debian/local/filters/pdf-filters/addtocups (original)
+++ cupsys/trunk/debian/local/filters/pdf-filters/addtocups Thu Aug 14 17:18:52 2008
@@ -6,11 +6,20 @@
# Copy files
cp filter/imagetopdf.c $1/filter/
cp filter/pdftoraster.cxx $1/filter/
+cp filter/texttopdf.c $1/filter/
+cp filter/pdfutils.h $1/filter/
+cp filter/pdfutils.c $1/filter/
+cp -r filter/fontembed $1/filter/
+cp filter/test_pdf1.c $1/filter/
+cp filter/test_pdf2.c $1/filter/
cp conf/imagetopdf.convs $1/conf/
cp conf/imagetopdf.types $1/conf/
cp conf/pdftopdf.convs $1/conf/
cp conf/pdftoraster.convs $1/conf/
cp conf/pdf.types $1/conf/
+cp conf/texttopdf.convs $1/conf/
+cp data/pdf.utf-8.heavy $1/data/
+cp data/pdf.utf-8.simple $1/data/
cp config-scripts/cups-pdf-filters.m4 $1/config-scripts/
# Copy directories
@@ -70,11 +79,13 @@
# Edit Makefiles
cp conf/Makefile conf/Makefile.pdf-filters
cp filter/Makefile filter/Makefile.pdf-filters
+cp data/Makefile data/Makefile.pdf-filters
cp Makefile Makefile.pdf-filters
cp Makedefs.in Makedefs.in.pdf-filters
-perl -p -i -e 's/^(\s*REPLACE\s*=.*)$/$1 imagetopdf.convs imagetopdf.types pdftopdf.convs pdftoraster.convs pdf.types/' conf/Makefile
-perl -p -i -e 's/^(\s*FILTERS\s*=\s+)/$1imagetopdf pdftoraster /' filter/Makefile
-perl -p -i -e 's/^(\s*OBJS\s*=\s+)/$1imagetopdf.o pdftoraster.o /' filter/Makefile
+perl -p -i -e 's/^(\s*REPLACE\s*=.*)$/$1 imagetopdf.convs imagetopdf.types pdftopdf.convs pdftoraster.convs pdf.types texttopdf.convs/' conf/Makefile
+perl -p -i -e 's/^(\s*FILTERS\s*=\s+)/$1imagetopdf pdftoraster texttopdf /' filter/Makefile
+perl -p -i -e 's/^(\s*OBJS\s*=\s+)/$1imagetopdf.o pdftoraster.o texttopdf.o pdfutils.o /' filter/Makefile
+perl -p -i -e 's/^(\s*CHARSETS\s*=\s+)/$1pdf.utf-8.heavy pdf.utf-8.simple /' data/Makefile
cat >> filter/Makefile <<EOF
#
@@ -98,6 +109,19 @@
\$(CC) \$(LDFLAGS) -o \$@ pdftoraster.o common.o \$(LINKCUPSIMAGE) \\
\$(POPPLER_LIBS)
+
+#
+# texttopdf
+#
+
+fontembed/libfontembed.a:
+ \$(MAKE) -C fontembed
+
+texttopdf: texttopdf.o textcommon.o common.o pdfutils.o fontembed/libfontembed.a \\
+ ../cups/\$(LIBCUPS)
+ echo Linking \$@...
+ \$(CC) \$(LDFLAGS) -o \$@ texttopdf.o textcommon.o common.o pdfutils.o -Lfontembed -lfontembed \$(LIBS)
+
EOF
perl -p -i -e 's/^(\s*DIRS\s*=.*\s+filter\s+)/$1pdftopdf /' Makefile
perl -p -i -e 's/^(\s*LIBS\s*=.*$)/$1\nPOPPLER_LIBS\t=\t\@POPPLER_LIBS\@ \$(LIBS)/' Makedefs.in
Added: cupsys/trunk/debian/local/filters/pdf-filters/conf/texttopdf.convs
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/conf/texttopdf.convs Thu Aug 14 17:18:52 2008
@@ -0,0 +1,6 @@
+application/x-cshell application/pdf 0 texttopdf
+application/x-csource application/pdf 0 texttopdf
+application/x-perl application/pdf 0 texttopdf
+application/x-shell application/pdf 0 texttopdf
+text/plain application/pdf 0 texttopdf
+text/html application/pdf 0 texttopdf
Added: cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.heavy
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.heavy Thu Aug 14 17:18:52 2008
@@ -0,0 +1,40 @@
+charset utf8
+
+#
+# This file defines the font mappings used for Unicode/UTF-8 text printing
+# through PDF.
+#
+# Each line consists of:
+#
+# first last direction width normal bold italic bold-italic
+#
+# First and last are the first and last glyphs in the font mapping
+# that correspond to that font; contrary to PostScript printing
+# they only select the font. To find the glyph the complete unicode
+# character will be looked up in the (3,1) resp. (3,0) cmap of the
+# TrueType font. The glyph values are hexadecimal.
+#
+# Direction is the string "ltor" or "rtol", indicating left-to-right or
+# right-to-left text.
+#
+# Width is the string "single" or "double"; double means that the glyphs
+# are twice as wide as ASCII characters in the Courier typeface.
+#
+# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use
+# for each presentation. If characters are only available in a single
+# style then only one typeface should be listed (e.g. "Symbol")
+#
+# Each font that is listed will be used (and downloaded if needed) when
+# printing.
+#
+
+0000 00FF ltor single COUR.TTF COURBD.TTF COURI.TTF COURBI.TTF
+0100 02FF ltor single DejaVuSansMono.ttf DejaVuSansMono-Bold.ttf DejaVuSansMono-Oblique.ttf DejaVuSansMono-BoldOblique.ttf
+0300 03FF ltor single DejaVuSansMono.ttf
+0400 04FF ltor single DejaVuSansMono.ttf DejaVuSansMono-Bold.ttf DejaVuSansMono-Oblique.ttf DejaVuSansMono-BoldOblique.ttf
+0500 05FF rtol single FreeMono.ttf
+1E00 1EFF ltor single COUR.TTF COURBD.TTF COURI.TTF COURBI.TTF
+2000 21FF ltor single DejaVuSansMono.ttf DejaVuSansMono-Bold.ttf DejaVuSansMono-Oblique.ttf DejaVuSansMono-BoldOblique.ttf
+2200 23FF ltor single SYMBOL.TTF
+3000 9FFF ltor double uming.ttc/0
+#0400 04FF ltor single FreeMono.ttf FreeMonoBold.ttf FreeMonoOblique.ttf FreeMonoBoldOblique.ttf
Added: cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.simple
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/data/pdf.utf-8.simple Thu Aug 14 17:18:52 2008
@@ -0,0 +1,32 @@
+charset utf8
+
+#
+# This file defines the font mappings used for Unicode/UTF-8 text printing
+# through PDF.
+#
+# Each line consists of:
+#
+# first last direction width normal bold italic bold-italic
+#
+# First and last are the first and last glyphs in the font mapping
+# that correspond to that font; contrary to PostScript printing
+# they only select the font. To find the glyph the complete unicode
+# character will be looked up in the (3,1) resp. (3,0) cmap of the
+# TrueType font. The glyph values are hexadecimal.
+#
+# Direction is the string "ltor" or "rtol", indicating left-to-right or
+# right-to-left text.
+#
+# Width is the string "single" or "double"; double means that the glyphs
+# are twice as wide as ASCII characters in the Courier typeface.
+#
+# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use
+# for each presentation. If characters are only available in a single
+# style then only one typeface should be listed (e.g. "Symbol")
+#
+# Each font that is listed will be used (and downloaded if needed) when
+# printing.
+#
+
+0000 04FF ltor single FreeMono.ttf FreeMonoBold.ttf FreeMonoOblique.ttf FreeMonoBoldOblique.ttf
+0500 05FF rtol single FreeMono.ttf
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/Makefile
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/Makefile Thu Aug 14 17:18:52 2008
@@ -0,0 +1,47 @@
+SOURCES=main.c sfnt.c embed.c embed_sfnt.c test_analyse.c dynstring.c test_pdf.c
+LIBOBJ=sfnt.o embed.o embed_sfnt.o dynstring.o
+EXEC=ttfread test_analyze test_pdf
+LIB=libfontembed.a
+
+#CPPFLAGS=-O3 -march=pentium -funroll-all-loops -finline-functions -Wall -g
+CPPFLAGS=-march=pentium -Wall -g
+LDFLAGS=
+
+OBJECTS=$(patsubst %.c,$(PREFIX)%$(SUFFIX).o,\
+ $(patsubst %.cpp,$(PREFIX)%$(SUFFIX).o,\
+$(SOURCES)))
+DEPENDS=$(patsubst %.c,$(PREFIX)%$(SUFFIX).d,\
+ $(patsubst %.cpp,$(PREFIX)%$(SUFFIX).d,\
+ $(filter-out %.o,""\
+$(SOURCES))))
+
+all: $(LIB)
+test: $(EXEC)
+ifneq "$(MAKECMDGOALS)" "clean"
+ -include $(DEPENDS)
+endif
+
+clean:
+ rm -f $(EXEC) $(LIB) $(OBJECTS) $(DEPENDS)
+
+%.d: %.c
+ @$(SHELL) -ec '$(CXX) -MM $(CPPFLAGS) $< \
+ | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@;\
+ [ -s $@ ] || rm -f $@'
+
+%.d: %.cpp
+ @$(SHELL) -ec '$(CXX) -MM $(CPPFLAGS) $< \
+ | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@;\
+ [ -s $@ ] || rm -f $@'
+
+$(LIB): $(LIBOBJ)
+ $(AR) rcu $@ $^
+
+ttfread: main.o $(LIB)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+test_analyze: test_analyze.o $(LIB)
+ $(CXX) -o $@ $^ $(LDFLAGS)
+
+test_pdf: test_pdf.o $(LIB)
+ $(CXX) -o $@ $^ $(LDFLAGS)
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/README
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/README Thu Aug 14 17:18:52 2008
@@ -0,0 +1,40 @@
+libfontembed - font embedding and subsetting library
+----------------------------------------------------
+
+This library implements all the stuff required to
+embed and subset TrueType fonts, as for example
+required in PDF files. It is completely self-contained,
+although a FreeType binding might come sometime in the future.
+
+Currently only glyf-flavored TrueType is supported,
+but OTF, i.e. CFF-flavored TrueType/OpenType is on the way.
+Also reencoding and conversion of Type1 to CFF is planned.
+PostScript embedding is another goal of the project.
+
+Usage
+-----
+(TODO)... see test_pdf.c ...
+
+
+License (MIT)
+-------------
+Copyright (c) 2008 by Tobias Hoffmann.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/bitset.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/bitset.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,24 @@
+#ifndef _BITSET_H
+#define _BITSET_H
+
+#include <stdlib.h>
+
+typedef int * BITSET;
+
+static inline void bit_set(BITSET bs,int num)
+{
+ bs[num/(8*sizeof(int))]|=1<<(num%(8*sizeof(int)));
+}
+
+static inline int bit_check(BITSET bs,int num)
+{
+ return bs[num/(8*sizeof(int))]&1<<(num%(8*sizeof(int)));
+}
+
+// use free() when done. returns NULL on bad_alloc
+static inline BITSET bitset_new(int size)
+{
+ return (BITSET)calloc(1,((size+31)&~31)/8);
+}
+
+#endif
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,104 @@
+#include "dynstring.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+int dyn_init(DYN_STRING *ds,int reserve_size) // {{{
+{
+ assert(ds);
+ assert(reserve_size>0);
+
+ ds->len=0;
+ ds->alloc=reserve_size;
+ ds->buf=malloc(ds->alloc+1);
+ if (!ds->buf) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ ds->len=-1;
+ return -1;
+ }
+ return 0;
+}
+// }}}
+
+void dyn_free(DYN_STRING *ds) // {{{
+{
+ assert(ds);
+
+ ds->len=-1;
+ ds->alloc=0;
+ free(ds->buf);
+ ds->buf=NULL;
+}
+// }}}
+
+int dyn_ensure(DYN_STRING *ds,int free_space) // {{{
+{
+ assert(ds);
+ assert(free_space);
+
+ if (ds->len<0) {
+ return -1;
+ }
+ if (ds->alloc - ds->len >= free_space) {
+ return 0; // done
+ }
+ ds->alloc+=free_space;
+ char *tmp=realloc(ds->buf,ds->alloc+1);
+ if (!tmp) {
+ ds->len=-1;
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ return -1;
+ }
+ ds->buf=tmp;
+ return 0;
+}
+// }}}
+
+inline int dyn_vprintf(DYN_STRING *ds,const char *fmt,va_list ap) // {{{
+{
+ assert(ds);
+
+ int need,len=strlen(fmt)+100;
+ va_list va;
+
+ if (dyn_ensure(ds,len)==-1) {
+ return -1;
+ }
+
+ while (1) {
+ va_copy(va,ap);
+ need=vsnprintf(ds->buf+ds->len,ds->alloc-ds->len+1,fmt,va);
+ va_end(va);
+ if (need==-1) {
+ len+=100;
+ } else if (need>=len) {
+ len=need;
+ } else {
+ ds->len+=need;
+ break;
+ }
+ if (dyn_ensure(ds,len)==-1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+// }}}
+
+int dyn_printf(DYN_STRING *ds,const char *fmt,...) // {{{
+{
+ va_list va;
+ int ret;
+
+ va_start(va,fmt);
+ ret=dyn_vprintf(ds,fmt,va);
+ va_end(va);
+
+ return ret;
+}
+// }}}
+
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/dynstring.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,15 @@
+#ifndef _DYNSTRING_H
+#define _DYNSTRING_H
+
+typedef struct {
+ int len,alloc;
+ char *buf;
+} DYN_STRING;
+
+int dyn_init(DYN_STRING *ds,int reserve_size); // -1 on error
+void dyn_free(DYN_STRING *ds);
+int dyn_ensure(DYN_STRING *ds,int free_space);
+int dyn_printf(DYN_STRING *ds,const char *fmt,...); // appends
+
+#endif
+
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,602 @@
+#include "embed.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "dynstring.h"
+
+#include "sfnt.h"
+
+// from embed_sfnt.c
+EMB_RIGHT_TYPE emb_otf_get_rights(OTF_FILE *otf);
+const char *emb_otf_get_fontname(OTF_FILE *otf);
+EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_widths(OTF_FILE *otf,const unsigned short *encoding,int len,const BITSET glyphs);
+EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_cidwidths(OTF_FILE *otf,const BITSET glyph);
+
+void emb_otf_get_pdf_fontdescr(OTF_FILE *otf,EMB_PDF_FONTDESCR *ret);
+
+struct _FONTFILE {
+ OTF_FILE *sfnt;
+ // ??? *cff;
+};
+void fontfile_close(FONTFILE *ff)
+{
+ if (ff) {
+ otf_close(ff->sfnt);
+ // ??? cff_close(ff->cff);
+ free(ff);
+ }
+}
+
+static inline int copy_file(FILE *f,OUTPUT_FN output,void *context) // {{{
+{
+ assert(f);
+ assert(output);
+
+ char buf[4096];
+ int iA,ret=0;
+
+ ret=0;
+ rewind(f);
+ do {
+ iA=fread(buf,1,4096,f);
+ (*output)(buf,iA,context);
+ ret+=iA;
+ } while (iA>0);
+ return ret;
+}
+// }}}
+
+EMB_PARAMS *emb_new(FONTFILE *font,EMB_DESTINATION dest,EMB_CONSTRAINTS mode) // {{{
+{
+ assert(font);
+
+ EMB_PARAMS *ret=calloc(1,sizeof(EMB_PARAMS));
+ if (!ret) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ if (mode&EMB_C_TAKE_FONTFILE) {
+ fontfile_close(font);
+ }
+ return NULL;
+ }
+ ret->dest=dest;
+ ret->font=font;
+ if (mode&EMB_C_TAKE_FONTFILE) {
+ ret->plan|=EMB_A_CLOSE_FONTFILE;
+ }
+
+ // check parameters
+ if ( (mode&EMB_C_KEEP_T1)&&(mode&EMB_C_FORCE_MULTIBYTE) ) {
+ fprintf(stderr,"Incompatible mode: KEEP_T1 and FORCE_MULTIBYTE\n");
+ emb_close(ret);
+ return NULL;
+ }
+ if ((mode&0x07)>5) {
+ fprintf(stderr,"Bad subset specification\n");
+ emb_close(ret);
+ return NULL;
+ }
+
+ // determine intype
+ // if (font->
+ ret->intype=EMB_INPUT_TTF; // for now
+ ret->rights=emb_otf_get_rights(ret->font->sfnt);
+ const int numGlyphs=ret->font->sfnt->numGlyphs; // TODO
+/*
+ if ( (ret->intype==EMB_INPUT_CFF)&&
+ (ret->cffFont.is_cid()) ) {
+ ret->plan|=EMB_A_MULTIBYTE;
+ }
+*/
+
+ // determine outtype
+ if ( (ret->intype==EMB_INPUT_T1)&&(mode&EMB_C_KEEP_T1) ) {
+ ret->outtype=EMB_OUTPUT_T1;
+ } else if (ret->intype==EMB_INPUT_TTF) {
+ if (mode&EMB_C_PDF_OT) {
+ ret->outtype=EMB_OUTPUT_SFNT;
+ } else {
+ ret->outtype=EMB_OUTPUT_TTF;
+ }
+ } else { // T1, OTF, CFF
+ if (ret->intype==EMB_INPUT_T1) {
+ ret->plan|=EMB_A_CONVERT_CFF;
+ }
+ if (mode&EMB_C_PDF_OT) {
+ ret->outtype=EMB_OUTPUT_SFNT;
+ ret->plan|=EMB_A_WRAP_SFNT;
+ } else {
+ ret->outtype=EMB_OUTPUT_CFF;
+ }
+ }
+
+ if (mode&EMB_C_FORCE_MULTIBYTE) {
+ ret->plan|=EMB_A_MULTIBYTE;
+ }
+
+ // check rights
+ if ( (ret->rights&EMB_RIGHT_NONE)||
+ (ret->rights&EMB_RIGHT_BITMAPONLY)||
+ ( (ret->rights&EMB_RIGHT_READONLY)&&(mode&EMB_C_EDITABLE_SUBSET) )||
+ ( (ret->rights&EMB_RIGHT_NO_SUBSET)&&(mode&EMB_C_MUST_SUBSET) ) ) {
+ fprintf(stderr,"The font does not permit the requested embedding\n");
+ emb_close(ret);
+ return NULL;
+ } else if ( (!(ret->rights&EMB_RIGHT_NO_SUBSET))&&
+ (!(mode&EMB_C_NEVER_SUBSET)) ) {
+ ret->plan|=EMB_A_SUBSET;
+ }
+
+ // alloc subset
+ if (ret->plan&EMB_A_SUBSET) {
+ ret->subset=bitset_new(numGlyphs);
+ if (!ret->subset) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ emb_close(ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+// }}}
+
+int emb_embed(EMB_PARAMS *emb,OUTPUT_FN output,void *context) // {{{
+{
+ assert(emb);
+
+ if (emb->intype==EMB_INPUT_TTF) {
+ assert(emb->font->sfnt);
+ if (emb->plan&EMB_A_SUBSET) {
+ return otf_subset(emb->font->sfnt,emb->subset,output,context);
+ } else if (emb->font->sfnt->numTTC) { //
+ return otf_ttc_extract(emb->font->sfnt,output,context);
+ } else {
+ // copy verbatim
+ return copy_file(emb->font->sfnt->f,output,context);
+ }
+ } else {
+ fprintf(stderr,"NOT IMPLEMENTED\n");
+ assert(0);
+ return -1;
+ }
+}
+// }}}
+
+void emb_close(EMB_PARAMS *emb) // {{{
+{
+ if (emb) {
+ free(emb->subset);
+ if (emb->plan&EMB_A_CLOSE_FONTFILE) {
+ fontfile_close(emb->font);
+ }
+ free(emb);
+ }
+}
+// }}}
+
+/*** PDF out stuff ***/
+static const int emb_pdf_font_format[]={0,1,0,0}; // {{{ (input_format) }}}
+
+static const char *emb_pdf_font_subtype[][2]={ // {{{ (format,multibyte)
+ {"Type1","CIDFontType0"},
+ {"TrueType","CIDFontType2"}};
+// }}}
+
+static const char *emb_pdf_fontfile_key[]={ // {{{ (output_format)
+ "FontFile1","FontFile2","FontFile3","Fontfile3"};
+// }}}
+
+static const char *emb_pdf_fontfile_subtype[][2]={ // {{{ (output_format,multibyte)
+ {NULL,NULL},
+ {NULL,NULL},
+ {"Type1C","CIDFontType0C"},
+ {"OpenType","OpenType"}};
+// }}}
+
+static inline int emb_multibyte(EMB_PARAMS *emb) // {{{
+{
+ return (emb->plan&EMB_A_MULTIBYTE)?1:0;
+}
+// }}}
+
+static const char *emb_pdf_escape_name(const char *name,int len) // {{{ // - statically allocated buffer
+{
+ assert(name);
+ if (len==-1) {
+ len=strlen(name);
+ }
+ assert(len<=127); // pdf implementation limit
+
+ static char buf[128*3];
+ int iA,iB;
+ const char hex[]="0123456789abcdef";
+
+ for (iA=0,iB=0;iA<len;iA++,iB++) {
+ if ( ((unsigned char)name[iA]<33)||((unsigned char)name[iA]>126)||
+ (strchr("#()<>[]{}/%",name[iA])) ) {
+ buf[iB]='#';
+ buf[++iB]=hex[(name[iA]>>4)&0x0f];
+ buf[++iB]=hex[name[iA]&0xf];
+ } else {
+ buf[iB]=name[iA];
+ }
+ }
+ buf[iB]=0;
+ return buf;
+}
+// }}}
+
+const char *emb_pdf_get_font_subtype(EMB_PARAMS *emb) // {{{
+{
+ assert(emb);
+ return emb_pdf_font_subtype[emb_pdf_font_format[emb->intype]][emb_multibyte(emb)];
+}
+// }}}
+
+const char *emb_pdf_get_fontfile_key(EMB_PARAMS *emb) // {{{
+{
+ assert(emb);
+ return emb_pdf_fontfile_key[emb->outtype];
+}
+// }}}
+
+const char *emb_pdf_get_fontfile_subtype(EMB_PARAMS *emb) // {{{
+{
+ assert(emb);
+ return emb_pdf_fontfile_subtype[emb->outtype][emb_multibyte(emb)];
+}
+// }}}
+
+// {{{ EMB_PDF_FONTDESCR *emb_pdf_fd_new(fontname,subset_tag,cid_registry,cid_ordering,cid_supplement,panose)
+EMB_PDF_FONTDESCR *emb_pdf_fd_new(const char *fontname,
+ const char *subset_tag,
+ const char *cid_registry, // or supplement==-1
+ const char *cid_ordering, // or supplement==-1
+ int cid_supplement) // -1 for non-cid
+{
+ assert(fontname);
+ EMB_PDF_FONTDESCR *ret;
+
+ int len=sizeof(EMB_PDF_FONTDESCR);
+ if (subset_tag) {
+ assert(strlen(subset_tag)==6);
+ len+=7;
+ }
+ len+=strlen(fontname)+1;
+ if (cid_supplement>=0) { // cid font
+ len+=12; // space for panose
+ assert(cid_registry);
+ assert(cid_ordering);
+ len+=strlen(cid_registry)+1;
+ len+=strlen(cid_ordering)+1;
+ }
+ ret=calloc(1,len);
+ if (!ret) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ return NULL;
+ }
+
+ // now fill the struct
+ len=0;
+ if (cid_supplement>=0) { // free space for panose is at beginning
+ len+=12;
+ }
+ ret->fontname=ret->data+len;
+ len+=strlen(fontname)+1;
+ if (subset_tag) {
+ strncpy(ret->fontname,subset_tag,6);
+ ret->fontname[6]='+';
+ strcpy(ret->fontname+7,fontname);
+ len+=7;
+ } else {
+ strcpy(ret->fontname,fontname);
+ }
+ ret->italicAngle=90;
+ if (cid_supplement>=0) {
+ ret->registry=ret->data+len;
+ strcpy(ret->registry,cid_registry);
+ len+=strlen(cid_registry)+1;
+
+ ret->ordering=ret->data+len;
+ strcpy(ret->ordering,cid_ordering);
+ len+=strlen(cid_registry)+1;
+ }
+ ret->supplement=cid_supplement;
+
+ return ret;
+}
+// }}}
+
+EMB_PDF_FONTDESCR *emb_pdf_fontdescr(EMB_PARAMS *emb) // {{{ - to be freed by user
+{
+ assert(emb);
+
+ const char *subset_tag=NULL;
+ // {{{ generate pdf subtag
+ static unsigned int rands=0;
+ if (!rands) {
+ rands=time(NULL);
+ }
+
+ char subtag[7];
+ subtag[6]=0;
+ if (emb->plan&EMB_A_SUBSET) {
+ int iA;
+ for (iA=0;iA<6;iA++) {
+ const int x=(int)(26.0*(rand_r(&rands)/(RAND_MAX+1.0)));
+ subtag[iA]='A'+x;
+ }
+ subset_tag=subtag;
+ }
+ // }}}
+
+ const char *fontname=NULL;
+ if (emb->intype==EMB_INPUT_TTF) {
+ assert(emb->font->sfnt);
+ fontname=emb_otf_get_fontname(emb->font->sfnt);
+ } else {
+ fprintf(stderr,"NOT IMPLEMENTED\n");
+ assert(0);
+ return NULL;
+ }
+
+ EMB_PDF_FONTDESCR *ret;
+ if (emb->plan&EMB_A_MULTIBYTE) { // multibyte
+ ret=emb_pdf_fd_new(fontname,subset_tag,"Adobe","Identity",0); // TODO /ROS
+ } else {
+ ret=emb_pdf_fd_new(fontname,subset_tag,NULL,NULL,-1);
+ }
+ if (!ret) {
+ return NULL;
+ }
+
+ if (emb->intype==EMB_INPUT_TTF) {
+ emb_otf_get_pdf_fontdescr(emb->font->sfnt,ret);
+ } else {
+ assert(0);
+ }
+ return ret;
+}
+// }}}
+
+// TODO: encoding into EMB_PARAMS
+EMB_PDF_FONTWIDTHS *emb_pdf_fw_new(int datasize);
+
+EMB_PDF_FONTWIDTHS *emb_pdf_fw_new(int datasize) // {{{
+{
+ assert(datasize>=0);
+ EMB_PDF_FONTWIDTHS *ret=calloc(1,sizeof(EMB_PDF_FONTWIDTHS)+datasize*sizeof(int));
+ if (!ret) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ return NULL;
+ }
+ return ret;
+}
+// }}}
+
+EMB_PDF_FONTWIDTHS *emb_pdf_fontwidths(EMB_PARAMS *emb) // {{{
+{
+ assert(emb);
+
+ if (emb->intype==EMB_INPUT_TTF) {
+ assert(emb->font->sfnt);
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ return emb_otf_get_pdf_cidwidths(emb->font->sfnt,emb->subset);
+ } else {
+ return emb_otf_get_pdf_widths(emb->font->sfnt,NULL,emb->font->sfnt->numGlyphs,emb->subset); // TODO: encoding
+ }
+ } else {
+ fprintf(stderr,"NOT IMPLEMENTED\n");
+ assert(0);
+ return NULL;
+ }
+}
+// }}}
+
+#define NEXT /* {{{ */ \
+ if ( (len<0)||(len>=size) ) { \
+ assert(0); \
+ free(ret); \
+ return NULL; \
+ } \
+ pos+=len; \
+ size-=len; /* }}} */
+
+char *emb_pdf_simple_fontdescr(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,int fontfile_obj_ref) // {{{ - to be freed by user
+{
+ assert(emb);
+ assert(fdes);
+
+ char *ret=NULL,*pos;
+ int len,size;
+
+ size=300;
+ pos=ret=malloc(size);
+ if (!ret) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return NULL;
+ }
+
+ len=snprintf(pos,size,
+ "<</Type /FontDescriptor\n"
+ " /FontName /%s\n" // TODO? handle quoting in struct?
+ " /Flags %d\n"
+ " /ItalicAngle %d\n",
+ emb_pdf_escape_name(fdes->fontname,-1),
+ fdes->flags,
+ fdes->italicAngle);
+ NEXT;
+
+ if (1) { // TODO type!=EMB_PDF_TYPE3
+ len=snprintf(pos,size,
+ " /FontBBox [%d %d %d %d]\n"
+ " /Ascend %d\n"
+ " /Descend %d\n"
+ " /CapHeight %d\n" // if font has Latin chars
+ " /StemV %d\n",
+ fdes->bbxmin,fdes->bbymin,fdes->bbxmax,fdes->bbymax,
+ fdes->ascend,
+ fdes->descend,
+ fdes->capHeight,
+ fdes->stemV);
+ NEXT;
+ }
+ if (fdes->xHeight) {
+ len=snprintf(pos,size," /XHeight %d\n",fdes->xHeight);
+ NEXT;
+ }
+ if (fdes->avgWidth) {
+ len=snprintf(pos,size," /AvgWidth %d\n",fdes->avgWidth);
+ NEXT;
+ }
+ if (fdes->panose) {
+ int iA;
+ len=snprintf(pos,size," /Style << /Panose <");
+ NEXT;
+ if (size<30) {
+ assert(0);
+ free(ret);
+ return NULL;
+ }
+ for (iA=0;iA<12;iA++) {
+ snprintf(pos+iA*2,size-iA*2,"%02x",fdes->panose[iA]);
+ }
+ size-=24;
+ pos+=24;
+ len=snprintf(pos,size,"> >>\n");
+ NEXT;
+ }
+ len=snprintf(pos,size,
+ " /%s %d 0 R\n"
+ ">>\n",
+ emb_pdf_get_fontfile_key(emb),
+ fontfile_obj_ref);
+ NEXT;
+
+ return ret;
+}
+// }}}
+
+char *emb_pdf_simple_font(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,EMB_PDF_FONTWIDTHS *fwid,int fontdescr_obj_ref) // {{{ - to be freed by user
+{
+ assert(emb);
+ assert(fdes);
+ assert(fwid);
+
+ int iA,iB;
+ DYN_STRING ret;
+
+ if (dyn_init(&ret,500)==-1) {
+ return NULL;
+ }
+
+ dyn_printf(&ret,"<</Type /Font\n"
+ " /Subtype /%s\n"
+ " /BaseFont /%s\n"
+ " /FontDescriptor %d 0 R\n",
+ emb_pdf_get_font_subtype(emb),
+ emb_pdf_escape_name(fdes->fontname,-1),
+ fontdescr_obj_ref);
+
+ if (emb->plan&EMB_A_MULTIBYTE) { // multibyte
+ assert(fwid->warray);
+ dyn_printf(&ret," /CIDSystemInfo <<\n"
+ " /Registry (%s)\n"
+ " /Ordering (%s)\n"
+ " /Supplement %d\n"
+ " >>\n"
+ " /DW %d\n",
+// " /CIDToGIDMap /Id...\n" // TrueType only, default /Identity
+ fdes->registry,
+ fdes->ordering,
+ fdes->supplement,
+ fwid->default_width);
+
+ if (fwid->warray[0]) {
+ dyn_printf(&ret," /W [");
+ for (iA=0;fwid->warray[iA];) {
+ if (fwid->warray[iA]<0) { // c1 (c1-len) w
+ dyn_printf(&ret," %d %d %d",
+ fwid->warray[iA+1],
+ fwid->warray[iA+1]-fwid->warray[iA],
+ fwid->warray[iA+2]);
+ iA+=3;
+ } else { // c [w ... w]
+ iB=fwid->warray[iA++]; // len
+ dyn_printf(&ret," %d [",fwid->warray[iA++]); // c
+ for (;iB>0;iB--) {
+ dyn_printf(&ret," %d",fwid->warray[iA++]);
+ }
+ dyn_printf(&ret,"]");
+ }
+ }
+ dyn_printf(&ret,"]\n");
+ }
+ } else { // "not std14"
+ assert(fwid->widths);
+ dyn_printf(&ret,
+ " /Encoding /MacRomanEncoding\n" // optional; TODO!!!!!
+// " /ToUnicode ?\n" // optional
+ " /FirstChar %d\n"
+ " /LastChar %d\n"
+ " /Widths [",
+ fwid->first,
+ fwid->last);
+ for (iA=0,iB=fwid->first;iB<=fwid->last;iA++,iB++) {
+ dyn_printf(&ret," %d",fwid->widths[iA]);
+ }
+ dyn_printf(&ret,"]\n");
+ }
+ dyn_printf(&ret,">>\n");
+ if (ret.len==-1) {
+ dyn_free(&ret);
+ assert(0);
+ return NULL;
+ }
+
+ return ret.buf;
+}
+// }}}
+
+char *emb_pdf_simple_cidfont(EMB_PARAMS *emb,const char *fontname,int descendant_obj_ref) // {{{ - to be freed by user
+{
+ assert(emb);
+ assert(fontname);
+
+ char *ret=NULL,*pos;
+ int len,size;
+
+ size=200;
+ pos=ret=malloc(size);
+ if (!ret) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return NULL;
+ }
+
+ len=snprintf(pos,size,
+ "<</Type /Font\n"
+ " /Subtype /Type0\n"
+ " /BaseFont /%s\n" // TODO? "-CMap-name"(/Encoding) for CidType0
+ " /Encoding /Identity-H\n"
+ // for CFF: one of:
+ // UniGB-UCS2-H, UniCNS-UCS2-H, UniJIS-UCS2-H, UniKS-UCS2-H
+ " /DescendantFonts [%d 0 R]\n",
+// " /ToUnicode ?\n" // TODO
+ emb_pdf_escape_name(fontname,-1),
+ descendant_obj_ref);
+ NEXT;
+
+ len=snprintf(pos,size,">>\n");
+ NEXT;
+
+ return ret;
+}
+// }}}
+#undef NEXT
+
+//...
+
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,118 @@
+#ifndef EMBED_H
+#define EMBED_H
+
+#include "bitset.h"
+
+typedef enum { EMB_INPUT_T1, // type1-lib, with AFM/PFM,PFA/PFB
+ EMB_INPUT_TTF, // sfnt-lib, for TTF(glyf)
+ EMB_INPUT_OTF, // sfnt-lib + cff-lib, for OTF
+ EMB_INPUT_CFF // cff-lib, for raw CFF
+ } EMB_INPUT_FORMAT;
+typedef enum { EMB_OUTPUT_T1, // original type1
+ EMB_OUTPUT_TTF, // ttf(glyf)
+ EMB_OUTPUT_CFF, // raw cff
+ EMB_OUTPUT_SFNT // OpenType (cff or glyf)
+ } EMB_OUTPUT_FORMAT;
+typedef enum { EMB_DEST_NATIVE, // just subsetting/conversion
+// TODO EMB_DEST_PS,
+ EMB_DEST_PDF16
+ } EMB_DESTINATION;
+
+typedef enum { EMB_RIGHT_FULL=0, EMB_RIGHT_NONE=0x02,
+ EMB_RIGHT_READONLY=0x04,
+ EMB_RIGHT_NO_SUBSET=0x0100,
+ EMB_RIGHT_BITMAPONLY=0x0200 } EMB_RIGHT_TYPE;
+
+typedef enum { EMB_A_MULTIBYTE=0x01, // embedd as multibyte font?
+ EMB_A_SUBSET=0x02, // do subsetting?
+ EMB_A_CONVERT_CFF=0x04, // convert Type1 to CFF?
+ EMB_A_WRAP_SFNT=0x08, // wrap in sfnt?
+
+ EMB_A_CLOSE_FONTFILE=0x8000
+ } EMB_ACTIONS;
+
+typedef struct _FONTFILE FONTFILE;
+typedef struct _EMB_PARAMS {
+ EMB_INPUT_FORMAT intype;
+ EMB_OUTPUT_FORMAT outtype;
+ EMB_DESTINATION dest;
+
+ EMB_ACTIONS plan;
+
+ // font infos
+ FONTFILE *font;
+ EMB_RIGHT_TYPE rights;
+// public:
+ BITSET subset;
+
+} EMB_PARAMS;
+
+typedef enum { EMB_C_MUST_SUBSET=0x01, // (fail, when not possible)
+ EMB_C_EDITABLE_SUBSET=0x02, // (...)
+ EMB_C_NEVER_SUBSET=0x04, // (...)
+
+ EMB_C_FORCE_MULTIBYTE=0x08, // always use multibyte fonts
+
+ EMB_C_PDF_OT=0x10, // output CFF and even TTF as OpenType (for PDF)
+ EMB_C_KEEP_T1=0x20, // don't convert T1 to CFF
+
+ EMB_C_TAKE_FONTFILE=0x8000 // take ownership of fontfile
+ } EMB_CONSTRAINTS;
+
+#ifndef OUTPUT_FN_DECLARED
+#define OUTPUT_FN_DECLARED
+typedef void (*OUTPUT_FN)(const char *buf,int len,void *context); // as in sfnt.h
+#endif
+EMB_PARAMS *emb_new(FONTFILE *font,EMB_DESTINATION dest,EMB_CONSTRAINTS mode);
+int emb_embed(EMB_PARAMS *emb,OUTPUT_FN output,void *context); // returns number of bytes written
+void emb_close(EMB_PARAMS *emb);
+
+/*** PDF out stuff ***/
+// all the necessary information for pdf font embedding
+typedef struct {
+ char *fontname;
+ unsigned int flags;
+
+ // for the following: 0=not set/invalid
+ int bbxmin,bbymin,bbxmax,bbymax;
+ int italicAngle; // >=90: not set/invalid
+ int ascend;
+ int descend;
+ int capHeight;
+ int stemV;
+ // optional, default=0:
+ int xHeight;
+ int avgWidth;
+
+ // CID-additions:
+ char *panose; // 12 bytes
+ char *registry,*ordering;
+ int supplement;
+
+ char data[]; // used for storing e.g. >fontname
+} EMB_PDF_FONTDESCR;
+
+typedef struct {
+ // normal font
+ int first,last;
+ int *widths;
+
+ // multibyte font
+ int default_width;
+ int *warray; // format: len c w ... w if (len<0) { c1 (c2=c1+(-len)) w } else { c w[len] }, terminated by len==0
+
+ int data[];
+} EMB_PDF_FONTWIDTHS;
+
+const char *emb_pdf_get_font_subtype(EMB_PARAMS *emb);
+const char *emb_pdf_get_fontfile_key(EMB_PARAMS *emb);
+const char *emb_pdf_get_fontfile_subtype(EMB_PARAMS *emb);
+
+EMB_PDF_FONTDESCR *emb_pdf_fontdescr(EMB_PARAMS *emb);
+EMB_PDF_FONTWIDTHS *emb_pdf_fontwidths(EMB_PARAMS *emb);
+
+char *emb_pdf_simple_fontdescr(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,int fontfile_obj_ref);
+char *emb_pdf_simple_font(EMB_PARAMS *emb,EMB_PDF_FONTDESCR *fdes,EMB_PDF_FONTWIDTHS *fwid,int fontdescr_obj_ref);
+char *emb_pdf_simple_cidfont(EMB_PARAMS *emb,const char *fontname,int descendant_obj_ref);
+
+#endif
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed_sfnt.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/embed_sfnt.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,582 @@
+#include "embed.h"
+#include "sfnt.h"
+#include "sfnt_int.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// from embed.c
+EMB_PDF_FONTWIDTHS *emb_pdf_fw_new(int datasize);
+
+EMB_RIGHT_TYPE emb_otf_get_rights(OTF_FILE *otf) // {{{
+{
+ EMB_RIGHT_TYPE ret=EMB_RIGHT_FULL;
+
+ int len;
+ char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len);
+ if (os2) {
+ const unsigned short os2_version=get_USHORT(os2);
+ // check len
+ assert( (os2_version!=0x0000)||(len==78) );
+ assert( (os2_version!=0x0001)||(len==86) );
+ assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) );
+ if (os2_version<=0x0004) {
+ // get rights
+ unsigned short fsType=get_USHORT(os2+8);
+ ret=fsType&0x0200;
+ if ((fsType&0x0f)==0x0002) {
+ ret|=EMB_RIGHT_NONE;
+ } else if ((fsType&0x0f)==0x0004) {
+ ret|=EMB_RIGHT_READONLY;
+ }
+ }
+ free(os2);
+ }
+ return ret;
+}
+// }}}
+
+// NOTE: statically allocated buffer
+const char *emb_otf_get_fontname(OTF_FILE *otf) // {{{
+{
+ static char fontname[64];
+
+ int len;
+ const char *fname=otf_get_name(otf,3,1,0x409,6,&len); // microsoft
+ if (fname) {
+ int iA,iB=0;
+ for (iA=0;(iA<63)&&(iA*2<len);iA++) {
+ if ( (fname[2*iA]==0)&&
+ (fname[2*iA+1]>=33)&&(fname[2*iA+1]<=126)&&
+ (!strchr("[](){}<>/%",fname[iA*2+1])) ) {
+ fontname[iB++]=fname[iA*2+1];
+ }
+ }
+ fontname[iB]=0;
+ } else if ((fname=otf_get_name(otf,1,0,0,6,&len))) { // mac
+ int iA,iB=0;
+ for (iA=0;(iA<63)&&(iA<len);iA++) {
+ if ( (fname[iA]>=33)&&(fname[iA]<=126)&&
+ (!strchr("[](){}<>/%",fname[iA])) ) {
+ fontname[iB++]=fname[iA];
+ }
+ }
+ fontname[iB]=0;
+ } else {
+ fontname[0]=0;
+ }
+ if (!*fontname) {
+ // TODO construct a fontname, eg from */*/*/4
+ fprintf(stderr,"WARNING: no fontName\n");
+ }
+ return fontname;
+}
+// }}}
+
+void emb_otf_get_pdf_fontdescr(OTF_FILE *otf,EMB_PDF_FONTDESCR *ret) // {{{
+{
+ int len;
+
+// TODO
+// ... fill in struct
+ char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len);
+ assert(head); // version is 1.0 from otf_load
+ ret->bbxmin=get_SHORT(head+36)*1000/otf->unitsPerEm;
+ ret->bbymin=get_SHORT(head+38)*1000/otf->unitsPerEm;
+ ret->bbxmax=get_SHORT(head+40)*1000/otf->unitsPerEm;
+ ret->bbymax=get_SHORT(head+42)*1000/otf->unitsPerEm;
+ const int macStyle=get_USHORT(head+44);
+ free(head);
+
+ char *post=otf_get_table(otf,OTF_TAG('p','o','s','t'),&len);
+ assert(post);
+ const unsigned int post_version=get_ULONG(post);
+ // check length
+ assert( (post_version!=0x00010000)||(len==32) );
+ assert( (post_version!=0x00020000)||(len>=34+2*otf->numGlyphs) );
+ assert( (post_version!=0x00025000)||(len==35+otf->numGlyphs) );
+ assert( (post_version!=0x00030000)||(len==32) );
+ assert( (post_version!=0x00020000)||(get_USHORT(post+32)==otf->numGlyphs) );
+// assert( (post_version==0x00030000)==(!!(otf->flags&OTF_F_FMT_CFF)) ); // ghostscript embedding does this..
+ // TODO: v4 (apple) : uint16 reencoding[numGlyphs]
+ if ( (post_version==0x00010000)||
+ (post_version==0x00020000)||
+ (post_version==0x00025000)||
+ (post_version==0x00030000) ) {
+ ret->italicAngle=get_LONG(post+4)>>16;
+ if (get_ULONG(post+12)>0) { // monospaced
+ ret->flags|=1;
+ }
+ } else {
+ fprintf(stderr,"WARNING: no italicAngle, no monospaced flag\n");
+ }
+ free(post);
+
+ char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len);
+ if (os2) {
+ const unsigned short os2_version=get_USHORT(os2);
+ // check len
+ assert( (os2_version!=0x0000)||(len==78) );
+ assert( (os2_version!=0x0001)||(len==86) );
+ assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) );
+ if (os2_version<=0x0004) {
+
+ // from PDF14Deltas.pdf, pg 113
+ const int weightClass=get_USHORT(os2+4);
+ ret->stemV=50+weightClass*weightClass/(65*65); // TODO, really bad
+//printf("a %d\n",weightClass);
+
+ if (ret->supplement>=0) { // cid
+ ret->panose=ret->data;
+ memcpy(ret->panose,os2+30,12); // sFamilyClass + panose
+ }
+ const unsigned short fsSelection=get_USHORT(os2+62);
+ if (fsSelection&0x01) { // italic
+ ret->flags|=0x0040;
+ }
+ if ( (fsSelection&0x10)&&(weightClass>600) ) { // force bold
+ ret->flags|=0x0400;
+ }
+ const unsigned char family_class=get_USHORT(os2+30)>>8;
+ if (family_class==10) { // script
+ ret->flags|=0x0008;
+ }
+ if (family_class!=8) { // not sans-serif
+ ret->flags|=0x0002;
+ }
+
+ ret->avgWidth=get_SHORT(os2+2);
+ ret->ascend=get_SHORT(os2+68)*1000/otf->unitsPerEm;
+ ret->descend=get_SHORT(os2+70)*1000/otf->unitsPerEm;
+ if (os2_version>=0x0002) {
+ ret->xHeight=get_SHORT(os2+86)*1000/otf->unitsPerEm;
+ ret->capHeight=get_SHORT(os2+88)*1000/otf->unitsPerEm;
+ } // else capHeight fixed later
+ } else {
+ free(os2);
+ os2=NULL;
+ }
+ } else {
+ fprintf(stderr,"WARNING: no OS/2 table\n");
+ // e.g. subsetted font from ghostscript // e.g. CFF
+ }
+ if (os2) {
+ free(os2);
+ } else { // TODO (if(CFF))
+ fprintf(stderr,"WARNING: no ascend/descend, capHeight, stemV, flags\n");
+ if (macStyle&0x01) { // force bold - just do it on bold
+ ret->flags|=0x0400;
+ }
+ if (macStyle&0x02) { // italic
+ ret->flags|=0x0004;
+ }
+ // ... flags TODO? (Serif, Script, Italic, AllCap,SmallCap, ForceBold)
+ }
+
+// ? maybe get ascend,descend,capHeight,xHeight,stemV directly from cff
+ // Fallbacks
+ if ( (!ret->ascend)||(!ret->descend) ) {
+ char *hhea=otf_get_table(otf,OTF_TAG('h','h','e','a'),&len);
+ if (hhea) {
+ ret->ascend=get_SHORT(hhea+4)*1000/otf->unitsPerEm;
+ ret->descend=get_SHORT(hhea+6)*1000/otf->unitsPerEm;
+ }
+ free(hhea);
+ }
+ if (!ret->stemV) { // TODO? use name
+ const unsigned short d_gid=otf_from_unicode(otf,'.');
+ if (d_gid) { // stemV=bbox['.'].width;
+ len=otf_get_glyph(otf,d_gid);
+ assert(len>=10);
+ ret->stemV=(get_SHORT(otf->gly+6)-get_SHORT(otf->gly+2))*1000/otf->unitsPerEm;
+ } else {
+ if (macStyle&1) { // bold
+ ret->stemV=165;
+ } else {
+ ret->stemV=109; // TODO... unserious values...
+ }
+ }
+ }
+ if (!ret->capHeight) { // TODO? only reqd. for fonts with latin...
+ ret->capHeight=ret->ascend;
+ }
+ if (0) { // TODO? uses only adobe latin standard? ?? e.g. Type1
+ ret->flags|=0x0020;
+ } else {
+ ret->flags|=0x0004;
+ }
+ // TODO SmallCap by font name(?)
+
+// TODO ; ? cid ?
+}
+// }}}
+
+EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_widths(OTF_FILE *otf,const unsigned short *encoding,int len,const BITSET glyphs) // {{{ glyphs==NULL -> all from 0 to len
+{
+ assert(otf);
+
+ int first=len,last=0;
+ int iA;
+
+ if (glyphs) {
+ for (iA=0;iA<len;iA++) {
+ const int gid=(encoding)?encoding[iA]:otf_from_unicode(otf,iA); // TODO
+ if (bit_check(glyphs,gid)) {
+ if (first>iA) {
+ first=iA;
+ }
+ if (last<iA) {
+ last=iA;
+ }
+ }
+ }
+ } else {
+ first=0;
+ last=len;
+ }
+ if (last<first) {
+ // empty
+ fprintf(stderr,"WARNING: empty embedding range\n");
+ return NULL;
+ }
+
+ // ensure hmtx is there
+ if (!otf->hmtx) {
+ if (otf_load_more(otf)!=0) {
+ assert(0);
+ return NULL;
+ }
+ }
+
+ // now create the array
+ EMB_PDF_FONTWIDTHS *ret=emb_pdf_fw_new(last-first+1);
+ if (!ret) {
+ return NULL;
+ }
+ ret->first=first;
+ ret->last=last;
+ ret->widths=ret->data;
+ for (iA=0;first<=last;iA++,first++) {
+ const int gid=(encoding)?encoding[first]:otf_from_unicode(otf,first); // TODO
+ if (gid>=otf->numGlyphs) {
+ fprintf(stderr,"Bad glyphid\n");
+ assert(0);
+ free(ret);
+ return NULL;
+ }
+ if ( (!glyphs)||(bit_check(glyphs,gid)) ) {
+ ret->widths[iA]=get_width_fast(otf,gid)*1000/otf->unitsPerEm;
+ } // else 0 from calloc
+ }
+
+ return ret;
+}
+// }}}
+
+// TODO: split into general part and otf specific part
+EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_cidwidths(OTF_FILE *otf,const BITSET glyphs) // {{{ // glyphs==NULL -> output all
+{
+ assert(otf);
+
+ int iA,b,c;
+ int dw=otf_get_width(otf,0)*1000/otf->unitsPerEm,size=0; // also ensures otf->hmtx
+ assert(dw>=0);
+ // TODO? dw from hmtx(otf->numberOfHMetrics);
+
+ int in_array=0; // current number of elements in array mode
+
+ // first pass
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+ if ( (!glyphs)||(glyphs[b]&c) ) {
+ if (in_array) {
+ in_array++;
+ } else {
+ size+=2; // len c
+ in_array=1;
+ }
+ } else {
+ size+=in_array;
+ in_array=0;
+ }
+ }
+ size+=in_array;
+
+ // now create the array
+ EMB_PDF_FONTWIDTHS *ret=emb_pdf_fw_new(size+1);
+ if (!ret) {
+ return NULL;
+ }
+ ret->default_width=dw;
+ ret->warray=ret->data;
+
+ // second pass
+ in_array=0;
+ size=0;
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+ if ( (!glyphs)||(glyphs[b]&c) ) {
+ const int w=get_width_fast(otf,iA)*1000/otf->unitsPerEm;
+ if ( (in_array<0)&&(ret->warray[size-1]==w) ) {
+ in_array--; // just add
+ ret->warray[size-3]=in_array; // fix len;
+ continue;
+ }
+ if (in_array>0) {
+ if ( (w==dw)&&(ret->warray[size-1]==dw) ) { // omit this and prev
+ size--;
+ in_array--; // !=0, as it does not start with >dw
+ ret->warray[size-in_array-2]=in_array; // fix len
+ } else if ( (in_array>=2)&&
+ (ret->warray[size-1]==w)&&
+ (ret->warray[size-2]==w) ) {
+ // three in a row. c1 c2 w is equally short
+ if (in_array==2) { // completely replace
+ size-=4;
+ } else {
+ size-=2;
+ ret->warray[size-in_array-2]=in_array; // fix len
+ in_array=-2;
+ }
+ in_array=-2;
+ ret->warray[size++]=in_array;
+ ret->warray[size++]=iA-2;
+ ret->warray[size++]=w;
+ } else { // just add
+ in_array++;
+ ret->warray[size++]=w;
+ ret->warray[size-in_array-2]=in_array; // fix len
+ }
+ } else if (w!=dw) {
+ in_array=1;
+ ret->warray[size++]=in_array; // len
+ ret->warray[size++]=iA; // c
+ ret->warray[size++]=w;
+ } else { // especially for in_array<0
+ in_array=0;
+ }
+ } else {
+ in_array=0;
+ }
+ }
+ ret->warray[size]=0; // terminator
+ return ret;
+}
+// }}}
+
+/*** PS stuff ***/
+
+#include "dynstring.h"
+
+// NOTE: statically allocated string
+const char *get_glyphname(const char *post,unsigned short *to_unicode,unsigned short gid)
+{
+ /*
+ ... TODO: consult post table, if there.
+ ... otherwise consult fallback table
+ ... otherwise generate "uni...".
+ ... otherwise unique name c01...
+ */
+ return "";
+}
+
+struct OUTFILTER_PS {
+ OUTPUT_FN out;
+ void *ctx;
+ int len;
+};
+
+static void outfilter_ascii_ps(const char *buf,int len,void *context) // {{{
+{
+ struct OUTFILTER_PS *of=context;
+ OUTPUT_FN out=of->out;
+ int iA;
+
+ if (len*2+of->len > 64000) {
+ (*out)("00>\n",4,of->ctx);
+ (*out)("<",1,of->ctx);
+ of->len+=5;
+ }
+ char tmp[256];
+ while (len>0) {
+ for (iA=0;(iA<40)&&(len>0);iA++,len--) {
+ sprintf(tmp+2*iA,"%02x",buf[iA]);
+ }
+ tmp[iA]='\n';
+ (*out)(tmp,iA*2+1,of->ctx);
+ of->len+=iA*2+1;
+ }
+}
+// }}}
+
+static void outfilter_binary_ps(const char *buf,int len,void *context) // {{{
+{
+ struct OUTFILTER_PS *of=context;
+ OUTPUT_FN out=of->out;
+
+ char tmp[100];
+ const int l=sprintf(tmp,"%d RD ",len);
+ (*out)(tmp,l,of->ctx);
+ of->len+=l;
+
+ (*out)(buf,len,of->ctx);
+ (*out)("\n",1,of->ctx);
+ of->len+=len+1;
+}
+// }}}
+
+/*
+ encoding: character-code -> glyph id ["required", NULL: identity(?)[or: from_unicode()]] // TODO: respect subsetting
+ to_unicode: character-code -> unicode [NULL: no char names]
+*/
+int emb_otf_ps(OTF_FILE *otf,unsigned short *encoding,int len,unsigned short *to_unicode,OUTPUT_FN output,void *context) // {{{
+{
+ const int binary=0; // binary format? // TODO
+ if (len>256) {
+ fprintf(stderr,"Encoding too big(%d) for Type42\n",len);
+ return -1;
+ }
+ int iA,ret=0;
+
+ DYN_STRING ds;
+ if (dyn_init(&ds,1024)==-1) {
+ return -1;
+ }
+
+ int rlen=0;
+ char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&rlen);
+ if (!head) {
+ free(ds.buf);
+ return -1;
+ }
+ dyn_printf(&ds,"%!PS-TrueTypeFont-%d-%d\n",
+ otf->version,get_ULONG(head+4));
+ const int bbxmin=get_SHORT(head+36)*1000/otf->unitsPerEm,
+ bbymin=get_SHORT(head+38)*1000/otf->unitsPerEm,
+ bbxmax=get_SHORT(head+40)*1000/otf->unitsPerEm,
+ bbymax=get_SHORT(head+42)*1000/otf->unitsPerEm;
+ free(head);
+
+ char *post=otf_get_table(otf,OTF_TAG('p','o','s','t'),&rlen);
+ if ( (!post)&&(rlen!=-1) ) { // other error than "not found"
+ free(ds.buf);
+ return -1;
+ }
+ if (post) {
+ const unsigned int minMem=get_ULONG(post+16),maxMem=get_ULONG(post+20);
+ if (minMem) {
+ dyn_printf(&ds,"%%VMusage: %d %d\n",minMem,maxMem);
+ }
+ }
+
+ dyn_printf(&ds,"11 dict begin\n"
+ "/FontName /%s def\n"
+ "/Encoding 256 array\n"
+ "0 1 255 { 1 index exch /.notdef put } for\n",
+ emb_otf_get_fontname(otf));
+ for (iA=0;iA<len;iA++) {
+ const int gid=(encoding)?encoding[iA]:iA;
+ dyn_printf(&ds,"dup %d /%s put\n",
+ iA,get_glyphname(post,to_unicode,gid));
+ }
+ dyn_printf(&ds,"readonly def\n");
+
+ dyn_printf(&ds,"/PaintType 0 def\n"
+ "/FontMatrix [1 0 0 1 0 0] def\n"
+ "/FontBBox [%d %d %d %d] def\n"
+ "/FontType 42 def\n",
+// "/XUID\n" // TODO?!?
+ bbxmin,bbymin,bbxmax,bbymax);
+ if (post) {
+ dyn_printf(&ds,"/FontInfo 4 dict dup begin\n"
+ " /ItalicAngle %d def\n"
+ " /isFixedPitch %d def\n"
+ " /UnderlinePosition %d def\n"
+ " /UnderlineThickness %d def\n"
+ "end readonly def\n",
+ get_LONG(post+4)>>16,
+ get_ULONG(post+12),
+ (get_SHORT(post+8)-get_SHORT(post+10)/2)*1000/otf->unitsPerEm,
+ get_SHORT(post+10)*1000/otf->unitsPerEm);
+ }
+ if (binary) {
+ dyn_printf(&ds,"/RD { string currentfile exch readstring pop } executeonly def\n");
+ }
+
+ dyn_printf(&ds,"/sfnts[");
+ if (ds.len<0) {
+ free(post);
+ free(ds.buf);
+ return -1;
+ }
+ (*output)(ds.buf,ds.len,context);
+ ret+=ds.len;
+ ds.len=0;
+
+ // {{{ copy tables verbatim
+ struct _OTF_WRITE *otw;
+ otw=malloc(sizeof(struct _OTF_WRITE)*otf->numTables);
+ if (!otw) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ free(post);
+ free(ds.buf);
+ return -1;
+ }
+ // just copy everything
+ for (iA=0;iA<otf->numTables;iA++) {
+ otw[iA].tag=otf->tables[iA].tag;
+ otw[iA].action=otf_action_copy;
+ otw[iA].param=otf;
+ otw[iA].length=iA;
+ }
+
+ struct OUTFILTER_PS of;
+ of.out=output;
+ of.ctx=context;
+ of.len=0;
+ if (binary) {
+ iA=otf_write_sfnt(otw,otf->version,otf->numTables,outfilter_binary_ps,&of);
+ } else {
+ iA=otf_write_sfnt(otw,otf->version,otf->numTables,outfilter_ascii_ps,&of);
+ }
+ free(otw);
+ if (iA==-1) {
+ free(post);
+ free(ds.buf);
+ return -1;
+ }
+ ret+=of.len;
+
+ dyn_printf(&ds,"] def\n");
+ // }}} done copying
+
+ const int num_chars=0;
+ dyn_printf(&ds,"/CharStrings %d dict dup begin\n",num_chars);
+ for (iA=0;iA<num_chars;iA++) {
+ const int gid=(encoding)?encoding[iA]:iA;
+ dyn_printf(&ds,"/%s %d def\n",get_glyphname(post,to_unicode,gid),gid);
+// ... from cmap [respecting subsetting...]
+ }
+ dyn_printf(&ds,"Fontname currentdict end definefont pop\n");
+ free(post);
+
+ if (ds.len<0) {
+ free(ds.buf);
+ return -1;
+ }
+ (*output)(ds.buf,ds.len,context);
+ ret+=ds.len;
+ ds.len=0;
+
+ free(ds.buf);
+ return ret;
+}
+// }}}
+
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/main.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/main.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,166 @@
+#include "sfnt.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "embed.h"
+
+struct _FONTFILE {
+ OTF_FILE *sfnt;
+ // CFF *;
+};
+
+#if 0
+enum { TTF_OTF, TYPE1 } inputFile;
+if (TTF_OTF) {
+ assert(!TTC);
+ if (CFF/OTF) {
+ // or EMB_PDF_FONTFILE3_OTF [unstripped]
+ if (CIDfont) {
+ asset(multiBYTE);
+ strip_sfnt() // "CIDFontType0" EMB_PDF_FONTFILE3_CID0C
+ } else {
+ ... strip_sfnt();
+ }
+ } else {
+ ...
+ }
+} else if (TYPE1) {
+ assert(!MMType1);
+ assert(!OCF);
+ assert(!WrappedCID_CFF);
+ ... convert_to_cff()
+}
+// not supported: MMType1 Type3
+#endif
+
+#include <string.h>
+
+static void example_outfn(const char *buf,int len,void *context) // {{{
+{
+ FILE *f=(FILE *)context;
+ if (fwrite(buf,1,len,f)!=len) {
+ fprintf(stderr,"Short write: %m\n");
+ assert(0);
+ return;
+ }
+}
+// }}}
+
+void example_write_fontdescr(OTF_FILE *otf,const char *outfile) // {{{
+{
+ struct _FONTFILE ff; ff.sfnt=otf; // TODO
+ EMB_PARAMS *emb=emb_new(&ff,
+ EMB_DEST_PDF16,
+// EMB_C_KEEP_T1
+ EMB_C_FORCE_MULTIBYTE
+
+ );
+ EMB_PDF_FONTDESCR *fdes=emb_pdf_fontdescr(emb);
+ assert(fdes);
+ assert(emb->subset);
+
+ bit_set(emb->subset,otf_from_unicode(otf,'a'));
+ bit_set(emb->subset,otf_from_unicode(otf,0x400));
+
+ EMB_PDF_FONTWIDTHS *fwid=emb_pdf_fontwidths(emb);
+ assert(fwid);
+
+ printf("0 0 obj\n");
+ char *res=emb_pdf_simple_fontdescr(emb,fdes,1);
+ assert(res);
+ fputs(res,stdout);
+ free(res);
+ printf("endobj\n");
+
+ printf("1 0 obj\n"
+ "<<\n");
+ if (emb_pdf_get_fontfile_subtype(emb)) {
+ printf(" /SubType /%s\n",
+ emb_pdf_get_fontfile_subtype(emb));
+ }
+ if (emb->outtype&EMB_OUTPUT_T1) {
+ printf(" /Length1 ?\n"
+ " /Length2 ?\n"
+ " /Length3 ?\n");
+ } else {
+ printf(" /Length1 2 0 R\n");
+ }
+ printf(" /Length 2 0 R\n" // maybe compress it...
+ ">>\n"
+ "stream\n");
+ int outlen=0; // TODO
+// TODO
+ if (outfile) {
+ FILE *f=fopen(outfile,"w");
+ if (!f) {
+ fprintf(stderr,"Opening \"%s\" for writing failed: %m\n",outfile);
+ assert(0);
+ return;
+ }
+ outlen=emb_embed(emb,example_outfn,f);
+// outlen=otf_ttc_extract(emb->font->sfnt,example_outfn,f);
+ fclose(f);
+ }
+puts("...");
+ printf("endstream\n"
+ "endobj\n");
+ printf("2 0 obj\n"
+ "%d\n"
+ "endobj\n",
+ outlen
+ );
+
+ printf("3 0 obj\n");
+ res=emb_pdf_simple_font(emb,fdes,fwid,0);
+ assert(res);
+ fputs(res,stdout);
+ free(res);
+ printf("endobj\n");
+
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ printf("4 0 obj\n");
+ res=emb_pdf_simple_cidfont(emb,fdes->fontname,3);
+ assert(res);
+ fputs(res,stdout);
+ free(res);
+ printf("endobj\n");
+ }
+
+ free(fdes);
+ free(fwid);
+}
+// }}}
+
+// TODO? reencode?
+int main(int argc,char **argv)
+{
+ const char *fn="/usr/share/fonts/truetype/microsoft/ARIALN.TTF";
+ if (argc==2) {
+ fn=argv[1];
+ }
+ OTF_FILE *otf=otf_load(fn);
+ assert(otf);
+ printf("width(4): %d\n",otf_get_width(otf,4));
+
+
+ if (strcmp(fn,"test.ttf")!=0) {
+ example_write_fontdescr(otf,"test.ttf");
+ } else {
+ example_write_fontdescr(otf,NULL);
+ }
+
+ // show_post(otf);
+
+ // show_name(otf);
+
+ // show_cmap(otf);
+ // printf("%d %d\n",otf_from_unicode(otf,'A'),0);
+
+ // ... name 6 -> FontName /20(cid)
+ // ? StemV Flags(?) from FontName
+
+ otf_close(otf);
+
+ return 0;
+}
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,1317 @@
+#include "sfnt.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "sfnt_int.h"
+
+// TODO?
+// get_SHORT(head+48) // fontDirectionHint
+/* reqd. Tables: cmap, head, hhea, hmtx, maxp, name, OS/2, post .
+ OTF: glyf,loca [cvt,fpgm,prep]
+ */
+
+static void otf_bsearch_params(int num, // {{{
+ int recordSize,
+ int *searchRange,
+ int *entrySelector,
+ int *rangeShift)
+{
+ assert(num>0);
+ assert(searchRange);
+ assert(entrySelector);
+ assert(rangeShift);
+
+ int iA,iB;
+ for (iA=1,iB=0;iA<=num;iA<<=1,iB++) {}
+
+ *searchRange=iA*recordSize/2;
+ *entrySelector=iB-1;
+ *rangeShift=num*recordSize-*searchRange;
+}
+// }}}
+
+static char *otf_bsearch(char *table, // {{{
+ const char *target,int len,
+ int searchRange,
+ int entrySelector,
+ int rangeShift,
+ int lower_bound) // return lower_bound, if !=0
+{
+ char *ret=table+rangeShift;
+ if (memcmp(target,ret,len)<0) {
+ ret=table;
+ }
+
+ for (;entrySelector>0;entrySelector--) {
+ searchRange>>=1;
+ ret+=searchRange;
+ if (memcmp(target,ret,len)<0) {
+ ret-=searchRange;
+ }
+ }
+ const int result=memcmp(target,ret,len);
+ if (result==0) {
+ return ret;
+ } else if (lower_bound) {
+ if (result>0) {
+ return ret+searchRange;
+ }
+ return ret;
+ }
+ return NULL; // not found;
+}
+// }}}
+
+static OTF_FILE *otf_new(FILE *f) // {{{
+{
+ assert(f);
+
+ OTF_FILE *ret;
+ ret=calloc(1,sizeof(OTF_FILE));
+ if (ret) {
+ ret->f=f;
+ }
+ ret->version=0x00010000;
+
+ return ret;
+}
+// }}}
+
+static char *otf_read(OTF_FILE *otf,char *buf,long pos,int length) // {{{ - will alloc, if >buf ==NULL, returns >buf, or NULL on error
+{
+ char *ours=NULL;
+
+ if (length==0) {
+ return buf;
+ } else if (length<0) {
+ assert(0);
+ return NULL;
+ }
+
+ int res=fseek(otf->f,pos,SEEK_SET);
+ if (res==-1) {
+ fprintf(stderr,"Seek failed: %m\n");
+ return NULL;
+ }
+
+ // (+3)&~3 for checksum...
+ const int pad_len=(length+3)&~3;
+ if (!buf) {
+ ours=buf=malloc(sizeof(char)*pad_len);
+ if (!buf) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return NULL;
+ }
+ }
+
+ res=fread(buf,1,pad_len,otf->f);
+ if (res!=pad_len) {
+ if (res==length) { // file size not multiple of 4, pad with zero
+ memset(buf+res,0,pad_len-length);
+ } else {
+ fprintf(stderr,"Short read\n");
+ free(ours);
+ return NULL;
+ }
+ }
+
+ return buf;
+}
+// }}}
+
+static unsigned int otf_checksum(const char *buf, unsigned int len) // {{{
+{
+ unsigned int ret=0;
+
+ for (len=(len+3)/4;len>0;len--,buf+=4) {
+ ret+=get_ULONG(buf);
+ }
+
+ return ret;
+}
+// }}}
+
+
+static int otf_get_ttc_start(OTF_FILE *otf,int use_ttc) // {{{
+{
+ char buf[4];
+
+ if (!otf->numTTC) { // >0 if TTC...
+ return 0;
+ }
+
+ int pos=0;
+ if ( (use_ttc<0)||(use_ttc>=otf->numTTC)||
+ (!otf_read(otf,buf,pos+12+4*use_ttc,4)) ) {
+ fprintf(stderr,"Bad TTC subfont number\n");
+ return -1;
+ }
+ return get_ULONG(buf);
+}
+// }}}
+
+OTF_FILE *otf_do_load(OTF_FILE *otf,int pos) // {{{
+{
+ int iA;
+ char buf[16];
+
+ // {{{ read offset table
+ if (otf_read(otf,buf,pos,12)) {
+ otf->version=get_ULONG(buf);
+ if (otf->version==0x00010000) { // 1.0 truetype
+ } else if (otf->version==OTF_TAG('O','T','T','O')) { // OTF(CFF)
+ otf->flags|=OTF_F_FMT_CFF;
+ } else if (otf->version==OTF_TAG('t','r','u','e')) { // (old mac)
+ } else if (otf->version==OTF_TAG('t','y','p','1')) { // sfnt wrapped type1
+ // TODO: unsupported
+ } else {
+ otf_close(otf);
+ otf=NULL;
+ }
+ pos+=12;
+ } else {
+ otf_close(otf);
+ otf=NULL;
+ }
+ if (!otf) {
+ fprintf(stderr,"Not a ttf font\n");
+ return NULL;
+ }
+ otf->numTables=get_USHORT(buf+4);
+ // }}}
+
+ // {{{ read directory
+ otf->tables=malloc(sizeof(OTF_DIRENT)*otf->numTables);
+ if (!otf->tables) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ otf_close(otf);
+ return NULL;
+ }
+ for (iA=0;iA<otf->numTables;iA++) {
+ if (!otf_read(otf,buf,pos,16)) {
+ otf_close(otf);
+ return NULL;
+ }
+ otf->tables[iA].tag=get_ULONG(buf);
+ otf->tables[iA].checkSum=get_ULONG(buf+4);
+ otf->tables[iA].offset=get_ULONG(buf+8);
+ otf->tables[iA].length=get_ULONG(buf+12);
+ if ( (otf->tables[iA].tag==OTF_TAG('C','F','F',' '))&&
+ ((otf->flags&OTF_F_FMT_CFF)==0) ) {
+ fprintf(stderr,"Wrong magic\n");
+ otf_close(otf);
+ return NULL;
+ } else if ( (otf->tables[iA].tag==OTF_TAG('g','l','y','p'))&&
+ (otf->flags&OTF_F_FMT_CFF) ) {
+ fprintf(stderr,"Wrong magic\n");
+ otf_close(otf);
+ return NULL;
+ }
+ pos+=16;
+ }
+ // }}}
+
+// otf->flags|=OTF_F_DO_CHECKSUM;
+ // {{{ check head table
+ int len=0;
+ char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len);
+ if ( (!head)||
+ (get_ULONG(head+0)!=0x00010000)|| // version
+ (len!=54)||
+ (get_ULONG(head+12)!=0x5F0F3CF5)|| // magic
+ (get_SHORT(head+52)!=0x0000) ) { // glyphDataFormat
+ fprintf(stderr,"Unsupported OTF font / head table \n");
+ free(head);
+ otf_close(otf);
+ return NULL;
+ }
+ // }}}
+ otf->unitsPerEm=get_USHORT(head+18);
+ otf->indexToLocFormat=get_SHORT(head+50);
+
+ // {{{ checksum whole file
+ if (otf->flags&OTF_F_DO_CHECKSUM) {
+ unsigned int csum=0;
+ char tmp[1024];
+ rewind(otf->f);
+ while (!feof(otf->f)) {
+ len=fread(tmp,1,1024,otf->f);
+ if (len&3) { // zero padding reqd.
+ memset(tmp+len,0,4-(len&3));
+ }
+ csum+=otf_checksum(tmp,len);
+ }
+ if (csum!=0xb1b0afba) {
+ fprintf(stderr,"Wrong global checksum\n");
+ free(head);
+ otf_close(otf);
+ return NULL;
+ }
+ }
+ // }}}
+ free(head);
+
+ // {{{ read maxp table / numGlyphs
+ char *maxp=otf_get_table(otf,OTF_TAG('m','a','x','p'),&len);
+ if (maxp) {
+ const unsigned int maxp_version=get_ULONG(maxp);
+ if ( (maxp_version==0x00005000)&&(len==6) ) { // version 0.5
+ otf->numGlyphs=get_USHORT(maxp+4);
+ if ( (otf->flags&OTF_F_FMT_CFF)==0) { // only CFF
+ free(maxp);
+ maxp=NULL;
+ }
+ } else if ( (maxp_version==0x00010000)&&(len==32) ) { // version 1.0
+ otf->numGlyphs=get_USHORT(maxp+4);
+ if (otf->flags&OTF_F_FMT_CFF) { // only TTF
+ free(maxp);
+ maxp=NULL;
+ }
+ } else {
+ free(maxp);
+ maxp=NULL;
+ }
+ }
+ if (!maxp) {
+ fprintf(stderr,"Unsupported OTF font / maxp table \n");
+ free(maxp);
+ otf_close(otf);
+ return NULL;
+ }
+ free(maxp);
+ // }}}
+
+ return otf;
+}
+// }}}
+
+OTF_FILE *otf_load(const char *file) // {{{
+{
+ FILE *f;
+ OTF_FILE *otf;
+
+ int use_ttc=-1;
+ if ((f=fopen(file,"rb"))==NULL) {
+ // check for TTC
+ char *tmp=strrchr(file,'/'),*end;
+ if (tmp) {
+ use_ttc=strtoul(tmp+1,&end,10);
+ if (!*end) {
+ end=malloc((tmp-file+1)*sizeof(char));
+ if (!end) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return NULL;
+ }
+ strncpy(end,file,tmp-file);
+ end[tmp-file]=0;
+ f=fopen(end,"rb");
+ free(end);
+ }
+ }
+ if (!f) {
+ fprintf(stderr,"Could not open \"%s\": %m\n",file);
+ return NULL;
+ }
+ }
+ otf=otf_new(f);
+ if (!otf) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ fclose(f);
+ return NULL;
+ }
+
+ char buf[12];
+ int pos=0;
+ // {{{ check for TTC
+ if (otf_read(otf,buf,pos,12)) {
+ const unsigned int version=get_ULONG(buf);
+ if (version==OTF_TAG('t','t','c','f')) {
+ const unsigned int ttc_version=get_ULONG(buf+4);
+ if ( (ttc_version!=0x00010000)&&(ttc_version!=0x00020000) ) {
+ fprintf(stderr,"Unsupported TTC version\n");
+ otf_close(otf);
+ return NULL;
+ }
+ otf->numTTC=get_ULONG(buf+8);
+ otf->useTTC=use_ttc;
+ pos=otf_get_ttc_start(otf,use_ttc);
+ if (pos==-1) {
+ otf_close(otf);
+ return NULL;
+ }
+ }
+ } else {
+ fprintf(stderr,"Not a ttf font\n");
+ otf_close(otf);
+ return NULL;
+ }
+ // }}}
+
+ return otf_do_load(otf,pos);
+}
+// }}}
+
+void otf_close(OTF_FILE *otf) // {{{
+{
+ assert(otf);
+ if (otf) {
+ free(otf->gly);
+ free(otf->cmap);
+ free(otf->name);
+ free(otf->hmtx);
+ free(otf->glyphOffsets);
+ fclose(otf->f);
+ free(otf->tables);
+ free(otf);
+ }
+}
+// }}}
+
+static int otf_find_table(OTF_FILE *otf,unsigned int tag) // {{{ -1 on error
+{
+#if 0
+ // binary search would require raw table
+ int pos=0;
+ char buf[12];
+ if (!otf_read(otf,buf,pos,12)) {
+ return -1;
+ }
+ pos=12;
+ const unsigned int numTables=get_USHORT(buf+4);
+ char *tables=malloc(16*numTables);
+ if (!tables) {
+ return -1;
+ }
+ if (!otf_read(otf,tables,pos,16*numTables)) {
+ free(tables);
+ return -1;
+ }
+ char target[]={(tag>>24),(tag>>16),(tag>>8),tag};
+ // assert(get_USHORT(buf+6)+get_USHORT(buf+10)==16*numTables);
+ char *result=otf_bsearch(tables,target,4,
+ get_USHORT(buf+6),
+ get_USHORT(buf+8),
+ get_USHORT(buf+10),0);
+ free(tables);
+ if (result) {
+ return (result-tables)/16;
+ }
+#else
+ int iA;
+ for (iA=0;iA<otf->numTables;iA++) {
+ if (otf->tables[iA].tag==tag) {
+ return iA;
+ }
+ }
+#endif
+ return -1;
+}
+// }}}
+
+char *otf_get_table(OTF_FILE *otf,unsigned int tag,int *ret_len) // {{{
+{
+ assert(otf);
+ assert(ret_len);
+
+ const int idx=otf_find_table(otf,tag);
+ if (idx==-1) {
+ *ret_len=-1;
+ return NULL;
+ }
+ const OTF_DIRENT *table=otf->tables+idx;
+
+ char *ret=otf_read(otf,NULL,table->offset,table->length);
+ if (!ret) {
+ return NULL;
+ }
+ if (otf->flags&OTF_F_DO_CHECKSUM) {
+ unsigned int csum=otf_checksum(ret,table->length);
+ if (tag==OTF_TAG('h','e','a','d')) { // special case
+ csum-=get_ULONG(ret+8);
+ }
+ if (csum!=table->checkSum) {
+ fprintf(stderr,"Wrong checksum for %c%c%c%c\n",OTF_UNTAG(tag));
+ free(ret);
+ return NULL;
+ }
+ }
+ *ret_len=table->length;
+ return ret;
+}
+// }}}
+
+int otf_load_glyf(OTF_FILE *otf) // {{{ - 0 on success
+{
+ assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
+ int iA,len;
+ // {{{ find glyf table
+ iA=otf_find_table(otf,OTF_TAG('g','l','y','f'));
+ if (iA==-1) {
+ fprintf(stderr,"Unsupported OTF font / glyf table \n");
+ return -1;
+ }
+ otf->glyfTable=otf->tables+iA;
+ // }}}
+
+ // {{{ read loca table
+ char *loca=otf_get_table(otf,OTF_TAG('l','o','c','a'),&len);
+ if ( (!loca)||
+ (otf->indexToLocFormat>=2)||
+ (((len+3)&~3)!=((((otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2)+3)&~3)) ) {
+ fprintf(stderr,"Unsupported OTF font / loca table \n");
+ return -1;
+ }
+ if (otf->glyphOffsets) {
+ free(otf->glyphOffsets);
+ assert(0);
+ }
+ otf->glyphOffsets=malloc((otf->numGlyphs+1)*sizeof(unsigned int));
+ if (!otf->glyphOffsets) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return -1;
+ }
+ if (otf->indexToLocFormat==0) {
+ for (iA=0;iA<=otf->numGlyphs;iA++) {
+ otf->glyphOffsets[iA]=get_USHORT(loca+iA*2)*2;
+ }
+ } else { // indexToLocFormat==1
+ for (iA=0;iA<=otf->numGlyphs;iA++) {
+ otf->glyphOffsets[iA]=get_ULONG(loca+iA*4);
+ }
+ }
+ free(loca);
+ if (otf->glyphOffsets[otf->numGlyphs]>otf->glyfTable->length) {
+ fprintf(stderr,"Bad loca table \n");
+ return -1;
+ }
+ // }}}
+
+ // {{{ allocate otf->gly slot
+ int maxGlyfLen=0; // no single glyf takes more space
+ for (iA=1;iA<=otf->numGlyphs;iA++) {
+ const int glyfLen=otf->glyphOffsets[iA]-otf->glyphOffsets[iA-1];
+ if (glyfLen<0) {
+ fprintf(stderr,"Bad loca table: glyph len %d\n",glyfLen);
+ return -1;
+ }
+ if (maxGlyfLen<glyfLen) {
+ maxGlyfLen=glyfLen;
+ }
+ }
+ if (otf->gly) {
+ free(otf->gly);
+ assert(0);
+ }
+ otf->gly=malloc(maxGlyfLen*sizeof(char));
+ if (!otf->gly) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return -1;
+ }
+ // }}}
+
+ return 0;
+}
+// }}}
+
+int otf_load_more(OTF_FILE *otf) // {{{ - 0 on success
+{
+ int iA;
+
+ int len;
+ if ((otf->flags&OTF_F_FMT_CFF)==0) { // not for CFF
+ if (otf_load_glyf(otf)==-1) {
+ return -1;
+ }
+ }
+
+ // {{{ read hhea table
+ char *hhea=otf_get_table(otf,OTF_TAG('h','h','e','a'),&len);
+ if ( (!hhea)||
+ (get_ULONG(hhea)!=0x00010000)|| // version
+ (len!=36)||
+ (get_SHORT(hhea+32)!=0) ) { // metric format
+ fprintf(stderr,"Unsupported OTF font / hhea table \n");
+ return -1;
+ }
+ otf->numberOfHMetrics=get_USHORT(hhea+34);
+ free(hhea);
+ // }}}
+
+ // {{{ read hmtx table
+ char *hmtx=otf_get_table(otf,OTF_TAG('h','m','t','x'),&len);
+ if ( (!hmtx)||
+ (len!=otf->numberOfHMetrics*2+otf->numGlyphs*2) ) {
+ fprintf(stderr,"Unsupported OTF font / hmtx table \n");
+ return -1;
+ }
+ if (otf->hmtx) {
+ free(otf->hmtx);
+ assert(0);
+ }
+ otf->hmtx=hmtx;
+ // }}}
+
+ // {{{ read name table
+ char *name=otf_get_table(otf,OTF_TAG('n','a','m','e'),&len);
+ if ( (!name)||
+ (get_USHORT(name)!=0x0000)|| // version
+ (len<get_USHORT(name+2)*12+6)||
+ (len<=get_USHORT(name+4)) ) {
+ fprintf(stderr,"Unsupported OTF font / name table \n");
+ return -1;
+ }
+ // check bounds
+ int name_count=get_USHORT(name+2);
+ const char *nstore=name+get_USHORT(name+4);
+ for (iA=0;iA<name_count;iA++) {
+ const char *nrec=name+6+12*iA;
+ if (nstore-name+get_USHORT(nrec+10)+get_USHORT(nrec+8)>len) {
+ fprintf(stderr,"Bad name table \n");
+ free(name);
+ return -1;
+ }
+ }
+ if (otf->name) {
+ free(otf->name);
+ assert(0);
+ }
+ otf->name=name;
+ // }}}
+
+ return 0;
+}
+// }}}
+
+int otf_load_cmap(OTF_FILE *otf) // {{{ - 0 on success
+{
+ int iA;
+ int len;
+
+ char *cmap=otf_get_table(otf,OTF_TAG('c','m','a','p'),&len);
+ if ( (!cmap)||
+ (get_USHORT(cmap)!=0x0000)|| // version
+ (len<get_USHORT(cmap+2)*8+4) ) {
+ fprintf(stderr,"Unsupported OTF font / cmap table \n");
+ assert(0);
+ return -1;
+ }
+ // check bounds, find (3,0) or (3,1) [TODO?]
+ const int numTables=get_USHORT(cmap+2);
+ for (iA=0;iA<numTables;iA++) {
+ const char *nrec=cmap+4+8*iA;
+ const unsigned int offset=get_ULONG(nrec+4);
+ const char *ndata=cmap+offset;
+ if ( (ndata<cmap+4+8*numTables)||
+ (offset>=len)||
+ (offset+get_USHORT(ndata+2)>len) ) {
+ fprintf(stderr,"Bad cmap table \n");
+ free(cmap);
+ assert(0);
+ return -1;
+ }
+ if ( (get_USHORT(nrec)==3)&&
+ (get_USHORT(nrec+2)<=1)&&
+ (get_USHORT(ndata)==4)&&
+ (get_USHORT(ndata+4)==0) ) {
+ otf->unimap=ndata;
+ }
+ }
+ if (otf->cmap) {
+ free(otf->cmap);
+ assert(0);
+ }
+ otf->cmap=cmap;
+
+ return 0;
+}
+// }}}
+
+int otf_get_width(OTF_FILE *otf,unsigned short gid) // {{{ -1 on error
+{
+ assert(otf);
+
+ if (gid>=otf->numGlyphs) {
+ return -1;
+ }
+
+ // ensure hmtx is there
+ if (!otf->hmtx) {
+ if (otf_load_more(otf)!=0) {
+ assert(0);
+ return -1;
+ }
+ }
+
+ return get_width_fast(otf,gid);
+#if 0
+ if (gid>=otf->numberOfHMetrics) {
+ return get_USHORT(otf->hmtx+(otf->numberOfHMetrics-1)*2);
+ // TODO? lsb=get_SHORT(otf->hmtx+otf->numberOfHMetrics*2+gid*2);
+ }
+ return get_USHORT(otf->hmtx+gid*4);
+ // TODO? lsb=get_SHORT(otf->hmtx+gid*4+2);
+#endif
+}
+// }}}
+
+static int otf_name_compare(const void *a,const void *b) // {{{
+{
+ return memcmp(a,b,8);
+}
+// }}}
+
+const char *otf_get_name(OTF_FILE *otf,int platformID,int encodingID,int languageID,int nameID,int *ret_len) // {{{
+{
+ assert(otf);
+ assert(ret_len);
+
+ // ensure name is there
+ if (!otf->name) {
+ if (otf_load_more(otf)!=0) {
+ *ret_len=-1;
+ assert(0);
+ return NULL;
+ }
+ }
+
+ char key[8];
+ set_USHORT(key,platformID);
+ set_USHORT(key+2,encodingID);
+ set_USHORT(key+4,languageID);
+ set_USHORT(key+6,nameID);
+
+ char *res=bsearch(key,otf->name+6,get_USHORT(otf->name+2),12,otf_name_compare);
+ if (res) {
+ *ret_len=get_USHORT(res+8);
+ int npos=get_USHORT(res+10);
+ const char *nstore=otf->name+get_USHORT(otf->name+4);
+ return nstore+npos;
+ }
+ *ret_len=0;
+ return NULL;
+}
+// }}}
+
+int otf_get_glyph(OTF_FILE *otf,unsigned short gid) // {{{ result in >otf->gly, returns length, -1 on error
+{
+ assert(otf);
+ assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF
+
+ if (gid>=otf->numGlyphs) {
+ return -1;
+ }
+
+ // ensure >glyphOffsets and >gly is there
+ if ( (!otf->gly)||(!otf->glyphOffsets) ) {
+ if (otf_load_more(otf)!=0) {
+ assert(0);
+ return -1;
+ }
+ }
+
+ const int len=otf->glyphOffsets[gid+1]-otf->glyphOffsets[gid];
+ if (len==0) {
+ return 0;
+ }
+
+ assert(otf->glyfTable->length>=otf->glyphOffsets[gid+1]);
+ if (!otf_read(otf,otf->gly,
+ otf->glyfTable->offset+otf->glyphOffsets[gid],len)) {
+ return -1;
+ }
+
+ return len;
+}
+// }}}
+
+unsigned short otf_from_unicode(OTF_FILE *otf,int unicode) // {{{ 0 = missing
+{
+ assert(otf);
+ assert( (unicode>=0)&&(unicode<65536) );
+// assert((otf->flags&OTF_F_FMT_CFF)==0); // not for CFF, other method!
+
+ // ensure >cmap and >unimap is there
+ if (!otf->cmap) {
+ if (otf_load_cmap(otf)!=0) {
+ assert(0);
+ return 0; // TODO?
+ }
+ }
+ if (!otf->unimap) {
+ fprintf(stderr,"Unicode (3,1) cmap in format 4 not found\n");
+ return 0;
+ }
+
+#if 0
+ // linear search is cache friendly and should be quite fast
+#else
+ const unsigned short segCountX2=get_USHORT(otf->unimap+6);
+ char target[]={unicode>>8,unicode}; // set_USHORT(target,unicode);
+ char *result=otf_bsearch((char *)otf->unimap+14,target,2,
+ get_USHORT(otf->unimap+8),
+ get_USHORT(otf->unimap+10),
+ get_USHORT(otf->unimap+12),1);
+ if (result>=otf->unimap+14+segCountX2) {
+ assert(0); // bad font, no 0xffff
+ return 0;
+ }
+
+ result+=2+segCountX2;
+ const unsigned short startCode=get_USHORT(result);
+ if (startCode>unicode) {
+ return 0;
+ }
+ result+=2*segCountX2;
+ const unsigned short rangeOffset=get_USHORT(result);
+ if (rangeOffset) {
+ return get_USHORT(result+rangeOffset+2*(unicode-startCode));
+ } else {
+ const short delta=get_SHORT(result-segCountX2);
+ return (delta+unicode)&0xffff;
+ }
+#endif
+}
+// }}}
+
+#include "bitset.h"
+
+static int otf_subset_glyf(OTF_FILE *otf,int gid,BITSET glyphs) // {{{ include components of compund glyphs, returns additional space requirements
+{
+ int ret=0;
+ if (get_SHORT(otf->gly)>=0) { // not composite
+ return ret; // done
+ }
+
+ char *cur=otf->gly+10;
+
+ unsigned short flags;
+ do {
+ flags=get_USHORT(cur);
+ const unsigned short sub_gid=get_USHORT(cur+2);
+ assert(sub_gid<otf->numGlyphs);
+ if (!bit_check(glyphs,sub_gid)) {
+ // bad: temporarily load sub glyph
+ const int len=otf_get_glyph(otf,sub_gid);
+ assert(len>0);
+ bit_set(glyphs,sub_gid);
+ if (sub_gid<gid) {
+ ret+=len;
+ ret+=otf_subset_glyf(otf,sub_gid,glyphs); // composite of composites?, e.g. in DejaVu
+ }
+ const int res=otf_get_glyph(otf,gid); // reload current glyph
+ assert(res);
+ }
+
+ // skip parameters
+ cur+=6;
+ if (flags&0x01) {
+ cur+=2;
+ }
+ if (flags&0x08) {
+ cur+=2;
+ } else if (flags&0x40) {
+ cur+=4;
+ } else if (flags&0x80) {
+ cur+=8;
+ }
+ } while (flags&0x20); // more components
+
+ return ret;
+}
+// }}}
+
+int otf_subset2(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written
+{
+ assert(otf);
+ assert(glyphs);
+ assert(output);
+
+ int iA,b,c;
+ int ret=0;
+
+ // first pass
+ bit_set(glyphs,0); // .notdef always required
+ int glyfSize=0;
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+ if (glyphs[b]&c) {
+ int len=otf_get_glyph(otf,iA);
+ if (len<0) {
+ assert(0);
+ return -1;
+ } else if (len>0) {
+ glyfSize+=len;
+ len=otf_subset_glyf(otf,iA,glyphs);
+ if (len<0) {
+ assert(0);
+ return -1;
+ }
+ glyfSize+=len;
+ }
+ }
+ }
+
+ int locaSize=((otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2+3)&~3;
+ glyfSize=(glyfSize+3)&~3;
+ // second pass
+ char *new_loca=malloc(locaSize);
+ char *new_glyf=malloc(glyfSize);
+ if ( (!new_loca)||(!new_glyf) ) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ free(new_loca);
+ free(new_glyf);
+ return -1;
+ }
+
+ int offset=0;
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+
+ assert(offset%2==0);
+ // TODO? change format? if glyfSize<0x20000
+ if (otf->indexToLocFormat==0) {
+ set_USHORT(new_loca+iA*2,offset/2);
+ } else { // ==1
+ set_ULONG(new_loca+iA*4,offset);
+ }
+
+ if (glyphs[b]&c) {
+ const int len=otf_get_glyph(otf,iA);
+ assert(len>=0);
+ memcpy(new_glyf+offset,otf->gly,len);
+ offset+=len;
+ }
+ }
+ // last entry
+ if (otf->indexToLocFormat==0) {
+ set_USHORT(new_loca+otf->numGlyphs*2,offset/2);
+ } else { // ==1
+ set_ULONG(new_loca+otf->numGlyphs*4,offset);
+ }
+ // zero padding
+ assert(glyfSize-offset<4);
+ for (iA=offset;iA<glyfSize;iA++) {
+ new_glyf[iA]=0;
+ }
+ assert(offset<=glyfSize);
+//assert(offset==glyfSize); // else TODO 0 padding
+
+ // copy some tables
+#define MAX_TABLES 11
+ int iB,new_numTables=MAX_TABLES;
+ OTF_DIRENT new_tables[MAX_TABLES]={
+ {OTF_TAG('c','m','a','p'),},
+ {OTF_TAG('c','v','t',' '),},
+ {OTF_TAG('f','p','g','m'),},
+ {OTF_TAG('g','l','y','f'),},
+ {OTF_TAG('h','e','a','d'),},
+ {OTF_TAG('h','h','e','a'),},
+ {OTF_TAG('h','m','t','x'),},
+ {OTF_TAG('l','o','c','a'),},
+ {OTF_TAG('m','a','x','p'),},
+ {OTF_TAG('n','a','m','e'),},
+ {OTF_TAG('p','r','e','p'),}};
+ for (iA=0,iB=0;(iA<otf->numTables)&&(iB<MAX_TABLES);) {
+ if (otf->tables[iA].tag==new_tables[iB].tag) {
+ new_tables[iB].checkSum=otf->tables[iA].checkSum;
+ new_tables[iB].offset=iA;
+ new_tables[iB].length=otf->tables[iA].length;
+ iA++;
+ iB++;
+ } else if (otf->tables[iA].tag<new_tables[iB].tag) {
+ iA++;
+ } else {
+ new_tables[iB].tag=0; // don't output
+ iB++;
+ new_numTables--;
+ }
+ }
+
+ // now we have to know all the checksums and lengths
+ //TODO ? reduce cmap [to (1,0) ;-)]
+ // glyf
+ new_tables[3].checkSum=otf_checksum(new_glyf,glyfSize);
+ new_tables[3].length=offset;
+ // loca
+ new_tables[7].checkSum=otf_checksum(new_loca,locaSize);
+ new_tables[7].length=(otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2;
+
+ // offset table + directory
+ char new_start[12+MAX_TABLES*16];
+ set_ULONG(new_start,0x00010000); // TODO ? true / original value
+ set_USHORT(new_start+4,new_numTables);
+ otf_bsearch_params(new_numTables,16,&iA,&iB,&c);
+ set_USHORT(new_start+6,iA);
+ set_USHORT(new_start+8,iB);
+ set_USHORT(new_start+10,c);
+
+ unsigned int csum=0;
+ offset=12+16*new_numTables;
+ iB=12;
+ for (iA=0;iA<MAX_TABLES;iA++) {
+ if (!new_tables[iA].tag) {
+ continue;
+ }
+ set_ULONG(new_start+iB,new_tables[iA].tag);
+ set_ULONG(new_start+iB+4,new_tables[iA].checkSum);
+ set_ULONG(new_start+iB+8,offset);
+ set_ULONG(new_start+iB+12,new_tables[iA].length);
+ iB+=16;
+ offset+=(new_tables[iA].length+3)&~3;
+ csum+=new_tables[iA].checkSum;
+ }
+ assert(iB==12+16*new_numTables);
+ (*output)(new_start,iB,context);
+ ret+=iB;
+ csum+=otf_checksum(new_start,iB);
+
+ // now output the tables / copy them
+ iB=12+8;
+ for (iA=0;iA<MAX_TABLES;iA++) {
+ if (!new_tables[iA].tag) {
+ continue;
+ }
+ if (iA==3) { // glyf
+ (*output)(new_glyf,glyfSize,context);
+ ret+=glyfSize;
+ } else if (iA==7) { // loca
+ (*output)(new_loca,locaSize,context);
+ ret+=locaSize;
+ } else { // just copy
+ const OTF_DIRENT *table=otf->tables+new_tables[iA].offset;
+ char *data=otf_read(otf,NULL,table->offset,table->length);
+ assert(data);
+ if (iA==4) { // head. fix global checksum
+ set_ULONG(data+8,0xb1b0afba-csum);
+ }
+ assert(ret==get_ULONG(new_start+iB));
+ (*output)(data,(table->length+3)&~3,context);
+ ret+=(table->length+3)&~3;
+ free(data);
+ }
+ iB+=16;
+ }
+
+ // TODO? suggested ordering
+ // head, hhea, maxp, hmtx, cmap, fpgm, prep, cvt, loca, glyf, name
+
+ // copy some tables [cvt,fpgm,(glyf),head!,hhea,hmtx,(loca),maxp,name(?),prep]
+
+ //TODO (cmap for non-cid)
+
+ free(new_loca);
+ free(new_glyf);
+ return ret;
+#undef MAX_TABLES
+}
+// }}}
+
+int otf_action_copy(void *param,int table_no,OUTPUT_FN output,void *context) // {{{
+{
+ OTF_FILE *otf=param;
+ const OTF_DIRENT *table=otf->tables+table_no;
+
+ if (!output) { // get checksum and unpadded length
+ *(unsigned int *)context=table->checkSum;
+ return table->length;
+ }
+
+ char *data=otf_read(otf,NULL,table->offset,table->length);
+ if (!data) {
+ return -1;
+ }
+ int ret=(table->length+3)&~3;
+ (*output)(data,ret,context);
+ free(data);
+ return ret; // padded length
+}
+// }}}
+
+// TODO? >modified time-stamp?
+int otf_action_copy_head(void *param,int csum,OUTPUT_FN output,void *context) // {{{
+{
+ OTF_FILE *otf=param;
+ const int table_no=otf_find_table(otf,OTF_TAG('h','e','a','d'));
+ assert(table_no!=-1);
+ const OTF_DIRENT *table=otf->tables+table_no;
+
+ if (!output) { // get checksum and unpadded length
+ *(unsigned int *)context=table->checkSum;
+ return table->length;
+ }
+
+ char *data=otf_read(otf,NULL,table->offset,table->length);
+ if (!data) {
+ return -1;
+ }
+ set_ULONG(data+8,0xb1b0afba-csum); // head. fix global checksum
+ int ret=(table->length+3)&~3;
+ (*output)(data,ret,context);
+ free(data);
+ return ret; // padded length
+}
+// }}}
+
+int otf_action_replace(void *param,int length,OUTPUT_FN output,void *context) // {{{
+{
+ char *data=param;
+ char pad[4]={0,0,0,0};
+
+ int ret=(length+3)&~3;
+ if (!output) { // get checksum and unpadded length
+ if (ret!=length) {
+ unsigned int csum=otf_checksum(data,ret-4);
+ memcpy(pad,data+ret-4,ret-length);
+ csum+=get_ULONG(pad);
+ *(unsigned int *)context=csum;
+ } else {
+ *(unsigned int *)context=otf_checksum(data,length);
+ }
+ return length;
+ }
+
+ (*output)(data,length,context);
+ if (ret!=length) {
+ (*output)(pad,ret-length,context);
+ }
+
+ return ret; // padded length
+}
+// }}}
+
+int otf_write_sfnt(struct _OTF_WRITE *otw,unsigned int version,int numTables,OUTPUT_FN output,void *context) // {{{
+{
+ int iA;
+ int ret;
+
+ // find head
+ int headAt=-1;
+ for (iA=0;iA<numTables;iA++) {
+ if ( (otw[iA].tag==OTF_TAG('h','e','a','d'))&&
+ (otw[iA].action==otf_action_copy) ) {
+ // only this supported for now
+ headAt=iA;
+ }
+ }
+
+ // TODO? sort tables
+
+ char *start=malloc(12+16*numTables);
+ if (!start) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return -1;
+ }
+
+ // the header
+ set_ULONG(start,version);
+ set_USHORT(start+4,numTables);
+ int a,b,c;
+ otf_bsearch_params(numTables,16,&a,&b,&c);
+ set_USHORT(start+6,a);
+ set_USHORT(start+8,b);
+ set_USHORT(start+10,c);
+
+ // first pass: calculate table directory / offsets and checksums
+ unsigned int globalSum=0,csum;
+ int pos,res;
+ int offset=12+16*numTables;
+ pos=12;
+ for (iA=0;iA<numTables;iA++) {
+ set_ULONG(start+pos,otw[iA].tag);
+ res=(*otw[iA].action)(otw[iA].param,otw[iA].length,NULL,&csum);
+ assert(res>=0);
+ set_ULONG(start+pos+4,csum);
+ set_ULONG(start+pos+8,offset);
+ set_ULONG(start+pos+12,res);
+ pos+=16;
+ offset+=(res+3)&~3; // padding
+ globalSum+=csum;
+ }
+
+ // second pass: write actual data
+ // write header + directory
+ (*output)(start,pos,context);
+ ret=pos;
+ globalSum+=otf_checksum(start,pos);
+ if (headAt!=-1) {
+ otw[headAt].action=otf_action_copy_head;
+ otw[headAt].length=globalSum;
+ }
+
+ // write tables
+ for (iA=0;iA<numTables;iA++) {
+ assert(ret==get_ULONG(start+12+16*iA+8)); // table directory correct?
+ res=(*otw[iA].action)(otw[iA].param,otw[iA].length,output,context);
+ if (res<0) {
+ free(start);
+ return -1;
+ }
+ assert(((res+3)&~3)==res); // correctly padded?
+ ret+=(res+3)&~3;
+ }
+ assert(offset==ret);
+ free(start);
+
+ return ret;
+}
+// }}}
+
+int otf_ttc_extract(OTF_FILE *otf,OUTPUT_FN output,void *context) // {{{
+{
+ assert(otf);
+ assert(output);
+ assert(otf->numTTC);
+ int iA;
+
+ struct _OTF_WRITE *otw;
+ otw=malloc(sizeof(struct _OTF_WRITE)*otf->numTables);
+ if (!otw) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ return -1;
+ }
+
+ // just copy everything
+ for (iA=0;iA<otf->numTables;iA++) {
+ otw[iA].tag=otf->tables[iA].tag;
+ otw[iA].action=otf_action_copy;
+ otw[iA].param=otf;
+ otw[iA].length=iA;
+ }
+ iA=otf_write_sfnt(otw,otf->version,otf->numTables,output,context);
+ free(otw);
+
+ return iA;
+}
+// }}}
+
+int otf_subset(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written
+{
+ assert(otf);
+ assert(glyphs);
+ assert(output);
+
+ int iA,iB,b,c;
+ int ret=0;
+
+ // first pass: include all required glyphs
+ bit_set(glyphs,0); // .notdef always required
+ int glyfSize=0;
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+ if (glyphs[b]&c) {
+ int len=otf_get_glyph(otf,iA);
+ if (len<0) {
+ assert(0);
+ return -1;
+ } else if (len>0) {
+ glyfSize+=len;
+ len=otf_subset_glyf(otf,iA,glyphs);
+ if (len<0) {
+ assert(0);
+ return -1;
+ }
+ glyfSize+=len;
+ }
+ }
+ }
+
+ // second pass: calculate new glyf and loca
+ int locaSize=(otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2;
+
+ char *new_loca=malloc(locaSize);
+ char *new_glyf=malloc(glyfSize);
+ if ( (!new_loca)||(!new_glyf) ) {
+ fprintf(stderr,"Bad alloc: %m\n");
+ assert(0);
+ free(new_loca);
+ free(new_glyf);
+ return -1;
+ }
+
+ int offset=0;
+ for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
+ if (!c) {
+ b++;
+ c=1;
+ }
+
+ assert(offset%2==0);
+ // TODO? change format? if glyfSize<0x20000
+ if (otf->indexToLocFormat==0) {
+ set_USHORT(new_loca+iA*2,offset/2);
+ } else { // ==1
+ set_ULONG(new_loca+iA*4,offset);
+ }
+
+ if (glyphs[b]&c) {
+ const int len=otf_get_glyph(otf,iA);
+ assert(len>=0);
+ memcpy(new_glyf+offset,otf->gly,len);
+ offset+=len;
+ }
+ }
+ // last entry
+ if (otf->indexToLocFormat==0) {
+ set_USHORT(new_loca+otf->numGlyphs*2,offset/2);
+ } else { // ==1
+ set_ULONG(new_loca+otf->numGlyphs*4,offset);
+ }
+ assert(offset==glyfSize);
+
+ // determine new tables.
+#define MAX_TABLES 12
+ int numTables=0;
+ struct _OTF_WRITE otw[MAX_TABLES]={
+ {OTF_TAG('c','m','a','p'),otf_action_copy,otf,},
+ {OTF_TAG('c','v','t',' '),otf_action_copy,otf,},
+ {OTF_TAG('f','p','g','m'),otf_action_copy,otf,},
+ {OTF_TAG('g','l','y','f'),otf_action_replace,new_glyf,glyfSize},
+ {OTF_TAG('h','e','a','d'),otf_action_copy,otf,}, // _copy_head
+ {OTF_TAG('h','h','e','a'),otf_action_copy,otf,},
+ {OTF_TAG('h','m','t','x'),otf_action_copy,otf,},
+ {OTF_TAG('l','o','c','a'),otf_action_replace,new_loca,locaSize},
+ {OTF_TAG('m','a','x','p'),otf_action_copy,otf,},
+ {OTF_TAG('n','a','m','e'),otf_action_copy,otf,},
+ {OTF_TAG('p','r','e','p'),otf_action_copy,otf,},
+ {0,0,0,0}};
+
+ for (iA=0;(iA<otf->numTables)&&(otw[numTables].tag);) {
+ if (otf->tables[iA].tag==otw[numTables].tag) {
+ if (otw[numTables].param==otf) {
+ otw[numTables].length=iA;
+ }
+ iA++;
+ numTables++;
+ } else if (otf->tables[iA].tag<otw[numTables].tag) {
+ iA++;
+ } else {
+ memmove(otw+numTables,otw+numTables+1,sizeof(struct _OTF_WRITE)*(MAX_TABLES-numTables-1)); // don't output
+ }
+ }
+ // write them
+ ret=otf_write_sfnt(otw,otf->version,numTables,output,context);
+
+ free(new_loca);
+ free(new_glyf);
+ return ret;
+
+ // TODO? suggested ordering
+ // head, hhea, maxp, hmtx, cmap, fpgm, prep, cvt, loca, glyf, name
+ // copy some tables [cvt,fpgm,(glyf),head!,hhea,hmtx,(loca),maxp,name(?),prep]
+
+ //TODO ? reduce cmap [to (1,0) ;-)]
+ //TODO (cmap for non-cid)
+}
+// }}}
+
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,64 @@
+#ifndef _SFNT_H
+#define _SFNT_H
+
+#include "bitset.h"
+
+typedef struct {
+ unsigned int tag;
+ unsigned int checkSum;
+ unsigned int offset;
+ unsigned int length;
+} OTF_DIRENT;
+
+typedef struct _IO_FILE FILE;
+
+typedef struct {
+ FILE *f;
+ unsigned int numTTC,useTTC;
+ unsigned int version;
+
+ unsigned short numTables;
+ OTF_DIRENT *tables;
+
+ int flags;
+ unsigned short unitsPerEm;
+ unsigned short indexToLocFormat; // 0=short, 1=long
+ unsigned short numGlyphs;
+
+ // optionally loaded data
+ unsigned int *glyphOffsets;
+ unsigned short numberOfHMetrics;
+ char *hmtx,*name,*cmap;
+ const char *unimap; // ptr to (3,1) or (3,0) cmap start
+
+ // single glyf buffer, allocated large enough by otf_load_more()
+ char *gly;
+ OTF_DIRENT *glyfTable;
+
+} OTF_FILE;
+#define OTF_F_FMT_CFF 0x10000
+#define OTF_F_DO_CHECKSUM 0x40000
+
+// to load TTC collections: append e.g. "/3" for the third font in the file.
+OTF_FILE *otf_load(const char *file);
+void otf_close(OTF_FILE *otf);
+
+#define OTF_TAG(a,b,c,d) (unsigned int)( ((a)<<24)|((b)<<16)|((c)<<8)|(d) )
+#define OTF_UNTAG(a) (((unsigned int)(a)>>24)&0xff),(((unsigned int)(a)>>16)&0xff),\
+ (((unsigned int)(a)>>8)&0xff),(((unsigned int)(a))&0xff)
+
+char *otf_get_table(OTF_FILE *otf,unsigned int tag,int *ret_len);
+
+int otf_get_width(OTF_FILE *otf,unsigned short gid);
+const char *otf_get_name(OTF_FILE *otf,int platformID,int encodingID,int languageID,int nameID,int *ret_len);
+int otf_get_glyph(OTF_FILE *otf,unsigned short gid);
+unsigned short otf_from_unicode(OTF_FILE *otf,int unicode);
+
+#ifndef OUTPUT_FN_DECLARED
+#define OUTPUT_FN_DECLARED
+typedef void (*OUTPUT_FN)(const char *buf,int len,void *context);
+#endif
+int otf_subset(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context);
+int otf_ttc_extract(OTF_FILE *otf,OUTPUT_FN output,void *context);
+
+#endif
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt_int.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/sfnt_int.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,79 @@
+#ifndef _SFNT_INT_H
+#define _SFNT_INT_H
+
+static inline unsigned short get_USHORT(const char *buf) // {{{
+{
+ return ((unsigned char)buf[0]<<8)|((unsigned char)buf[1]);
+}
+// }}}
+static inline short get_SHORT(const char *buf) // {{{
+{
+ return (buf[0]<<8)|((unsigned char)buf[1]);
+}
+// }}}
+static inline unsigned int get_UINT24(const char *buf) // {{{
+{
+ return ((unsigned char)buf[0]<<16)|
+ ((unsigned char)buf[1]<<8)|
+ ((unsigned char)buf[2]);
+}
+// }}}
+static inline unsigned int get_ULONG(const char *buf) // {{{
+{
+ return ((unsigned char)buf[0]<<24)|
+ ((unsigned char)buf[1]<<16)|
+ ((unsigned char)buf[2]<<8)|
+ ((unsigned char)buf[3]);
+}
+// }}}
+static inline int get_LONG(const char *buf) // {{{
+{
+ return (buf[0]<<24)|
+ ((unsigned char)buf[1]<<16)|
+ ((unsigned char)buf[2]<<8)|
+ ((unsigned char)buf[3]);
+}
+// }}}
+
+static inline void set_USHORT(char *buf,unsigned short val) // {{{
+{
+ buf[0]=val>>8;
+ buf[1]=val&0xff;
+}
+// }}}
+static inline void set_ULONG(char *buf,unsigned int val) // {{{
+{
+ buf[0]=val>>24;
+ buf[1]=(val>>16)&0xff;
+ buf[2]=(val>>8)&0xff;
+ buf[3]=val&0xff;
+}
+// }}}
+
+static inline int get_width_fast(OTF_FILE *otf,int gid) // {{{
+{
+ if (gid>=otf->numberOfHMetrics) {
+ return get_USHORT(otf->hmtx+(otf->numberOfHMetrics-1)*4);
+ } else {
+ return get_USHORT(otf->hmtx+gid*4);
+ }
+}
+// }}}
+
+int otf_load_glyf(OTF_FILE *otf); // - 0 on success
+int otf_load_more(OTF_FILE *otf); // - 0 on success
+
+int otf_action_copy(void *param,int csum,OUTPUT_FN output,void *context);
+int otf_action_copy_head(void *param,int csum,OUTPUT_FN output,void *context);
+int otf_action_replace(void *param,int csum,OUTPUT_FN output,void *context);
+
+struct _OTF_WRITE {
+ unsigned long tag;
+ int (*action)(void *param,int length,OUTPUT_FN output,void *context); // -1 on error, num_bytes_written on success; if >output==NULL return checksum in (unsigned int *)context instead.
+ void *param;
+ int length;
+};
+
+int otf_write_sfnt(struct _OTF_WRITE *otw,unsigned int version,int numTables,OUTPUT_FN output,void *context);
+
+#endif
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_analyze.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_analyze.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,205 @@
+#include "sfnt.h"
+#include "sfnt_int.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+enum { WEIGHT_THIN=100,
+ WEIGHT_EXTRALIGHT=200, WEIGHT_ULTRALIGHT=200,
+ WEIGHT_LIGHT=300,
+ WEIGHT_NORMAL=400, WEIGHT_REGULAR=400,
+ WEIGHT_MEDIUM=500,
+ WEIGHT_SEMIBOLD=600, // DEMI
+ WEIGHT_BOLD=700,
+ WEIGHT_EXTRABOLD=800, WEIGHT_ULTRABOLD=800,
+ WEIGHT_BLACK=900, WEIGHT_HEAVY=900 };
+
+void show_post(OTF_FILE *otf) // {{{
+{
+ assert(otf);
+ int len=0;
+ char *buf;
+
+ buf=otf_get_table(otf,OTF_TAG('p','o','s','t'),&len);
+ if (!buf) {
+ assert(len==-1);
+ printf("No post table\n");
+ return;
+ }
+ // TODO: check len
+ printf("POST: (%d bytes)\n"
+ " version: %08x\n"
+ " italicAngle: %d.%d\n"
+ " underlinePosition: %d\n"
+ " underlineThickness: %d\n"
+ " isFixedPitch: %d\n"
+ " vmType42: %d %d\n"
+ " vmType1: %d %d\n",len,
+ get_ULONG(buf),
+ get_LONG(buf+4)>>16,get_ULONG(buf+4)&0xffff,
+ get_SHORT(buf+8),
+ get_SHORT(buf+10),
+ get_ULONG(buf+12),
+ get_ULONG(buf+16),get_ULONG(buf+20),
+ get_ULONG(buf+24),get_ULONG(buf+38));
+ free(buf);
+}
+// }}}
+
+void show_name(OTF_FILE *otf) // {{{
+{
+ assert(otf);
+ int iA,len=0;
+ char *buf;
+
+ buf=otf_get_table(otf,OTF_TAG('n','a','m','e'),&len);
+ if (!buf) {
+ assert(len==-1);
+ printf("No name table\n");
+ return;
+ }
+ printf("NAME:\n");
+ int name_count=get_USHORT(buf+2);
+ const char *nstore=buf+get_USHORT(buf+4);
+ for (iA=0;iA<name_count;iA++) {
+ const char *nrec=buf+6+12*iA;
+ printf(" { platformID/encodingID/languageID/nameID: %d/%d/%d/%d\n"
+ " length: %d, offset: %d, data :",
+ get_USHORT(nrec),
+ get_USHORT(nrec+2),
+ get_USHORT(nrec+4),
+ get_USHORT(nrec+6),
+ get_USHORT(nrec+8),
+ get_USHORT(nrec+10));
+ if ( (get_USHORT(nrec)==0)||
+ ( (get_USHORT(nrec)==3) ) ) { // WCHAR
+ int nlen=get_USHORT(nrec+8);
+ int npos=get_USHORT(nrec+10);
+ for (;nlen>0;nlen-=2,npos+=2) {
+ if (nstore[npos]!=0x00) {
+ printf("?");
+ } else {
+ printf("%c",nstore[npos+1]);
+ }
+ }
+ printf(" }\n");
+ } else {
+ printf("%.*s }\n",
+ get_USHORT(nrec+8),nstore+get_USHORT(nrec+10));
+ }
+ }
+ free(buf);
+}
+// }}}
+
+void show_cmap(OTF_FILE *otf) // {{{
+{
+ assert(otf);
+ int iA,len=0;
+
+ char *cmap=otf_get_table(otf,OTF_TAG('c','m','a','p'),&len);
+ if (!cmap) {
+ assert(len==-1);
+ printf("No cmap table\n");
+ return;
+ }
+ printf("cmap:\n");
+ assert(get_USHORT(cmap)==0x0000); // version
+ const int numTables=get_USHORT(cmap+2);
+ printf(" numTables: %d\n",numTables);
+ for (iA=0;iA<numTables;iA++) {
+ const char *nrec=cmap+4+8*iA;
+ const char *ndata=cmap+get_ULONG(nrec+4);
+ assert(ndata>=cmap+4+8*numTables);
+ printf(" platformID/encodingID: %d/%d\n"
+ " offset: %d data (format: %d, length: %d, language: %d);\n",
+ get_USHORT(nrec),get_USHORT(nrec+2),
+ get_ULONG(nrec+4),
+ get_USHORT(ndata),get_USHORT(ndata+2),get_USHORT(ndata+4));
+ }
+ free(cmap);
+}
+// }}}
+
+void show_glyf(OTF_FILE *otf,int full) // {{{
+{
+ assert(otf);
+
+ // ensure >glyphOffsets and >gly is there
+ if ( (!otf->gly)||(!otf->glyphOffsets) ) {
+ if (otf_load_glyf(otf)!=0) {
+ assert(0);
+ return;
+ }
+ }
+
+ int iA;
+ int compGlyf=0,zeroGlyf=0;
+
+ // {{{ glyf
+ assert(otf->gly);
+ for (iA=0;iA<otf->numGlyphs;iA++) {
+ int len=otf_get_glyph(otf,iA);
+ if (len==0) {
+ zeroGlyf++;
+ } else if (get_SHORT(otf->gly)==-1) {
+ compGlyf++;
+ }
+ if (full) {
+ printf("%d(%d) ",get_SHORT(otf->gly),len);
+ }
+ }
+ if (full) {
+ printf("\n");
+ }
+ printf("numGlyf(nonnull): %d(%d), composites: %d\n",otf->numGlyphs,otf->numGlyphs-zeroGlyf,compGlyf);
+ // }}}
+}
+// }}}
+
+int main(int argc,char **argv)
+{
+ const char *fn="/usr/share/fonts/truetype/microsoft/ARIALN.TTF";
+ if (argc==2) {
+ fn=argv[1];
+ }
+ OTF_FILE *otf=otf_load(fn);
+ assert(otf);
+ if (otf->numTTC) {
+ printf("TTC has %d fonts, using %d\n",otf->numTTC,otf->useTTC);
+ }
+ if (otf->version==0x00010000) {
+ printf("Got TTF 1.0\n");
+ } else if (otf->version==OTF_TAG('O','T','T','O')) {
+ printf("Got OTF(CFF)\n");
+ } else if (otf->version==OTF_TAG('t','r','u','e')) {
+ printf("Got TTF (true)\n");
+ } else if (otf->version==OTF_TAG('t','y','p','1')) {
+ printf("Got SFNT(Type1)\n");
+ }
+
+ printf("Has %d tables\n",otf->numTables);
+
+ int iA;
+ for (iA=0;iA<otf->numTables;iA++) {
+ printf("%c%c%c%c %d\n",OTF_UNTAG(otf->tables[iA].tag),otf->tables[iA].length);
+ }
+ printf("unitsPerEm: %d, indexToLocFormat: %d\n",
+ otf->unitsPerEm,otf->indexToLocFormat);
+ printf("num glyphs: %d\n",otf->numGlyphs);
+ otf_get_width(otf,0); // load table.
+ printf("numberOfHMetrics: %d\n",otf->numberOfHMetrics);
+
+ show_post(otf);
+
+ show_name(otf);
+
+ show_cmap(otf);
+ // printf("%d %d\n",otf_from_unicode(otf,'A'),0);
+
+ show_glyf(otf,1);
+
+ otf_close(otf);
+
+ return 0;
+}
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_pdf.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/fontembed/test_pdf.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,222 @@
+#include "embed.h"
+#include "sfnt.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct _FONTFILE { // TODO
+ OTF_FILE *sfnt;
+};
+
+static void example_outfn(const char *buf,int len,void *context) // {{{
+{
+ FILE *f=(FILE *)context;
+ if (fwrite(buf,1,len,f)!=len) {
+ fprintf(stderr,"Short write: %m\n");
+ assert(0);
+ return;
+ }
+}
+// }}}
+
+#define OBJ \
+ xref[xrefpos++]=ftell(f); \
+ fprintf(f,"%d 0 obj\n",xrefpos);
+
+#define ENDOBJ \
+ fprintf(f,"endobj\n");
+
+#define STREAMDICT \
+ OBJ; \
+ fprintf(f,"<<\n" \
+ " /Length %d 0 R\n",xrefpos+1);
+
+#define STREAMDATA \
+ fprintf(f,">>\n" \
+ "stream\n"); \
+ stream_len=-ftell(f);
+
+#define STREAM \
+ STREAMDICT \
+ STREAMDATA
+
+#define ENDSTREAM \
+ stream_len+=ftell(f); \
+ fprintf(f,"endstream\n" \
+ "endobj\n"); \
+ OBJ; \
+ fprintf(f,"%d\n",stream_len); \
+ ENDOBJ;
+
+static inline void write_string(FILE *f,EMB_PARAMS *emb,const char *str) // {{{
+{
+ assert(f);
+ assert(emb);
+ OTF_FILE *otf=emb->font->sfnt;
+ assert(otf);
+ int iA;
+
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ putc('<',f);
+ for (iA=0;str[iA];iA++) {
+ const unsigned short gid=otf_from_unicode(otf,(unsigned char)str[iA]);
+ fprintf(f,"%04x",gid);
+ bit_set(emb->subset,gid);
+ }
+ putc('>',f);
+ } else {
+ putc('(',f);
+ for (iA=0;str[iA];iA++) {
+ bit_set(emb->subset,otf_from_unicode(otf,(unsigned char)str[iA])); // TODO: emb_set(...) encoding/unicode->gid
+ }
+ fprintf(f,"%s",str); // TODO
+ putc(')',f);
+ }
+}
+// }}}
+
+int main(int argc,char **argv)
+{
+ const char *fn="/usr/share/fonts/truetype/microsoft/ARIALN.TTF";
+ if (argc==2) {
+ fn=argv[1];
+ }
+ OTF_FILE *otf=otf_load(fn);
+ assert(otf);
+ struct _FONTFILE ff; ff.sfnt=otf; // TODO
+ EMB_PARAMS *emb=emb_new(&ff,
+ EMB_DEST_PDF16,
+ EMB_C_FORCE_MULTIBYTE
+);
+
+ FILE *f=fopen("test.pdf","w");
+ assert(f);
+ int xref[100],xrefpos=3;
+ int stream_len;
+
+ assert(emb->subset);
+
+ fprintf(f,"%%PDF-1.3\n");
+ // content
+ STREAM;
+ fprintf(f,"BT\n" // content
+ " 100 100 Td\n"
+ " /F1 10 Tf\n");
+ write_string(f,emb,"Hallo");
+ fprintf(f," Tj\n"
+ "ET\n");
+ ENDSTREAM;
+
+ bit_set(emb->subset,otf_from_unicode(otf,'a'));
+
+ // {{{ do font
+ EMB_PDF_FONTDESCR *fdes=emb_pdf_fontdescr(emb);
+ assert(fdes);
+ EMB_PDF_FONTWIDTHS *fwid=emb_pdf_fontwidths(emb);
+ assert(fwid);
+
+ STREAMDICT;
+ int ff_ref=xrefpos;
+ if (emb_pdf_get_fontfile_subtype(emb)) {
+ fprintf(f," /SubType /%s\n",
+ emb_pdf_get_fontfile_subtype(emb));
+ }
+ if (emb->outtype&EMB_OUTPUT_T1) {
+ fprintf(f," /Length1 ?\n"
+ " /Length2 ?\n"
+ " /Length3 ?\n");
+ } else {
+ fprintf(f," /Length1 %d 0 R\n",xrefpos+2);
+ }
+ STREAMDATA;
+ const int outlen=emb_embed(emb,example_outfn,f);
+ ENDSTREAM;
+ OBJ;
+ fprintf(f,"%d\n",outlen);
+ ENDOBJ;
+
+ OBJ;
+ const int fd_ref=xrefpos;
+ char *res=emb_pdf_simple_fontdescr(emb,fdes,ff_ref);
+ assert(res);
+ fputs(res,f);
+ free(res);
+ ENDOBJ;
+
+ OBJ;
+ int f_ref=xrefpos;
+ res=emb_pdf_simple_font(emb,fdes,fwid,fd_ref);
+ assert(res);
+ fputs(res,f);
+ free(res);
+ ENDOBJ;
+
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ OBJ;
+ res=emb_pdf_simple_cidfont(emb,fdes->fontname,f_ref);
+ f_ref=xrefpos;
+ assert(res);
+ fputs(res,f);
+ free(res);
+ ENDOBJ;
+ }
+
+ free(fdes);
+ free(fwid);
+ // }}}
+
+ int iA;
+
+ xref[2]=ftell(f);
+ fprintf(f,"3 0 obj\n"
+ "<</Type/Page\n"
+ " /Parent 2 0 R\n"
+ " /MediaBox [0 0 595 842]\n"
+ " /Contents 4 0 R\n"
+ " /Resources <<\n"
+ " /Font <<\n"
+ " /F1 %d 0 R\n"
+ " >>\n"
+ " >>\n"
+ ">>\n"
+ "endobj\n",
+ f_ref);
+ xref[1]=ftell(f);
+ fprintf(f,"2 0 obj\n"
+ "<</Type/Pages\n"
+ " /Count 1\n"
+ " /Kids [3 0 R]"
+ ">>\n"
+ "endobj\n");
+ xref[0]=ftell(f);
+ fprintf(f,"1 0 obj\n"
+ "<</Type/Catalog\n"
+ " /Pages 2 0 R\n"
+ ">>\n"
+ "endobj\n");
+ // {{{ pdf trailer
+ int xref_start=ftell(f);
+ fprintf(f,"xref\n"
+ "0 %d\n"
+ "%010d 65535 f \n",
+ xrefpos+1,0);
+ for (iA=0;iA<xrefpos;iA++) {
+ fprintf(f,"%010d 00000 n \n",xref[iA]);
+ }
+ fprintf(f,"trailer\n"
+ "<<\n"
+ " /Size %d\n"
+ " /Root 1 0 R\n"
+ ">>\n"
+ "startxref\n"
+ "%d\n"
+ "%%%%EOF\n",
+ xrefpos+1,xref_start);
+ // }}}
+ fclose(f);
+
+ emb_close(emb);
+ otf_close(otf);
+
+ return 0;
+}
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,411 @@
+/*
+ * PDF file output routines.
+ *
+ * Copyright 2008 by Tobias Hoffmann.
+ *
+ * This file is licensed as noted in "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <memory.h>
+#include <stdlib.h>
+#include "pdfutils.h"
+#include "fontembed/embed.h"
+
+void pdfOut_printf(pdfOut *pdf,const char *fmt,...) // {{{
+{
+ assert(pdf);
+ int len;
+ va_list ap;
+
+ va_start(ap,fmt);
+ len=vprintf(fmt,ap);
+ va_end(ap);
+ pdf->filepos+=len;
+}
+// }}}
+
+void pdfOut_putString(pdfOut *pdf,const char *str,int len) // {{{ - >len==-1: strlen()
+{
+ assert(pdf);
+ assert(str);
+ if (len==-1) {
+ len=strlen(str);
+ }
+ putc('(',stdout);
+ // escape special chars: \0 \\ \)
+ int iA=0;
+ for (;len>0;iA++,len--) {
+ if ( (str[iA]<32)||(str[iA]>126) ) {
+ fwrite(str,1,iA,stdout);
+ fprintf(stdout,"\\%03o",str[iA]);
+ pdf->filepos+=iA+4;
+ str+=iA+1;
+ iA=-1;
+ } else if ( (str[iA]==')')||(str[iA]=='\\') ) {
+ fwrite(str,1,iA,stdout);
+ fprintf(stdout,"\\%c",str[iA]);
+ pdf->filepos+=iA+2;
+ str+=iA+1;
+ iA=-1;
+ }
+ }
+ pdf->filepos+=iA+2;
+ fwrite(str,1,iA,stdout);
+ putc(')',stdout);
+}
+// }}}
+
+void pdfOut_putHexString(pdfOut *pdf,const char *str,int len) // {{{ - >len==-1: strlen()
+{
+ assert(pdf);
+ assert(str);
+ if (len==-1) {
+ len=strlen(str);
+ }
+ pdf->filepos+=2*len+2;
+ putc('<',stdout);
+ for (;len>0;str++,len--) {
+ fprintf(stdout,"%02x",(unsigned char)*str);
+ }
+ putc('>',stdout);
+}
+// }}}
+
+pdfOut *pdfOut_new() // {{{ - NULL on error
+{
+ pdfOut *ret=malloc(sizeof(pdfOut));
+ if (ret) {
+ memset(ret,0,sizeof(pdfOut));
+ }
+
+ return ret;
+}
+// }}}
+
+// NOTE: uses statically allocated buffer
+const char *pdfOut_to_pdfdate(struct tm *curtm) // {{{
+{
+ static char curdate[250];
+ if (!curtm) {
+ time_t curtime;
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+ }
+ strftime(curdate, sizeof(curdate), "D:%Y%m%d%H%M%S%z", curtm);
+ curdate[23]=0;
+ curdate[22]='\'';
+ curdate[21]=curdate[18];
+ curdate[20]=curdate[17];
+ curdate[19]='\'';
+ return curdate;
+}
+// }}}
+
+int pdfOut_add_xref(pdfOut *pdf) // {{{ - returns obj_no
+{
+ assert(pdf);
+ assert(pdf->xrefsize<=pdf->xrefalloc);
+
+ if (pdf->xrefsize==pdf->xrefalloc) {
+ long *tmp;
+ pdf->xrefalloc+=50;
+ tmp=realloc(pdf->xref,sizeof(long)*pdf->xrefalloc);
+ if (!tmp) {
+ pdf->xrefalloc=-1;
+ return -1;
+ }
+ pdf->xref=tmp;
+ }
+ pdf->xref[pdf->xrefsize++]=pdf->filepos;
+ return pdf->xrefsize; // xrefsize+1
+}
+// }}}
+
+int pdfOut_add_page(pdfOut *pdf,int obj) // {{{ - returns false on error
+{
+ assert(pdf);
+ assert(obj>0);
+ assert(pdf->pagessize<=pdf->pagesalloc);
+
+ if (pdf->pagessize==pdf->pagesalloc) {
+ int *tmp;
+ pdf->pagesalloc+=10;
+ tmp=realloc(pdf->pages,sizeof(int)*pdf->pagesalloc);
+ if (!tmp) {
+ pdf->pagesalloc=-1;
+ return 0;
+ }
+ pdf->pages=tmp;
+ }
+ pdf->pages[pdf->pagessize++]=obj;
+ return 1;
+}
+// }}}
+
+int pdfOut_add_kv(pdfOut *pdf,const char *key,const char *val) // {{{ - returns false on error
+{
+ assert(pdf);
+ assert(pdf->kvsize<=pdf->kvalloc);
+
+ if (pdf->kvsize==pdf->kvalloc) {
+ struct keyval_t *tmp;
+ pdf->kvalloc+=10;
+ tmp=realloc(pdf->kv,sizeof(struct keyval_t)*pdf->kvalloc);
+ if (!tmp) {
+ pdf->kvalloc=-1;
+ return 0;
+ }
+ pdf->kv=tmp;
+ }
+ pdf->kv[pdf->kvsize].key=strdup(key);
+ pdf->kv[pdf->kvsize].value=strdup(val);
+ if ( (!pdf->kv[pdf->kvsize].key)||(!pdf->kv[pdf->kvsize].value) ) {
+ return 0;
+ }
+ pdf->kvsize++;
+ return 1;
+}
+// }}}
+
+int pdfOut_begin_pdf(pdfOut *pdf) // ,...output_device?...) // {{{ - false on error
+{
+ assert(pdf);
+ assert(pdf->kvsize==0); // otherwise: finish_pdf has not been called
+ int pages_obj;
+
+ pdf->xrefsize=pdf->pagessize=0;
+ pdf->filepos=0;
+ pages_obj=pdfOut_add_xref(pdf); // fixed later
+ if (pages_obj!=1) {
+ return 0;
+ }
+ pdfOut_printf(pdf,"%%PDF-1.3\n");
+ return 1;
+}
+// }}}
+
+void pdfOut_finish_pdf(pdfOut *pdf) // {{{
+{
+ int iA;
+ int root_obj,info_obj=0,xref_start;
+ assert( (pdf)&&(pdf->filepos!=-1) );
+
+ // pages
+ const int pages_obj=1;
+ pdf->xref[0]=pdf->filepos; // now fix it
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Pages\n"
+ " /Count %d\n"
+ " /Kids [",
+ pages_obj,pdf->pagessize);
+ for (iA=0;iA<pdf->pagessize;iA++) {
+ pdfOut_printf(pdf,"%d 0 R ",pdf->pages[iA]);
+ }
+ pdfOut_printf(pdf,"]\n"
+ ">>\n"
+ "endobj\n");
+
+ // rootdict
+ root_obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Catalog\n"
+ " /Pages %d 0 R\n"
+ ">>\n"
+ "endobj\n",
+ root_obj,pages_obj);
+
+ // info
+ if (pdf->kvsize) {
+ info_obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<<\n",
+ info_obj);
+ for (iA=0;iA<pdf->kvsize;iA++) {
+ pdfOut_printf(pdf," /%s ",pdf->kv[iA].key);
+ pdfOut_putString(pdf,pdf->kv[iA].value,-1);
+ pdfOut_printf(pdf,"\n");
+ }
+ pdfOut_printf(pdf,">>\n"
+ "endobj\n");
+ }
+ // TODO: some return-value checking (??)
+
+ // write xref
+ xref_start=pdf->filepos;
+ pdfOut_printf(pdf,"xref\n"
+ "%d %d\n"
+ "%010d 65535 f \n",
+ 0,pdf->xrefsize+1,0);
+ for (iA=0;iA<pdf->xrefsize;iA++) {
+ pdfOut_printf(pdf,"%010d 00000 n \n",
+ pdf->xref[iA]);
+ }
+ pdfOut_printf(pdf,"trailer\n"
+ "<<\n"
+ " /Size %d\n"
+ " /Root %d 0 R\n",
+ pdf->xrefsize+1,
+ root_obj);
+ if (info_obj) {
+ pdfOut_printf(pdf," /Info %d 0 R\n",info_obj);
+ }
+ pdfOut_printf(pdf,">>\n"
+ "startxref\n"
+ "%d\n"
+ "%%%%EOF\n",
+ xref_start);
+
+ // set to done
+ pdf->filepos=-1;
+ for (iA=0;iA<pdf->kvsize;iA++) {
+ free(pdf->kv[iA].key);
+ free(pdf->kv[iA].value);
+ }
+ pdf->kvsize=0;
+}
+// }}}
+
+void pdfOut_free(pdfOut *pdf) // {{{
+{
+ if (pdf) {
+ assert(pdf->kvsize==0); // otherwise: finish_pdf has not been called
+ free(pdf->kv);
+ free(pdf->pages);
+ free(pdf->xref);
+ free(pdf);
+ }
+}
+// }}}
+
+static void pdfOut_outfn(const char *buf,int len,void *context) // {{{
+{
+ pdfOut *pdf=(pdfOut *)context;
+
+ if (fwrite(buf,1,len,stdout)!=len) {
+ fprintf(stderr,"Short write: %m\n");
+ assert(0);
+ return;
+ }
+ pdf->filepos+=len;
+}
+// }}}
+
+int pdfOut_write_font(pdfOut *pdf,EMB_PARAMS *emb) // {{{
+{
+ assert(pdf);
+ assert(emb);
+
+ EMB_PDF_FONTDESCR *fdes=emb_pdf_fontdescr(emb);
+ if (!fdes) {
+ return 0;
+ }
+
+ const int ff_obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Length %d 0 R\n"
+ " /Length1 %d 0 R\n"
+ ,ff_obj,ff_obj+1,ff_obj+2);
+ if (emb_pdf_get_fontfile_subtype(emb)) {
+ pdfOut_printf(pdf," /SubType /%s\n",
+ emb_pdf_get_fontfile_subtype(emb));
+ }
+ if (emb->outtype&EMB_OUTPUT_T1) { // TODO
+ pdfOut_printf(pdf," /Length2 ?\n"
+ " /Length3 ?\n");
+ }
+ pdfOut_printf(pdf,">>\n"
+ "stream\n");
+ long streamsize=-pdf->filepos;
+ const int outlen=emb_embed(emb,pdfOut_outfn,pdf);
+ streamsize+=pdf->filepos;
+ pdfOut_printf(pdf,"\nendstream\n"
+ "endobj\n");
+
+ const int l0_obj=pdfOut_add_xref(pdf);
+ assert(l0_obj==ff_obj+1);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%d\n"
+ "endobj\n"
+ ,l0_obj,streamsize);
+
+ const int l1_obj=pdfOut_add_xref(pdf);
+ assert(l1_obj==ff_obj+2);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%d\n"
+ "endobj\n"
+ ,l1_obj,outlen);
+
+ const int fd_obj=pdfOut_add_xref(pdf);
+ char *res=emb_pdf_simple_fontdescr(emb,fdes,ff_obj);
+ if (!res) {
+ free(fdes);
+ return 0;
+ }
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%s"
+ "endobj\n"
+ ,fd_obj,res);
+ free(res);
+
+ EMB_PDF_FONTWIDTHS *fwid=emb_pdf_fontwidths(emb);
+ if (!fwid) {
+ free(fdes);
+ return 0;
+ }
+ const int f_obj=pdfOut_add_xref(pdf);
+ res=emb_pdf_simple_font(emb,fdes,fwid,fd_obj);
+ if (!res) {
+ free(fwid);
+ free(fdes);
+ return 0;
+ }
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%s"
+ "endobj\n"
+ ,f_obj,res);
+ free(res);
+ free(fwid);
+
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ res=emb_pdf_simple_cidfont(emb,fdes->fontname,f_obj);
+ if (!res) {
+ free(fdes);
+ return 0;
+ }
+ const int cf_obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%s"
+ "endobj\n"
+ ,cf_obj,res);
+ free(res);
+ free(fdes);
+ return cf_obj;
+ }
+
+ free(fdes);
+ return f_obj;
+}
+// }}}
+
+#if 0
+one_page(...parent,resources,mediabox,contents);
+{
+// " /Resources %d 0 R\n"
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Page\n"
+ " /Parent 1 0 R\n"
+ " /MediaBox [0 0 %d %d]\n"
+ " /Contents %d 0 R\n"
+ ">>\n"
+ "endobj\n"
+ ,,,PageWidth,PageLength // TODO: into pdf->
+ ...
+}
+
+... pfb_embedder ... pfa?
+#endif
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.h
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/pdfutils.h Thu Aug 14 17:18:52 2008
@@ -0,0 +1,80 @@
+/*
+ * PDF file output routines.
+ *
+ * Copyright 2008 by Tobias Hoffmann.
+ *
+ * This file is licensed as noted in "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ */
+#include <time.h>
+
+struct keyval_t {
+ char *key,*value;
+};
+
+typedef struct {
+ long filepos;
+
+ int pagessize,pagesalloc;
+ int *pages;
+
+ int xrefsize,xrefalloc;
+ long *xref;
+
+ int kvsize,kvalloc;
+ struct keyval_t *kv;
+} pdfOut;
+
+/* allocates a new pdfOut structure
+ * returns NULL on error
+ */
+pdfOut *pdfOut_new();
+void pdfOut_free(pdfOut *pdf);
+
+/* start outputting a pdf
+ * returns false on error
+ */
+int pdfOut_begin_pdf(pdfOut *pdf);
+void pdfOut_finish_pdf(pdfOut *pdf);
+
+/* General output routine for our pdf.
+ * Keeps track of characters actually written out
+ */
+void pdfOut_printf(pdfOut *pdf,const char *fmt,...);
+
+/* write out an escaped pdf string: e.g. (Text \(Test\)\n)
+ * >len==-1: use strlen(str)
+ */
+void pdfOut_putString(pdfOut *pdf,const char *str,int len);
+void pdfOut_putHexString(pdfOut *pdf,const char *str,int len);
+
+/* Format the broken up timestamp according to
+ * pdf requirements for /CreationDate
+ * NOTE: uses statically allocated buffer
+ */
+const char *pdfOut_to_pdfdate(struct tm *curtm);
+
+/* begin a new object at current point of the
+ * output stream and add it to the xref table.
+ * returns the obj number.
+ */
+int pdfOut_add_xref(pdfOut *pdf);
+
+/* adds page dictionary >obj to the global Pages tree
+ * returns false on error
+ */
+int pdfOut_add_page(pdfOut *pdf,int obj);
+
+/* add a >key,>val pair to the document's Info dictionary
+ * returns false on error
+ */
+int pdfOut_add_kv(pdfOut *pdf,const char *key,const char *val);
+
+/* Writes the font >emb including descriptor to the pdf
+ * and returns the object number.
+ * On error 0 is returned.
+ */
+struct _EMB_PARAMS;
+int pdfOut_write_font(pdfOut *pdf,struct _EMB_PARAMS *emb);
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/test.sh
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/test.sh Thu Aug 14 17:18:52 2008
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# just for comparison
+/usr/lib/cups/filter/texttops 1 hi_user there_title 1 "" Makefile > test1.ps
+
+# for the next to work, you'll have to make a subdirectory fonts/ here, containing the fonts
+# and a subdirectory charsets/ with a file pdf.utf-8
+export CUPS_DATADIR=`pwd`/
+
+./texttopdf 1 hi_user there_title 1 "" Makefile > test1.pdf
+./texttopdf 1 hi_user there_title 1 "PrettyPrint=1" Makefile > test2.pdf
+(export CONTENT_TYPE=application/x-csource; ./texttopdf 1 hi_user there_title 1 "PrettyPrint=1" test_pdf1.c > test3.pdf)
+(export CHARSET=utf-8; ./texttopdf 1 hi_user there_title 1 "PrettyPrint=1" Makefile > test4.pdf)
+(export CHARSET=utf-8; ./texttopdf 1 hi_user there_title 1 "" testin > test5.pdf)
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf1.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf1.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,51 @@
+#include "pdfutils.h"
+#include <assert.h>
+
+int main()
+{
+ pdfOut *pdf;
+
+ pdf=pdfOut_new();
+ assert(pdf);
+
+ pdfOut_begin_pdf(pdf);
+
+ // bad font
+ int font_obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Font\n"
+ " /Subtype /Type1\n" // /TrueType,/Type3
+ " /BaseFont /%s\n"
+ ">>\n"
+ "endobj\n"
+ ,font_obj,"Courier");
+ // test
+ const int PageWidth=595,PageLength=842;
+ int cobj=pdfOut_add_xref(pdf);
+ const char buf[]="BT /a 10 Tf (abc) Tj ET";
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Length %d\n"
+ ">>\n"
+ "stream\n"
+ "%s\n"
+ "endstream\n"
+ "endobj\n"
+ ,cobj,strlen(buf),buf);
+
+ int obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Page\n"
+ " /Parent 1 0 R\n"
+ " /MediaBox [0 0 %d %d]\n"
+ " /Contents %d 0 R\n"
+ " /Resources << /Font << /a %d 0 R >> >>\n"
+ ">>\n"
+ "endobj\n"
+ ,obj,PageWidth,PageLength,cobj,font_obj); // TODO: into pdf->
+ pdfOut_add_page(pdf,obj);
+ pdfOut_finish_pdf(pdf);
+
+ pdfOut_free(pdf);
+
+ return 0;
+}
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf2.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/test_pdf2.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,108 @@
+#include "pdfutils.h"
+#include <assert.h>
+#include "fontembed/embed.h"
+#include "fontembed/sfnt.h"
+
+#include <stdio.h>
+
+struct _FONTFILE { // TODO
+ OTF_FILE *sfnt;
+};
+
+static inline void write_string(pdfOut *pdf,EMB_PARAMS *emb,const char *str) // {{{
+{
+ assert(pdf);
+ assert(emb);
+ OTF_FILE *otf=emb->font->sfnt;
+ assert(otf);
+ int iA;
+
+ if (emb->plan&EMB_A_MULTIBYTE) {
+ putc('<',stdout);
+ for (iA=0;str[iA];iA++) {
+ const unsigned short gid=otf_from_unicode(otf,(unsigned char)str[iA]);
+ fprintf(stdout,"%04x",gid);
+ if (emb->subset) {
+ bit_set(emb->subset,gid);
+ }
+ }
+ putc('>',stdout);
+ pdf->filepos+=4*iA+2;
+ } else {
+ if (emb->subset) {
+ for (iA=0;str[iA];iA++) {
+ bit_set(emb->subset,otf_from_unicode(otf,(unsigned char)str[iA])); // TODO: emb_set(...) encoding/unicode->gid // TODO: pdf: otf_from_pdf_default_encoding
+ }
+ }
+ pdfOut_putString(pdf,str,-1);
+ }
+}
+// }}}
+
+int main()
+{
+ pdfOut *pdf;
+
+ pdf=pdfOut_new();
+ assert(pdf);
+
+ pdfOut_begin_pdf(pdf);
+
+ // font, pt.1
+ const char *fn="/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf";
+/*
+ if (argc==2) {
+ fn=argv[1];
+ }
+*/
+ OTF_FILE *otf=otf_load(fn);
+ assert(otf);
+ struct _FONTFILE ff; ff.sfnt=otf; // TODO
+ EMB_PARAMS *emb=emb_new(&ff,
+ EMB_DEST_PDF16,
+ EMB_C_FORCE_MULTIBYTE);
+
+ // test
+ const int PageWidth=595,PageLength=842;
+ const int cobj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Length %d 0 R\n"
+ ">>\n"
+ "stream\n"
+ ,cobj,cobj+1);
+ long streamlen=-pdf->filepos;
+ pdfOut_printf(pdf,"BT /a 10 Tf ");
+ write_string(pdf,emb,"Test");
+ pdfOut_printf(pdf," Tj ET");
+
+ streamlen+=pdf->filepos;
+ pdfOut_printf(pdf,"\nendstream\n"
+ "endobj\n");
+ const int clobj=pdfOut_add_xref(pdf);
+ assert(clobj==cobj+1);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%d\n"
+ "endobj\n"
+ ,clobj,streamlen);
+
+ // font
+ int font_obj=pdfOut_write_font(pdf,emb);
+ assert(font_obj);
+
+ int obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Page\n"
+ " /Parent 1 0 R\n"
+ " /MediaBox [0 0 %d %d]\n"
+ " /Contents %d 0 R\n"
+ " /Resources << /Font << /a %d 0 R >> >>\n"
+ ">>\n"
+ "endobj\n"
+ ,obj,PageWidth,PageLength,cobj,font_obj); // TODO: into pdf->
+ pdfOut_add_page(pdf,obj);
+ pdfOut_finish_pdf(pdf);
+
+ pdfOut_free(pdf);
+
+ return 0;
+}
Added: cupsys/trunk/debian/local/filters/pdf-filters/filter/texttopdf.c
==============================================================================
--- (empty file)
+++ cupsys/trunk/debian/local/filters/pdf-filters/filter/texttopdf.c Thu Aug 14 17:18:52 2008
@@ -0,0 +1,1148 @@
+/*
+ * Text to PDF filter for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2008 by Tobias Hoffmann.
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1993-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * main() - Main entry for text to PDF filter.
+ * WriteEpilogue() - Write the PDF file epilogue.
+ * WritePage() - Write a page of text.
+ * WriteProlog() - Write the PDF file prolog with options.
+ * write_line() - Write a row of text.
+ * write_string() - Write a string of text.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "textcommon.h"
+#include <cups/i18n.h>
+#include "pdfutils.h"
+#include "fontembed/embed.h"
+#include <assert.h>
+#include "fontembed/sfnt.h"
+
+// TODO:
+struct _FONTFILE { // TODO
+ OTF_FILE *sfnt;
+ int fobj; // TODO
+};
+EMB_PARAMS *font_load(const char *datadir,const char *font);
+
+static int bits_used(BITSET bits,int len) // {{{
+{
+ len=((len+31)&~31)/8;
+ while (len>0) {
+ if (*bits) {
+ return 1;
+ }
+ bits++;
+ len--;
+ }
+ return 0;
+}
+// }}}
+
+EMB_PARAMS *font_load(const char *datadir,const char *font)
+{
+ char filename[1024]; /* Glyph filenames */
+ snprintf(filename, sizeof(filename), "%s/fonts/%s", datadir, font);
+
+ OTF_FILE *otf=otf_load(filename);
+ assert(otf);
+ struct _FONTFILE *ff=malloc(sizeof(struct _FONTFILE));
+ assert(ff);
+ ff->sfnt=otf; // TODO
+ ff->fobj=0; // TODO
+ EMB_PARAMS *emb=emb_new(ff,
+ EMB_DEST_PDF16,
+ EMB_C_FORCE_MULTIBYTE|
+ EMB_C_TAKE_FONTFILE);
+ assert(emb);
+ assert(emb->plan&EMB_A_MULTIBYTE);
+ return emb;
+}
+
+/*
+ * Globals...
+ */
+
+int NumFonts; /* Number of fonts to use */
+EMB_PARAMS *Fonts[256][4]; /* Fonts to use */
+unsigned short Chars[256]; /* Input char to unicode */
+unsigned char Codes[65536]; /* Unicode glyph mapping to font */
+int Widths[256]; /* Widths of each font */
+int Directions[256];/* Text directions for each font */
+pdfOut *pdf;
+int FontResource; /* Object number of font resource dictionary */
+float FontScaleX,FontScaleY; /* The font matrix */
+lchar_t *Title,*Date; /* The title and date strings */
+
+/*
+ * Local functions...
+ */
+
+static void write_line(int row, lchar_t *line);
+static void write_string(int col, int row, int len, lchar_t *s);
+static lchar_t *make_wide(const char *buf);
+static void write_font_str(float x,float y,int fontid, lchar_t *str, int len);
+static void write_pretty_header();
+
+
+/*
+ * 'main()' - Main entry for text to PDF filter.
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ return (TextMain("texttopdf", argc, argv));
+}
+
+
+/*
+ * 'WriteEpilogue()' - Write the PDF file epilogue.
+ */
+
+void
+WriteEpilogue(void)
+{
+ static char *names[] = /* Font names */
+ { "FN","FB","FI" };
+ int i,j;
+
+ free(Page[0]);
+ free(Page);
+
+ // embed fonts
+ for (i = PrettyPrint ? 2 : 1; i >= 0; i --) {
+ for (j = 0; j < NumFonts; j ++)
+ {
+ EMB_PARAMS *emb=Fonts[j][i];
+ if (emb->font->fobj) { // already embedded
+ continue;
+ }
+ if ( (!emb->subset)||(bits_used(emb->subset,emb->font->sfnt->numGlyphs)) ) {
+ emb->font->fobj=pdfOut_write_font(pdf,emb);
+ assert(emb->font->fobj);
+ }
+ }
+ }
+
+ /*
+ * Create the global fontdict
+ */
+
+ // now fix FontResource
+ pdf->xref[FontResource-1]=pdf->filepos;
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<<\n",
+ FontResource);
+
+ for (i = PrettyPrint ? 2 : 1; i >= 0; i --) {
+ for (j = 0; j < NumFonts; j ++) {
+ EMB_PARAMS *emb=Fonts[j][i];
+ if (emb->font->fobj) { // used
+ pdfOut_printf(pdf," /%s%02x %d 0 R\n",names[i],j,emb->font->fobj);
+ }
+ }
+ }
+
+ pdfOut_printf(pdf,">>\n"
+ "endobj\n");
+
+ pdfOut_finish_pdf(pdf);
+
+ pdfOut_free(pdf);
+}
+
+/*
+ * {{{ 'WritePage()' - Write a page of text.
+ */
+
+void
+WritePage(void)
+{
+ int line; /* Current line */
+
+ int content=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Length %d 0 R\n"
+ ">>\n"
+ "stream\n"
+ "q\n"
+ ,content,content+1);
+ long size=-(pdf->filepos-2);
+
+ NumPages ++;
+ if (PrettyPrint)
+ write_pretty_header(pdf);
+
+ for (line = 0; line < SizeLines; line ++)
+ write_line(line, Page[line]);
+
+ size+=pdf->filepos+2;
+ pdfOut_printf(pdf,"Q\n"
+ "endstream\n"
+ "endobj\n");
+
+ int len_obj=pdfOut_add_xref(pdf);
+ assert(len_obj==content+1);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "%d\n"
+ "endobj\n",
+ len_obj,size);
+
+ int obj=pdfOut_add_xref(pdf);
+ pdfOut_printf(pdf,"%d 0 obj\n"
+ "<</Type/Page\n"
+ " /Parent 1 0 R\n"
+ " /MediaBox [0 0 %.0f %.0f]\n"
+ " /Contents %d 0 R\n"
+ " /Resources << /Font %d 0 R >>\n"
+ ">>\n"
+ "endobj\n",
+ obj,PageWidth,PageLength,content,FontResource);
+ pdfOut_add_page(pdf,obj);
+
+ memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines);
+}
+// }}}
+
+/*
+ * {{{'WriteProlog()' - Write the PDF file prolog with options.
+ */
+
+void
+WriteProlog(const char *title, /* I - Title of job */
+ const char *user, /* I - Username */
+ const char *classification, /* I - Classification */
+ const char *label, /* I - Page label */
+ ppd_file_t *ppd) /* I - PPD file info */
+{
+ int i, j, k; /* Looping vars */
+ char *charset; /* Character set string */
+ char filename[1024]; /* Glyph filenames */
+ FILE *fp; /* Glyph files */
+ const char *datadir; /* CUPS_DATADIR environment variable */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *valptr; /* Pointer to value in line */
+ int ch, unicode; /* Character values */
+ int start, end; /* Start and end values for range */
+ time_t curtime; /* Current time */
+ struct tm *curtm; /* Current date */
+ char curdate[255]; /* Current date (text format) */
+ int num_fonts=0; /* Number of unique fonts */
+ EMB_PARAMS *fonts[1024]; /* Unique fonts */
+ char *fontnames[1024]; /* Unique fonts */
+#if 0
+ static char *names[] = /* Font names */
+ {
+ "FN","FB","FI"
+ /*
+ "cupsNormal",
+ "cupsBold",
+ "cupsItalic"
+ */
+ };
+#endif
+
+
+ /*
+ * Get the data directory...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ /*
+ * Adjust margins as necessary...
+ */
+
+ if (classification || label)
+ {
+ /*
+ * Leave room for labels...
+ */
+
+ PageBottom += 36;
+ PageTop -= 36;
+ }
+
+ /*
+ * Allocate memory for the page...
+ */
+
+ SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
+ SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
+
+ Page = calloc(sizeof(lchar_t *), SizeLines);
+ Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
+ for (i = 1; i < SizeLines; i ++)
+ Page[i] = Page[0] + i * SizeColumns;
+
+ if (PageColumns > 1)
+ {
+ ColumnGutter = CharsPerInch / 2;
+ ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
+ PageColumns;
+ }
+ else
+ ColumnWidth = SizeColumns;
+
+ /*
+ * {{{ Output the PDF header...
+ */
+
+ assert(!pdf);
+ pdf=pdfOut_new();
+ assert(pdf);
+
+ pdfOut_begin_pdf(pdf);
+ pdfOut_printf(pdf,"%%cupsRotation: %d\n", (Orientation & 3) * 90); // TODO?
+
+ pdfOut_add_kv(pdf,"Creator","texttopdf/" CUPS_SVERSION);
+
+ curtime = time(NULL);
+ curtm = localtime(&curtime);
+ strftime(curdate, sizeof(curdate), "%c", curtm);
+
+ pdfOut_add_kv(pdf,"CreationDate",pdfOut_to_pdfdate(curtm));
+ pdfOut_add_kv(pdf,"Title",title);
+ pdfOut_add_kv(pdf,"Author",user); // was(PostScript): /For
+ // }}}
+
+ /*
+ * {{{ Initialize globals...
+ */
+
+ NumFonts = 0;
+ memset(Fonts, 0, sizeof(Fonts));
+ memset(Chars, 0, sizeof(Chars));
+ memset(Codes, 0, sizeof(Codes));
+ // }}}
+
+ /*
+ * Get the output character set...
+ */
+
+ charset = getenv("CHARSET");
+ if (charset != NULL && strcmp(charset, "us-ascii") != 0) // {{{
+ {
+ snprintf(filename, sizeof(filename), "%s/charsets/pdf.%s", datadir, charset);
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ /*
+ * Can't open charset file!
+ */
+
+ fprintf(stderr, _("ERROR: Unable to open %s: %s\n"), filename,
+ strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * Opened charset file; now see if this is really a charset file...
+ */
+
+ if (fgets(line, sizeof(line), fp) == NULL)
+ {
+ /*
+ * Bad/empty charset file!
+ */
+
+ fclose(fp);
+ fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
+ exit(1);
+ }
+
+ if (strncmp(line, "charset", 7) != 0)
+ {
+ /*
+ * Bad format/not a charset file!
+ */
+
+ fclose(fp);
+ fprintf(stderr, _("ERROR: Bad charset file %s\n"), filename);
+ exit(1);
+ }
+
+ /*
+ * See if this is an 8-bit or UTF-8 character set file...
+ */
+
+ line[strlen(line) - 1] = '\0'; /* Drop \n */
+ for (lineptr = line + 7; isspace(*lineptr & 255); lineptr ++); /* Skip whitespace */
+
+ if (strcmp(lineptr, "8bit") == 0) // {{{
+ {
+ /*
+ * 8-bit text...
+ */
+
+ UTF8 = 0;
+ NumFonts = 0;
+
+ /*
+ * Read the font description(s)...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * first last direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ if (!*lineptr)
+ break; /* Must be a font mapping */
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "ltor") == 0)
+ Directions[NumFonts] = 1;
+ else if (strcmp(valptr, "rtol") == 0)
+ Directions[NumFonts] = -1;
+ else
+ {
+ fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "single") == 0)
+ Widths[NumFonts] = 1;
+ else if (strcmp(valptr, "double") == 0)
+ Widths[NumFonts] = 2;
+ else
+ {
+ fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr) {
+ // search for duplicates
+ for (k = 0; k < num_fonts; k ++)
+ if (strcmp(valptr, fontnames[k]) == 0) {
+ Fonts[NumFonts][i] = fonts[k];
+ break;
+ }
+
+ if (k==num_fonts) { // not found
+ fonts[num_fonts] = Fonts[NumFonts][i] = font_load(datadir,valptr);
+ fontnames[num_fonts++] = strdup(valptr);
+ }
+ }
+ }
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ Fonts[NumFonts][j] = Fonts[NumFonts][0];
+
+ /*
+ * Define the character mappings...
+ */
+
+ for (i = start; i <= end; i ++)
+ Codes[i] = NumFonts;
+
+ NumFonts ++;
+ }
+
+ /*
+ * Read encoding lines...
+ */
+
+ do
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Grab the character and unicode glyph number.
+ */
+
+ if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
+ Chars[ch] = unicode;
+ }
+ while (fgets(line, sizeof(line), fp) != NULL);
+
+ fclose(fp);
+ } // }}}
+ else if (strcmp(lineptr, "utf8") == 0) // {{{
+ {
+ /*
+ * UTF-8 (Unicode) text...
+ */
+
+ UTF8 = 1;
+
+ /*
+ * Read the font descriptions...
+ */
+
+ NumFonts = 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * start end direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "ltor") == 0)
+ Directions[NumFonts] = 1;
+ else if (strcmp(valptr, "rtol") == 0)
+ Directions[NumFonts] = -1;
+ else
+ {
+ fprintf(stderr, _("ERROR: Bad text direction %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, _("ERROR: Bad font description line: %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "single") == 0)
+ Widths[NumFonts] = 1;
+ else if (strcmp(valptr, "double") == 0)
+ Widths[NumFonts] = 2;
+ else
+ {
+ fprintf(stderr, _("ERROR: Bad text width %s\n"), valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr & 255))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr & 255) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr) {
+ // search for duplicates
+ for (k = 0; k < num_fonts; k ++)
+ if (strcmp(valptr, fontnames[k]) == 0) {
+ Fonts[NumFonts][i] = fonts[k];
+ break;
+ }
+
+ if (k==num_fonts) { // not found
+ fonts[num_fonts] = Fonts[NumFonts][i] = font_load(datadir,valptr);
+ fontnames[num_fonts++] = strdup(valptr);
+ }
+ }
+ }
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ Fonts[NumFonts][j] = Fonts[NumFonts][0];
+
+ /*
+ * Define the character mappings...
+ */
+
+ for (i = start; i <= end; i ++)
+ {
+ Codes[i] = NumFonts;
+ }
+
+ /*
+ * Move to the next font, stopping if needed...
+ */
+
+ NumFonts ++;
+ if (NumFonts >= 256)
+ break;
+ }
+
+ fclose(fp);
+ } // }}}
+ else // {{{
+ {
+ fprintf(stderr, _("ERROR: Bad charset type %s\n"), lineptr);
+ fclose(fp);
+ exit(1);
+ } // }}}
+ } // }}}
+ else // {{{ Standard ASCII
+ {
+ /*
+ * Standard ASCII output just uses Courier, Courier-Bold, and
+ * possibly Courier-Oblique.
+ */
+
+ NumFonts = 1;
+
+ Fonts[0][ATTR_NORMAL] = font_load(datadir,"Courier");
+ Fonts[0][ATTR_BOLD] = font_load(datadir,"Courier-Bold");
+ Fonts[0][ATTR_ITALIC] = font_load(datadir,"Courier-Oblique");
+ Fonts[0][ATTR_BOLDITALIC] = font_load(datadir,"Courier-BoldOblique");
+
+ Widths[0] = 1;
+ Directions[0] = 1;
+
+ /*
+ * Define US-ASCII characters...
+ */
+
+ for (i = 32; i < 127; i ++)
+ {
+ Chars[i] = i;
+ Codes[i] = NumFonts-1;
+ }
+ }
+ // }}}
+
+ FontScaleX=120.0 / CharsPerInch;
+ FontScaleY=68.0 / LinesPerInch;
+
+ // allocate now, for pages to use. will be fixed in epilogue
+ FontResource=pdfOut_add_xref(pdf);
+
+ if (PrettyPrint)
+ {
+ Date=make_wide(curdate);
+ Title=make_wide(title);
+ }
+}
+// }}}
+
+/*
+ * {{{ 'write_line()' - Write a row of text.
+ */
+
+static void
+write_line(int row, /* I - Row number (0 to N) */
+ lchar_t *line) /* I - Line to print */
+{
+ int i; /* Looping var */
+ int col,xcol,xwid; /* Current column */
+ int attr; /* Current attribute */
+ int font, /* Font to use */
+ lastfont, /* Last font */
+ mono; /* Monospaced? */
+ lchar_t *start; /* First character in sequence */
+
+
+ xcol=0;
+ for (col = 0, start = line; col < SizeColumns;)
+ {
+ while (col < SizeColumns && (line->ch == ' ' || line->ch == 0))
+ {
+ col ++;
+ xcol ++;
+ line ++;
+ }
+
+ if (col >= SizeColumns)
+ break;
+
+ if (NumFonts == 1)
+ {
+ /*
+ * All characters in a single font - assume monospaced and single width...
+ */
+
+ attr = line->attr;
+ start = line;
+
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ col ++;
+ line ++;
+ }
+
+ write_string(col - (line - start), row, line - start, start);
+ }
+ else
+ {
+ /*
+ * Multiple fonts; break up based on the font...
+ */
+
+ attr = line->attr;
+ start = line;
+ xwid = 0;
+ if (UTF8) {
+ lastfont = Codes[line->ch];
+ } else {
+ lastfont = Codes[Chars[line->ch]];
+ }
+// mono = strncmp(Fonts[lastfont][0], "Courier", 7) == 0;
+mono=1; // TODO
+
+ col ++;
+ xwid += Widths[lastfont];
+ line ++;
+
+ if (mono)
+ {
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ if (UTF8) {
+ font = Codes[line->ch];
+ } else {
+ font = Codes[Chars[line->ch]];
+ }
+ if (/*strncmp(Fonts[font][0], "Courier", 7) != 0 ||*/ // TODO
+ font != lastfont)
+ break;
+
+ col ++;
+ xwid += Widths[lastfont];
+ line ++;
+ }
+ }
+
+ if (Directions[lastfont] > 0) {
+ write_string(xcol, row, line - start, start);
+ xcol += xwid;
+ }
+ else
+ {
+ /*
+ * Do right-to-left text... ; assume no font change without direction change
+ */
+
+ while (col < SizeColumns && line->ch != 0 && attr == line->attr)
+ {
+ if (UTF8) {
+ font = Codes[line->ch];
+ } else {
+ font = Codes[Chars[line->ch]];
+ }
+ if (Directions[font] > 0 &&
+ !ispunct(line->ch & 255) && !isspace(line->ch & 255))
+ break;
+
+ col ++;
+ xwid += Widths[lastfont];
+ line ++;
+ }
+
+ for (i = 1; start < line; i ++, start ++)
+ if (!isspace(start->ch & 255)) {
+ xwid-=Widths[lastfont];
+ write_string(xcol + xwid, row, 1, start);
+ } else {
+ xwid--;
+ }
+ }
+ }
+ }
+}
+// }}}
+
+static lchar_t *make_wide(const char *buf) // {{{ - convert to lchar_t
+{
+ const unsigned char *utf8; /* UTF8 text */
+ lchar_t *ret,*out;
+
+ // this is enough, utf8 chars will only require less space
+ out=ret=malloc((strlen(buf)+1)*sizeof(lchar_t));
+
+ utf8 = (const unsigned char *)buf;
+ while (*utf8)
+ {
+ out->attr=0;
+
+ if (*utf8 < 0xc0 || !UTF8)
+ out->ch = *utf8 ++;
+ else if ((*utf8 & 0xe0) == 0xc0)
+ {
+ /*
+ * Two byte character...
+ */
+
+ out->ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f);
+ utf8 += 2;
+ }
+ else
+ {
+ /*
+ * Three byte character...
+ */
+
+ out->ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) |
+ (utf8[2] & 0x3f);
+ utf8 += 3;
+ }
+
+ out++;
+ }
+ out->ch=out->attr=0;
+ return ret;
+}
+// }}}
+
+/*
+ * {{{ 'write_string()' - Write a string of text.
+ */
+
+static void
+write_string(int col, /* I - Start column */
+ int row, /* I - Row */
+ int len, /* I - Number of characters */
+ lchar_t *s) /* I - String to print */
+{
+ float x, y; /* Position of text */
+ unsigned attr; /* Character attributes */
+
+
+ /*
+ * Position the text and set the font...
+ */
+
+ if (Duplex && (NumPages & 1) == 0)
+ {
+ x = PageWidth - PageRight;
+ y = PageTop;
+ }
+ else
+ {
+ x = PageLeft;
+ y = PageTop;
+ }
+
+ x += (float)col * 72.0f / (float)CharsPerInch;
+ y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch;
+
+ attr = s->attr;
+
+ if (attr & ATTR_RAISED)
+ y += 36.0 / (float)LinesPerInch;
+ else if (attr & ATTR_LOWERED)
+ y -= 36.0 / (float)LinesPerInch;
+
+ if (attr & ATTR_UNDERLINE)
+ pdfOut_printf(pdf,"q 0.5 w 0 g %.3f %.3f m %.3f %.3f l S Q ",
+ x, y - 6.8 / LinesPerInch,
+ x + (float)len * 72.0 / (float)CharsPerInch,
+ y - 6.8 / LinesPerInch);
+
+ if (PrettyPrint)
+ {
+ if (ColorDevice) {
+ if (attr & ATTR_RED)
+ pdfOut_printf(pdf,"0.5 0 0 rg\n");
+ else if (attr & ATTR_GREEN)
+ pdfOut_printf(pdf,"0 0.5 0 rg\n");
+ else if (attr & ATTR_BLUE)
+ pdfOut_printf(pdf,"0 0 0.5 rg\n");
+ else
+ pdfOut_printf(pdf,"0 g\n");
+ } else {
+ if ( (attr & ATTR_RED)||(attr & ATTR_GREEN)||(attr & ATTR_BLUE) )
+ pdfOut_printf(pdf,"0.2 g\n");
+ else
+ pdfOut_printf(pdf,"0 g\n");
+ }
+ }
+ else
+ pdfOut_printf(pdf,"0 g\n");
+
+ write_font_str(x,y,attr & ATTR_FONT,s,len);
+}
+// }}}
+
+// {{{ show >len characters from >str, using the right font(s) at >x,>y
+static void write_font_str(float x,float y,int fontid, lchar_t *str, int len)
+{
+ unsigned short ch; /* Current character */
+ static char *names[] = /* Font names */
+ { "FN","FB","FI" };
+
+ if (len==-1) {
+ for (len=0;str[len].ch;len++);
+ }
+ pdfOut_printf(pdf,"BT\n");
+
+ if (x == (int)x)
+ pdfOut_printf(pdf," %.0f ", x);
+ else
+ pdfOut_printf(pdf," %.3f ", x);
+
+ if (y == (int)y)
+ pdfOut_printf(pdf,"%.0f Td\n", y);
+ else
+ pdfOut_printf(pdf,"%.3f Td\n", y);
+
+ int lastfont,font;
+
+ // split on font boundary
+ while (len > 0)
+ {
+ /*
+ * Write a hex string...
+ */
+ if (UTF8) {
+ lastfont=Codes[str->ch];
+ } else {
+ lastfont=Codes[Chars[str->ch]];
+ }
+ EMB_PARAMS *emb=Fonts[lastfont][fontid];
+ OTF_FILE *otf=emb->font->sfnt;
+
+ pdfOut_printf(pdf," %.3f Tz\n",
+ FontScaleX*600.0/(otf_get_width(otf,0)*1000.0/otf->unitsPerEm)*100.0/FontScaleY); // TODO?
+
+ pdfOut_printf(pdf," /%s%02x %.3f Tf <",
+ names[fontid],lastfont,FontScaleY);
+
+ while (len > 0)
+ {
+ if (UTF8) {
+ ch=str->ch;
+ } else {
+ ch=Chars[str->ch];
+ }
+ const unsigned short gid=otf_from_unicode(otf,ch);
+
+ font = Codes[ch];
+ if (lastfont != font) {
+ assert(0); // should never happen; TODO
+ break;
+ }
+ pdfOut_printf(pdf,"%04x", gid);
+
+ if (emb->subset) {
+ bit_set(emb->subset,gid);
+ }
+
+ len --;
+ str ++;
+ }
+
+ pdfOut_printf(pdf,"> Tj\n");
+ }
+ pdfOut_printf(pdf,"ET\n");
+}
+// }}}
+
+static float stringwidth_x(lchar_t *str)
+{
+ int len;
+
+ for (len=0;str[len].ch;len++);
+
+ return (float)len * 72.0 / (float)CharsPerInch;
+}
+
+static void write_pretty_header() // {{{
+{
+ float x,y;
+ pdfOut_printf(pdf,"q\n"
+ "0.9 g\n");
+
+ if (Duplex && (NumPages & 1) == 0) {
+ x = PageWidth - PageRight;
+ y = PageTop + 72.0f / LinesPerInch;
+ } else {
+ x = PageLeft;
+ y = PageTop + 72.0f / LinesPerInch;
+ }
+
+ pdfOut_printf(pdf,"1 0 0 1 %.3f %.3f cm\n",x,y); // translate
+ pdfOut_printf(pdf,"0 0 %.3f %.3f re f\n",
+ PageRight - PageLeft, 144.0f / LinesPerInch);
+ pdfOut_printf(pdf,"0 g 0 G\n");
+
+ if (Duplex && (NumPages & 1) == 0) {
+ x = PageRight - PageLeft - 36.0f / LinesPerInch - stringwidth_x(Title);
+ y = (0.5f + 0.157f) * 72.0f / LinesPerInch;
+ } else {
+ x = 36.0f / LinesPerInch;
+ y = (0.5f + 0.157f) * 72.0f / LinesPerInch;
+ }
+ write_font_str(x,y,ATTR_BOLD,Title,-1);
+
+ x = (-stringwidth_x(Date) + PageRight - PageLeft) * 0.5;
+ write_font_str(x,y,ATTR_BOLD,Date,-1);
+
+ // convert pagenumber to string
+ char tmp[20];
+ tmp[19]=0;
+ snprintf(tmp,19,"%d",NumPages);
+ lchar_t *pagestr=make_wide(tmp);
+
+ if (Duplex && (NumPages & 1) == 0) {
+ x = 36.0f / LinesPerInch;
+ } else {
+ x = PageRight - PageLeft - 36.0f / LinesPerInch - stringwidth_x(pagestr);
+ }
+ write_font_str(x,y,ATTR_BOLD,pagestr,-1);
+
+ pdfOut_printf(pdf,"Q\n");
+}
+// }}}
+
Modified: cupsys/trunk/debian/local/filters/pdf-filters/removefromcups
==============================================================================
--- cupsys/trunk/debian/local/filters/pdf-filters/removefromcups (original)
+++ cupsys/trunk/debian/local/filters/pdf-filters/removefromcups Thu Aug 14 17:18:52 2008
@@ -6,11 +6,20 @@
# Remove files
rm -f $1/filter/imagetopdf.c
rm -f $1/filter/pdftoraster.cxx
+rm -f $1/filter/texttopdf.c
+rm -f $1/filter/pdfutils.h
+rm -f $1/filter/pdfutils.c
+rm -rf $1/filter/fontembed
+rm -f $1/filter/test_pdf1.c
+rm -f $1/filter/test_pdf2.c
rm -f $1/conf/imagetopdf.convs
rm -f $1/conf/imagetopdf.types
rm -f $1/conf/pdftopdf.convs
rm -f $1/conf/pdftoraster.convs
rm -f $1/conf/pdf.types
+rm -f $1/conf/texttopdf.convs
+rm -f $1/data/pdf.utf-8.heavy
+rm -f $1/data/pdf.utf-8.simple
rm -f $1/config-scripts/cups-pdf-filters.m4
# Remove directories
@@ -26,5 +35,6 @@
# Restore Makefiles
mv -f conf/Makefile.pdf-filters conf/Makefile
mv -f filter/Makefile.pdf-filters filter/Makefile
+mv -f data/Makefile.pdf-filters data/Makefile
mv -f Makefile.pdf-filters Makefile
mv -f Makedefs.in.pdf-filters Makedefs.in
Modified: cupsys/trunk/debian/rules
==============================================================================
--- cupsys/trunk/debian/rules (original)
+++ cupsys/trunk/debian/rules Thu Aug 14 17:18:52 2008
@@ -83,10 +83,13 @@
# Install documentation of the PDF CUPS filters
install -m 644 debian/local/filters/pdf-filters/README $(DEB_DESTDIR)/../cups/usr/share/doc/cups/README.pdf-filters
+ install -m 644 debian/local/filters/pdf-filters/filter/test.sh $(DEB_DESTDIR)/../cups/usr/share/doc/cups/examples/texttopdf-text.sh
# Move file detection and conversion rules to /usr/share/cups/mime/ so
# that the package manager does not consider them conffiles
install -d $(DEB_DESTDIR)/../cups/usr/share/cups/mime
- ( cd $(DEB_DESTDIR)/../cups/etc/cups; mv imagetopdf.* pdftopdf.* pdftoraster.* pdf.* $(DEB_DESTDIR)/../cups/usr/share/cups/mime/ )
+ ( cd $(DEB_DESTDIR)/../cups/etc/cups; mv imagetopdf.* pdftopdf.* pdftoraster.* pdf.* texttopdf.* $(DEB_DESTDIR)/../cups/usr/share/cups/mime/ )
+ # Configure fonts for texttopdf
+ for f in /usr/share/fonts/truetype/freefont/FreeMono*.ttf; do ln -s $$f $(DEB_DESTDIR)/../cups/usr/share/cups/fonts/; done
# Simple Ghostscript-based PostScript-to-PDF filter
install -m 0755 debian/filters/pstopdf $(DEB_DESTDIR)/../cups/usr/lib/cups/filter
@@ -102,3 +105,7 @@
binary-post-install/cups-client::
rm -r debian/cups-client/usr/share/doc/cups-client
ln -s libcups2 debian/cups-client/usr/share/doc/cups-client
+
+binary-post-install/cups-common::
+ # Configure fonts for texttopdf
+ ln -s /usr/share/cups/charsets/pdf.utf-8.simple $(DEB_DESTDIR)/../cups-common/usr/share/cups/charsets/pdf.utf-8
More information about the Pkg-cups-devel
mailing list