From 64676031423465996e83c4a685290f0c3d97a249 Mon Sep 17 00:00:00 2001 From: Martin Kretzschmar Date: Mon, 31 Mar 2003 21:08:43 +0000 Subject: kill traces of ltk, incorporate new sources * xpdf/Makefile.am: kill traces of ltk, incorporate new sources * Makefile.am, configure.in: don't build the ltk subdir * ANNOUNCE, CHANGES, ChangeLog, README, aconf-dj.h, aconf-win32.h, dj_make.bat, ms_make.bat, vms_make.com: update * xpdf/LTKOutputDev.cc, xpdf/LTKOutputDev.h, xpdf/postscript.xbm, xpdf/xpdf-flip.ltk, xpdf/xpdf-ltk.h, xpdf/xpdf-top.ltk, xpdf/xpdf.ltk: remove. * xpdf/Annot.cc, xpdf/Annot.h, xpdf/Array.cc, xpdf/Array.h, xpdf/BuiltinFont.cc, xpdf/BuiltinFont.h, xpdf/BuiltinFontTables.cc, xpdf/CMap.cc, xpdf/CMap.h, xpdf/Catalog.cc, xpdf/Catalog.h, xpdf/CharCodeToUnicode.cc, xpdf/CharCodeToUnicode.h, xpdf/Decrypt.cc, xpdf/Decrypt.h, xpdf/Dict.cc, xpdf/Dict.h, xpdf/Error.cc, xpdf/Error.h, xpdf/FTFont.cc, xpdf/FTFont.h, xpdf/FontFile.cc, xpdf/FontFile.h, xpdf/Function.cc, xpdf/Function.h, xpdf/Gfx.cc, xpdf/Gfx.h, xpdf/GfxFont.cc, xpdf/GfxFont.h, xpdf/GfxState.cc, xpdf/GfxState.h, xpdf/GlobalParams.cc, xpdf/GlobalParams.h, xpdf/ImageOutputDev.cc, xpdf/ImageOutputDev.h, xpdf/Lexer.cc, xpdf/Lexer.h, xpdf/Link.cc, xpdf/Link.h, xpdf/NameToCharCode.cc, xpdf/NameToCharCode.h, xpdf/NameToUnicodeTable.h, xpdf/Object.cc, xpdf/Object.h, xpdf/OutputDev.cc, xpdf/OutputDev.h, xpdf/PBMOutputDev.cc, xpdf/PBMOutputDev.h, xpdf/PDFDoc.cc, xpdf/PDFDoc.h, xpdf/PSOutputDev.cc, xpdf/PSOutputDev.h, xpdf/PSTokenizer.cc, xpdf/PSTokenizer.h, xpdf/Page.cc, xpdf/Page.h, xpdf/Parser.cc, xpdf/Parser.h, xpdf/SFont.cc, xpdf/SFont.h, xpdf/Stream.cc, xpdf/Stream.h, xpdf/T1Font.cc, xpdf/T1Font.h, xpdf/TTFont.cc, xpdf/TTFont.h, xpdf/TextOutputDev.cc, xpdf/TextOutputDev.h, xpdf/UnicodeMap.cc, xpdf/UnicodeMap.h, xpdf/XOutputDev.cc, xpdf/XOutputDev.h, xpdf/XRef.cc, xpdf/XRef.h, xpdf/config.h, xpdf/pdffonts.cc, xpdf/pdfimages.cc, xpdf/pdfinfo.cc, xpdf/pdftopbm.cc, xpdf/pdftops.cc, xpdf/pdftotext.cc, xpdf/vms_make.com, xpdf/xpdf.cc: update. * goo/GHash.cc, goo/GHash.h, goo/GList.cc, goo/GList.h, goo/GString.cc, goo/GString.h: mostly Mac OS X gcc fixage. * doc/pdffonts.1, doc/pdffonts.cat, doc/pdffonts.hlp, doc/pdfimages.1, doc/pdfimages.cat, doc/pdfimages.hlp, doc/pdfinfo.1, doc/pdfinfo.cat, doc/pdfinfo.hlp, doc/pdftopbm.1, doc/pdftopbm.cat, doc/pdftopbm.hlp, doc/pdftops.1, doc/pdftops.cat, doc/pdftops.hlp, doc/pdftotext.1, doc/pdftotext.cat, doc/pdftotext.hlp, doc/xpdf.1, doc/xpdf.cat, doc/xpdf.hlp, doc/xpdfrc.5, doc/xpdfrc.cat, doc/xpdfrc.hlp: update docs. --- diff --git a/pdf/goo/GString.cc b/pdf/goo/GString.cc index 3bf626a..25e0e05 100644 --- a/pdf/goo/GString.cc +++ b/pdf/goo/GString.cc @@ -8,11 +8,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -203,8 +204,12 @@ GString *GString::del(int i, int n) { int j; if (n > 0) { - for (j = i; j <= length - n; ++j) + if (i + n > length) { + n = length - i; + } + for (j = i; j <= length - n; ++j) { s[j] = s[j + n]; + } resize(length -= n); } return this; diff --git a/pdf/goo/GString.h b/pdf/goo/GString.h index 93796cb..d22cc19 100644 --- a/pdf/goo/GString.h +++ b/pdf/goo/GString.h @@ -11,7 +11,9 @@ #ifndef GSTRING_H #define GSTRING_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/Array.cc b/pdf/xpdf/Array.cc index fbdde49..9c6cb34 100644 --- a/pdf/xpdf/Array.cc +++ b/pdf/xpdf/Array.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "gmem.h" #include "Object.h" diff --git a/pdf/xpdf/Array.h b/pdf/xpdf/Array.h index a118f68..09dbe2b 100644 --- a/pdf/xpdf/Array.h +++ b/pdf/xpdf/Array.h @@ -9,7 +9,9 @@ #ifndef ARRAY_H #define ARRAY_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/Catalog.cc b/pdf/xpdf/Catalog.cc index 1212e2e..efea828 100644 --- a/pdf/xpdf/Catalog.cc +++ b/pdf/xpdf/Catalog.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "gmem.h" #include "Object.h" @@ -26,7 +27,7 @@ // Catalog //------------------------------------------------------------------------ -Catalog::Catalog(XRef *xrefA, GBool printCommands) { +Catalog::Catalog(XRef *xrefA) { Object catDict, pagesDict; Object obj, obj2; int numPages0; @@ -69,7 +70,7 @@ Catalog::Catalog(XRef *xrefA, GBool printCommands) { pageRefs[i].num = -1; pageRefs[i].gen = -1; } - numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands); + numPages = readPageTree(pagesDict.getDict(), NULL, 0); if (numPages != numPages0) { error(-1, "Page count in top-level pages object is incorrect"); } @@ -100,6 +101,9 @@ Catalog::Catalog(XRef *xrefA, GBool printCommands) { // get the structure tree root catDict.dictLookup("StructTreeRoot", &structTreeRoot); + // get the outline dictionary + catDict.dictLookup("Outlines", &outline); + catDict.free(); return; @@ -133,6 +137,7 @@ Catalog::~Catalog() { } metadata.free(); structTreeRoot.free(); + outline.free(); } GString *Catalog::readMetadata() { @@ -159,8 +164,7 @@ GString *Catalog::readMetadata() { return s; } -int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, - GBool printCommands) { +int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { Object kids; Object kid; Object kidRef; @@ -179,7 +183,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, kids.arrayGet(i, &kid); if (kid.isDict("Page")) { attrs2 = new PageAttrs(attrs1, kid.getDict()); - page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands); + page = new Page(xref, start+1, kid.getDict(), attrs2); if (!page->isOk()) { ++start; goto err3; @@ -205,7 +209,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, // This should really be isDict("Pages"), but I've seen at least one // PDF file where the /Type entry is missing. } else if (kid.isDict()) { - if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands)) + if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0) goto err2; } else { @@ -276,6 +280,10 @@ LinkDest *Catalog::findDest(GString *name) { error(-1, "Bad named destination value"); } obj1.free(); + if (dest && !dest->isOk()) { + delete dest; + dest = NULL; + } return dest; } diff --git a/pdf/xpdf/Catalog.h b/pdf/xpdf/Catalog.h index afad803..7f89a61 100644 --- a/pdf/xpdf/Catalog.h +++ b/pdf/xpdf/Catalog.h @@ -9,7 +9,9 @@ #ifndef CATALOG_H #define CATALOG_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -28,7 +30,7 @@ class Catalog { public: // Constructor. - Catalog(XRef *xrefA, GBool printCommands = gFalse); + Catalog(XRef *xrefA); // Destructor. ~Catalog(); @@ -63,6 +65,8 @@ public: // NULL if is not a destination. LinkDest *findDest(GString *name); + Object *getOutline() { return &outline; } + private: XRef *xref; // the xref table for this PDF file @@ -75,10 +79,10 @@ private: GString *baseURI; // base URI for URI-type links Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary + Object outline; // outline dictionary GBool ok; // true if catalog is valid - int readPageTree(Dict *pages, PageAttrs *attrs, int start, - GBool printCommands); + int readPageTree(Dict *pages, PageAttrs *attrs, int start); Object *findDestInTree(Object *tree, GString *name, Object *obj); }; diff --git a/pdf/xpdf/Dict.cc b/pdf/xpdf/Dict.cc index 5eb077e..ad4ec3e 100644 --- a/pdf/xpdf/Dict.cc +++ b/pdf/xpdf/Dict.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" diff --git a/pdf/xpdf/Dict.h b/pdf/xpdf/Dict.h index b994514..e87ed90 100644 --- a/pdf/xpdf/Dict.h +++ b/pdf/xpdf/Dict.h @@ -9,7 +9,9 @@ #ifndef DICT_H #define DICT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/Error.cc b/pdf/xpdf/Error.cc index 3eae5c9..4b2d120 100644 --- a/pdf/xpdf/Error.cc +++ b/pdf/xpdf/Error.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include diff --git a/pdf/xpdf/Error.h b/pdf/xpdf/Error.h index 77801c5..c924065 100644 --- a/pdf/xpdf/Error.h +++ b/pdf/xpdf/Error.h @@ -9,7 +9,9 @@ #ifndef ERROR_H #define ERROR_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc index 7476909..6860e4a 100644 --- a/pdf/xpdf/FontFile.cc +++ b/pdf/xpdf/FontFile.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include #include @@ -2214,7 +2215,11 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) { } } while (i < 64); buf[i] = '\0'; - x = atof(buf); + { + char *theLocale = setlocale(LC_NUMERIC, "C"); + x = atof(buf); + setlocale(LC_NUMERIC, theLocale); + } *isFP = gTrue; } else if (b0 == 31) { x = 0; diff --git a/pdf/xpdf/Function.cc b/pdf/xpdf/Function.cc index 82bbdce..cafb63f 100644 --- a/pdf/xpdf/Function.cc +++ b/pdf/xpdf/Function.cc @@ -12,6 +12,7 @@ #pragma implementation #endif +#include #include #include #include @@ -1072,7 +1073,11 @@ GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { resizeCode(*codePtr); if (isReal) { code[*codePtr].type = psReal; - code[*codePtr].real = atof(tok->getCString()); + { + char *theLocale = setlocale(LC_NUMERIC, "C"); + code[*codePtr].real = atof(tok->getCString()); + setlocale(LC_NUMERIC, theLocale); + } } else { code[*codePtr].type = psInt; code[*codePtr].intg = atoi(tok->getCString()); diff --git a/pdf/xpdf/Gfx.cc b/pdf/xpdf/Gfx.cc index 0b00f91..2717a04 100644 --- a/pdf/xpdf/Gfx.cc +++ b/pdf/xpdf/Gfx.cc @@ -6,16 +6,18 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include #include #include "gmem.h" +#include "GlobalParams.h" #include "CharTypes.h" #include "Object.h" #include "Array.h" @@ -381,12 +383,13 @@ GBool GfxResources::lookupGState(char *name, Object *obj) { Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, - GBool printCommandsA) { + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { int i; xref = xrefA; subPage = gFalse; - printCommands = printCommandsA; + printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); @@ -403,6 +406,8 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; // set crop box if (crop) { @@ -418,12 +423,14 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, } Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox) { + PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { int i; xref = xrefA; subPage = gTrue; - printCommands = gFalse; + printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); @@ -437,6 +444,8 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; // set crop box if (crop) { @@ -494,11 +503,11 @@ void Gfx::display(Object *obj, GBool topLevel) { void Gfx::go(GBool topLevel) { Object obj; Object args[maxArgs]; - int numArgs; - int i; + int numArgs, i; + int lastAbortCheck; // scan a sequence of objects - updateLevel = 0; + updateLevel = lastAbortCheck = 0; numArgs = 0; parser->getObj(&obj); while (!obj.isEOF()) { @@ -526,6 +535,16 @@ void Gfx::go(GBool topLevel) { updateLevel = 0; } + // check for an abort + if (abortCheckCbk) { + if (updateLevel - lastAbortCheck > 10) { + if ((*abortCheckCbk)(abortCheckCbkData)) { + break; + } + lastAbortCheck = updateLevel; + } + } + // got an argument - save it } else if (numArgs < maxArgs) { args[numArgs++] = obj; @@ -575,7 +594,7 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) { int i; // find operator - name = cmd->getName(); + name = cmd->getCmd(); if (!(op = findOp(name))) { if (ignoreUndef == 0) error(getPos(), "Unknown operator '%s'", name); diff --git a/pdf/xpdf/Gfx.h b/pdf/xpdf/Gfx.h index bdf56e8..c3c57cf 100644 --- a/pdf/xpdf/Gfx.h +++ b/pdf/xpdf/Gfx.h @@ -9,7 +9,9 @@ #ifndef GFX_H #define GFX_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -31,7 +33,7 @@ class GfxAxialShading; class GfxRadialShading; class GfxState; class Gfx; -struct PDFRectangle; +class PDFRectangle; //------------------------------------------------------------------------ // Gfx @@ -97,11 +99,14 @@ public: // Constructor for regular output. Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi, PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate, - GBool printCommandsA); + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); // Constructor for a sub-page object. Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, GBool crop, PDFRectangle *cropBox); + PDFRectangle *box, GBool crop, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); ~Gfx(); @@ -134,6 +139,10 @@ private: Parser *parser; // parser for page content stream(s) + GBool // callback to check for an abort + (*abortCheckCbk)(void *data); + void *abortCheckCbkData; + static Operator opTab[]; // table of operators void go(GBool topLevel); diff --git a/pdf/xpdf/GfxFont.cc b/pdf/xpdf/GfxFont.cc index 8dcd8e7..5acb845 100644 --- a/pdf/xpdf/GfxFont.cc +++ b/pdf/xpdf/GfxFont.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -564,8 +565,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, if (!baseEnc) { if (builtinFont) { baseEnc = builtinFont->defaultBaseEnc; + hasEncoding = gTrue; } else if (type == fontTrueType) { - baseEnc = macRomanEncoding; + baseEnc = winAnsiEncoding; } else { baseEnc = standardEncoding; } @@ -1240,21 +1242,31 @@ GString *GfxCIDFont::getCollection() { GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) { int i; Object obj1, obj2; + Ref r; numFonts = fontDict->getLength(); fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); - if (obj1.isRef() && obj2.isDict()) { + if (obj2.isDict()) { + if (obj1.isRef()) { + r = obj1.getRef(); + } else { + // no indirect reference for this font, so invent a unique one + // (legal generation numbers are five digits, so any 6-digit + // number would be safe) + r.num = i; + r.gen = 999999; + } fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), - obj1.getRef(), obj2.getDict()); + r, obj2.getDict()); if (fonts[i] && !fonts[i]->isOk()) { delete fonts[i]; fonts[i] = NULL; } } else { - error(-1, "font resource is not a dictionary reference"); + error(-1, "font resource is not a dictionary"); fonts[i] = NULL; } obj1.free(); diff --git a/pdf/xpdf/GfxFont.h b/pdf/xpdf/GfxFont.h index c67ac29..bcabe5f 100644 --- a/pdf/xpdf/GfxFont.h +++ b/pdf/xpdf/GfxFont.h @@ -9,7 +9,9 @@ #ifndef GFXFONT_H #define GFXFONT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc index 94501a8..d968ac1 100644 --- a/pdf/xpdf/GfxState.cc +++ b/pdf/xpdf/GfxState.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include // for memcpy() @@ -852,12 +853,14 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) { void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { Guchar *p; GfxColor color2; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; int n, i; n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); p = &lookup[(int)(color->c[0] + 0.5) * n]; for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; + color2.c[i] = low[i] + (p[i] / 255.0) * range[i]; } base->getGray(&color2, gray); } @@ -865,12 +868,14 @@ void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) { void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { Guchar *p; GfxColor color2; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; int n, i; n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); p = &lookup[(int)(color->c[0] + 0.5) * n]; for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; + color2.c[i] = low[i] + (p[i] / 255.0) * range[i]; } base->getRGB(&color2, rgb); } @@ -878,12 +883,14 @@ void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { Guchar *p; GfxColor color2; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; int n, i; n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); p = &lookup[(int)(color->c[0] + 0.5) * n]; for (i = 0; i < n; ++i) { - color2.c[i] = p[i] / 255.0; + color2.c[i] = low[i] + (p[i] / 255.0) * range[i]; } base->getCMYK(&color2, cmyk); } @@ -1682,10 +1689,11 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, nComps2 = colorSpace2->getNComps(); lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double)); lookup2 = indexedCS->getLookup(); + colorSpace2->getDefaultRanges(x, y, indexHigh); for (i = 0; i <= indexHigh; ++i) { - j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5); + j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); for (k = 0; k < nComps2; ++k) { - lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0; + lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k]; } } } else if (colorSpace->getMode() == csSeparation) { diff --git a/pdf/xpdf/GfxState.h b/pdf/xpdf/GfxState.h index b1f6f28..e99735c 100644 --- a/pdf/xpdf/GfxState.h +++ b/pdf/xpdf/GfxState.h @@ -9,7 +9,9 @@ #ifndef GFXSTATE_H #define GFXSTATE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -19,7 +21,7 @@ class Array; class GfxFont; -struct PDFRectangle; +class PDFRectangle; //------------------------------------------------------------------------ // GfxColor @@ -406,7 +408,9 @@ public: virtual int getNComps() { return nComps; } // DeviceN-specific access. + GString *getColorantName(int i) { return names[i]; } GfxColorSpace *getAlt() { return alt; } + Function *getTintTransformFunc() { return func; } private: diff --git a/pdf/xpdf/ImageOutputDev.cc b/pdf/xpdf/ImageOutputDev.cc index d6c2eb3..1a6d87e 100644 --- a/pdf/xpdf/ImageOutputDev.cc +++ b/pdf/xpdf/ImageOutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -98,7 +99,7 @@ void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int *maskColors, GBool inlineImg) { FILE *f; ImageStream *imgStr; - Guchar pixBuf[4]; + Guchar *p; GfxRGB rgb; int x, y; int c; @@ -148,7 +149,7 @@ void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, // copy the stream size = height * ((width + 7) / 8); for (i = 0; i < size; ++i) { - fputc(str->getChar(), f); + fputc(str->getChar() ^ 0xff, f); } str->close(); @@ -177,12 +178,13 @@ void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, for (y = 0; y < height; ++y) { // write the line + p = imgStr->getLine(); for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getRGB(pixBuf, &rgb); + colorMap->getRGB(p, &rgb); fputc((int)(rgb.r * 255 + 0.5), f); fputc((int)(rgb.g * 255 + 0.5), f); fputc((int)(rgb.b * 255 + 0.5), f); + p += colorMap->getNumPixelComps(); } } delete imgStr; diff --git a/pdf/xpdf/ImageOutputDev.h b/pdf/xpdf/ImageOutputDev.h index 5828841..c3eb36e 100644 --- a/pdf/xpdf/ImageOutputDev.h +++ b/pdf/xpdf/ImageOutputDev.h @@ -9,7 +9,9 @@ #ifndef IMAGEOUTPUTDEV_H #define IMAGEOUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/LTKOutputDev.cc b/pdf/xpdf/LTKOutputDev.cc deleted file mode 100644 index ba5a332..0000000 --- a/pdf/xpdf/LTKOutputDev.cc +++ /dev/null @@ -1,72 +0,0 @@ -//======================================================================== -// -// LTKOutputDev.cc -// -// Copyright 1998-2002 Glyph & Cog, LLC -// -//======================================================================== - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include "gmem.h" -#include "GString.h" -#include "LTKWindow.h" -#include "LTKScrollingCanvas.h" -#include "Object.h" -#include "Stream.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "Error.h" -#include "LTKOutputDev.h" - -//------------------------------------------------------------------------ - -LTKOutputDev::LTKOutputDev(LTKWindow *winA, GBool reverseVideoA, - unsigned long paperColor, GBool installCmap, - GBool rgbCubeSize, GBool incrementalUpdateA): - XOutputDev(winA->getDisplay(), - ((LTKScrollingCanvas *)winA->findWidget("canvas"))->getPixmap(), - 0, winA->getColormap(), reverseVideoA, paperColor, - installCmap, rgbCubeSize) -{ - win = winA; - canvas = (LTKScrollingCanvas *)win->findWidget("canvas"); - setPixmap(canvas->getPixmap(), - canvas->getRealWidth(), canvas->getRealHeight()); - incrementalUpdate = incrementalUpdateA; -} - -LTKOutputDev::~LTKOutputDev() { -} - -void LTKOutputDev::startPage(int pageNum, GfxState *state) { - canvas->resize((int)(state->getPageWidth() + 0.5), - (int)(state->getPageHeight() + 0.5)); - setPixmap(canvas->getPixmap(), - canvas->getRealWidth(), canvas->getRealHeight()); - XOutputDev::startPage(pageNum, state); - if (incrementalUpdate) { - canvas->redraw(); - } -} - -void LTKOutputDev::endPage() { - if (!incrementalUpdate) { - canvas->redraw(); - } - XOutputDev::endPage(); -} - -void LTKOutputDev::dump() { - if (incrementalUpdate) { - canvas->redraw(); - } - XOutputDev::dump(); -} diff --git a/pdf/xpdf/LTKOutputDev.h b/pdf/xpdf/LTKOutputDev.h deleted file mode 100644 index 7b996dc..0000000 --- a/pdf/xpdf/LTKOutputDev.h +++ /dev/null @@ -1,52 +0,0 @@ -//======================================================================== -// -// LTKOutputDev.h -// -// Copyright 1998-2002 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef LTKOUTPUTDEV_H -#define LTKOUTPUTDEV_H - -#ifdef __GNUC__ -#pragma interface -#endif - -#include -#include "config.h" -#include "XOutputDev.h" - -class LTKApp; -class LTKWindow; - -//------------------------------------------------------------------------ - -class LTKOutputDev: public XOutputDev { -public: - - LTKOutputDev(LTKWindow *winA, GBool reverseVideoA, - unsigned long paperColor, GBool installCmap, - GBool rgbCubeSize, GBool incrementalUpdateA); - - ~LTKOutputDev(); - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - // Dump page contents to display. - virtual void dump(); - -private: - - LTKWindow *win; // window - LTKScrollingCanvas *canvas; // drawing canvas - GBool incrementalUpdate; // incrementally update the display? -}; - -#endif diff --git a/pdf/xpdf/Lexer.cc b/pdf/xpdf/Lexer.cc index d037469..982295e 100644 --- a/pdf/xpdf/Lexer.cc +++ b/pdf/xpdf/Lexer.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include diff --git a/pdf/xpdf/Lexer.h b/pdf/xpdf/Lexer.h index 8a01ab2..2dfe314 100644 --- a/pdf/xpdf/Lexer.h +++ b/pdf/xpdf/Lexer.h @@ -9,7 +9,9 @@ #ifndef LEXER_H #define LEXER_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/Link.cc b/pdf/xpdf/Link.cc index eb9d033..b16563a 100644 --- a/pdf/xpdf/Link.cc +++ b/pdf/xpdf/Link.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include "gmem.h" @@ -22,8 +23,117 @@ #include "Link.h" //------------------------------------------------------------------------ +// LinkAction +//------------------------------------------------------------------------ + +LinkAction *LinkAction::parseDest(Object *obj) { + LinkAction *action; + + action = new LinkGoTo(obj); + if (!action->isOk()) { + delete action; + return NULL; + } + return action; +} + +LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { + LinkAction *action; + Object obj2, obj3, obj4; + + if (!obj->isDict()) { + error(-1, "Bad annotation action"); + return NULL; + } + + obj->dictLookup("S", &obj2); + + // GoTo action + if (obj2.isName("GoTo")) { + obj->dictLookup("D", &obj3); + action = new LinkGoTo(&obj3); + obj3.free(); + + // GoToR action + } else if (obj2.isName("GoToR")) { + obj->dictLookup("F", &obj3); + obj->dictLookup("D", &obj4); + action = new LinkGoToR(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // Launch action + } else if (obj2.isName("Launch")) { + action = new LinkLaunch(obj); + + // URI action + } else if (obj2.isName("URI")) { + obj->dictLookup("URI", &obj3); + action = new LinkURI(&obj3, baseURI); + obj3.free(); + + // Named action + } else if (obj2.isName("Named")) { + obj->dictLookup("N", &obj3); + action = new LinkNamed(&obj3); + obj3.free(); + + // Movie action + } else if (obj2.isName("Movie")) { + obj->dictLookupNF("Annot", &obj3); + obj->dictLookup("T", &obj4); + action = new LinkMovie(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // unknown action + } else if (obj2.isName()) { + action = new LinkUnknown(obj2.getName()); + + // action is missing or wrong type + } else { + error(-1, "Bad annotation action"); + action = NULL; + } -static GString *getFileSpecName(Object *fileSpecObj); + obj2.free(); + + if (action && !action->isOk()) { + delete action; + return NULL; + } + return action; +} + +GString *LinkAction::getFileSpecName(Object *fileSpecObj) { + GString *name; + Object obj1; + + name = NULL; + + // string + if (fileSpecObj->isString()) { + name = fileSpecObj->getString()->copy(); + + // dictionary + } else if (fileSpecObj->isDict()) { + if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { + obj1.free(); + fileSpecObj->dictLookup("F", &obj1); + } + if (obj1.isString()) + name = obj1.getString()->copy(); + else + error(-1, "Illegal file spec in link"); + obj1.free(); + + // error + } else { + error(-1, "Illegal file spec in link"); + } + + return name; +} //------------------------------------------------------------------------ // LinkDest @@ -37,6 +147,10 @@ LinkDest::LinkDest(Array *a) { ok = gFalse; // get page + if (a->getLength() < 2) { + error(-1, "Annotation destination array has wrong length"); + return; + } a->getNF(0, &obj1); if (obj1.isInt()) { pageNum = obj1.getInt() + 1; @@ -56,6 +170,10 @@ LinkDest::LinkDest(Array *a) { // XYZ link if (obj1.isName("XYZ")) { + if (a->getLength() != 5) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destXYZ; a->get(2, &obj2); if (obj2.isNull()) { @@ -93,10 +211,18 @@ LinkDest::LinkDest(Array *a) { // Fit link } else if (obj1.isName("Fit")) { + if (a->getLength() != 2) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFit; // FitH link } else if (obj1.isName("FitH")) { + if (a->getLength() != 3) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -107,6 +233,10 @@ LinkDest::LinkDest(Array *a) { // FitV link } else if (obj1.isName("FitV")) { + if (a->getLength() != 3) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -117,6 +247,10 @@ LinkDest::LinkDest(Array *a) { // FitR link } else if (obj1.isName("FitR")) { + if (a->getLength() != 6) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitR; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -145,10 +279,18 @@ LinkDest::LinkDest(Array *a) { // FitB link } else if (obj1.isName("FitB")) { + if (a->getLength() != 2) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitB; // FitBH link } else if (obj1.isName("FitBH")) { + if (a->getLength() != 3) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitBH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -159,6 +301,10 @@ LinkDest::LinkDest(Array *a) { // FitBV link } else if (obj1.isName("FitBV")) { + if (a->getLength() != 3) { + error(-1, "Annotation destination array has wrong length"); + goto err2; + } kind = destFitBV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); @@ -292,18 +438,33 @@ LinkLaunch::LinkLaunch(Object *actionObj) { fileName = getFileSpecName(&obj1); } else { obj1.free(); +#ifdef WIN32 + if (actionObj->dictLookup("Win", &obj1)->isDict()) { + obj1.dictLookup("F", &obj2); + fileName = getFileSpecName(&obj2); + obj2.free(); + if (obj1.dictLookup("P", &obj2)->isString()) { + params = obj2.getString()->copy(); + } + obj2.free(); + } else { + error(-1, "Bad launch-type link action"); + } +#else //~ This hasn't been defined by Adobe yet, so assume it looks //~ just like the Win dictionary until they say otherwise. if (actionObj->dictLookup("Unix", &obj1)->isDict()) { obj1.dictLookup("F", &obj2); fileName = getFileSpecName(&obj2); obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) + if (obj1.dictLookup("P", &obj2)->isString()) { params = obj2.getString()->copy(); + } obj2.free(); } else { error(-1, "Bad launch-type link action"); } +#endif } obj1.free(); } @@ -378,6 +539,28 @@ LinkNamed::~LinkNamed() { } //------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { + annotRef.num = -1; + title = NULL; + if (annotObj->isRef()) { + annotRef = annotObj->getRef(); + } else if (titleObj->isString()) { + title = titleObj->getString()->copy(); + } else { + error(-1, "Movie action is missing both the Annot and T keys"); + } +} + +LinkMovie::~LinkMovie() { + if (title) { + delete title; + } +} + +//------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ @@ -394,7 +577,7 @@ LinkUnknown::~LinkUnknown() { //------------------------------------------------------------------------ Link::Link(Dict *dict, GString *baseURI) { - Object obj1, obj2, obj3, obj4; + Object obj1, obj2; double t; action = NULL; @@ -457,66 +640,21 @@ Link::Link(Dict *dict, GString *baseURI) { // look for destination if (!dict->lookup("Dest", &obj1)->isNull()) { - action = new LinkGoTo(&obj1); + action = LinkAction::parseDest(&obj1); // look for action } else { obj1.free(); if (dict->lookup("A", &obj1)->isDict()) { - obj1.dictLookup("S", &obj2); - - // GoTo action - if (obj2.isName("GoTo")) { - obj1.dictLookup("D", &obj3); - action = new LinkGoTo(&obj3); - obj3.free(); - - // GoToR action - } else if (obj2.isName("GoToR")) { - obj1.dictLookup("F", &obj3); - obj1.dictLookup("D", &obj4); - action = new LinkGoToR(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // Launch action - } else if (obj2.isName("Launch")) { - action = new LinkLaunch(&obj1); - - // URI action - } else if (obj2.isName("URI")) { - obj1.dictLookup("URI", &obj3); - action = new LinkURI(&obj3, baseURI); - obj3.free(); - - // Named action - } else if (obj2.isName("Named")) { - obj1.dictLookup("N", &obj3); - action = new LinkNamed(&obj3); - obj3.free(); - - // unknown action - } else if (obj2.isName()) { - action = new LinkUnknown(obj2.getName()); - - // action is missing or wrong type - } else { - error(-1, "Bad annotation action"); - action = NULL; - } - - obj2.free(); - - } else { - error(-1, "Missing annotation destination/action"); - action = NULL; + action = LinkAction::parseAction(&obj1, baseURI); } } obj1.free(); // check for bad action - if (action && action->isOk()) + if (action) { ok = gTrue; + } return; @@ -595,36 +733,3 @@ GBool Links::onLink(double x, double y) const { } return gFalse; } - -//------------------------------------------------------------------------ - -// Extract a file name from a file specification (string or dictionary). -static GString *getFileSpecName(Object *fileSpecObj) { - GString *name; - Object obj1; - - name = NULL; - - // string - if (fileSpecObj->isString()) { - name = fileSpecObj->getString()->copy(); - - // dictionary - } else if (fileSpecObj->isDict()) { - if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { - obj1.free(); - fileSpecObj->dictLookup("F", &obj1); - } - if (obj1.isString()) - name = obj1.getString()->copy(); - else - error(-1, "Illegal file spec in link"); - obj1.free(); - - // error - } else { - error(-1, "Illegal file spec in link"); - } - - return name; -} diff --git a/pdf/xpdf/Link.h b/pdf/xpdf/Link.h index e5b15e3..e19c3c0 100644 --- a/pdf/xpdf/Link.h +++ b/pdf/xpdf/Link.h @@ -9,7 +9,9 @@ #ifndef LINK_H #define LINK_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -29,6 +31,7 @@ enum LinkActionKind { actionLaunch, // launch app (or open document) actionURI, // URI actionNamed, // named action + actionMovie, // movie action actionUnknown // anything else }; @@ -43,6 +46,16 @@ public: // Check link action type. virtual LinkActionKind getKind() = 0; + + // Parse a destination (old-style action) name, string, or array. + static LinkAction *parseDest(Object *obj); + + // Parse an action dictionary. + static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); + + // Extract a file name from a file specification (string or + // dictionary). + static GString *getFileSpecName(Object *fileSpecObj); }; //------------------------------------------------------------------------ @@ -240,6 +253,30 @@ private: }; //------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +class LinkMovie: public LinkAction { +public: + + LinkMovie(Object *annotObj, Object *titleObj); + + virtual ~LinkMovie(); + + virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } + + virtual LinkActionKind getKind() { return actionMovie; } + GBool hasAnnotRef() { return annotRef.num >= 0; } + Ref *getAnnotRef() { return &annotRef; } + GString *getTitle() { return title; } + +private: + + Ref annotRef; + GString *title; +}; + +//------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ diff --git a/pdf/xpdf/Makefile.am b/pdf/xpdf/Makefile.am index 1ab6b31..3e39038 100644 --- a/pdf/xpdf/Makefile.am +++ b/pdf/xpdf/Makefile.am @@ -1,7 +1,6 @@ INCLUDES = \ -I$(top_srcdir)/goo \ - -I$(top_srcdir)/ltk \ -DDATADIR=\""$(datadir)"\" \ -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DGNOMEICONDIR=\""$(datadir)/pixmaps"\" \ @@ -67,6 +66,8 @@ common_sources = \ GfxState.h \ GlobalParams.cc \ GlobalParams.h \ + JBIG2Stream.cc \ + JBIG2Stream.h \ Lexer.cc \ Lexer.h \ Link.cc \ @@ -76,10 +77,14 @@ common_sources = \ NameToUnicodeTable.h \ Object.cc \ Object.h \ + Outline.cc \ + Outline.h \ OutputDev.cc \ OutputDev.h \ PDFDoc.cc \ PDFDoc.h \ + PDFDocEncoding.cc \ + PDFDocEncoding.h \ PSTokenizer.cc \ PSTokenizer.h \ Page.cc \ @@ -152,8 +157,18 @@ gnome_pdf_viewer_LDADD = \ xpdf_SOURCES = \ $(common_sources) \ + XPDFApp.cc \ + XPDFApp.h \ + XPDFCore.cc \ + XPDFCore.h \ + XPDFTree.cc \ + XPDFTree.h \ + XPDFViewer.cc \ + XPDFViewer.h \ XOutputDev.cc \ - LTKOutputDev.cc \ + XOutputDev.h \ + XPixmapOutputDev.cc \ + XPixmapOutputDev.h \ PSOutputDev.cc \ PSOutputDev.h \ xpdf.cc @@ -161,7 +176,6 @@ xpdf_SOURCES = \ xpdf_CFLAGS = $(X_CFLAGS) xpdf_LDADD = \ $(top_builddir)/goo/libgoo.a \ - $(top_builddir)/ltk/libltk.a \ -lXpm \ $(EXTRA_GNOME_LIBS) \ $(libpaper_LIBS) @@ -201,11 +215,6 @@ xpdf_LDADD = \ #pdftopbm_LDADD = ../goo/libgoo.a $(EXTRA_GNOME_LIBS) -xpdf-ltk.h: xpdf.ltk - rm -f $@ - $(top_srcdir)/ltk/ltkbuild $@.new - mv $@.new $@ - #bitmaps = # about.xbm # dblLeftArrow.xbm diff --git a/pdf/xpdf/Object.cc b/pdf/xpdf/Object.cc index 6d92c6a..a1c71af 100644 --- a/pdf/xpdf/Object.cc +++ b/pdf/xpdf/Object.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Array.h" diff --git a/pdf/xpdf/Object.h b/pdf/xpdf/Object.h index 65d0be0..d8a5fb5 100644 --- a/pdf/xpdf/Object.h +++ b/pdf/xpdf/Object.h @@ -9,7 +9,9 @@ #ifndef OBJECT_H #define OBJECT_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -152,6 +154,7 @@ public: Ref getRef() { return ref; } int getRefNum() { return ref.num; } int getRefGen() { return ref.gen; } + char *getCmd() { return cmd; } // Array accessors. int arrayGetLength(); diff --git a/pdf/xpdf/OutputDev.cc b/pdf/xpdf/OutputDev.cc index 6d46542..15e6a86 100644 --- a/pdf/xpdf/OutputDev.cc +++ b/pdf/xpdf/OutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Stream.h" diff --git a/pdf/xpdf/OutputDev.h b/pdf/xpdf/OutputDev.h index ec99ffa..995c7e7 100644 --- a/pdf/xpdf/OutputDev.h +++ b/pdf/xpdf/OutputDev.h @@ -9,7 +9,9 @@ #ifndef OUTPUTDEV_H #define OUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/PBMOutputDev.cc b/pdf/xpdf/PBMOutputDev.cc index 5778244..3443299 100644 --- a/pdf/xpdf/PBMOutputDev.cc +++ b/pdf/xpdf/PBMOutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -82,10 +83,12 @@ void PBMOutputDev::killPBMOutputDev(PBMOutputDev *out) { PBMOutputDev::PBMOutputDev(Display *displayA, int screenA, Pixmap pixmapA, Window dummyWinA, int invertA, char *fileRootA): - XOutputDev(displayA, pixmapA, 1, - DefaultColormap(displayA, screenA), gFalse, + XOutputDev(displayA, screenA, + DefaultVisual(displayA, screenA), + DefaultColormap(displayA, screenA), + gFalse, WhitePixel(displayA, DefaultScreen(displayA)), - gFalse, 1) + gFalse, 1, 1) { display = displayA; screen = screenA; diff --git a/pdf/xpdf/PBMOutputDev.h b/pdf/xpdf/PBMOutputDev.h index 5b28fc5..6926ce0 100644 --- a/pdf/xpdf/PBMOutputDev.h +++ b/pdf/xpdf/PBMOutputDev.h @@ -9,7 +9,9 @@ #ifndef PBMOUTPUTDEV_H #define PBMOUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/PDFDoc.cc b/pdf/xpdf/PDFDoc.cc index f3b7f79..ff6cefa 100644 --- a/pdf/xpdf/PDFDoc.cc +++ b/pdf/xpdf/PDFDoc.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -18,6 +19,7 @@ #include #include "GString.h" #include "config.h" +#include "GlobalParams.h" #include "Page.h" #include "Catalog.h" #include "Stream.h" @@ -28,6 +30,9 @@ #include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" +#ifndef DISABLE_OUTLINE +#include "Outline.h" +#endif #include "PDFDoc.h" //------------------------------------------------------------------------ @@ -40,9 +45,9 @@ //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword, GBool printCommandsA) { + GString *userPassword) { Object obj; - GString *fileName2; + GString *fileName1, *fileName2; ok = gFalse; errCode = errNone; @@ -52,19 +57,24 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, xref = NULL; catalog = NULL; links = NULL; - printCommands = printCommandsA; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif - // try to open file fileName = fileNameA; + fileName1 = fileName; + + + // try to open file fileName2 = NULL; #ifdef VMS - if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) { - error(-1, "Couldn't open file '%s'", fileName->getCString()); + if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { + error(-1, "Couldn't open file '%s'", fileName1->getCString()); errCode = errOpenFile; return; } #else - if (!(file = fopen(fileName->getCString(), "rb"))) { + if (!(file = fopen(fileName1->getCString(), "rb"))) { fileName2 = fileName->copy(); fileName2->lowerCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { @@ -88,7 +98,7 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, } PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword, GBool printCommandsA) { + GString *userPassword) { ok = gFalse; errCode = errNone; fileName = NULL; @@ -97,7 +107,9 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, xref = NULL; catalog = NULL; links = NULL; - printCommands = printCommandsA; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif ok = setup(ownerPassword, userPassword); } @@ -114,18 +126,28 @@ GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { } // read catalog - catalog = new Catalog(xref, printCommands); + catalog = new Catalog(xref); if (!catalog->isOk()) { error(-1, "Couldn't read page catalog"); errCode = errBadCatalog; return gFalse; } +#ifndef DISABLE_OUTLINE + // read outline + outline = new Outline(catalog->getOutline(), xref); +#endif + // done return gTrue; } PDFDoc::~PDFDoc() { +#ifndef DISABLE_OUTLINE + if (outline) { + delete outline; + } +#endif if (catalog) { delete catalog; } @@ -182,10 +204,12 @@ void PDFDoc::checkHeader() { } void PDFDoc::displayPage(OutputDev *out, int page, double zoom, - int rotate, GBool doLinks) { + int rotate, GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { Page *p; - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } p = catalog->getPage(page); @@ -195,21 +219,38 @@ void PDFDoc::displayPage(OutputDev *out, int page, double zoom, links = NULL; } getLinks(p); - p->display(out, zoom, rotate, links, catalog); + p->display(out, zoom, rotate, links, catalog, + abortCheckCbk, abortCheckCbkData); } else { - p->display(out, zoom, rotate, NULL, catalog); + p->display(out, zoom, rotate, NULL, catalog, + abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - int zoom, int rotate, GBool doLinks) { + int zoom, int rotate, GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, zoom, rotate, doLinks); + displayPage(out, page, zoom, rotate, doLinks, + abortCheckCbk, abortCheckCbkData); } } +void PDFDoc::displayPageSlice(OutputDev *out, int page, double zoom, + int rotate, int sliceX, int sliceY, + int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + Page *p; + + p = catalog->getPage(page); + p->displaySlice(out, zoom, rotate, sliceX, sliceY, sliceW, sliceH, + NULL, catalog, abortCheckCbk, abortCheckCbkData); +} + GBool PDFDoc::isLinearized() { Parser *parser; Object obj1, obj2, obj3, obj4, obj5; diff --git a/pdf/xpdf/PDFDoc.h b/pdf/xpdf/PDFDoc.h index c12531e..ff6e359 100644 --- a/pdf/xpdf/PDFDoc.h +++ b/pdf/xpdf/PDFDoc.h @@ -9,7 +9,9 @@ #ifndef PDFDOC_H #define PDFDOC_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -25,6 +27,7 @@ class OutputDev; class Links; class LinkAction; class LinkDest; +class Outline; //------------------------------------------------------------------------ // PDFDoc @@ -34,9 +37,9 @@ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL, GBool printCommandsA = gFalse); + GString *userPassword = NULL); PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL, GBool printCommandsA = gFalse); + GString *userPassword = NULL); ~PDFDoc(); // Was PDF document successfully opened? @@ -77,11 +80,22 @@ public: // Display a page. void displayPage(OutputDev *out, int page, double zoom, - int rotate, GBool doLinks); + int rotate, GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, - int zoom, int rotate, GBool doLinks); + int zoom, int rotate, GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displayPageSlice(OutputDev *out, int page, double zoom, + int rotate, int sliceX, int sliceY, + int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); // Find a page, given its object ID. Returns page number, or 0 if // not found. @@ -99,6 +113,11 @@ public: LinkDest *findDest(GString *name) { return catalog->findDest(name); } +#ifndef DISABLE_OUTLINE + // Return the outline object. + Outline *getOutline() { return outline; } +#endif + // Is the file encrypted? GBool isEncrypted() { return xref->isEncrypted(); } @@ -117,6 +136,7 @@ public: // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } + Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } // Return the PDF version specified by the file. double getPDFVersion() { return pdfVersion; } @@ -124,6 +144,7 @@ public: // Save this file with another name. GBool saveAs(GString *name); + private: GBool setup(GString *ownerPassword, GString *userPassword); @@ -137,7 +158,10 @@ private: XRef *xref; Catalog *catalog; Links *links; - GBool printCommands; +#ifndef DISABLE_OUTLINE + Outline *outline; +#endif + GBool ok; int errCode; diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc index 1835911..9844ab3 100644 --- a/pdf/xpdf/PSOutputDev.cc +++ b/pdf/xpdf/PSOutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -54,7 +55,7 @@ static char *prolog[] = { " /PageSize exch def", " /ImagingBBox null def", " /Policies 1 dict dup begin /PageSize 3 def end def", - " /Duplex exch def", + " { /Duplex true def } if", " currentdict end setpagedevice", " } {", " pop pop", @@ -268,7 +269,8 @@ static char *prolog[] = { " } if", " pdfTextRender 3 and dup 1 eq exch 2 eq or {", " 8 6 roll moveto", - " sCol false awcp currentpoint stroke moveto", + " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", + " false awcp currentpoint stroke moveto", " } {", " 8 {pop} repeat", " } ifelse", @@ -488,50 +490,29 @@ extern "C" { typedef void (*SignalFunc)(int); } +static void outputToFile(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA) { - Page *page; - PDFRectangle *box; - Dict *resDict; - Annots *annots; - char **p; - int pg; - Object obj1, obj2; - int i; + FILE *f; + PSFileType fileTypeA; - // initialize - xref = xrefA; - level = globalParams->getPSLevel(); - mode = modeA; - paperWidth = globalParams->getPSPaperWidth(); - paperHeight = globalParams->getPSPaperHeight(); fontIDs = NULL; fontFileIDs = NULL; fontFileNames = NULL; font16Enc = NULL; embFontList = NULL; - f = NULL; - if (mode == psModeForm) { - lastPage = firstPage; - } - processColors = 0; customColors = NULL; - inType3Char = gFalse; t3String = NULL; -#if OPI_SUPPORT - // initialize OPI nesting levels - opi13Nest = 0; - opi20Nest = 0; -#endif - // open file or pipe - ok = gTrue; if (!strcmp(fileName, "-")) { - fileType = psStdout; + fileTypeA = psStdout; f = stdout; } else if (fileName[0] == '|') { - fileType = psPipe; + fileTypeA = psPipe; #ifdef HAVE_POPEN #ifndef WIN32 signal(SIGPIPE, (SignalFunc)SIG_IGN); @@ -547,7 +528,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, return; #endif } else { - fileType = psFile; + fileTypeA = psFile; if (!(f = fopen(fileName, "w"))) { error(-1, "Couldn't open PostScript file '%s'", fileName); ok = gFalse; @@ -555,6 +536,59 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, } } + init(outputToFile, f, fileTypeA, + xrefA, catalog, firstPage, lastPage, modeA); +} + +PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA) { + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font16Enc = NULL; + embFontList = NULL; + customColors = NULL; + t3String = NULL; + + init(outputFuncA, outputStreamA, psGeneric, + xrefA, catalog, firstPage, lastPage, modeA); +} + +void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA) { + Page *page; + PDFRectangle *box; + Dict *resDict; + Annots *annots; + char **p; + int pg; + Object obj1, obj2; + int i; + + // initialize + ok = gTrue; + outputFunc = outputFuncA; + outputStream = outputStreamA; + fileType = fileTypeA; + xref = xrefA; + level = globalParams->getPSLevel(); + mode = modeA; + paperWidth = globalParams->getPSPaperWidth(); + paperHeight = globalParams->getPSPaperHeight(); + if (mode == psModeForm) { + lastPage = firstPage; + } + processColors = 0; + inType3Char = gFalse; + +#if OPI_SUPPORT + // initialize OPI nesting levels + opi13Nest = 0; + opi20Nest = 0; +#endif + // initialize fontIDs, fontFileIDs, and fontFileNames lists fontIDSize = 64; fontIDLen = 0; @@ -574,66 +608,66 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, // write header switch (mode) { case psModePS: - writePS("%%!PS-Adobe-3.0\n"); - writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePS("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + writePS("%!PS-Adobe-3.0\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%%%DocumentProcessColors: (atend)\n"); - writePS("%%%%DocumentCustomColors: (atend)\n"); - } - writePS("%%%%DocumentSuppliedResources: (atend)\n"); - writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n", - paperWidth, paperHeight); - writePS("%%%%Pages: %d\n", lastPage - firstPage + 1); - writePS("%%%%EndComments\n"); - writePS("%%%%BeginDefaults\n"); - writePS("%%%%PageMedia: plain\n"); - writePS("%%%%EndDefaults\n"); + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n", + paperWidth, paperHeight); + writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1); + writePS("%%EndComments\n"); + writePS("%%BeginDefaults\n"); + writePS("%%PageMedia: plain\n"); + writePS("%%EndDefaults\n"); break; case psModeEPS: - writePS("%%!PS-Adobe-3.0 EPSF-3.0\n"); - writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePS("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%%%DocumentProcessColors: (atend)\n"); - writePS("%%%%DocumentCustomColors: (atend)\n"); + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); } page = catalog->getPage(firstPage); box = page->getBox(); - writePS("%%%%BoundingBox: %d %d %d %d\n", - (int)floor(box->x1), (int)floor(box->y1), - (int)ceil(box->x2), (int)ceil(box->y2)); + writePSFmt("%%%%BoundingBox: %d %d %d %d\n", + (int)floor(box->x1), (int)floor(box->y1), + (int)ceil(box->x2), (int)ceil(box->y2)); if (floor(box->x1) != ceil(box->x1) || floor(box->y1) != ceil(box->y1) || floor(box->x2) != ceil(box->x2) || floor(box->y2) != ceil(box->y2)) { - writePS("%%%%HiResBoundingBox: %g %g %g %g\n", - box->x1, box->y1, box->x2, box->y2); + writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", + box->x1, box->y1, box->x2, box->y2); } - writePS("%%%%DocumentSuppliedResources: (atend)\n"); - writePS("%%%%EndComments\n"); + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePS("%%EndComments\n"); break; case psModeForm: - writePS("%%!PS-Adobe-3.0 Resource-Form\n"); - writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); - writePS("%%%%LanguageLevel: %d\n", - (level == psLevel1 || level == psLevel1Sep) ? 1 : - (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + writePS("%!PS-Adobe-3.0 Resource-Form\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%%%DocumentProcessColors: (atend)\n"); - writePS("%%%%DocumentCustomColors: (atend)\n"); + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); } - writePS("%%%%DocumentSuppliedResources: (atend)\n"); - writePS("%%%%EndComments\n"); + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePS("%%EndComments\n"); page = catalog->getPage(firstPage); box = page->getBox(); writePS("32 dict dup begin\n"); - writePS("/BBox [%d %d %d %d] def\n", - (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2); + writePSFmt("/BBox [%d %d %d %d] def\n", + (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2); writePS("/FormType 1 def\n"); writePS("/Matrix [1 0 0 1 0 0] def\n"); break; @@ -641,20 +675,20 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, // write prolog if (mode != psModeForm) { - writePS("%%%%BeginProlog\n"); + writePS("%%BeginProlog\n"); } - writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); + writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); for (p = prolog; *p; ++p) { - writePS("%s\n", *p); + writePSFmt("%s\n", *p); } - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); if (level >= psLevel3) { for (p = cmapProlog; *p; ++p) { - writePS("%s\n", *p); + writePSFmt("%s\n", *p); } } if (mode != psModeForm) { - writePS("%%%%EndProlog\n"); + writePS("%%EndProlog\n"); } // set up fonts and images @@ -662,7 +696,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, // swap the form and xpdf dicts writePS("xpdf end begin dup begin\n"); } else { - writePS("%%%%BeginSetup\n"); + writePS("%%BeginSetup\n"); writePS("xpdf begin\n"); } for (pg = firstPage; pg <= lastPage; ++pg) { @@ -686,16 +720,16 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, } if (mode != psModeForm) { if (mode != psModeEPS) { - writePS("%d %d %s pdfSetup\n", - paperWidth, paperHeight, - globalParams->getPSDuplex() ? "true" : "false"); + writePSFmt("%d %d %s pdfSetup\n", + paperWidth, paperHeight, + globalParams->getPSDuplex() ? "true" : "false"); } #if OPI_SUPPORT if (globalParams->getPSOPI()) { writePS("/opiMatrix matrix currentmatrix def\n"); } #endif - writePS("%%%%EndSetup\n"); + writePS("%%EndSetup\n"); } // initialize sequential page number @@ -706,17 +740,17 @@ PSOutputDev::~PSOutputDev() { PSOutCustomColor *cc; int i; - if (f) { + if (ok) { if (mode == psModeForm) { writePS("/Foo exch /Form defineresource pop\n"); } else { - writePS("%%%%Trailer\n"); + writePS("%%Trailer\n"); writePS("end\n"); - writePS("%%%%DocumentSuppliedResources:\n"); - writePS("%s", embFontList->getCString()); + writePS("%%DocumentSuppliedResources:\n"); + writePS(embFontList->getCString()); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { - writePS("%%%%DocumentProcessColors:"); + writePS("%%DocumentProcessColors:"); if (processColors & psProcessCyan) { writePS(" Cyan"); } @@ -730,28 +764,28 @@ PSOutputDev::~PSOutputDev() { writePS(" Black"); } writePS("\n"); - writePS("%%%%DocumentCustomColors:"); + writePS("%%DocumentCustomColors:"); for (cc = customColors; cc; cc = cc->next) { - writePS(" (%s)", cc->name->getCString()); + writePSFmt(" (%s)", cc->name->getCString()); } writePS("\n"); - writePS("%%%%CMYKCustomColor:\n"); + writePS("%%CMYKCustomColor:\n"); for (cc = customColors; cc; cc = cc->next) { - writePS("%%%%+ %g %g %g %g (%s)\n", + writePSFmt("%%%%+ %g %g %g %g (%s)\n", cc->c, cc->m, cc->y, cc->k, cc->name->getCString()); } } - writePS("%%%%EOF\n"); + writePS("%%EOF\n"); } if (fileType == psFile) { #ifdef MACOS - ICS_MapRefNumAndAssign((short)f->handle); + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); #endif - fclose(f); + fclose((FILE *)outputStream); } #ifdef HAVE_POPEN else if (fileType == psPipe) { - pclose(f); + pclose((FILE *)outputStream); #ifndef WIN32 signal(SIGPIPE, (SignalFunc)SIG_DFL); #endif @@ -834,7 +868,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { PSFontParam *fontParam; GString *psNameStr; char *psName; - char type3Name[64]; + char type3Name[64], buf[16]; UnicodeMap *uMap; char *charName; double xs, ys; @@ -1020,29 +1054,36 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { // generate PostScript code to set up the font if (font->isCIDFont()) { if (level == psLevel3 || level == psLevel3Sep) { - writePS("/F%d_%d /%s %d pdfMakeFont16L3\n", - font->getID()->num, font->getID()->gen, psName, - font->getWMode()); + writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); } else { - writePS("/F%d_%d /%s %d pdfMakeFont16\n", - font->getID()->num, font->getID()->gen, psName, - font->getWMode()); + writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); } } else { - writePS("/F%d_%d /%s %g %g\n", - font->getID()->num, font->getID()->gen, psName, xs, ys); + writePSFmt("/F%d_%d /%s %g %g\n", + font->getID()->num, font->getID()->gen, psName, xs, ys); for (i = 0; i < 256; i += 8) { - writePS((i == 0) ? "[ " : " "); + writePSFmt((i == 0) ? "[ " : " "); for (j = 0; j < 8; ++j) { - charName = ((Gfx8BitFont *)font)->getCharName(i+j); - // this is a kludge for broken PDF files that encode char 32 - // as .notdef - if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { - charName = "space"; + if (font->getType() == fontTrueType && + !((Gfx8BitFont *)font)->getHasEncoding()) { + sprintf(buf, "c%02x", i+j); + charName = buf; + } else { + charName = ((Gfx8BitFont *)font)->getCharName(i+j); + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { + charName = "space"; + } } - writePS("/%s", charName ? charName : ".notdef"); + writePS("/"); + writePSName(charName ? charName : (char *)".notdef"); } - writePS((i == 256-8) ? "]\n" : "\n"); + writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); } writePS("pdfMakeFont\n"); } @@ -1102,7 +1143,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) { obj2.free(); // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1168,7 +1209,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) { writePS("cleartomark\n"); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); err1: strObj.streamClose(); @@ -1198,7 +1239,7 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) { fontFileNames[fontFileNameLen++] = fileName->copy(); // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1214,7 +1255,7 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) { fclose(fontFile); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, @@ -1239,7 +1280,7 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, fontFileIDs[fontFileIDLen++] = *id; // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1247,12 +1288,12 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, // convert it to a Type 1 font fontBuf = font->readEmbFontFile(xref, &fontLen); t1cFile = new Type1CFontFile(fontBuf, fontLen); - t1cFile->convertToType1(f); + t1cFile->convertToType1(outputFunc, outputStream); delete t1cFile; gfree(fontBuf); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, @@ -1278,7 +1319,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, fontFileIDs[fontFileIDLen++] = *id; // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1288,13 +1329,14 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, ttFile = new TrueTypeFontFile(fontBuf, fontLen); ctu = ((Gfx8BitFont *)font)->getToUnicode(); ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), - ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f); + ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + outputFunc, outputStream); ctu->decRefCnt(); delete ttFile; gfree(fontBuf); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) { @@ -1322,7 +1364,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) { fontFileNames[fontFileNameLen++] = fileName->copy(); // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1332,13 +1374,14 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) { ttFile = new TrueTypeFontFile(fontBuf, fontLen); ctu = ((Gfx8BitFont *)font)->getToUnicode(); ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), - ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f); + ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + outputFunc, outputStream); ctu->decRefCnt(); delete ttFile; gfree(fontBuf); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, @@ -1363,7 +1406,7 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, fontFileIDs[fontFileIDLen++] = *id; // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1373,16 +1416,16 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, t1cFile = new Type1CFontFile(fontBuf, fontLen); if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font - t1cFile->convertToCIDType0(psName, f); + t1cFile->convertToCIDType0(psName, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font - t1cFile->convertToType0(psName, f); + t1cFile->convertToType0(psName, outputFunc, outputStream); } delete t1cFile; gfree(fontBuf); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, @@ -1407,7 +1450,7 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, fontFileIDs[fontFileIDLen++] = *id; // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1418,17 +1461,19 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, if (globalParams->getPSLevel() >= psLevel3) { ttFile->convertToCIDType2(psName, ((GfxCIDFont *)font)->getCIDToGID(), - ((GfxCIDFont *)font)->getCIDToGIDLen(), f); + ((GfxCIDFont *)font)->getCIDToGIDLen(), + outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(), - ((GfxCIDFont *)font)->getCIDToGIDLen(), f); + ((GfxCIDFont *)font)->getCIDToGIDLen(), + outputFunc, outputStream); } delete ttFile; gfree(fontBuf); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupType3Font(GfxFont *font, char *psName, @@ -1439,6 +1484,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, Gfx *gfx; PDFRectangle box; double *m; + char buf[256]; int i; // set up resources used by font @@ -1449,7 +1495,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, } // beginning comment - writePS("%%%%BeginResource: font %s\n", psName); + writePSFmt("%%%%BeginResource: font %s\n", psName); embFontList->append("%%+ font "); embFontList->append(psName); embFontList->append("\n"); @@ -1458,11 +1504,11 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, writePS("7 dict begin\n"); writePS("/FontType 3 def\n"); m = font->getFontMatrix(); - writePS("/FontMatrix [%g %g %g %g %g %g] def\n", - m[0], m[1], m[2], m[3], m[4], m[5]); + writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n", + m[0], m[1], m[2], m[3], m[4], m[5]); m = font->getFontBBox(); - writePS("/FontBBox [%g %g %g %g] def\n", - m[0], m[1], m[2], m[3]); + writePSFmt("/FontBBox [%g %g %g %g] def\n", + m[0], m[1], m[2], m[3]); writePS("/Encoding 256 array def\n"); writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); writePS("/BuildGlyph {\n"); @@ -1475,7 +1521,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, writePS(" 1 index /BuildGlyph get exec\n"); writePS("} bind def\n"); if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { - writePS("/CharProcs %d dict def\n", charProcs->getLength()); + writePSFmt("/CharProcs %d dict def\n", charProcs->getLength()); writePS("CharProcs begin\n"); box.x1 = m[0]; box.y1 = m[1]; @@ -1483,22 +1529,27 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, box.y2 = m[3]; gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL); inType3Char = gTrue; + t3Cacheable = gFalse; for (i = 0; i < charProcs->getLength(); ++i) { - writePS("/%s {\n", charProcs->getKey(i)); + writePS("/"); + writePSName(charProcs->getKey(i)); + writePS(" {\n"); gfx->display(charProcs->getVal(i, &charProc)); charProc.free(); if (t3String) { if (t3Cacheable) { - fprintf(f, "%g %g %g %g %g %g setcachedevice\n", + sprintf(buf, "%g %g %g %g %g %g setcachedevice\n", t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); } else { - fprintf(f, "%g %g setcharwidth\n", t3WX, t3WY); + sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY); } - fputs(t3String->getCString(), f); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, t3String->getCString(), + t3String->getLength()); delete t3String; t3String = NULL; } - fputs("Q\n", f); + (*outputFunc)(outputStream, "Q\n", 2); writePS("} def\n"); } inType3Char = gFalse; @@ -1506,10 +1557,10 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName, writePS("end\n"); } writePS("currentdict end\n"); - writePS("/%s exch definefont pop\n", psName); + writePSFmt("/%s exch definefont pop\n", psName); // ending comment - writePS("%%%%EndResource\n"); + writePS("%%EndResource\n"); } void PSOutputDev::setupImages(Dict *resDict) { @@ -1584,7 +1635,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { } } while (c != '~' && c != EOF); ++size; - writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); + writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); // write the data into the array str->reset(); @@ -1621,7 +1672,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { if (col > 225) { writePS("~> put\n"); ++line; - writePS("dup %d <~", line); + writePSFmt("dup %d <~", line); col = 0; } } while (c != '~' && c != EOF); @@ -1634,11 +1685,12 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { void PSOutputDev::startPage(int pageNum, GfxState *state) { int x1, y1, x2, y2, width, height, t; + switch (mode) { case psModePS: - writePS("%%%%Page: %d %d\n", pageNum, seqPage); - writePS("%%%%BeginPageSetup\n"); + writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage); + writePS("%%BeginPageSetup\n"); // rotate, translate, and scale page x1 = (int)(state->getX1() + 0.5); @@ -1649,8 +1701,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { height = y2 - y1; if (width > height && width > paperWidth) { landscape = gTrue; - writePS("%%%%PageOrientation: %s\n", - state->getCTM()[0] ? "Landscape" : "Portrait"); + writePSFmt("%%%%PageOrientation: %s\n", + state->getCTM()[0] ? "Landscape" : "Portrait"); writePS("pdfStartPage\n"); writePS("90 rotate\n"); tx = -x1; @@ -1660,8 +1712,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { height = t; } else { landscape = gFalse; - writePS("%%%%PageOrientation: %s\n", - state->getCTM()[0] ? "Portrait" : "Landscape"); + writePSFmt("%%%%PageOrientation: %s\n", + state->getCTM()[0] ? "Portrait" : "Landscape"); writePS("pdfStartPage\n"); tx = -x1; ty = -y1; @@ -1673,7 +1725,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { ty += (paperHeight - height) / 2; } if (tx != 0 || ty != 0) { - writePS("%g %g translate\n", tx, ty); + writePSFmt("%g %g translate\n", tx, ty); } if (width > paperWidth || height > paperHeight) { xScale = (double)paperWidth / (double)width; @@ -1683,12 +1735,12 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { } else { yScale = xScale; } - writePS("%0.4f %0.4f scale\n", xScale, xScale); + writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); } else { xScale = yScale = 1; } - writePS("%%%%EndPageSetup\n"); + writePS("%%EndPageSetup\n"); ++seqPage; break; @@ -1711,6 +1763,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { } void PSOutputDev::endPage() { + if (mode == psModeForm) { writePS("pdfEndPage\n"); writePS("end end\n"); @@ -1718,7 +1771,7 @@ void PSOutputDev::endPage() { writePS("end end\n"); } else { writePS("showpage\n"); - writePS("%%%%PageTrailer\n"); + writePS("%%PageTrailer\n"); writePS("pdfEndPage\n"); } } @@ -1733,7 +1786,7 @@ void PSOutputDev::restoreState(GfxState *state) { void PSOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) { - writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32); + writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32); } void PSOutputDev::updateLineDash(GfxState *state) { @@ -1744,28 +1797,28 @@ void PSOutputDev::updateLineDash(GfxState *state) { state->getLineDash(&dash, &length, &start); writePS("["); for (i = 0; i < length; ++i) - writePS("%g%s", dash[i], (i == length-1) ? "" : " "); - writePS("] %g d\n", start); + writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " "); + writePSFmt("] %g d\n", start); } void PSOutputDev::updateFlatness(GfxState *state) { - writePS("%d i\n", state->getFlatness()); + writePSFmt("%d i\n", state->getFlatness()); } void PSOutputDev::updateLineJoin(GfxState *state) { - writePS("%d j\n", state->getLineJoin()); + writePSFmt("%d j\n", state->getLineJoin()); } void PSOutputDev::updateLineCap(GfxState *state) { - writePS("%d J\n", state->getLineCap()); + writePSFmt("%d J\n", state->getLineCap()); } void PSOutputDev::updateMiterLimit(GfxState *state) { - writePS("%g M\n", state->getMiterLimit()); + writePSFmt("%g M\n", state->getMiterLimit()); } void PSOutputDev::updateLineWidth(GfxState *state) { - writePS("%g w\n", state->getLineWidth()); + writePSFmt("%g w\n", state->getLineWidth()); } void PSOutputDev::updateFillColor(GfxState *state) { @@ -1778,23 +1831,24 @@ void PSOutputDev::updateFillColor(GfxState *state) { switch (level) { case psLevel1: state->getFillGray(&gray); - writePS("%g g\n", gray); + writePSFmt("%g g\n", gray); break; case psLevel1Sep: state->getFillCMYK(&cmyk); - writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); break; case psLevel2: case psLevel3: if (state->getFillColorSpace()->getMode() == csDeviceCMYK) { state->getFillCMYK(&cmyk); - writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); } else { state->getFillRGB(&rgb); if (rgb.r == rgb.g && rgb.g == rgb.b) { - writePS("%g g\n", rgb.r); + writePSFmt("%g g\n", rgb.r); } else { - writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b); + writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b); } } break; @@ -1804,14 +1858,14 @@ void PSOutputDev::updateFillColor(GfxState *state) { sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); color.c[0] = 1; sepCS->getCMYK(&color, &cmyk); - writePS("%g %g %g %g %g (%s) ck\n", - state->getFillColor()->c[0], - cmyk.c, cmyk.m, cmyk.y, cmyk.k, - sepCS->getName()->getCString()); + writePSFmt("%g %g %g %g %g (%s) ck\n", + state->getFillColor()->c[0], + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); addCustomColor(sepCS); } else { state->getFillCMYK(&cmyk); - writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); } break; @@ -1829,23 +1883,24 @@ void PSOutputDev::updateStrokeColor(GfxState *state) { switch (level) { case psLevel1: state->getStrokeGray(&gray); - writePS("%g G\n", gray); + writePSFmt("%g G\n", gray); break; case psLevel1Sep: state->getStrokeCMYK(&cmyk); - writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); break; case psLevel2: case psLevel3: if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) { state->getStrokeCMYK(&cmyk); - writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); } else { state->getStrokeRGB(&rgb); if (rgb.r == rgb.g && rgb.g == rgb.b) { - writePS("%g G\n", rgb.r); + writePSFmt("%g G\n", rgb.r); } else { - writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b); + writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b); } } break; @@ -1855,14 +1910,14 @@ void PSOutputDev::updateStrokeColor(GfxState *state) { sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); color.c[0] = 1; sepCS->getCMYK(&color, &cmyk); - writePS("%g %g %g %g %g (%s) CK\n", - state->getStrokeColor()->c[0], - cmyk.c, cmyk.m, cmyk.y, cmyk.k, - sepCS->getName()->getCString()); + writePSFmt("%g %g %g %g %g (%s) CK\n", + state->getStrokeColor()->c[0], + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); addCustomColor(sepCS); } else { state->getStrokeCMYK(&cmyk); - writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); } break; @@ -1905,9 +1960,9 @@ void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { void PSOutputDev::updateFont(GfxState *state) { if (state->getFont()) { - writePS("/F%d_%d %g Tf\n", - state->getFont()->getID()->num, state->getFont()->getID()->gen, - state->getFontSize()); + writePSFmt("/F%d_%d %g Tf\n", + state->getFont()->getID()->num, state->getFont()->getID()->gen, + state->getFontSize()); } } @@ -1915,19 +1970,19 @@ void PSOutputDev::updateTextMat(GfxState *state) { double *mat; mat = state->getTextMat(); - writePS("[%g %g %g %g %g %g] Tm\n", - mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("[%g %g %g %g %g %g] Tm\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); } void PSOutputDev::updateCharSpace(GfxState *state) { - writePS("%g Tc\n", state->getCharSpace()); + writePSFmt("%g Tc\n", state->getCharSpace()); } void PSOutputDev::updateRender(GfxState *state) { int rm; rm = state->getRender(); - writePS("%d Tr\n", rm); + writePSFmt("%d Tr\n", rm); rm &= 3; if (rm != 0 && rm != 3) { t3Cacheable = gFalse; @@ -1935,26 +1990,26 @@ void PSOutputDev::updateRender(GfxState *state) { } void PSOutputDev::updateRise(GfxState *state) { - writePS("%g Ts\n", state->getRise()); + writePSFmt("%g Ts\n", state->getRise()); } void PSOutputDev::updateWordSpace(GfxState *state) { - writePS("%g Tw\n", state->getWordSpace()); + writePSFmt("%g Tw\n", state->getWordSpace()); } void PSOutputDev::updateHorizScaling(GfxState *state) { - writePS("%g Tz\n", state->getHorizScaling()); + writePSFmt("%g Tz\n", state->getHorizScaling()); } void PSOutputDev::updateTextPos(GfxState *state) { - writePS("%g %g Td\n", state->getLineX(), state->getLineY()); + writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY()); } void PSOutputDev::updateTextShift(GfxState *state, double shift) { if (state->getFont()->getWMode()) { - writePS("%g TJmV\n", shift); + writePSFmt("%g TJmV\n", shift); } else { - writePS("%g TJm\n", shift); + writePSFmt("%g TJm\n", shift); } } @@ -2010,14 +2065,14 @@ void PSOutputDev::doPath(GfxPath *path) { x3 = subpath->getX(3); y3 = subpath->getY(3); if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) { - writePS("%g %g %g %g re\n", - x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1, - fabs(x2 - x0), fabs(y1 - y0)); + writePSFmt("%g %g %g %g re\n", + x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1, + fabs(x2 - x0), fabs(y1 - y0)); return; } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) { - writePS("%g %g %g %g re\n", - x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2, - fabs(x1 - x0), fabs(y2 - y0)); + writePSFmt("%g %g %g %g re\n", + x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2, + fabs(x1 - x0), fabs(y2 - y0)); return; } } @@ -2026,16 +2081,16 @@ void PSOutputDev::doPath(GfxPath *path) { for (i = 0; i < n; ++i) { subpath = path->getSubpath(i); m = subpath->getNumPoints(); - writePS("%g %g m\n", subpath->getX(0), subpath->getY(0)); + writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0)); j = 1; while (j < m) { if (subpath->getCurve(j)) { - writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j), - subpath->getX(j+1), subpath->getY(j+1), - subpath->getX(j+2), subpath->getY(j+2)); + writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j), + subpath->getX(j+1), subpath->getY(j+1), + subpath->getX(j+2), subpath->getY(j+2)); j += 3; } else { - writePS("%g %g l\n", subpath->getX(j), subpath->getY(j)); + writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j)); ++j; } } @@ -2134,12 +2189,12 @@ void PSOutputDev::drawString(GfxState *state, GString *s) { writePSString(s2); if (font->isCIDFont()) { if (wMode) { - writePS(" %d %g Tj16V\n", nChars, dy); + writePSFmt(" %d %g Tj16V\n", nChars, dy); } else { - writePS(" %d %g Tj16\n", nChars, dx); + writePSFmt(" %d %g Tj16\n", nChars, dx); } } else { - writePS(" %g Tj\n", dx); + writePSFmt(" %g Tj\n", dx); } } if (font->isCIDFont()) { @@ -2195,13 +2250,13 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, // width, height, matrix, bits per component if (colorMap) { - writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", - width, height, - width, -height, height); + writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", + width, height, + width, -height, height); } else { - writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n", - width, height, invert ? "true" : "false", - width, -height, height); + writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n", + width, height, invert ? "true" : "false", + width, -height, height); } // image @@ -2220,7 +2275,7 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); colorMap->getGray(pixBuf, &gray); - writePS("%02x", (int)(gray * 255 + 0.5)); + writePSFmt("%02x", (int)(gray * 255 + 0.5)); if (++i == 32) { writePSChar('\n'); i = 0; @@ -2238,7 +2293,7 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, i = 0; for (y = 0; y < height; ++y) { for (x = 0; x < width; x += 8) { - writePS("%02x", str->getChar() & 0xff); + writePSFmt("%02x", str->getChar() & 0xff); if (++i == 32) { writePSChar('\n'); i = 0; @@ -2262,9 +2317,9 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, int x, y, i, comp; // width, height, matrix, bits per component - writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n", - width, height, - width, -height, height); + writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n", + width, height, + width, -height, height); // allocate a line buffer lineBuf = (Guchar *)gmalloc(4 * width); @@ -2286,12 +2341,13 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5); lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5); lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); } // write one line of each color component for (comp = 0; comp < 4; ++comp) { for (x = 0; x < width; ++x) { - writePS("%02x", lineBuf[4*x + comp]); + writePSFmt("%02x", lineBuf[4*x + comp]); if (++i == 32) { writePSChar('\n'); i = 0; @@ -2318,7 +2374,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, GfxColor color; GfxCMYK cmyk; int c; - int i; + int line, col, i; // color space if (colorMap) { @@ -2326,20 +2382,72 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, writePS(" setcolorspace\n"); } - // set up to use the array created by setupImages() - if ((mode == psModeForm || inType3Char) && !inlineImg) { - writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + // set up the image data + if (mode == psModeForm || inType3Char) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + if (globalParams->getPSASCIIHex()) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + str->reset(); + line = col = 0; + writePS("[<~"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= 4; ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "dup nnnnn <~...data...~> put" + // so max data length = 255 - 20 = 235 + // chunks are 1 or 4 bytes each, so we have to stop at 232 + // but make it 225 just to be safe + if (col > 225) { + writePS("~>\n"); + ++line; + writePSFmt("<~", line); + col = 0; + } + } while (c != '~' && c != EOF); + writePS("~>]\n"); + writePS("0\n"); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + } } // image dictionary writePS("<<\n /ImageType 1\n"); // width, height, matrix, bits per component - writePS(" /Width %d\n", width); - writePS(" /Height %d\n", height); - writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); - writePS(" /BitsPerComponent %d\n", - colorMap ? colorMap->getBits() : 1); + writePSFmt(" /Width %d\n", width); + writePSFmt(" /Height %d\n", height); + writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); + writePSFmt(" /BitsPerComponent %d\n", + colorMap ? colorMap->getBits() : 1); // decode if (colorMap) { @@ -2347,55 +2455,33 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, if (colorMap->getColorSpace()->getMode() == csSeparation) { //~ this is a kludge -- see comment in dumpColorSpaceL2 n = (1 << colorMap->getBits()) - 1; - writePS("%g %g", colorMap->getDecodeLow(0) * n, - colorMap->getDecodeHigh(0) * n); + writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); } else { numComps = colorMap->getNumPixelComps(); for (i = 0; i < numComps; ++i) { if (i > 0) { writePS(" "); } - writePS("%g %g", colorMap->getDecodeLow(i), - colorMap->getDecodeHigh(i)); + writePSFmt("%g %g", colorMap->getDecodeLow(i), + colorMap->getDecodeHigh(i)); } } writePS("]\n"); } else { - writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1); + writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1); } if (mode == psModeForm || inType3Char) { - if (inlineImg) { - - // data source - writePS(" /DataSource <~\n"); - - // write image data stream, using ASCII85 encode filter - str = new FixedLengthEncoder(str, len); - if (globalParams->getPSASCIIHex()) { - str = new ASCIIHexEncoder(str); - } else { - str = new ASCII85Encoder(str); - } - str->reset(); - while ((c = str->getChar()) != EOF) { - writePSChar(c); - } - writePSChar('\n'); - delete str; - - } else { - writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); - } + // data source + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); // end of image dictionary - writePS(">>\n%s\n", colorMap ? "image" : "imagemask"); + writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask"); // get rid of the array and index - if (!inlineImg) { - writePS("pop pop\n"); - } + writePS("pop pop\n"); } else { @@ -2412,14 +2498,14 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, useCompressed = gTrue; } if (useASCII) { - writePS(" /ASCII%sDecode filter\n", - globalParams->getPSASCIIHex() ? "Hex" : "85"); + writePSFmt(" /ASCII%sDecode filter\n", + globalParams->getPSASCIIHex() ? "Hex" : "85"); } if (useRLE) { writePS(" /RunLengthDecode filter\n"); } if (useCompressed) { - writePS("%s", s->getCString()); + writePS(s->getCString()); } if (s) { delete s; @@ -2465,7 +2551,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, // +6/7 for "pdfIm\n" / "pdfImM\n" // +8 for newline + trailer n += colorMap ? 14 : 15; - writePS("%%%%BeginData: %d Hex Bytes\n", n); + writePSFmt("%%%%BeginData: %d Hex Bytes\n", n); } #endif if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && @@ -2473,10 +2559,11 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, color.c[0] = 1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); - writePS("%g %g %g %g (%s) pdfImSep\n", - cmyk.c, cmyk.m, cmyk.y, cmyk.k, sepCS->getName()->getCString()); + writePSFmt("%g %g %g %g (%s) pdfImSep\n", + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); } else { - writePS("%s\n", colorMap ? "pdfIm" : "pdfImM"); + writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM"); } // copy the stream data @@ -2488,10 +2575,10 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, // add newline and trailer to the end writePSChar('\n'); - writePS("%%-EOD-\n"); + writePS("%-EOD-\n"); #if OPI_SUPPORT if (opi13Nest) { - writePS("%%%%EndData\n"); + writePS("%%EndData\n"); } #endif @@ -2508,11 +2595,14 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { GfxLabColorSpace *labCS; GfxIndexedColorSpace *indexedCS; GfxSeparationColorSpace *separationCS; - Guchar *lookup; + GfxColorSpace *baseCS; + Guchar *lookup, *p; double x[gfxColorMaxComps], y[gfxColorMaxComps]; GfxColor color; GfxCMYK cmyk; - int n, numComps; + Function *func; + int n, numComps, numAltComps; + int byte; int i, j, k; switch (colorSpace->getMode()) { @@ -2525,16 +2615,16 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { case csCalGray: calGrayCS = (GfxCalGrayColorSpace *)colorSpace; writePS("[/CIEBasedA <<\n"); - writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); - writePS(" /MatrixA [%g %g %g]\n", - calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), - calGrayCS->getWhiteZ()); - writePS(" /WhitePoint [%g %g %g]\n", - calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), - calGrayCS->getWhiteZ()); - writePS(" /BlackPoint [%g %g %g]\n", - calGrayCS->getBlackX(), calGrayCS->getBlackY(), - calGrayCS->getBlackZ()); + writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); + writePSFmt(" /MatrixA [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calGrayCS->getBlackX(), calGrayCS->getBlackY(), + calGrayCS->getBlackZ()); writePS(">>]"); processColors |= psProcessBlack; break; @@ -2547,21 +2637,21 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { case csCalRGB: calRGBCS = (GfxCalRGBColorSpace *)colorSpace; writePS("[/CIEBasedABC <<\n"); - writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", - calRGBCS->getGammaR(), calRGBCS->getGammaG(), - calRGBCS->getGammaB()); - writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n", - calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], - calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], - calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], - calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], - calRGBCS->getMatrix()[8]); - writePS(" /WhitePoint [%g %g %g]\n", - calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), - calRGBCS->getWhiteZ()); - writePS(" /BlackPoint [%g %g %g]\n", - calRGBCS->getBlackX(), calRGBCS->getBlackY(), - calRGBCS->getBlackZ()); + writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", + calRGBCS->getGammaR(), calRGBCS->getGammaG(), + calRGBCS->getGammaB()); + writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n", + calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], + calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], + calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], + calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], + calRGBCS->getMatrix()[8]); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), + calRGBCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calRGBCS->getBlackX(), calRGBCS->getBlackY(), + calRGBCS->getBlackZ()); writePS(">>]"); processColors |= psProcessCMYK; break; @@ -2574,25 +2664,25 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { case csLab: labCS = (GfxLabColorSpace *)colorSpace; writePS("[/CIEBasedABC <<\n"); - writePS(" /RangeABC [0 100 %g %g %g %g]\n", - labCS->getAMin(), labCS->getAMax(), - labCS->getBMin(), labCS->getBMax()); + writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n", + labCS->getAMin(), labCS->getAMax(), + labCS->getBMin(), labCS->getBMax()); writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n"); writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n"); writePS(" /DecodeLMN\n"); writePS(" [{dup 6 29 div ge {dup dup mul mul}\n"); - writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", - labCS->getWhiteX()); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", + labCS->getWhiteX()); writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); - writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", - labCS->getWhiteY()); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", + labCS->getWhiteY()); writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); - writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", - labCS->getWhiteZ()); - writePS(" /WhitePoint [%g %g %g]\n", - labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); - writePS(" /BlackPoint [%g %g %g]\n", - labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", + labCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); writePS(">>]"); processColors |= psProcessCMYK; break; @@ -2603,23 +2693,52 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { case csIndexed: indexedCS = (GfxIndexedColorSpace *)colorSpace; + baseCS = indexedCS->getBase(); writePS("[/Indexed "); - dumpColorSpaceL2(indexedCS->getBase()); + dumpColorSpaceL2(baseCS); n = indexedCS->getIndexHigh(); - numComps = indexedCS->getBase()->getNComps(); + numComps = baseCS->getNComps(); lookup = indexedCS->getLookup(); - writePS(" %d <\n", n); - for (i = 0; i <= n; i += 8) { - writePS(" "); - for (j = i; j < i+8 && j <= n; ++j) { - for (k = 0; k < numComps; ++k) { - writePS("%02x", lookup[j * numComps + k]); + writePSFmt(" %d <\n", n); + if (baseCS->getMode() == csDeviceN) { + func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); + numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); + p = lookup; + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + x[k] = *p++ / 255.0; + } + func->transform(x, y); + for (k = 0; k < numAltComps; ++k) { + byte = (int)(y[k] * 255 + 0.5); + if (byte < 0) { + byte = 0; + } else if (byte > 255) { + byte = 255; + } + writePSFmt("%02x", byte); + } + color.c[0] = j; + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); } - color.c[0] = j; - indexedCS->getCMYK(&color, &cmyk); - addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + writePS("\n"); + } + } else { + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + writePSFmt("%02x", lookup[j * numComps + k]); + } + color.c[0] = j; + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + writePS("\n"); } - writePS("\n"); } writePS(">]"); break; @@ -2639,7 +2758,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { x[0] = (double)j / 255.0; separationCS->getFunc()->transform(x, y); for (k = 0; k < numComps; ++k) { - writePS("%02x", (int)(255 * y[k] + 0.5)); + writePSFmt("%02x", (int)(255 * y[k] + 0.5)); } } writePS("\n"); @@ -2686,20 +2805,20 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { int w, h; int i; - writePS("%%%%BeginOPI: 2.0\n"); - writePS("%%%%Distilled\n"); + writePS("%%BeginOPI: 2.0\n"); + writePS("%%Distilled\n"); dict->lookup("F", &obj1); if (getFileSpec(&obj1, &obj2)) { - writePS("%%%%ImageFileName: %s\n", - obj2.getString()->getCString()); + writePSFmt("%%%%ImageFileName: %s\n", + obj2.getString()->getCString()); obj2.free(); } obj1.free(); dict->lookup("MainImage", &obj1); if (obj1.isString()) { - writePS("%%%%MainImage: %s\n", obj1.getString()->getCString()); + writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString()); } obj1.free(); @@ -2714,7 +2833,7 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { obj1.arrayGet(1, &obj2); height = obj2.getNum(); obj2.free(); - writePS("%%%%ImageDimensions: %g %g\n", width, height); + writePSFmt("%%%%ImageDimensions: %g %g\n", width, height); } obj1.free(); @@ -2732,31 +2851,31 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { obj1.arrayGet(3, &obj2); bottom = obj2.getNum(); obj2.free(); - writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); + writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); } obj1.free(); dict->lookup("Overprint", &obj1); if (obj1.isBool()) { - writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); } obj1.free(); dict->lookup("Inks", &obj1); if (obj1.isName()) { - writePS("%%%%ImageInks: %s\n", obj1.getName()); + writePSFmt("%%%%ImageInks: %s\n", obj1.getName()); } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { obj1.arrayGet(0, &obj2); if (obj2.isName()) { - writePS("%%%%ImageInks: %s %d", - obj2.getName(), (obj1.arrayGetLength() - 1) / 2); + writePSFmt("%%%%ImageInks: %s %d", + obj2.getName(), (obj1.arrayGetLength() - 1) / 2); for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { obj1.arrayGet(i, &obj3); obj1.arrayGet(i+1, &obj4); if (obj3.isString() && obj4.isNum()) { writePS(" "); writePSString(obj3.getString()); - writePS(" %g", obj4.getNum()); + writePSFmt(" %g", obj4.getNum()); } obj3.free(); obj4.free(); @@ -2769,7 +2888,7 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { writePS("gsave\n"); - writePS("%%%%BeginIncludedImage\n"); + writePS("%%BeginIncludedImage\n"); dict->lookup("IncludedImageDimensions", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { @@ -2779,13 +2898,13 @@ void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { obj1.arrayGet(1, &obj2); h = obj2.getInt(); obj2.free(); - writePS("%%%%IncludedImageDimensions: %d %d\n", w, h); + writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h); } obj1.free(); dict->lookup("IncludedImageQuality", &obj1); if (obj1.isNum()) { - writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum()); + writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum()); } obj1.free(); @@ -2807,8 +2926,8 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { dict->lookup("F", &obj1); if (getFileSpec(&obj1, &obj2)) { - writePS("%%ALDImageFileName: %s\n", - obj2.getString()->getCString()); + writePSFmt("%%ALDImageFileName: %s\n", + obj2.getString()->getCString()); obj2.free(); } obj1.free(); @@ -2827,7 +2946,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj1.arrayGet(3, &obj2); bottom = obj2.getInt(); obj2.free(); - writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom); + writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom); } obj1.free(); @@ -2847,7 +2966,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj2.free(); obj1.arrayGet(4, &obj2); if (obj2.isString()) { - writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k); + writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k); writePSString(obj2.getString()); writePS("\n"); } @@ -2857,7 +2976,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { dict->lookup("ColorType", &obj1); if (obj1.isName()) { - writePS("%%ALDImageColorType: %s\n", obj1.getName()); + writePSFmt("%%ALDImageColorType: %s\n", obj1.getName()); } obj1.free(); @@ -2878,20 +2997,20 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj1.arrayGet(3, &obj2); lry = obj2.getNum(); obj2.free(); - writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry); + writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry); } obj1.free(); dict->lookup("GrayMap", &obj1); if (obj1.isArray()) { - writePS("%%ALDImageGrayMap:"); + writePS("%ALDImageGrayMap:"); for (i = 0; i < obj1.arrayGetLength(); i += 16) { if (i > 0) { - writePS("\n%%%%+"); + writePS("\n%%+"); } for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) { obj1.arrayGet(i+j, &obj2); - writePS(" %d", obj2.getInt()); + writePSFmt(" %d", obj2.getInt()); obj2.free(); } } @@ -2901,7 +3020,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { dict->lookup("ID", &obj1); if (obj1.isString()) { - writePS("%%ALDImageID: %s\n", obj1.getString()->getCString()); + writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString()); } obj1.free(); @@ -2913,13 +3032,13 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj1.arrayGet(1, &obj2); bits = obj2.getInt(); obj2.free(); - writePS("%%ALDImageType: %d %d\n", samples, bits); + writePSFmt("%%ALDImageType: %d %d\n", samples, bits); } obj1.free(); dict->lookup("Overprint", &obj1); if (obj1.isBool()) { - writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); } obj1.free(); @@ -2953,8 +3072,8 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { opiTransform(state, ulx, uly, &tulx, &tuly); opiTransform(state, urx, ury, &turx, &tury); opiTransform(state, lrx, lry, &tlrx, &tlry); - writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n", - tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); + writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n", + tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); obj2.free(); } obj1.free(); @@ -2967,7 +3086,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj1.arrayGet(1, &obj2); vert = obj2.getNum(); obj2.free(); - writePS("%%ALDImageResoution: %g %g\n", horiz, vert); + writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert); obj2.free(); } obj1.free(); @@ -2980,7 +3099,7 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { obj1.arrayGet(1, &obj2); height = obj2.getInt(); obj2.free(); - writePS("%%ALDImageDimensions: %d %d\n", width, height); + writePSFmt("%%ALDImageDimensions: %d %d\n", width, height); } obj1.free(); @@ -2989,17 +3108,17 @@ void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { dict->lookup("Tint", &obj1); if (obj1.isNum()) { - writePS("%%ALDImageTint: %g\n", obj1.getNum()); + writePSFmt("%%ALDImageTint: %g\n", obj1.getNum()); } obj1.free(); dict->lookup("Transparency", &obj1); if (obj1.isBool()) { - writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false"); + writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false"); } obj1.free(); - writePS("%%%%BeginObject: image\n"); + writePS("%%BeginObject: image\n"); writePS("opiMatrix2 setmatrix\n"); ++opi13Nest; } @@ -3029,8 +3148,8 @@ void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { if (globalParams->getPSOPI()) { opiDict->lookup("2.0", &dict); if (dict.isDict()) { - writePS("%%%%EndIncludedImage\n"); - writePS("%%%%EndOPI\n"); + writePS("%%EndIncludedImage\n"); + writePS("%%EndOPI\n"); writePS("grestore\n"); --opi20Nest; dict.free(); @@ -3038,7 +3157,7 @@ void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { dict.free(); opiDict->lookup("1.3", &dict); if (dict.isDict()) { - writePS("%%%%EndObject\n"); + writePS("%%EndObject\n"); writePS("restore\n"); --opi13Nest; } @@ -3079,7 +3198,7 @@ GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) { #endif // OPI_SUPPORT void PSOutputDev::type3D0(GfxState *state, double wx, double wy) { - writePS("%g %g setcharwidth\n", wx, wy); + writePSFmt("%g %g setcharwidth\n", wx, wy); writePS("q\n"); } @@ -3112,18 +3231,34 @@ void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { str->close(); } -void PSOutputDev::writePS(const char *fmt, ...) { +void PSOutputDev::writePSChar(char c) { + if (t3String) { + t3String->append(c); + } else { + (*outputFunc)(outputStream, &c, 1); + } +} + +void PSOutputDev::writePS(char *s) { + if (t3String) { + t3String->append(s); + } else { + (*outputFunc)(outputStream, s, strlen(s)); + } +} + +void PSOutputDev::writePSFmt(const char *fmt, ...) { va_list args; char buf[512]; va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); if (t3String) { - vsprintf(buf, fmt, args); t3String->append(buf); } else { - vfprintf(f, fmt, args); + (*outputFunc)(outputStream, buf, strlen(buf)); } - va_end(args); } void PSOutputDev::writePSString(GString *s) { @@ -3137,11 +3272,11 @@ void PSOutputDev::writePSString(GString *s) { writePSChar('\\'); writePSChar((char)*p); } else if (*p < 0x20 || *p >= 0x80) { + sprintf(buf, "\\%03o", *p); if (t3String) { - sprintf(buf, "\\%03o", *p); t3String->append(buf); } else { - fprintf(f, "\\%03o", *p); + (*outputFunc)(outputStream, buf, strlen(buf)); } } else { writePSChar((char)*p); @@ -3150,11 +3285,20 @@ void PSOutputDev::writePSString(GString *s) { writePSChar(')'); } -void PSOutputDev::writePSChar(char c) { - if (t3String) { - t3String->append(c); - } else { - fputc(c, f); +void PSOutputDev::writePSName(char *s) { + char *p; + char c; + + p = s; + while ((c = *p++)) { + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + writePSFmt("#%02x", c & 0xff); + } else { + writePSChar(c); + } } } diff --git a/pdf/xpdf/PSOutputDev.h b/pdf/xpdf/PSOutputDev.h index ba208de..fbfc3a5 100644 --- a/pdf/xpdf/PSOutputDev.h +++ b/pdf/xpdf/PSOutputDev.h @@ -9,7 +9,9 @@ #ifndef PSOUTPUTDEV_H #define PSOUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -39,9 +41,12 @@ enum PSOutMode { enum PSFileType { psFile, // write to file psPipe, // write to pipe - psStdout // write to stdout + psStdout, // write to stdout + psGeneric // write to a generic stream }; +typedef void (*PSOutputFunc)(void *stream, char *data, int len); + class PSOutputDev: public OutputDev { public: @@ -49,6 +54,11 @@ public: PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA); + // Open a PSOutputDev that will write to a generic stream. + PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA); + // Destructor -- writes the trailer and closes the file. virtual ~PSOutputDev(); @@ -137,8 +147,12 @@ public: //----- PostScript XObjects virtual void psXObject(Stream *psStream, Stream *level1Stream); + private: + void init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA); void setupResources(Dict *resDict); void setupFonts(Dict *resDict); void setupFont(GfxFont *font, Dict *parentResDict); @@ -172,9 +186,11 @@ private: double *x1, double *y1); GBool getFileSpec(Object *fileSpec, Object *fileName); #endif - void writePS(const char *fmt, ...); - void writePSString(GString *s); void writePSChar(char c); + void writePS(char *s); + void writePSFmt(const char *fmt, ...); + void writePSString(GString *s); + void writePSName(char *s); GString *filterPSName(GString *name); PSLevel level; // PostScript level (1, 2, separation) @@ -182,7 +198,8 @@ private: int paperWidth; // width of paper, in pts int paperHeight; // height of paper, in pts - FILE *f; // PostScript file + PSOutputFunc outputFunc; + void *outputStream; PSFileType fileType; // file / pipe / stdout int seqPage; // current sequential page number @@ -223,6 +240,7 @@ private: #endif GBool ok; // set up ok? + }; #endif diff --git a/pdf/xpdf/Page.cc b/pdf/xpdf/Page.cc index c601857..72b4a8e 100644 --- a/pdf/xpdf/Page.cc +++ b/pdf/xpdf/Page.cc @@ -6,12 +6,14 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include +#include "GlobalParams.h" #include "Object.h" #include "Array.h" #include "Dict.h" @@ -170,13 +172,10 @@ GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { // Page //------------------------------------------------------------------------ -Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, - GBool printCommandsA) { - +Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { ok = gTrue; xref = xrefA; num = numA; - printCommands = printCommandsA; // get attributes attrs = attrsA; @@ -216,21 +215,87 @@ Page::~Page() { } void Page::display(OutputDev *out, double dpi, int rotate, - Links *links, Catalog *catalog) { + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + displaySlice(out, dpi, rotate, -1, -1, -1, -1, links, catalog, + abortCheckCbk, abortCheckCbkData); +} + +void Page::displaySlice(OutputDev *out, double dpi, int rotate, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { #ifndef PDF_PARSER_ONLY - PDFRectangle *box, *cropBox; + PDFRectangle *mediaBox, *cropBox; + PDFRectangle box; Gfx *gfx; Object obj; Link *link; - int i; Annots *annotList; + double k; + int i; - box = getBox(); + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + + mediaBox = getBox(); + if (sliceW >= 0 && sliceH >= 0) { + k = 72.0 / dpi; + if (rotate == 90) { + if (out->upsideDown()) { + box.x1 = mediaBox->x1 + k * sliceY; + box.x2 = mediaBox->x1 + k * (sliceY + sliceH); + } else { + box.x1 = mediaBox->x2 - k * (sliceY + sliceH); + box.x2 = mediaBox->x2 - k * sliceY; + } + box.y1 = mediaBox->y1 + k * sliceX; + box.y2 = mediaBox->y1 + k * (sliceX + sliceW); + } else if (rotate == 180) { + box.x1 = mediaBox->x2 - k * (sliceX + sliceW); + box.x2 = mediaBox->x2 - k * sliceX; + if (out->upsideDown()) { + box.y1 = mediaBox->y1 + k * sliceY; + box.y2 = mediaBox->y1 + k * (sliceY + sliceH); + } else { + box.y1 = mediaBox->y2 - k * (sliceY + sliceH); + box.y2 = mediaBox->y2 - k * sliceY; + } + } else if (rotate == 270) { + if (out->upsideDown()) { + box.x1 = mediaBox->x2 - k * (sliceY + sliceH); + box.x2 = mediaBox->x2 - k * sliceY; + } else { + box.x1 = mediaBox->x1 + k * sliceY; + box.x2 = mediaBox->x1 + k * (sliceY + sliceH); + } + box.y1 = mediaBox->y2 - k * (sliceX + sliceW); + box.y2 = mediaBox->y2 - k * sliceX; + } else { + box.x1 = mediaBox->x1 + k * sliceX; + box.x2 = mediaBox->x1 + k * (sliceX + sliceW); + if (out->upsideDown()) { + box.y1 = mediaBox->y2 - k * (sliceY + sliceH); + box.y2 = mediaBox->y2 - k * sliceY; + } else { + box.y1 = mediaBox->y1 + k * sliceY; + box.y2 = mediaBox->y1 + k * (sliceY + sliceH); + } + } + } else { + box = *mediaBox; + } cropBox = getCropBox(); - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", - box->x1, box->y1, box->x2, box->y2); + box.x1, box.y1, box.x2, box.y2); if (isCropped()) { printf("***** CropBox = ll:%g,%g ur:%g,%g\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); @@ -238,14 +303,9 @@ void Page::display(OutputDev *out, double dpi, int rotate, printf("***** Rotate = %d\n", attrs->getRotate()); } - rotate += getRotate(); - if (rotate >= 360) { - rotate -= 360; - } else if (rotate < 0) { - rotate += 360; - } gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - dpi, box, isCropped(), cropBox, rotate, printCommands); + dpi, &box, isCropped(), cropBox, rotate, + abortCheckCbk, abortCheckCbkData); contents.fetch(xref, &obj); if (!obj.isNull()) { gfx->display(&obj); @@ -266,7 +326,7 @@ void Page::display(OutputDev *out, double dpi, int rotate, annotList = new Annots(xref, annots.fetch(xref, &obj)); obj.free(); if (annotList->getNumAnnots() > 0) { - if (printCommands) { + if (globalParams->getPrintCommands()) { printf("***** Annotations\n"); } for (i = 0; i < annotList->getNumAnnots(); ++i) { diff --git a/pdf/xpdf/Page.h b/pdf/xpdf/Page.h index 7207b20..911c5b0 100644 --- a/pdf/xpdf/Page.h +++ b/pdf/xpdf/Page.h @@ -9,7 +9,9 @@ #ifndef PAGE_H #define PAGE_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -23,8 +25,14 @@ class Catalog; //------------------------------------------------------------------------ -struct PDFRectangle { +class PDFRectangle { +public: double x1, y1, x2, y2; + + PDFRectangle() { x1 = y1 = x2 = y2 = 0; } + PDFRectangle(double x1A, double y1A, double x2A, double y2A) + { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } + GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } }; //------------------------------------------------------------------------ @@ -97,8 +105,7 @@ class Page { public: // Constructor. - Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, - GBool printCommandsA); + Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); // Destructor. ~Page(); @@ -135,7 +142,16 @@ public: // Display a page. void display(OutputDev *out, double dpi, int rotate, - Links *links, Catalog *catalog); + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displaySlice(OutputDev *out, double dpi, int rotate, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); private: @@ -144,7 +160,6 @@ private: PageAttrs *attrs; // page attributes Object annots; // annotations array Object contents; // page contents - GBool printCommands; // print the drawing commands (for debugging) GBool ok; // true if page is valid }; diff --git a/pdf/xpdf/Parser.cc b/pdf/xpdf/Parser.cc index 4df53c9..4bcb0ce 100644 --- a/pdf/xpdf/Parser.cc +++ b/pdf/xpdf/Parser.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include "Object.h" #include "Array.h" @@ -88,8 +89,10 @@ Object *Parser::getObj(Object *obj) { } else { key = copyString(buf1.getName()); shift(); - if (buf1.isEOF() || buf1.isError()) + if (buf1.isEOF() || buf1.isError()) { + gfree(key); break; + } #ifndef NO_DECRYPTION obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); #else @@ -200,7 +203,13 @@ Stream *Parser::makeStream(Object *dict) { void Parser::shift() { if (inlineImg > 0) { - ++inlineImg; + if (inlineImg < 2) { + ++inlineImg; + } else { + // in a damaged content stream, if 'ID' shows up in the middle + // of a dictionary, we need to reset + inlineImg = 0; + } } else if (buf2.isCmd("ID")) { lexer->skipChar(); // skip char after 'ID' command inlineImg = 1; diff --git a/pdf/xpdf/Parser.h b/pdf/xpdf/Parser.h index c11475b..7b7a812 100644 --- a/pdf/xpdf/Parser.h +++ b/pdf/xpdf/Parser.h @@ -9,7 +9,9 @@ #ifndef PARSER_H #define PARSER_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc index 9777940..0d19d4d 100644 --- a/pdf/xpdf/Stream.cc +++ b/pdf/xpdf/Stream.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -28,6 +29,7 @@ #include "Decrypt.h" #endif #include "Stream.h" +#include "JBIG2Stream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ @@ -35,9 +37,6 @@ static GBool setDJSYSFLAGS = gFalse; #endif #ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif #ifdef __GNUC__ #define SEEK_SET 0 #define SEEK_CUR 1 @@ -45,10 +44,6 @@ extern "C" int unlink(char *filename); #endif #endif -#ifdef MACOS -#include "StuffItEngineLib.h" -#endif - //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -145,7 +140,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int encoding; GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; - Object obj; + Object globals, obj; if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { str = new ASCIIHexStream(str); @@ -255,6 +250,12 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { obj.free(); } str = new FlateStream(str, pred, columns, colors, bits); + } else if (!strcmp(name, "JBIG2Decode")) { + if (params->isDict()) { + params->dictLookup("JBIG2Globals", &globals); + } + str = new JBIG2Stream(str, &globals); + globals.free(); } else { error(getPos(), "Unknown filter '%s'", name); str = new EOFStream(str); @@ -338,51 +339,54 @@ void ImageStream::reset() { } GBool ImageStream::getPixel(Guchar *pix) { + int i; + + if (imgIdx >= nVals) { + getLine(); + imgIdx = 0; + } + for (i = 0; i < nComps; ++i) { + pix[i] = imgLine[imgIdx++]; + } + return gTrue; +} + +Guchar *ImageStream::getLine() { Gulong buf, bitMask; int bits; int c; int i; - if (imgIdx >= nVals) { - - // read one line of image pixels - if (nBits == 1) { - for (i = 0; i < nVals; i += 8) { - c = str->getChar(); - imgLine[i+0] = (Guchar)((c >> 7) & 1); - imgLine[i+1] = (Guchar)((c >> 6) & 1); - imgLine[i+2] = (Guchar)((c >> 5) & 1); - imgLine[i+3] = (Guchar)((c >> 4) & 1); - imgLine[i+4] = (Guchar)((c >> 3) & 1); - imgLine[i+5] = (Guchar)((c >> 2) & 1); - imgLine[i+6] = (Guchar)((c >> 1) & 1); - imgLine[i+7] = (Guchar)(c & 1); - } - } else if (nBits == 8) { - for (i = 0; i < nVals; ++i) { - imgLine[i] = str->getChar(); - } - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); - bits -= nBits; + if (nBits == 1) { + for (i = 0; i < nVals; i += 8) { + c = str->getChar(); + imgLine[i+0] = (Guchar)((c >> 7) & 1); + imgLine[i+1] = (Guchar)((c >> 6) & 1); + imgLine[i+2] = (Guchar)((c >> 5) & 1); + imgLine[i+3] = (Guchar)((c >> 4) & 1); + imgLine[i+4] = (Guchar)((c >> 3) & 1); + imgLine[i+5] = (Guchar)((c >> 2) & 1); + imgLine[i+6] = (Guchar)((c >> 1) & 1); + imgLine[i+7] = (Guchar)(c & 1); + } + } else if (nBits == 8) { + for (i = 0; i < nVals; ++i) { + imgLine[i] = str->getChar(); + } + } else { + bitMask = (1 << nBits) - 1; + buf = 0; + bits = 0; + for (i = 0; i < nVals; ++i) { + if (bits < nBits) { + buf = (buf << 8) | (str->getChar() & 0xff); + bits += 8; } + imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); + bits -= nBits; } - - // reset to start of line - imgIdx = 0; } - - for (i = 0; i < nComps; ++i) - pix[i] = imgLine[imgIdx++]; - return gTrue; + return imgLine; } void ImageStream::skipLine() { @@ -577,7 +581,10 @@ Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, } void FileStream::reset() { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + savePos = (Guint)ftello(f); + fseeko(f, start, SEEK_SET); +#elif HAVE_FSEEK64 savePos = (Guint)ftell64(f); fseek64(f, start, SEEK_SET); #else @@ -595,7 +602,9 @@ void FileStream::reset() { void FileStream::close() { if (saved) { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, savePos, SEEK_SET); +#elif HAVE_FSEEK64 fseek64(f, savePos, SEEK_SET); #else fseek(f, savePos, SEEK_SET); @@ -639,14 +648,19 @@ void FileStream::setPos(Guint pos, int dir) { Guint size; if (dir >= 0) { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, pos, SEEK_SET); +#elif HAVE_FSEEK64 fseek64(f, pos, SEEK_SET); #else fseek(f, pos, SEEK_SET); #endif bufPos = pos; } else { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + size = (Guint)ftello(f); +#elif HAVE_FSEEK64 fseek64(f, 0, SEEK_END); size = (Guint)ftell64(f); #else @@ -659,7 +673,10 @@ void FileStream::setPos(Guint pos, int dir) { //~ work around a bug in cygwin's implementation of fseek rewind(f); #endif -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftello(f); +#elif HAVE_FSEEK64 fseek64(f, -(int)pos, SEEK_END); bufPos = (Guint)ftell64(f); #else @@ -969,21 +986,12 @@ LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, pred = NULL; } early = earlyA; - zPipe = NULL; - bufPtr = bufEnd = buf; + eof = gFalse; + inputBits = 0; + clearTable(); } LZWStream::~LZWStream() { - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } if (pred) { delete pred; } @@ -994,264 +1002,142 @@ int LZWStream::getChar() { if (pred) { return pred->getChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } int LZWStream::lookChar() { if (pred) { return pred->lookChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex]; } int LZWStream::getRawChar() { - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } void LZWStream::reset() { - FILE *f; - GString *zCmd; + str->reset(); + eof = gFalse; + inputBits = 0; + clearTable(); +} - //----- close old LZW stream - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } +GBool LZWStream::processNextCode() { + int code; + int nextLength; + int i, j; - //----- tell Delorie runtime to spawn a new instance of COMMAND.COM - // to run gzip -#if __DJGPP__ - if (!setDJSYSFLAGS) { - setenv("DJSYSFLAGS", "0x0002", 0); - setDJSYSFLAGS = gTrue; + // check for EOF + if (eof) { + return gFalse; } -#endif - //----- create the .Z file - if (!openTempFile(&zName, &f, "wb", ".Z")) { - error(getPos(), "Couldn't create temporary file for LZW stream"); - return; - } - dumpFile(f); - fclose(f); - - //----- execute uncompress / gzip - zCmd = new GString(uncompressCmd); - zCmd->append(' '); - zCmd->append(zName); -#if defined(MACOS) - long magicCookie; - // first we open the engine up - OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie); - // if we found it - let's use it! - if (!err && magicCookie) { - // make sure we have the correct version of the Engine - if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) { - FSSpec myFSS; - Str255 pName; - strcpy((char *)pName, zName->getCString()); - c2pstr((char *)pName); - FSMakeFSSpec(0, 0, pName, &myFSS); - short ftype = DetermineFileType(magicCookie, &myFSS); - OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS, - NULL, NULL, kCreateFolderNever, - kDeleteOriginal, kTextConvertSmart); - } - } -#elif defined(HAVE_POPEN) - if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) { - error(getPos(), "Couldn't popen '%s'", zCmd->getCString()); - unlink(zName->getCString()); - delete zName; - return; - } -#else // HAVE_POPEN - if (!executeCommand(zCmd->getCString())) { - error(getPos(), "Couldn't execute '%s'", zCmd->getCString()); - unlink(zName->getCString()); - delete zName; - return; + // check for eod and clear-table codes + start: + code = getCode(); + if (code == EOF || code == 257) { + eof = gTrue; + return gFalse; } - zName->del(zName->getLength() - 2, 2); - if (!(zPipe = fopen(zName->getCString(), "rb"))) { - error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString()); - unlink(zName->getCString()); - delete zName; - return; + if (code == 256) { + clearTable(); + goto start; + } + if (nextCode >= 4097) { + error(getPos(), "Bad LZW stream - expected clear-table code"); + clearTable(); + } + + // process the next code + nextLength = seqLength + 1; + if (code < 256) { + seqBuf[0] = code; + seqLength = 1; + } else if (code < nextCode) { + seqLength = table[code].length; + for (i = seqLength - 1, j = code; i > 0; --i) { + seqBuf[i] = table[j].tail; + j = table[j].head; + } + seqBuf[0] = j; + } else if (code == nextCode) { + seqBuf[seqLength] = newChar; + ++seqLength; + } else { + error(getPos(), "Bad LZW stream - unexpected code"); + eof = gTrue; + return gFalse; } -#endif // HAVE_POPEN - - //----- clean up - delete zCmd; + newChar = seqBuf[0]; + if (first) { + first = gFalse; + } else { + table[nextCode].length = nextLength; + table[nextCode].head = prevCode; + table[nextCode].tail = newChar; + ++nextCode; + if (nextCode + early == 512) + nextBits = 10; + else if (nextCode + early == 1024) + nextBits = 11; + else if (nextCode + early == 2048) + nextBits = 12; + } + prevCode = code; + + // reset buffer + seqIndex = 0; - //----- initialize buffer - bufPtr = bufEnd = buf; + return gTrue; } -void LZWStream::dumpFile(FILE *f) { - int outCodeBits; // size of output code - int outBits; // max output code - int outBuf[8]; // output buffer - int outData; // temporary output buffer - int inCode, outCode; // input and output codes - int nextCode; // next code index - GBool eof; // set when EOF is reached - GBool clear; // set if table needs to be cleared - GBool first; // indicates first code word after clear - int i, j; - - str->reset(); - - // magic number - fputc(0x1f, f); - fputc(0x9d, f); - - // max code length, block mode flag - fputc(0x8c, f); - - // init input side - inCodeBits = 9; - inputBuf = 0; - inputBits = 0; - eof = gFalse; - - // init output side - outCodeBits = 9; - - // clear table - first = gTrue; +void LZWStream::clearTable() { nextCode = 258; - - clear = gFalse; - do { - for (i = 0; i < 8; ++i) { - // check for table overflow - if (nextCode + early > 0x1001) { - inCode = 256; - - // read input code - } else { - do { - inCode = getCode(); - if (inCode == EOF) { - eof = gTrue; - inCode = 0; - } - } while (first && inCode == 256); - } - - // compute output code - if (inCode < 256) { - outCode = inCode; - } else if (inCode == 256) { - outCode = 256; - clear = gTrue; - } else if (inCode == 257) { - outCode = 0; - eof = gTrue; - } else { - outCode = inCode - 1; - } - outBuf[i] = outCode; - - // next code index - if (first) - first = gFalse; - else - ++nextCode; - - // check input code size - if (nextCode + early == 0x200) - inCodeBits = 10; - else if (nextCode + early == 0x400) { - inCodeBits = 11; - } else if (nextCode + early == 0x800) { - inCodeBits = 12; - } - - // check for eof/clear - if (eof) - break; - if (clear) { - i = 8; - break; - } - } - - // write output block - outData = 0; - outBits = 0; - j = 0; - while (j < i || outBits > 0) { - if (outBits < 8 && j < i) { - outData = outData | (outBuf[j++] << outBits); - outBits += outCodeBits; - } - fputc(outData & 0xff, f); - outData >>= 8; - outBits -= 8; - } - - // check output code size - if (nextCode - 1 == 512 || - nextCode - 1 == 1024 || - nextCode - 1 == 2048 || - nextCode - 1 == 4096) { - outCodeBits = inCodeBits; - } - - // clear table if necessary - if (clear) { - inCodeBits = 9; - outCodeBits = 9; - first = gTrue; - nextCode = 258; - clear = gFalse; - } - } while (!eof); + nextBits = 9; + seqIndex = seqLength = 0; + first = gTrue; } int LZWStream::getCode() { int c; int code; - while (inputBits < inCodeBits) { + while (inputBits < nextBits) { if ((c = str->getChar()) == EOF) return EOF; inputBuf = (inputBuf << 8) | (c & 0xff); inputBits += 8; } - code = (inputBuf >> (inputBits - inCodeBits)) & ((1 << inCodeBits) - 1); - inputBits -= inCodeBits; + code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); + inputBits -= nextBits; return code; } -GBool LZWStream::fillBuf() { - int n; - - if (!zPipe) - return gFalse; - if ((n = fread(buf, 1, 256, zPipe)) < 256) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } - bufPtr = buf; - bufEnd = buf + n; - return n > 0; -} - GString *LZWStream::getPSFilter(char *indent) { GString *s; @@ -1882,7 +1768,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { //------------------------------------------------------------------------ // IDCT constants (20.12 fixed point format) -#ifndef FP_IDCT #define dctCos1 4017 // cos(pi/16) #define dctSin1 799 // sin(pi/16) #define dctCos3 3406 // cos(3*pi/16) @@ -1891,19 +1776,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { #define dctSin6 3784 // sin(6*pi/16) #define dctSqrt2 5793 // sqrt(2) #define dctSqrt1d2 2896 // sqrt(2) / 2 -#endif - -// IDCT constants -#ifdef FP_IDCT -#define dctCos1 0.98078528 // cos(pi/16) -#define dctSin1 0.19509032 // sin(pi/16) -#define dctCos3 0.83146961 // cos(3*pi/16) -#define dctSin3 0.55557023 // sin(3*pi/16) -#define dctCos6 0.38268343 // cos(6*pi/16) -#define dctSin6 0.92387953 // sin(6*pi/16) -#define dctSqrt2 1.41421356 // sqrt(2) -#define dctSqrt1d2 0.70710678 // sqrt(2) / 2 -#endif // color conversion parameters (16.16 fixed point format) #define dctCrToR 91881 // 1.4020 @@ -1939,14 +1811,18 @@ DCTStream::DCTStream(Stream *strA): FilterStream(strA) { int i, j; + progressive = interleaved = gFalse; width = height = 0; mcuWidth = mcuHeight = 0; numComps = 0; comp = 0; x = y = dy = 0; - for (i = 0; i < 4; ++i) - for (j = 0; j < 32; ++j) + for (i = 0; i < 4; ++i) { + for (j = 0; j < 32; ++j) { rowBuf[i][j] = NULL; + } + frameBuf[i] = NULL; + } if (!dctClipInit) { for (i = -256; i < 0; ++i) @@ -1963,53 +1839,172 @@ DCTStream::~DCTStream() { int i, j; delete str; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - gfree(rowBuf[i][j]); + if (progressive || !interleaved) { + for (i = 0; i < numComps; ++i) { + gfree(frameBuf[i]); + } + } else { + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + gfree(rowBuf[i][j]); + } + } + } } void DCTStream::reset() { + int minHSample, minVSample; + int i, j; + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + colorXform = 0; + gotAdobeMarker = gFalse; + restartInterval = 0; + if (!readHeader()) { y = height; return; } - restartMarker = 0xd0; - restart(); + + // compute MCU size + mcuWidth = minHSample = compInfo[0].hSample; + mcuHeight = minVSample = compInfo[0].vSample; + for (i = 1; i < numComps; ++i) { + if (compInfo[i].hSample < minHSample) + minHSample = compInfo[i].hSample; + if (compInfo[i].vSample < minVSample) + minVSample = compInfo[i].vSample; + if (compInfo[i].hSample > mcuWidth) + mcuWidth = compInfo[i].hSample; + if (compInfo[i].vSample > mcuHeight) + mcuHeight = compInfo[i].vSample; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].hSample /= minHSample; + compInfo[i].vSample /= minVSample; + } + mcuWidth = (mcuWidth / minHSample) * 8; + mcuHeight = (mcuHeight / minVSample) * 8; + + // figure out color transform + if (!gotAdobeMarker && numComps == 3) { + if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { + colorXform = 1; + } + } + + if (progressive || !interleaved) { + + // allocate a buffer for the whole image + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; + for (i = 0; i < numComps; ++i) { + frameBuf[i] = (int *)gmalloc(bufWidth * bufHeight * sizeof(int)); + memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); + } + + // read the image data + do { + restartMarker = 0xd0; + restart(); + readScan(); + } while (readHeader()); + + // decode + decodeImage(); + + // initialize counters + comp = 0; + x = 0; + y = 0; + + } else { + + // allocate a buffer for one row of MCUs + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); + } + } + + // initialize counters + comp = 0; + x = 0; + y = 0; + dy = mcuHeight; + + restartMarker = 0xd0; + restart(); + } } int DCTStream::getChar() { int c; - c = lookChar(); - if (c == EOF) + if (y >= height) { return EOF; - if (++comp == numComps) { - comp = 0; - if (++x == width) { + } + if (progressive || !interleaved) { + c = frameBuf[comp][y * bufWidth + x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + } + } + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; x = 0; - ++y; - ++dy; + dy = 0; + } + c = rowBuf[comp][dy][x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + ++dy; + if (y == height) { + readTrailer(); + } + } } } - if (y == height) - readTrailer(); return c; } int DCTStream::lookChar() { - if (y >= height) + if (y >= height) { return EOF; - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; + } + if (progressive || !interleaved) { + return frameBuf[comp][y * bufWidth + x]; + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; } - comp = 0; - x = 0; - dy = 0; + return rowBuf[comp][dy][x]; } - return rowBuf[comp][dy][x]; } void DCTStream::restart() { @@ -2017,12 +2012,16 @@ void DCTStream::restart() { inputBits = 0; restartCtr = restartInterval; - for (i = 0; i < numComps; ++i) + for (i = 0; i < numComps; ++i) { compInfo[i].prevDC = 0; + } + eobRun = 0; } +// Read one row of MCUs from a sequential JPEG stream. GBool DCTStream::readMCURow() { - Guchar data[64]; + int data1[64]; + Guchar data2[64]; Guchar *p1, *p2; int pY, pCb, pCr, pR, pG, pB; int h, v, horiz, vert, hSub, vSub; @@ -2053,36 +2052,38 @@ GBool DCTStream::readMCURow() { vSub = vert / 8; for (y2 = 0; y2 < mcuHeight; y2 += vert) { for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - if (!readDataUnit(&dcHuffTables[compInfo[cc].dcHuffTable], - &acHuffTables[compInfo[cc].acHuffTable], - quantTables[compInfo[cc].quantTable], + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, - data)) + data1)) { return gFalse; + } + transformDataUnit(quantTables[compInfo[cc].quantTable], + data1, data2); if (hSub == 1 && vSub == 1) { for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; - p1[0] = data[i]; - p1[1] = data[i+1]; - p1[2] = data[i+2]; - p1[3] = data[i+3]; - p1[4] = data[i+4]; - p1[5] = data[i+5]; - p1[6] = data[i+6]; - p1[7] = data[i+7]; + p1[0] = data2[i]; + p1[1] = data2[i+1]; + p1[2] = data2[i+2]; + p1[3] = data2[i+3]; + p1[4] = data2[i+4]; + p1[5] = data2[i+5]; + p1[6] = data2[i+6]; + p1[7] = data2[i+7]; } } else if (hSub == 2 && vSub == 2) { for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; p2 = &rowBuf[cc][y2+y3+1][x1+x2]; - p1[0] = p1[1] = p2[0] = p2[1] = data[i]; - p1[2] = p1[3] = p2[2] = p2[3] = data[i+1]; - p1[4] = p1[5] = p2[4] = p2[5] = data[i+2]; - p1[6] = p1[7] = p2[6] = p2[7] = data[i+3]; - p1[8] = p1[9] = p2[8] = p2[9] = data[i+4]; - p1[10] = p1[11] = p2[10] = p2[11] = data[i+5]; - p1[12] = p1[13] = p2[12] = p2[13] = data[i+6]; - p1[14] = p1[15] = p2[14] = p2[15] = data[i+7]; + p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; + p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; + p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; + p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; + p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; + p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; + p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; + p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; } } else { i = 0; @@ -2090,7 +2091,7 @@ GBool DCTStream::readMCURow() { for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { for (y5 = 0; y5 < vSub; ++y5) for (x5 = 0; x5 < hSub; ++x5) - rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data[i]; + rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; ++i; } } @@ -2138,71 +2139,466 @@ GBool DCTStream::readMCURow() { return gTrue; } -// This IDCT algorithm is taken from: -// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, -// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", -// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, -// 988-991. -// The stage numbers mentioned in the comments refer to Figure 1 in this -// paper. -#ifndef FP_IDCT +// Read one scan from a progressive or non-interleaved JPEG stream. +void DCTStream::readScan() { + int data[64]; + int x1, y1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p1; + int c; + + if (scanInfo.numComps == 1) { + for (cc = 0; cc < numComps; ++cc) { + if (scanInfo.comp[cc]) { + break; + } + } + dy1 = mcuHeight / compInfo[cc].vSample; + } else { + dy1 = mcuHeight; + } + + for (y1 = 0; y1 < bufHeight; y1 += dy1) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return; + } + if (++restartMarker == 0xd8) { + restartMarker = 0xd0; + } + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + if (!scanInfo.comp[cc]) { + continue; + } + + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < dy1; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + + // pull out the current values + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + data[i] = p1[0]; + data[i+1] = p1[1]; + data[i+2] = p1[2]; + data[i+3] = p1[3]; + data[i+4] = p1[4]; + data[i+5] = p1[5]; + data[i+6] = p1[6]; + data[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // read one data unit + if (progressive) { + if (!readProgressiveDataUnit( + &dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } else { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } + + // add the data unit into frameBuf + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = data[i]; + p1[1] = data[i+1]; + p1[2] = data[i+2]; + p1[3] = data[i+3]; + p1[4] = data[i+4]; + p1[5] = data[i+5]; + p1[6] = data[i+6]; + p1[7] = data[i+7]; + p1 += bufWidth * vSub; + } + } + } + } + --restartCtr; + } + } +} + +// Read one data unit from a sequential JPEG stream. GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - int tmp1[64]; - int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *prevDC, int data[64]) { int run, size, amp; int c; int i, j; - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) + if ((size = readHuffSym(dcHuffTable)) == 9999) { return gFalse; + } if (size > 0) { - amp = readAmp(size); - if (amp == 9999) + if ((amp = readAmp(size)) == 9999) { return gFalse; + } } else { amp = 0; } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; + data[0] = *prevDC += amp; + for (i = 1; i < 64; ++i) { + data[i] = 0; + } i = 1; while (i < 64) { run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) + while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { run += 0x10; - if (c == 9999) + } + if (c == 9999) { return gFalse; + } if (c == 0x00) { break; } else { run += (c >> 4) & 0x0f; size = c & 0x0f; amp = readAmp(size); - if (amp == 9999) + if (amp == 9999) { return gFalse; + } i += run; j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; + data[j] = amp; + } + } + return gTrue; +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp, bit, c; + int i, j, k; + + // get the DC coefficient + i = scanInfo.firstCoeff; + if (i == 0) { + if (scanInfo.ah == 0) { + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] += (*prevDC += amp) << scanInfo.al; + } else { + if ((bit = readBit()) == 9999) { + return gFalse; + } + data[0] += bit << scanInfo.al; + } + ++i; + } + if (scanInfo.lastCoeff == 0) { + return gTrue; + } + + // check for an EOB run + if (eobRun > 0) { + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } } + --eobRun; + return gTrue; + } + + // read the AC coefficients + while (i <= scanInfo.lastCoeff) { + if ((c = readHuffSym(acHuffTable)) == 9999) { + return gFalse; + } + + // ZRL + if (c == 0xf0) { + k = 0; + while (k < 16) { + j = dctZigZag[i++]; + if (data[j] == 0) { + ++k; + } else { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + + // EOB run + } else if ((c & 0x0f) == 0x00) { + j = c >> 4; + eobRun = 0; + for (k = 0; k < j; ++k) { + if ((bit = readBit()) == EOF) { + return 9999; + } + eobRun = (eobRun << 1) | bit; + } + eobRun += 1 << j; + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + break; + + // zero run and one AC coefficient + } else { + run = (c >> 4) & 0x0f; + size = c & 0x0f; + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + k = 0; + do { + j = dctZigZag[i++]; + while (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + j = dctZigZag[i++]; + } + ++k; + } while (k <= run); + data[j] = amp << scanInfo.al; + } + } + + return gTrue; +} + +// Decode a progressive JPEG image. +void DCTStream::decodeImage() { + int dataIn[64]; + Guchar dataOut[64]; + Guchar *quantTable; + int pY, pCb, pCr, pR, pG, pB; + int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p0, *p1, *p2; + + for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (cc = 0; cc < numComps; ++cc) { + quantTable = quantTables[compInfo[cc].quantTable]; + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < mcuHeight; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + + // pull out the coded data unit + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + dataIn[i] = p1[0]; + dataIn[i+1] = p1[1]; + dataIn[i+2] = p1[2]; + dataIn[i+3] = p1[3]; + dataIn[i+4] = p1[4]; + dataIn[i+5] = p1[5]; + dataIn[i+6] = p1[6]; + dataIn[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // transform + transformDataUnit(quantTable, dataIn, dataOut); + + // store back into frameBuf, doing replication for + // subsampled components + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = dataOut[i] & 0xff; + p1[1] = dataOut[i+1] & 0xff; + p1[2] = dataOut[i+2] & 0xff; + p1[3] = dataOut[i+3] & 0xff; + p1[4] = dataOut[i+4] & 0xff; + p1[5] = dataOut[i+5] & 0xff; + p1[6] = dataOut[i+6] & 0xff; + p1[7] = dataOut[i+7] & 0xff; + p1 += bufWidth; + } + } else if (hSub == 2 && vSub == 2) { + p2 = p1 + bufWidth; + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; + p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; + p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; + p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; + p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; + p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; + p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; + p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; + p1 += bufWidth * 2; + p2 += bufWidth * 2; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + p2 = p1 + x4; + for (y5 = 0; y5 < vSub; ++y5) { + for (x5 = 0; x5 < hSub; ++x5) { + p2[x5] = dataOut[i] & 0xff; + } + p2 += bufWidth; + } + ++i; + } + p1 += bufWidth * vSub; + } + } + } + } + } + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } + } + } +} + +// Transform one data unit -- this performs the dequantization and +// IDCT steps. This IDCT algorithm is taken from: +// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, +// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", +// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, +// 988-991. +// The stage numbers mentioned in the comments refer to Figure 1 in this +// paper. +void DCTStream::transformDataUnit(Guchar *quantTable, + int dataIn[64], Guchar dataOut[64]) { + int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *p; + int i; + + // dequant + for (i = 0; i < 64; ++i) { + dataIn[i] *= quantTable[i]; } // inverse DCT on rows for (i = 0; i < 64; i += 8) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1] == 0 && p[2] == 0 && p[3] == 0 && + p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { + t = (dctSqrt2 * p[0] + 512) >> 10; + p[0] = t; + p[1] = t; + p[2] = t; + p[3] = t; + p[4] = t; + p[5] = t; + p[6] = t; + p[7] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[i+0] + 128) >> 8; - v1 = (dctSqrt2 * tmp1[i+4] + 128) >> 8; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = (dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]) + 128) >> 8; - v7 = (dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]) + 128) >> 8; - v5 = tmp1[i+3] << 4; - v6 = tmp1[i+5] << 4; + v0 = (dctSqrt2 * p[0] + 128) >> 8; + v1 = (dctSqrt2 * p[4] + 128) >> 8; + v2 = p[2]; + v3 = p[6]; + v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; + v5 = p[3] << 4; + v6 = p[5] << 4; // stage 3 t = (v0 - v1+ 1) >> 1; @@ -2233,28 +2629,44 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, v6 = t; // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; + p[0] = v0 + v7; + p[7] = v0 - v7; + p[1] = v1 + v6; + p[6] = v1 - v6; + p[2] = v2 + v5; + p[5] = v2 - v5; + p[3] = v3 + v4; + p[4] = v3 - v4; } // inverse DCT on columns for (i = 0; i < 8; ++i) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && + p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { + t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; + p[0*8] = t; + p[1*8] = t; + p[2*8] = t; + p[3*8] = t; + p[4*8] = t; + p[5*8] = t; + p[6*8] = t; + p[7*8] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[0*8+i] + 2048) >> 12; - v1 = (dctSqrt2 * tmp1[4*8+i] + 2048) >> 12; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = (dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]) + 2048) >> 12; - v7 = (dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]) + 2048) >> 12; - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; + v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; + v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; + v2 = p[2*8]; + v3 = p[6*8]; + v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; + v5 = p[3*8]; + v6 = p[5*8]; // stage 3 t = (v0 - v1 + 1) >> 1; @@ -2285,181 +2697,21 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, v6 = t; // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; + p[0*8] = v0 + v7; + p[7*8] = v0 - v7; + p[1*8] = v1 + v6; + p[6*8] = v1 - v6; + p[2*8] = v2 + v5; + p[5*8] = v2 - v5; + p[3*8] = v3 + v4; + p[4*8] = v3 - v4; } // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + 128 + ((tmp1[i] + 8) >> 4)]; - - return gTrue; -} -#endif - -#ifdef FP_IDCT -GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - double tmp1[64]; - double v0, v1, v2, v3, v4, v5, v6, v7, t; - int run, size, amp; - int c; - int i, j; - - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) - return gFalse; - if (size > 0) { - amp = readAmp(size); - if (amp == 9999) - return gFalse; - } else { - amp = 0; - } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; - i = 1; - while (i < 64) { - run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) - run += 0x10; - if (c == 9999) - return gFalse; - if (c == 0x00) { - break; - } else { - run += (c >> 4) & 0x0f; - size = c & 0x0f; - amp = readAmp(size); - if (amp == 9999) - return gFalse; - i += run; - j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; - } - } - - // inverse DCT on rows - for (i = 0; i < 64; i += 8) { - - // stage 4 - v0 = dctSqrt2 * tmp1[i+0]; - v1 = dctSqrt2 * tmp1[i+4]; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]); - v7 = dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]); - v5 = tmp1[i+3]; - v6 = tmp1[i+5]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; - v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); - v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); - v7 = t; - - // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); - v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); - v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; - v6 = t; - - // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; - } - - // inverse DCT on columns - for (i = 0; i < 8; ++i) { - - // stage 4 - v0 = dctSqrt2 * tmp1[0*8+i]; - v1 = dctSqrt2 * tmp1[4*8+i]; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]); - v7 = dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]); - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; - v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); - v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); - v7 = t; - - // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); - v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); - v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; - v6 = t; - - // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; + for (i = 0; i < 64; ++i) { + dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; } - - // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + (int)(tmp1[i] + 128.5)]; - - return gTrue; } -#endif int DCTStream::readHuffSym(DCTHuffTable *table) { Gushort code; @@ -2527,20 +2779,9 @@ int DCTStream::readBit() { GBool DCTStream::readHeader() { GBool doScan; - int minHSample, minVSample; - int bufWidth; int n; int c = 0; - int i, j; - - width = height = 0; - numComps = 0; - numQuantTables = 0; - numDCHuffTables = 0; - numACHuffTables = 0; - colorXform = 0; - gotAdobeMarker = gFalse; - restartInterval = 0; + int i; // read headers doScan = gFalse; @@ -2548,31 +2789,45 @@ GBool DCTStream::readHeader() { c = readMarker(); switch (c) { case 0xc0: // SOF0 - if (!readFrameInfo()) + if (!readBaselineSOF()) { return gFalse; + } + break; + case 0xc2: // SOF2 + if (!readProgressiveSOF()) { + return gFalse; + } break; case 0xc4: // DHT - if (!readHuffmanTables()) + if (!readHuffmanTables()) { return gFalse; + } break; case 0xd8: // SOI break; + case 0xd9: // EOI + return gFalse; + break; case 0xda: // SOS - if (!readScanInfo()) + if (!readScanInfo()) { return gFalse; + } doScan = gTrue; break; case 0xdb: // DQT - if (!readQuantTables()) + if (!readQuantTables()) { return gFalse; + } break; case 0xdd: // DRI - if (!readRestartInterval()) + if (!readRestartInterval()) { return gFalse; + } break; case 0xee: // APP14 - if (!readAdobeMarker()) + if (!readAdobeMarker()) { return gFalse; + } break; case EOF: error(getPos(), "Bad DCT header"); @@ -2581,8 +2836,9 @@ GBool DCTStream::readHeader() { // skip APPn / COM / etc. if (c >= 0xe0) { n = read16() - 2; - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { str->getChar(); + } } else { error(getPos(), "Unknown DCT marker <%02x>", c); return gFalse; @@ -2591,107 +2847,98 @@ GBool DCTStream::readHeader() { } } - // compute MCU size - mcuWidth = minHSample = compInfo[0].hSample; - mcuHeight = minVSample = compInfo[0].vSample; - for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample < minHSample) - minHSample = compInfo[i].hSample; - if (compInfo[i].vSample < minVSample) - minVSample = compInfo[i].vSample; - if (compInfo[i].hSample > mcuWidth) - mcuWidth = compInfo[i].hSample; - if (compInfo[i].vSample > mcuHeight) - mcuHeight = compInfo[i].vSample; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].hSample /= minHSample; - compInfo[i].vSample /= minVSample; - } - mcuWidth = (mcuWidth / minHSample) * 8; - mcuHeight = (mcuHeight / minVSample) * 8; + return gTrue; +} - // allocate buffers - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); +GBool DCTStream::readBaselineSOF() { + int length; + int prec; + int i; + int c; - // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { - colorXform = 1; - } + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; } - - // initialize counters - comp = 0; - x = 0; - y = 0; - dy = mcuHeight; - + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gFalse; return gTrue; } -GBool DCTStream::readFrameInfo() { +GBool DCTStream::readProgressiveSOF() { int length; int prec; int i; int c; - length = read16() - 2; + length = read16(); prec = str->getChar(); height = read16(); width = read16(); numComps = str->getChar(); - length -= 6; if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; } for (i = 0; i < numComps; ++i) { compInfo[i].id = str->getChar(); - compInfo[i].inScan = gFalse; c = str->getChar(); compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); - compInfo[i].dcHuffTable = 0; - compInfo[i].acHuffTable = 0; } + progressive = gTrue; return gTrue; } GBool DCTStream::readScanInfo() { int length; - int scanComps, id, c; + int id, c; int i, j; length = read16() - 2; - scanComps = str->getChar(); + scanInfo.numComps = str->getChar(); --length; - if (length != 2 * scanComps + 3) { + if (length != 2 * scanInfo.numComps + 3) { error(getPos(), "Bad DCT scan info block"); return gFalse; } - for (i = 0; i < scanComps; ++i) { + interleaved = scanInfo.numComps == numComps; + for (j = 0; j < numComps; ++j) { + scanInfo.comp[j] = gFalse; + } + for (i = 0; i < scanInfo.numComps; ++i) { id = str->getChar(); for (j = 0; j < numComps; ++j) { - if (id == compInfo[j].id) + if (id == compInfo[j].id) { break; + } } if (j == numComps) { error(getPos(), "Bad DCT component ID in scan info block"); return gFalse; } - compInfo[j].inScan = gTrue; + scanInfo.comp[j] = gTrue; c = str->getChar(); - compInfo[j].dcHuffTable = (c >> 4) & 0x0f; - compInfo[j].acHuffTable = c & 0x0f; + scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; + scanInfo.acHuffTable[j] = c & 0x0f; } - str->getChar(); - str->getChar(); - str->getChar(); + scanInfo.firstCoeff = str->getChar(); + scanInfo.lastCoeff = str->getChar(); + c = str->getChar(); + scanInfo.ah = (c >> 4) & 0x0f; + scanInfo.al = c & 0x0f; return gTrue; } @@ -2779,17 +3026,25 @@ GBool DCTStream::readAdobeMarker() { int c; length = read16(); - if (length != 14) + if (length < 14) { goto err; + } for (i = 0; i < 12; ++i) { - if ((c = str->getChar()) == EOF) + if ((c = str->getChar()) == EOF) { goto err; + } buf[i] = c; } - if (strncmp(buf, "Adobe", 5)) + if (strncmp(buf, "Adobe", 5)) { goto err; + } colorXform = buf[11]; gotAdobeMarker = gTrue; + for (i = 14; i < length; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } return gTrue; err: @@ -2927,9 +3182,13 @@ FlateStream::FlateStream(Stream *strA, int predictor, int columns, } else { pred = NULL; } + litCodeTab.codes = NULL; + distCodeTab.codes = NULL; } FlateStream::~FlateStream() { + gfree(litCodeTab.codes); + gfree(distCodeTab.codes); if (pred) { delete pred; } @@ -3096,6 +3355,12 @@ GBool FlateStream::startBlock() { int c; int check; + // free the code tables from the previous block + gfree(litCodeTab.codes); + litCodeTab.codes = NULL; + gfree(distCodeTab.codes); + distCodeTab.codes = NULL; + // read block header blockHdr = getCodeWord(3); if (blockHdr & 1) @@ -3130,8 +3395,9 @@ GBool FlateStream::startBlock() { // compressed block with dynamic codes } else if (blockHdr == 2) { compressedBlock = gTrue; - if (!readDynamicCodes()) + if (!readDynamicCodes()) { goto err; + } // unknown block type } else { @@ -3150,186 +3416,182 @@ err: void FlateStream::loadFixedCodes() { int i; - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + flateMaxLitCodes; - - // initialize literal code table - for (i = 0; i <= 143; ++i) - litCodeTab.codes[i].len = 8; - for (i = 144; i <= 255; ++i) - litCodeTab.codes[i].len = 9; - for (i = 256; i <= 279; ++i) - litCodeTab.codes[i].len = 7; - for (i = 280; i <= 287; ++i) - litCodeTab.codes[i].len = 8; - compHuffmanCodes(&litCodeTab, flateMaxLitCodes); - - // initialize distance code table - for (i = 0; i <= 5; ++i) { - distCodeTab.start[i] = 0; + // build the literal code table + for (i = 0; i <= 143; ++i) { + codeLengths[i] = 8; + } + for (i = 144; i <= 255; ++i) { + codeLengths[i] = 9; } - for (i = 6; i <= flateMaxHuffman+1; ++i) { - distCodeTab.start[i] = flateMaxDistCodes; + for (i = 256; i <= 279; ++i) { + codeLengths[i] = 7; } + for (i = 280; i <= 287; ++i) { + codeLengths[i] = 8; + } + compHuffmanCodes(codeLengths, flateMaxLitCodes, &litCodeTab); + + // build the distance code table for (i = 0; i < flateMaxDistCodes; ++i) { - distCodeTab.codes[i].len = 5; - distCodeTab.codes[i].code = i; - distCodeTab.codes[i].val = i; + codeLengths[i] = 5; } + compHuffmanCodes(codeLengths, flateMaxDistCodes, &distCodeTab); } GBool FlateStream::readDynamicCodes() { int numCodeLenCodes; int numLitCodes; int numDistCodes; - FlateCode codeLenCodes[flateMaxCodeLenCodes]; + int codeLenCodeLengths[flateMaxCodeLenCodes]; FlateHuffmanTab codeLenCodeTab; int len, repeat, code; int i; // read lengths - if ((numLitCodes = getCodeWord(5)) == EOF) + if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; + } numLitCodes += 257; - if ((numDistCodes = getCodeWord(5)) == EOF) + if ((numDistCodes = getCodeWord(5)) == EOF) { goto err; + } numDistCodes += 1; - if ((numCodeLenCodes = getCodeWord(4)) == EOF) + if ((numCodeLenCodes = getCodeWord(4)) == EOF) { goto err; + } numCodeLenCodes += 4; if (numLitCodes > flateMaxLitCodes || numDistCodes > flateMaxDistCodes || - numCodeLenCodes > flateMaxCodeLenCodes) + numCodeLenCodes > flateMaxCodeLenCodes) { goto err; + } - // read code length code table - codeLenCodeTab.codes = codeLenCodes; - for (i = 0; i < flateMaxCodeLenCodes; ++i) - codeLenCodes[i].len = 0; + // build the code length code table + for (i = 0; i < flateMaxCodeLenCodes; ++i) { + codeLenCodeLengths[i] = 0; + } for (i = 0; i < numCodeLenCodes; ++i) { - if ((codeLenCodes[codeLenCodeMap[i]].len = getCodeWord(3)) == -1) + if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { goto err; + } } - compHuffmanCodes(&codeLenCodeTab, flateMaxCodeLenCodes); - - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + numLitCodes; + compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); - // read literal and distance code tables + // build the literal and distance code tables len = 0; repeat = 0; i = 0; while (i < numLitCodes + numDistCodes) { - if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) + if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { goto err; + } if (code == 16) { - if ((repeat = getCodeWord(2)) == EOF) + if ((repeat = getCodeWord(2)) == EOF) { goto err; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = len; + } + for (repeat += 3; repeat > 0; --repeat) { + codeLengths[i++] = len; + } } else if (code == 17) { - if ((repeat = getCodeWord(3)) == EOF) + if ((repeat = getCodeWord(3)) == EOF) { goto err; + } len = 0; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (repeat += 3; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else if (code == 18) { - if ((repeat = getCodeWord(7)) == EOF) + if ((repeat = getCodeWord(7)) == EOF) { goto err; + } len = 0; - for (repeat += 11; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (repeat += 11; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else { - allCodes[i++].len = len = code; + codeLengths[i++] = len = code; } } - compHuffmanCodes(&litCodeTab, numLitCodes); - compHuffmanCodes(&distCodeTab, numDistCodes); + compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); + compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); + gfree(codeLenCodeTab.codes); return gTrue; err: error(getPos(), "Bad dynamic code table in flate stream"); + gfree(codeLenCodeTab.codes); return gFalse; } -// On entry, the codes> array contains the lengths of each code, -// stored in code value order. This function computes the code words. -// The result is sorted in order of (1) code length and (2) code word. -// The length values are no longer valid. The start> array is -// filled with the indexes of the first code of each length. -void FlateStream::compHuffmanCodes(FlateHuffmanTab *tab, int n) { - int numLengths[flateMaxHuffman+1]; - int nextCode[flateMaxHuffman+1]; - int nextIndex[flateMaxHuffman+2]; - int code; - int i, j; +// Convert an array of lengths, in value order, into a +// Huffman code lookup table. +void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { + int tabSize, len, code, code2, skip, val, i, t; - // count number of codes for each code length - for (i = 0; i <= flateMaxHuffman; ++i) - numLengths[i] = 0; - for (i = 0; i < n; ++i) - ++numLengths[tab->codes[i].len]; + // find max code length + tab->maxLen = 0; + for (val = 0; val < n; ++val) { + if (lengths[val] > tab->maxLen) { + tab->maxLen = lengths[val]; + } + } - // compute first index for each length - tab->start[0] = nextIndex[0] = 0; - for (i = 1; i <= flateMaxHuffman + 1; ++i) - tab->start[i] = nextIndex[i] = tab->start[i-1] + numLengths[i-1]; + // allocate the table + tabSize = 1 << tab->maxLen; + tab->codes = (FlateCode *)gmalloc(tabSize * sizeof(FlateCode)); - // compute first code for each length - code = 0; - numLengths[0] = 0; - for (i = 1; i <= flateMaxHuffman; ++i) { - code = (code + numLengths[i-1]) << 1; - nextCode[i] = code; + // clear the table + for (i = 0; i < tabSize; ++i) { + tab->codes[i].len = 0; + tab->codes[i].val = 0; } - // compute the codes -- this permutes the codes array from value - // order to length/code order - for (i = 0; i < n; ++i) { - j = nextIndex[tab->codes[i].len]++; - if (tab->codes[i].len == 0) - tab->codes[j].code = 0; - else - tab->codes[j].code = nextCode[tab->codes[i].len]++; - tab->codes[j].val = i; + // build the table + for (len = 1, code = 0, skip = 2; + len <= tab->maxLen; + ++len, code <<= 1, skip <<= 1) { + for (val = 0; val < n; ++val) { + if (lengths[val] == len) { + + // bit-reverse the code + code2 = 0; + t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill in the table entries + for (i = code2; i < tabSize; i += skip) { + tab->codes[i].len = (Gushort)len; + tab->codes[i].val = (Gushort)val; + } + + ++code; + } + } } } int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { - int len; - int code; + FlateCode *code; int c; - int i, j; - - code = 0; - for (len = 1; len <= flateMaxHuffman; ++len) { - - // add a bit to the code - if (codeSize == 0) { - if ((c = str->getChar()) == EOF) - return EOF; - codeBuf = c & 0xff; - codeSize = 8; - } - code = (code << 1) | (codeBuf & 1); - codeBuf >>= 1; - --codeSize; - // look for code - i = tab->start[len]; - j = tab->start[len + 1]; - if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) { - i += code - tab->codes[i].code; - return tab->codes[i].val; + while (codeSize < tab->maxLen) { + if ((c = str->getChar()) == EOF) { + break; } + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; } - - // not found - error(getPos(), "Bad code (%04x) in flate stream", code); - return EOF; + code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; + if (codeSize == 0 || codeSize < code->len || code->len == 0) { + return EOF; + } + codeBuf >>= code->len; + codeSize -= code->len; + return (int)code->val; } int FlateStream::getCodeWord(int bits) { diff --git a/pdf/xpdf/Stream.h b/pdf/xpdf/Stream.h index 3319dcc..b0a0c26 100644 --- a/pdf/xpdf/Stream.h +++ b/pdf/xpdf/Stream.h @@ -9,7 +9,9 @@ #ifndef STREAM_H #define STREAM_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -33,6 +35,7 @@ enum StreamKind { strCCITTFax, strDCT, strFlate, + strJBIG2, strWeird // internal-use stream types }; @@ -190,6 +193,10 @@ public: // at least nComps elements. Returns false at end of file. GBool getPixel(Guchar *pix); + // Returns a pointer to the next line of pixels. Returns NULL at + // end of file. + Guchar *getLine(); + // Skip an entire line from the image. void skipLine(); @@ -419,18 +426,26 @@ private: StreamPredictor *pred; // predictor int early; // early parameter - FILE *zPipe; // uncompress pipe - GString *zName; // .Z file name + GBool eof; // true if at eof int inputBuf; // input buffer int inputBits; // number of bits in input buffer - int inCodeBits; // size of input code - char buf[256]; // buffer - char *bufPtr; // next char to read - char *bufEnd; // end of buffer - - void dumpFile(FILE *f); + struct { // decoding table + int length; + int head; + Guchar tail; + } table[4097]; + int nextCode; // next code to be used + int nextBits; // number of bits in next code word + int prevCode; // previous code used in stream + int newChar; // next char to be added to table + Guchar seqBuf[4097]; // buffer for current sequence + int seqLength; // length of current sequence + int seqIndex; // index into current sequence + GBool first; // first code after a table clear + + GBool processNextCode(); + void clearTable(); int getCode(); - GBool fillBuf(); }; //------------------------------------------------------------------------ @@ -517,13 +532,21 @@ private: // DCT component info struct DCTCompInfo { int id; // component ID - GBool inScan; // is this component in the current scan? int hSample, vSample; // horiz/vert sampling resolutions int quantTable; // quantization table number - int dcHuffTable, acHuffTable; // Huffman table numbers int prevDC; // DC coefficient accumulator }; +struct DCTScanInfo { + GBool comp[4]; // comp[i] is set if component i is + // included in this scan + int numComps; // number of components in the scan + int dcHuffTable[4]; // DC Huffman table numbers + int acHuffTable[4]; // AC Huffman table numbers + int firstCoeff, lastCoeff; // first and last DCT coefficient + int ah, al; // successive approximation parameters +}; + // DCT Huffman decoding table struct DCTHuffTable { Guchar firstSym[17]; // first symbol for this bit length @@ -547,9 +570,13 @@ public: private: + GBool progressive; // set if in progressive mode + GBool interleaved; // set if in interleaved mode int width, height; // image size int mcuWidth, mcuHeight; // size of min coding unit, in data units + int bufWidth, bufHeight; // frameBuf size DCTCompInfo compInfo[4]; // info for each component + DCTScanInfo scanInfo; // info for the current scan int numComps; // number of components in image int colorXform; // need YCbCr-to-RGB transform? GBool gotAdobeMarker; // set if APP14 Adobe marker was present @@ -560,22 +587,33 @@ private: DCTHuffTable acHuffTables[4]; // AC Huffman tables int numDCHuffTables; // number of DC Huffman tables int numACHuffTables; // number of AC Huffman tables - Guchar *rowBuf[4][32]; // buffer for one MCU + Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) + int *frameBuf[4]; // buffer for frame (progressive mode) int comp, x, y, dy; // current position within image/MCU int restartCtr; // MCUs left until restart int restartMarker; // next restart marker + int eobRun; // number of EOBs left in the current run int inputBuf; // input buffer for variable length codes int inputBits; // number of valid bits in input buffer void restart(); GBool readMCURow(); - GBool readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, Guchar data[64]); + void readScan(); + GBool readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + void decodeImage(); + void transformDataUnit(Guchar *quantTable, + int dataIn[64], Guchar dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); int readBit(); GBool readHeader(); - GBool readFrameInfo(); + GBool readBaselineSOF(); + GBool readProgressiveSOF(); GBool readScanInfo(); GBool readQuantTables(); GBool readHuffmanTables(); @@ -599,15 +637,13 @@ private: // Huffman code table entry struct FlateCode { - int len; // code length in bits - int code; // code word - int val; // value represented by this code + Gushort len; // code length, in bits + Gushort val; // value represented by this code }; -// Huffman code table struct FlateHuffmanTab { - int start[flateMaxHuffman+2]; // indexes of first code of each length - FlateCode *codes; // codes, sorted by length and code word + FlateCode *codes; + int maxLen; }; // Decoding info for length and distance code words @@ -638,8 +674,8 @@ private: int remain; // number valid bytes in output buffer int codeBuf; // input buffer int codeSize; // number of bits in input buffer - FlateCode // literal and distance codes - allCodes[flateMaxLitCodes + flateMaxDistCodes]; + int // literal and distance code lengths + codeLengths[flateMaxLitCodes + flateMaxDistCodes]; FlateHuffmanTab litCodeTab; // literal code table FlateHuffmanTab distCodeTab; // distance code table GBool compressedBlock; // set if reading a compressed block @@ -658,7 +694,7 @@ private: GBool startBlock(); void loadFixedCodes(); GBool readDynamicCodes(); - void compHuffmanCodes(FlateHuffmanTab *tab, int n); + void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; diff --git a/pdf/xpdf/TextOutputDev.cc b/pdf/xpdf/TextOutputDev.cc index 5e5761f..891752c 100644 --- a/pdf/xpdf/TextOutputDev.cc +++ b/pdf/xpdf/TextOutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -31,14 +32,100 @@ #endif //------------------------------------------------------------------------ + +#define textOutSpace 0.2 +#define textOutColSpace 0.2 + +//------------------------------------------------------------------------ + +struct TextOutColumnEdge { + double x, y0, y1; +}; + +//------------------------------------------------------------------------ +// TextBlock +//------------------------------------------------------------------------ + +class TextBlock { +public: + + TextBlock(); + ~TextBlock(); + + double xMin, xMax; + double yMin, yMax; + TextString *strings; // list of strings in the block + TextBlock *next; // next block in line + TextBlock *xyNext; // next block on xyBlocks list + Unicode *text; // Unicode text of the block, including + // spaces between strings + double *xRight; // right-hand x coord of each char + int len; // total number of Unicode characters + int convertedLen; // total number of converted characters + int *col; // starting column number for each + // Unicode character +}; + +TextBlock::TextBlock() { + strings = NULL; + next = NULL; + xyNext = NULL; + text = NULL; + xRight = NULL; + col = NULL; +} + +TextBlock::~TextBlock() { + TextString *p1, *p2; + + for (p1 = strings; p1; p1 = p2) { + p2 = p1->next; + delete p1; + } + gfree(text); + gfree(xRight); + gfree(col); +} + +//------------------------------------------------------------------------ +// TextLine +//------------------------------------------------------------------------ + +class TextLine { +public: + + TextLine(); + ~TextLine(); + + TextBlock *blocks; + TextLine *next; + double yMin, yMax; +}; + +TextLine::TextLine() { + blocks = NULL; + next = NULL; +} + +TextLine::~TextLine() { + TextBlock *p1, *p2; + + for (p1 = blocks; p1; p1 = p2) { + p2 = p1->next; + delete p1; + } +} + +//------------------------------------------------------------------------ // TextString //------------------------------------------------------------------------ -TextString::TextString(GfxState *state, double fontSize) { +TextString::TextString(GfxState *state, double x0, double y0, + double fontSize) { GfxFont *font; double x, y; - state->transform(state->getCurX(), state->getCurY(), &x, &y); + state->transform(x0, y0, &x, &y); if ((font = state->getFont())) { yMin = y - font->getAscent() * fontSize; yMax = y - font->getDescent() * fontSize; @@ -54,14 +141,14 @@ TextString::TextString(GfxState *state, double fontSize) { yMin = y; yMax = y + 1; } - col = 0; + marked = gFalse; text = NULL; xRight = NULL; len = size = 0; - yxNext = NULL; - xyNext = NULL; + next = NULL; } + TextString::~TextString() { gfree(text); gfree(xRight); @@ -90,10 +177,11 @@ TextPage::TextPage(GBool rawOrderA) { rawOrder = rawOrderA; curStr = NULL; fontSize = 0; - yxStrings = NULL; xyStrings = NULL; - yxCur1 = yxCur2 = NULL; + xyCur1 = xyCur2 = NULL; + lines = NULL; nest = 0; + nTinyChars = 0; } TextPage::~TextPage() { @@ -104,7 +192,7 @@ void TextPage::updateFont(GfxState *state) { GfxFont *font; double *fm; char *name; - int code; + int code, mCode, letterCode, anyCode; double w; // adjust the font size @@ -116,18 +204,33 @@ void TextPage::updateFont(GfxState *state) { // rendering the font. This code tries to guess by looking at the // width of the character 'm' (which breaks if the font is a // subset that doesn't contain 'm'). + mCode = letterCode = anyCode = -1; for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)font)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; + name = ((Gfx8BitFont *)font)->getCharName(code); + if (name && name[0] == 'm' && name[1] == '\0') { + mCode = code; } - } - if (code < 256) { - w = ((Gfx8BitFont *)font)->getWidth(code); - if (w != 0) { - // 600 is a generic average 'm' width -- yes, this is a hack - fontSize *= w / 0.6; + if (letterCode < 0 && name && name[1] == '\0' && + ((name[0] >= 'A' && name[0] <= 'Z') || + (name[0] >= 'a' && name[0] <= 'z'))) { + letterCode = code; } + if (anyCode < 0 && name && ((Gfx8BitFont *)font)->getWidth(code) > 0) { + anyCode = code; + } + } + if (mCode >= 0 && + (w = ((Gfx8BitFont *)font)->getWidth(mCode)) > 0) { + // 0.6 is a generic average 'm' width -- yes, this is a hack + fontSize *= w / 0.6; + } else if (letterCode >= 0 && + (w = ((Gfx8BitFont *)font)->getWidth(letterCode)) > 0) { + // even more of a hack: 0.5 is a generic letter width + fontSize *= w / 0.5; + } else if (anyCode >= 0 && + (w = ((Gfx8BitFont *)font)->getWidth(anyCode)) > 0) { + // better than nothing: 0.5 is a generic character width + fontSize *= w / 0.5; } fm = font->getFontMatrix(); if (fm[0] != 0) { @@ -136,7 +239,7 @@ void TextPage::updateFont(GfxState *state) { } } -void TextPage::beginString(GfxState *state) { +void TextPage::beginString(GfxState *state, double x0, double y0) { // This check is needed because Type 3 characters can contain // text-drawing operations. if (curStr) { @@ -144,7 +247,7 @@ void TextPage::beginString(GfxState *state) { return; } - curStr = new TextString(state, fontSize); + curStr = new TextString(state, x0, y0, fontSize); } void TextPage::addChar(GfxState *state, double x, double y, @@ -153,17 +256,33 @@ void TextPage::addChar(GfxState *state, double x, double y, int n, i; state->transform(x, y, &x1, &y1); - n = curStr->len; - if (n > 0 && - x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) { - endString(); - beginString(state); + if (x1 < 0 || x1 > state->getPageWidth() || + y1 < 0 || y1 > state->getPageHeight()) { + return; } state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(), 0, &dx2, &dy2); dx -= dx2; dy -= dy2; state->transformDelta(dx, dy, &w1, &h1); + if (!globalParams->getTextKeepTinyChars() && + fabs(w1) < 3 && fabs(h1) < 3) { + if (++nTinyChars > 20000) { + return; + } + } + n = curStr->len; + if (n > 0 && x1 - curStr->xRight[n-1] > + 0.1 * (curStr->yMax - curStr->yMin)) { + // large char spacing is sometimes used to move text around + endString(); + beginString(state, x, y); + } + if (uLen == 1 && u[0] == (Unicode)0x20 && + w1 > 0.5 * (curStr->yMax - curStr->yMin)) { + // large word spacing is sometimes used to move text around + return; + } if (uLen != 0) { w1 /= uLen; h1 /= uLen; @@ -174,9 +293,6 @@ void TextPage::addChar(GfxState *state, double x, double y, } void TextPage::endString() { - TextString *p1, *p2; - double h, y1, y2; - // This check is needed because Type 3 characters can contain // text-drawing operations. if (nest > 0) { @@ -184,58 +300,72 @@ void TextPage::endString() { return; } + addString(curStr); + curStr = NULL; +} + +void TextPage::addString(TextString *str) { + TextString *p1, *p2; + // throw away zero-length strings -- they don't have valid xMin/xMax // values, and they're useless anyway - if (curStr->len == 0) { - delete curStr; - curStr = NULL; + if (str->len == 0) { + delete str; return; } - // insert string in y-major list - h = curStr->yMax - curStr->yMin; - y1 = curStr->yMin + 0.5 * h; - y2 = curStr->yMin + 0.8 * h; + // insert string in xy list if (rawOrder) { - p1 = yxCur1; + p1 = xyCur1; p2 = NULL; - } else if ((!yxCur1 || - (y1 >= yxCur1->yMin && - (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) && - (!yxCur2 || - (y1 < yxCur2->yMin || - (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) { - p1 = yxCur1; - p2 = yxCur2; + } else if ((!xyCur1 || xyBefore(xyCur1, str)) && + (!xyCur2 || xyBefore(str, xyCur2))) { + p1 = xyCur1; + p2 = xyCur2; + } else if (xyCur1 && xyBefore(xyCur1, str)) { + for (p1 = xyCur1, p2 = xyCur2; p2; p1 = p2, p2 = p2->next) { + if (xyBefore(str, p2)) { + break; + } + } + xyCur2 = p2; } else { - for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) { - if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin)) { + for (p1 = NULL, p2 = xyStrings; p2; p1 = p2, p2 = p2->next) { + if (xyBefore(str, p2)) { break; } } - yxCur2 = p2; + xyCur2 = p2; } - yxCur1 = curStr; + xyCur1 = str; if (p1) { - p1->yxNext = curStr; + p1->next = str; } else { - yxStrings = curStr; + xyStrings = str; } - curStr->yxNext = p2; - curStr = NULL; + str->next = p2; } void TextPage::coalesce() { - TextString *str1, *str2; - double space, d; - GBool addSpace; - int n, i; + TextLine *line, *line0; + TextBlock *yxBlocks, *xyBlocks, *blk, *blk0, *blk1, *blk2; + TextString *str0, *str1, *str2, *str3, *str4; + TextString *str1prev, *str2prev, *str3prev; + TextOutColumnEdge *edges; + UnicodeMap *uMap; + GBool isUnicode; + char buf[8]; + int edgesLength, edgesSize; + double x, yMin, yMax; + double space, fit1, fit2, h; + int col1, col2, d; + int i, j; #if 0 //~ for debugging - for (str1 = yxStrings; str1; str1 = str1->yxNext) { - printf("x=%3d..%3d y=%3d..%3d size=%2d '", - (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax, - (int)(str1->yMax - str1->yMin)); + for (str1 = xyStrings; str1; str1 = str1->next) { + printf("x=%.2f..%.2f y=%.2f..%.2f size=%.2f '", + str1->xMin, str1->xMax, str1->yMin, str1->yMax, + (str1->yMax - str1->yMin)); for (i = 0; i < str1->len; ++i) { fputc(str1->text[i] & 0xff, stdout); } @@ -243,123 +373,493 @@ void TextPage::coalesce() { } printf("\n------------------------------------------------------------\n\n"); #endif - str1 = yxStrings; - while (str1 && (str2 = str1->yxNext)) { - space = str1->yMax - str1->yMin; - d = str2->xMin - str1->xMax; - if (((rawOrder && - ((str2->yMin >= str1->yMin && str2->yMin <= str1->yMax) || - (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax))) || - (!rawOrder && str2->yMin < str1->yMax)) && - d > -0.5 * space && d < space) { - n = str1->len + str2->len; - if ((addSpace = d > 0.1 * space)) { - ++n; - } - str1->size = (n + 15) & ~15; - str1->text = (Unicode *)grealloc(str1->text, - str1->size * sizeof(Unicode)); - str1->xRight = (double *)grealloc(str1->xRight, - str1->size * sizeof(double)); - if (addSpace) { - str1->text[str1->len] = 0x20; - str1->xRight[str1->len] = str2->xMin; - ++str1->len; - } - for (i = 0; i < str2->len; ++i) { - str1->text[str1->len] = str2->text[i]; - str1->xRight[str1->len] = str2->xRight[i]; - ++str1->len; - } - if (str2->xMax > str1->xMax) { - str1->xMax = str2->xMax; - } - if (str2->yMax > str1->yMax) { - str1->yMax = str2->yMax; - } - str1->yxNext = str2->yxNext; - delete str2; + + // build the list of column edges + edges = NULL; + edgesLength = edgesSize = 0; + if (!rawOrder) { + for (str1prev = NULL, str1 = xyStrings; + str1; + str1prev = str1, str1 = str1->next) { + if (str1->marked) { + continue; + } + h = str1->yMax - str1->yMin; + if (str1prev && (str1->xMin - str1prev->xMax) / h < textOutColSpace) { + continue; + } + x = str1->xMin; + yMin = str1->yMin; + yMax = str1->yMax; + for (str2prev = str1, str2 = str1->next; + str2; + str2prev = str2, str2 = str2->next) { + h = str2->yMax - str2->yMin; + if (!str2->marked && + (str2->xMin - str2prev->xMax) / h > textOutColSpace && + fabs(str2->xMin - x) < 0.5 && + str2->yMin - yMax < 0.3 * h && + yMin - str2->yMax < 0.3 * h) { + break; + } + } + if (str2) { + if (str2->yMin < yMin) { + yMin = str2->yMin; + } + if (str2->yMax > yMax) { + yMax = str2->yMax; + } + str2->marked = gTrue; + for (str3prev = str1, str3 = str1->next; + str3; + str3prev = str3, str3 = str3->next) { + h = str3->yMax - str3->yMin; + if (!str3->marked && + (str3->xMin - str3prev->xMax) / h > textOutColSpace && + fabs(str3->xMin - x) < 0.5 && + str3->yMin - yMax < 0.3 * h && + yMin - str3->yMax < 0.3 * h) { + break; + } + } + if (str3) { + if (str3->yMin < yMin) { + yMin = str3->yMin; + } + if (str3->yMax > yMax) { + yMax = str3->yMax; + } + str3->marked = gTrue; + do { + for (str2prev = str1, str2 = str1->next; + str2; + str2prev = str2, str2 = str2->next) { + h = str2->yMax - str2->yMin; + if (!str2->marked && + (str2->xMin - str2prev->xMax) / h > textOutColSpace && + fabs(str2->xMin - x) < 0.5 && + str2->yMin - yMax < 0.3 * h && + yMin - str2->yMax < 0.3 * h) { + if (str2->yMin < yMin) { + yMin = str2->yMin; + } + if (str2->yMax > yMax) { + yMax = str2->yMax; + } + str2->marked = gTrue; + break; + } + } + } while (str2); + if (edgesLength == edgesSize) { + edgesSize = edgesSize ? 2 * edgesSize : 16; + edges = (TextOutColumnEdge *) + grealloc(edges, edgesSize * sizeof(TextOutColumnEdge)); + } + edges[edgesLength].x = x; + edges[edgesLength].y0 = yMin; + edges[edgesLength].y1 = yMax; + ++edgesLength; + } else { + str2->marked = gFalse; + } + } + str1->marked = gTrue; + } + } + +#if 0 //~ for debugging + printf("column edges:\n"); + for (i = 0; i < edgesLength; ++i) { + printf("%d: x=%.2f y0=%.2f y1=%.2f\n", + i, edges[i].x, edges[i].y0, edges[i].y1); + } + printf("\n------------------------------------------------------------\n\n"); +#endif + + // build the blocks + yxBlocks = NULL; + blk1 = blk2 = NULL; + while (xyStrings) { + + // build the block + str0 = xyStrings; + xyStrings = xyStrings->next; + str0->next = NULL; + blk = new TextBlock(); + blk->strings = str0; + blk->xMin = str0->xMin; + blk->xMax = str0->xMax; + blk->yMin = str0->yMin; + blk->yMax = str0->yMax; + while (xyStrings) { + str1 = NULL; + str2 = xyStrings; + fit1 = coalesceFit(str0, str2); + if (!rawOrder) { + // look for best-fitting string + space = str0->yMax - str0->yMin; + for (str3 = xyStrings, str4 = xyStrings->next; + str4 && str4->xMin - str0->xMax <= space; + str3 = str4, str4 = str4->next) { + fit2 = coalesceFit(str0, str4); + if (fit2 < fit1) { + str1 = str3; + str2 = str4; + fit1 = fit2; + } + } + } + if (fit1 > 1) { + // no fit - we're done with this block + break; + } + + // if we've hit a column edge we're done with this block + if (fit1 > 0.2) { + for (i = 0; i < edgesLength; ++i) { + if (str0->xMax < edges[i].x + 0.5 && edges[i].x - 0.5 < str2->xMin && + str0->yMin < edges[i].y1 && str0->yMax > edges[i].y0 && + str2->yMin < edges[i].y1 && str2->yMax > edges[i].y0) { + break; + } + } + if (i < edgesLength) { + break; + } + } + + if (str1) { + str1->next = str2->next; + } else { + xyStrings = str2->next; + } + str0->next = str2; + str2->next = NULL; + if (str2->xMax > blk->xMax) { + blk->xMax = str2->xMax; + } + if (str2->yMin < blk->yMin) { + blk->yMin = str2->yMin; + } + if (str2->yMax > blk->yMax) { + blk->yMax = str2->yMax; + } + str0 = str2; + } + + // insert block on list + if (!rawOrder) { + // insert block on list in yx order + for (blk1 = NULL, blk2 = yxBlocks; + blk2 && !yxBefore(blk, blk2); + blk1 = blk2, blk2 = blk2->next) ; + } + blk->next = blk2; + if (blk1) { + blk1->next = blk; + } else { + yxBlocks = blk; + } + blk1 = blk; + } + + gfree(edges); + + // the strings are now owned by the lines/blocks tree + xyStrings = NULL; + + // build the block text + uMap = globalParams->getTextEncoding(); + isUnicode = uMap ? uMap->isUnicode() : gFalse; + for (blk = yxBlocks; blk; blk = blk->next) { + blk->len = 0; + for (str1 = blk->strings; str1; str1 = str1->next) { + blk->len += str1->len; + if (str1->next && str1->next->xMin - str1->xMax > + textOutSpace * (str1->yMax - str1->yMin)) { + str1->spaceAfter = gTrue; + ++blk->len; + } else { + str1->spaceAfter = gFalse; + } + } + blk->text = (Unicode *)gmalloc(blk->len * sizeof(Unicode)); + blk->xRight = (double *)gmalloc(blk->len * sizeof(double)); + blk->col = (int *)gmalloc(blk->len * sizeof(int)); + i = 0; + for (str1 = blk->strings; str1; str1 = str1->next) { + for (j = 0; j < str1->len; ++j) { + blk->text[i] = str1->text[j]; + blk->xRight[i] = str1->xRight[j]; + ++i; + } + if (str1->spaceAfter) { + blk->text[i] = (Unicode)0x0020; + blk->xRight[i] = str1->next->xMin; + ++i; + } + } + blk->convertedLen = 0; + for (j = 0; j < blk->len; ++j) { + blk->col[j] = blk->convertedLen; + if (isUnicode) { + ++blk->convertedLen; + } else if (uMap) { + blk->convertedLen += uMap->mapUnicode(blk->text[j], buf, sizeof(buf)); + } + } + } + if (uMap) { + uMap->decRefCnt(); + } + +#if 0 //~ for debugging + for (blk = yxBlocks; blk; blk = blk->next) { + printf("[block: x=%.2f..%.2f y=%.2f..%.2f len=%d]\n", + blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->len); + TextString *str; + for (str = blk->strings; str; str = str->next) { + printf(" x=%.2f..%.2f y=%.2f..%.2f size=%.2f'", + str->xMin, str->xMax, str->yMin, str->yMax, + (str->yMax - str->yMin)); + for (i = 0; i < str->len; ++i) { + fputc(str->text[i] & 0xff, stdout); + } + if (str->spaceAfter) { + fputc(' ', stdout); + } + printf("'\n"); + } + } + printf("\n------------------------------------------------------------\n\n"); +#endif + + // build the lines + lines = NULL; + line0 = NULL; + while (yxBlocks) { + blk0 = yxBlocks; + yxBlocks = yxBlocks->next; + blk0->next = NULL; + line = new TextLine(); + line->blocks = blk0; + line->yMin = blk0->yMin; + line->yMax = blk0->yMax; + while (yxBlocks) { + + // remove duplicated text (fake boldface, shadowed text) + h = blk0->yMax - blk0->yMin; + if (yxBlocks->len == blk0->len && + !memcmp(yxBlocks->text, blk0->text, + yxBlocks->len * sizeof(Unicode)) && + fabs(yxBlocks->yMin - blk0->yMin) / h < 0.2 && + fabs(yxBlocks->yMax - blk0->yMax) / h < 0.2 && + fabs(yxBlocks->xMin - blk0->xMin) / h < 0.2 && + fabs(yxBlocks->xMax - blk0->xMax) / h < 0.2) { + blk1 = yxBlocks; + yxBlocks = yxBlocks->next; + delete blk1; + continue; + } + + if (rawOrder && yxBlocks->yMax < blk0->yMin) { + break; + } + if (yxBlocks->yMin > 0.2*blk0->yMin + 0.8*blk0->yMax || + yxBlocks->xMin < blk0->xMax) { + break; + } + blk1 = yxBlocks; + yxBlocks = yxBlocks->next; + blk0->next = blk1; + blk1->next = NULL; + if (blk1->yMin < line->yMin) { + line->yMin = blk1->yMin; + } + if (blk1->yMax > line->yMax) { + line->yMax = blk1->yMax; + } + blk0 = blk1; + } + if (line0) { + line0->next = line; } else { - str1 = str2; + lines = line; + } + line->next = NULL; + line0 = line; + } + + + // sort the blocks into xy order + xyBlocks = NULL; + for (line = lines; line; line = line->next) { + for (blk = line->blocks; blk; blk = blk->next) { + for (blk1 = NULL, blk2 = xyBlocks; + blk2 && !xyBefore(blk, blk2); + blk1 = blk2, blk2 = blk2->xyNext) ; + blk->xyNext = blk2; + if (blk1) { + blk1->xyNext = blk; + } else { + xyBlocks = blk; + } + } + } + +#if 0 //~ for debugging + for (blk = xyBlocks; blk; blk = blk->xyNext) { + printf("[block: x=%.2f..%.2f y=%.2f..%.2f len=%d]\n", + blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->len); + TextString *str; + for (str = blk->strings; str; str = str->next) { + printf(" x=%.2f..%.2f y=%.2f..%.2f size=%.2f '", + str->xMin, str->xMax, str->yMin, str->yMax, + (str->yMax - str->yMin)); + for (i = 0; i < str->len; ++i) { + fputc(str->text[i] & 0xff, stdout); + } + printf("'\n"); + } + } + printf("\n------------------------------------------------------------\n\n"); +#endif + + // do column assignment + for (blk1 = xyBlocks; blk1; blk1 = blk1->xyNext) { + col1 = 0; + for (blk2 = xyBlocks; blk2 != blk1; blk2 = blk2->xyNext) { + if (blk1->xMin >= blk2->xMax) { + d = (int)((blk1->xMin - blk2->xMax) / + (0.4 * (blk1->yMax - blk1->yMin))); + if (d > 4) { + d = 4; + } + col2 = blk2->col[0] + blk2->convertedLen + d; + if (col2 > col1) { + col1 = col2; + } + } else if (blk1->xMin > blk2->xMin) { + for (i = 0; i < blk2->len && blk1->xMin >= blk2->xRight[i]; ++i) ; + col2 = blk2->col[i]; + if (col2 > col1) { + col1 = col2; + } + } + } + for (j = 0; j < blk1->len; ++j) { + blk1->col[j] += col1; } } + +#if 0 //~ for debugging + for (line = lines; line; line = line->next) { + printf("[line]\n"); + for (blk = line->blocks; blk; blk = blk->next) { + printf("[block: col=%d, len=%d]\n", blk->col[0], blk->len); + TextString *str; + for (str = blk->strings; str; str = str->next) { + printf(" x=%.2f..%.2f y=%.2f..%.2f size=%.2f '", + str->xMin, str->xMax, str->yMin, str->yMax, + (str->yMax - str->yMin)); + for (i = 0; i < str->len; ++i) { + fputc(str->text[i] & 0xff, stdout); + } + if (str->spaceAfter) { + printf(" [space]\n"); + } + printf("'\n"); + } + } + } + printf("\n------------------------------------------------------------\n\n"); +#endif } + GBool TextPage::findText(Unicode *s, int len, GBool top, GBool bottom, double *xMin, double *yMin, double *xMax, double *yMax) { - TextString *str; + TextLine *line; + TextBlock *blk; Unicode *p; Unicode u1, u2; int m, i, j; - double x; + double x0, x1, x; - // scan all strings on page - for (str = yxStrings; str; str = str->yxNext) { - - // check: above top limit? - if (!top && (str->yMax < *yMin || - (str->yMin < *yMin && str->xMax <= *xMin))) { - continue; - } - - // check: below bottom limit? - if (!bottom && (str->yMin > *yMax || - (str->yMax > *yMax && str->xMin >= *xMax))) { - return gFalse; - } - - // search each position in this string - m = str->len; - for (i = 0, p = str->text; i <= m - len; ++i, ++p) { + // scan all blocks on page + for (line = lines; line; line = line->next) { + for (blk = line->blocks; blk; blk = blk->next) { // check: above top limit? - if (!top && str->yMin < *yMin) { - x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2; - if (x < *xMin) { - continue; - } + if (!top && (blk->yMax < *yMin || + (blk->yMin < *yMin && blk->xMax <= *xMin))) { + continue; } // check: below bottom limit? - if (!bottom && str->yMax > *yMax) { - x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2; - if (x > *xMax) { - return gFalse; - } + if (!bottom && (blk->yMin > *yMax || + (blk->yMax > *yMax && blk->xMin >= *xMax))) { + return gFalse; } - // compare the strings - for (j = 0; j < len; ++j) { -#if 1 //~ this lowercases Latin A-Z only -- this will eventually be - //~ extended to handle other character sets - if (p[j] >= 0x41 && p[j] <= 0x5a) { - u1 = p[j] + 0x20; - } else { - u1 = p[j]; + // search each position in this block + m = blk->len; + for (i = 0, p = blk->text; i <= m - len; ++i, ++p) { + + x0 = (i == 0) ? blk->xMin : blk->xRight[i-1]; + x1 = blk->xRight[i]; + x = 0.5 * (x0 + x1); + + // check: above top limit? + if (!top && blk->yMin < *yMin) { + if (x < *xMin) { + continue; + } } - if (s[j] >= 0x41 && s[j] <= 0x5a) { - u2 = s[j] + 0x20; - } else { - u2 = s[j]; + + // check: below bottom limit? + if (!bottom && blk->yMax > *yMax) { + if (x > *xMax) { + return gFalse; + } } + + // compare the strings + for (j = 0; j < len; ++j) { +#if 1 //~ this lowercases Latin A-Z only -- this will eventually be + //~ extended to handle other character sets + if (p[j] >= 0x41 && p[j] <= 0x5a) { + u1 = p[j] + 0x20; + } else { + u1 = p[j]; + } + if (s[j] >= 0x41 && s[j] <= 0x5a) { + u2 = s[j] + 0x20; + } else { + u2 = s[j]; + } #endif - if (u1 != u2) { - break; + if (u1 != u2) { + break; + } } - } - // found it - if (j == len) { - *xMin = (i == 0) ? str->xMin : str->xRight[i-1]; - *xMax = str->xRight[i + len - 1]; - *yMin = str->yMin; - *yMax = str->yMax; - return gTrue; + // found it + if (j == len) { + *xMin = x0; + *xMax = blk->xRight[i + len - 1]; + *yMin = blk->yMin; + *yMax = blk->yMax; + return gTrue; + } } } } + return gFalse; } @@ -367,18 +867,22 @@ GString *TextPage::getText(double xMin, double yMin, double xMax, double yMax) { GString *s; UnicodeMap *uMap; + GBool isUnicode; char space[8], eol[16], buf[8]; - int spaceLen, eolLen, n; - TextString *str1; - double x0, x1, x2, y; - double xPrev, yPrev; - int i1, i2, i; + int spaceLen, eolLen, len; + TextLine *line; + TextBlock *blk; + double x0, x1, y; + int firstCol, col, i; GBool multiLine; s = new GString(); + + // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { return s; } + isUnicode = uMap->isUnicode(); spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); eolLen = 0; // make gcc happy switch (globalParams->getTextEOL()) { @@ -393,61 +897,126 @@ GString *TextPage::getText(double xMin, double yMin, eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); break; } - xPrev = yPrev = 0; + + // find the leftmost column multiLine = gFalse; - for (str1 = yxStrings; str1; str1 = str1->yxNext) { - y = 0.5 * (str1->yMin + str1->yMax); - if (y > yMax) { + firstCol = -1; + for (line = lines; line; line = line->next) { + if (line->yMin > yMax) { break; } - if (y > yMin && str1->xMin < xMax && str1->xMax > xMin) { - x0 = x1 = x2 = str1->xMin; - for (i1 = 0; i1 < str1->len; ++i1) { - x0 = (i1==0) ? str1->xMin : str1->xRight[i1-1]; - x1 = str1->xRight[i1]; - if (0.5 * (x0 + x1) >= xMin) { - break; - } + if (line->yMax < yMin) { + continue; + } + + for (blk = line->blocks; blk && blk->xMax < xMin; blk = blk->next) ; + if (!blk || blk->xMin > xMax) { + continue; + } + + y = 0.5 * (blk->yMin + blk->yMax); + if (y < yMin || y > yMax) { + continue; + } + + if (firstCol >= 0) { + multiLine = gTrue; + } + + i = 0; + while (1) { + x0 = (i==0) ? blk->xMin : blk->xRight[i-1]; + x1 = blk->xRight[i]; + if (0.5 * (x0 + x1) > xMin) { + break; } - for (i2 = str1->len - 1; i2 > i1; --i2) { - x1 = (i2==0) ? str1->xMin : str1->xRight[i2-1]; - x2 = str1->xRight[i2]; - if (0.5 * (x1 + x2) <= xMax) { - break; - } + ++i; + } + col = blk->col[i]; + + if (firstCol < 0 || col < firstCol) { + firstCol = col; + } + } + + // extract the text + for (line = lines; line; line = line->next) { + if (line->yMin > yMax) { + break; + } + if (line->yMax < yMin) { + continue; + } + + for (blk = line->blocks; blk && blk->xMax < xMin; blk = blk->next) ; + if (!blk || blk->xMin > xMax) { + continue; + } + + y = 0.5 * (blk->yMin + blk->yMax); + if (y < yMin || y > yMax) { + continue; + } + + i = 0; + while (1) { + x0 = (i==0) ? blk->xMin : blk->xRight[i-1]; + x1 = blk->xRight[i]; + if (0.5 * (x0 + x1) > xMin) { + break; } - if (s->getLength() > 0) { - if (x0 < xPrev || str1->yMin > yPrev) { - s->append(eol, eolLen); - multiLine = gTrue; - } else { - for (i = 0; i < 4; ++i) { - s->append(space, spaceLen); - } + ++i; + } + + col = firstCol; + + do { + + // line this block up with the correct column + for (; col < blk->col[i]; ++col) { + s->append(space, spaceLen); + } + + // print the block + for (; i < blk->len; ++i) { + + x0 = (i==0) ? blk->xMin : blk->xRight[i-1]; + x1 = blk->xRight[i]; + if (0.5 * (x0 + x1) > xMax) { + break; } + + len = uMap->mapUnicode(blk->text[i], buf, sizeof(buf)); + s->append(buf, len); + col += isUnicode ? 1 : len; } - for (i = i1; i <= i2; ++i) { - n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf)); - s->append(buf, n); + if (i < blk->len) { + break; } - xPrev = x2; - yPrev = str1->yMax; + + // next block + blk = blk->next; + i = 0; + + } while (blk && blk->xMin < xMax); + + if (multiLine) { + s->append(eol, eolLen); } } - if (multiLine) { - s->append(eol, eolLen); - } + uMap->decRefCnt(); + return s; } void TextPage::dump(void *outputStream, TextOutputFunc outputFunc) { UnicodeMap *uMap; char space[8], eol[16], eop[8], buf[8]; - int spaceLen, eolLen, eopLen, n; - TextString *str1, *str2, *str3; - double yMin, yMax; - int col1, col2, d, i; + int spaceLen, eolLen, eopLen, len; + TextLine *line; + TextBlock *blk; + int col, d, i; // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { @@ -469,129 +1038,46 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc) { } eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop)); - // build x-major list - xyStrings = NULL; - for (str1 = yxStrings; str1; str1 = str1->yxNext) { - for (str2 = NULL, str3 = xyStrings; - str3; - str2 = str3, str3 = str3->xyNext) { - if (str1->xMin < str3->xMin || - (str1->xMin == str3->xMin && str1->yMin < str3->yMin)) { - break; - } - } - if (str2) { - str2->xyNext = str1; - } else { - xyStrings = str1; - } - str1->xyNext = str3; - } - - // do column assignment - for (str1 = xyStrings; str1; str1 = str1->xyNext) { - col1 = 0; - for (str2 = xyStrings; str2 != str1; str2 = str2->xyNext) { - if (str1->xMin >= str2->xMax) { - col2 = str2->col + str2->len + 4; - if (col2 > col1) { - col1 = col2; - } - } else if (str1->xMin > str2->xMin) { - col2 = str2->col + - (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) * - str2->len); - if (col2 > col1) { - col1 = col2; + // output + for (line = lines; line; line = line->next) { + col = 0; + for (blk = line->blocks; blk; blk = blk->next) { + + // line this block up with the correct column + if (rawOrder && col == 0) { + col = blk->col[0]; + } else { + for (; col < blk->col[0]; ++col) { + (*outputFunc)(outputStream, space, spaceLen); } } - } - str1->col = col1; - } - -#if 0 //~ for debugging - fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); - for (str1 = yxStrings; str1; str1 = str1->yxNext) { - fprintf((FILE *)outputStream, "(%4d,%4d) - (%4d,%4d) [%3d] '", - (int)str1->xMin, (int)str1->yMin, - (int)str1->xMax, (int)str1->yMax, str1->col); - for (i = 0; i < str1->len; ++i) { - fputc(str1->text[i] & 0xff, stdout); - } - printf("'\n"); - } - fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); -#endif - - // output - col1 = 0; - yMax = yxStrings ? yxStrings->yMax : 0; - for (str1 = yxStrings; str1; str1 = str1->yxNext) { - // line this string up with the correct column - if (rawOrder && col1 == 0) { - col1 = str1->col; - } else { - for (; col1 < str1->col; ++col1) { - (*outputFunc)(outputStream, space, spaceLen); + // print the block + for (i = 0; i < blk->len; ++i) { + len = uMap->mapUnicode(blk->text[i], buf, sizeof(buf)); + (*outputFunc)(outputStream, buf, len); } + col += blk->convertedLen; } - // print the string - for (i = 0; i < str1->len; ++i) { - if ((n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf))) > 0) { - (*outputFunc)(outputStream, buf, n); + // print a return + (*outputFunc)(outputStream, eol, eolLen); + + // print extra vertical space if necessary + if (line->next) { + d = (int)((line->next->yMin - line->yMax) / + (line->blocks->strings->yMax - lines->blocks->strings->yMin) + + 0.5); + // various things (weird font matrices) can result in bogus + // values here, so do a sanity check + if (rawOrder && d > 2) { + d = 2; + } else if (!rawOrder && d > 5) { + d = 5; } - } - - // increment column - col1 += str1->len; - - // update yMax for this line - if (str1->yMax > yMax) { - yMax = str1->yMax; - } - - // if we've hit the end of the line... - if (!(str1->yxNext && - !(rawOrder && str1->yxNext->yMax < str1->yMin) && - str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax && - str1->yxNext->xMin >= str1->xMax)) { - - // print a return - (*outputFunc)(outputStream, eol, eolLen); - - // print extra vertical space if necessary - if (str1->yxNext) { - - // find yMin for next line - yMin = str1->yxNext->yMin; - for (str2 = str1->yxNext; str2; str2 = str2->yxNext) { - if (str2->yMin < yMin) { - yMin = str2->yMin; - } - if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax && - str2->yxNext->xMin >= str2->xMax)) - break; - } - - // print the space - d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5); - // various things (weird font matrices) can result in bogus - // values here, so do a sanity check - if (rawOrder && d > 2) { - d = 2; - } else if (!rawOrder && d > 5) { - d = 5; - } - for (; d > 0; --d) { - (*outputFunc)(outputStream, eol, eolLen); - } + for (; d > 0; --d) { + (*outputFunc)(outputStream, eol, eolLen); } - - // set up for next line - col1 = 0; - yMax = str1->yxNext ? str1->yxNext->yMax : 0; } } @@ -603,20 +1089,89 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc) { uMap->decRefCnt(); } +// Returns true if should be inserted before in xy +// order. +GBool TextPage::xyBefore(TextString *str1, TextString *str2) { + return str1->xMin < str2->xMin || + (str1->xMin == str2->xMin && str1->yMin < str2->yMin); +} + +// Returns true if should be inserted before in xy +// order. +GBool TextPage::xyBefore(TextBlock *blk1, TextBlock *blk2) { + return blk1->xMin < blk2->xMin || + (blk1->xMin == blk2->xMin && blk1->yMin < blk2->yMin); +} + +// Returns true if should be inserted before in yx +// order, allowing a little slack for vertically overlapping text. +GBool TextPage::yxBefore(TextBlock *blk1, TextBlock *blk2) { + double h1, h2, overlap; + + h1 = blk1->yMax - blk1->yMin; + h2 = blk2->yMax - blk2->yMin; + overlap = ((blk1->yMax < blk2->yMax ? blk1->yMax : blk2->yMax) - + (blk1->yMin > blk2->yMin ? blk1->yMin : blk2->yMin)) / + (h1 < h2 ? h1 : h2); + if (overlap > 0.6) { + return blk1->xMin < blk2->xMin; + } + return blk1->yMin < blk2->yMin; +} + +double TextPage::coalesceFit(TextString *str1, TextString *str2) { + double h1, h2, w1, w2, r, overlap, spacing; + + h1 = str1->yMax - str1->yMin; + h2 = str2->yMax - str2->yMin; + w1 = str1->xMax - str1->xMin; + w2 = str2->xMax - str2->xMin; + r = h1 / h2; + if (r < (1.0 / 3.0) || r > 3) { + return 10; + } + overlap = ((str1->yMax < str2->yMax ? str1->yMax : str2->yMax) - + (str1->yMin > str2->yMin ? str1->yMin : str2->yMin)) / + (h1 < h2 ? h1 : h2); + if (overlap < 0.5) { + return 10; + } + spacing = (str2->xMin - str1->xMax) / (h1 > h2 ? h1 : h2); + if (spacing < -0.5) { + return 10; + } + // separate text that overlaps - duplicated text (so that fake + // boldface and shadowed text can be cleanly removed) + if ((str2->xMin - str1->xMax) / (w1 < w2 ? w1 : w2) < -0.7) { + return 10; + } + return spacing; +} + void TextPage::clear() { - TextString *p1, *p2; + TextLine *p1, *p2; + TextString *s1, *s2; if (curStr) { delete curStr; curStr = NULL; } - for (p1 = yxStrings; p1; p1 = p2) { - p2 = p1->yxNext; - delete p1; + if (lines) { + for (p1 = lines; p1; p1 = p2) { + p2 = p1->next; + delete p1; + } + } else if (xyStrings) { + for (s1 = xyStrings; s1; s1 = s2) { + s2 = s1->next; + delete s1; + } } - yxStrings = NULL; xyStrings = NULL; - yxCur1 = yxCur2 = NULL; + xyCur1 = xyCur2 = NULL; + lines = NULL; + nest = 0; + nTinyChars = 0; } //------------------------------------------------------------------------ @@ -691,7 +1246,7 @@ void TextOutputDev::updateFont(GfxState *state) { } void TextOutputDev::beginString(GfxState *state, GString *s) { - text->beginString(state); + text->beginString(state, state->getCurX(), state->getCurY()); } void TextOutputDev::endString(GfxState *state) { @@ -711,3 +1266,9 @@ GBool TextOutputDev::findText(Unicode *s, int len, double *xMax, double *yMax) { return text->findText(s, len, top, bottom, xMin, yMin, xMax, yMax); } + +GString *TextOutputDev::getText(double xMin, double yMin, + double xMax, double yMax) { + return text->getText(xMin, yMin, xMax, yMax); +} + diff --git a/pdf/xpdf/TextOutputDev.h b/pdf/xpdf/TextOutputDev.h index daab3c4..f681ecf 100644 --- a/pdf/xpdf/TextOutputDev.h +++ b/pdf/xpdf/TextOutputDev.h @@ -9,7 +9,9 @@ #ifndef TEXTOUTPUTDEV_H #define TEXTOUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -20,11 +22,16 @@ class GfxState; class GString; +class TextBlock; +class TextLine; + +#undef TEXTOUT_DO_SYMBOLS //------------------------------------------------------------------------ typedef void (*TextOutputFunc)(void *stream, char *text, int len); + //------------------------------------------------------------------------ // TextString //------------------------------------------------------------------------ @@ -33,7 +40,9 @@ class TextString { public: // Constructor. - TextString(GfxState *state, double fontSize); + TextString(GfxState *state, double x0, double y0, + double fontSize); + // Destructor. ~TextString(); @@ -46,15 +55,18 @@ private: double xMin, xMax; // bounding box x coordinates double yMin, yMax; // bounding box y coordinates - int col; // starting column + union { + GBool marked; // temporary flag used by coalesce() + GBool spaceAfter; // insert a space after this string? + }; Unicode *text; // the text double *xRight; // right-hand x coord of each char int len; // length of text and xRight int size; // size of text and xRight arrays - TextString *yxNext; // next string in y-major order - TextString *xyNext; // next string in x-major order + TextString *next; friend class TextPage; + friend class TextBlock; }; //------------------------------------------------------------------------ @@ -73,8 +85,9 @@ public: // Update the current font. void updateFont(GfxState *state); + // Begin a new string. - void beginString(GfxState *state); + void beginString(GfxState *state, double x0, double y0); // Add a character to the current string. void addChar(GfxState *state, double x, double y, @@ -83,6 +96,10 @@ public: // End the current string, sorting it into the list of strings. void endString(); + // Add a string, sorting it into the list of strings. + void addString(TextString *str); + + // Coalesce strings that look like parts of the same line. void coalesce(); @@ -108,16 +125,25 @@ public: private: + GBool xyBefore(TextString *str1, TextString *str2); + GBool xyBefore(TextBlock *blk1, TextBlock *blk2); + GBool yxBefore(TextBlock *blk1, TextBlock *blk2); + double coalesceFit(TextString *str1, TextString *str2); + GBool rawOrder; // keep strings in content stream order TextString *curStr; // currently active string double fontSize; // current font size - TextString *yxStrings; // strings in y-major order - TextString *xyStrings; // strings in x-major order - TextString *yxCur1, *yxCur2; // cursors for yxStrings list + TextString *xyStrings; // strings in x-major order (before + // they're sorted into lines) + TextString *xyCur1, *xyCur2; // cursors for xyStrings list + TextLine *lines; // list of lines int nest; // current nesting level (for Type 3 fonts) + + int nTinyChars; // number of "tiny" chars seen so far + }; //------------------------------------------------------------------------ @@ -177,6 +203,8 @@ public: double originX, double originY, CharCode c, Unicode *u, int uLen); + //----- path painting + //----- special access // Find a string. If is true, starts looking at top of page; @@ -189,6 +217,10 @@ public: double *xMin, double *yMin, double *xMax, double *yMax); + // Get the text which is inside the specified rectangle. + GString *getText(double xMin, double yMin, + double xMax, double yMax); + private: TextOutputFunc outputFunc; // output function @@ -198,6 +230,7 @@ private: TextPage *text; // text for the current page GBool rawOrder; // keep text in content stream order GBool ok; // set up ok? + }; #endif diff --git a/pdf/xpdf/XOutputDev.cc b/pdf/xpdf/XOutputDev.cc index 6f207d8..3c58f56 100644 --- a/pdf/xpdf/XOutputDev.cc +++ b/pdf/xpdf/XOutputDev.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -96,6 +97,12 @@ static XOutFontSubst xOutSubstFonts[16] = { }; //------------------------------------------------------------------------ + +static void outputToFile(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ // XOutputFont //------------------------------------------------------------------------ @@ -581,18 +588,30 @@ void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap, #if HAVE_T1LIB_H XOutputT1FontFile::~XOutputT1FontFile() { delete fontFile; + if (tmpFileName) { + unlink(tmpFileName->getCString()); + delete tmpFileName; + } } #endif #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) XOutputFTFontFile::~XOutputFTFontFile() { delete fontFile; + if (tmpFileName) { + unlink(tmpFileName->getCString()); + delete tmpFileName; + } } #endif #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) XOutputTTFontFile::~XOutputTTFontFile() { delete fontFile; + if (tmpFileName) { + unlink(tmpFileName->getCString()); + delete tmpFileName; + } } #endif @@ -626,8 +645,8 @@ XOutputFontCache::~XOutputFontCache() { delFonts(); } -void XOutputFontCache::startDoc(int screenNum, Colormap colormap, - GBool trueColor, +void XOutputFontCache::startDoc(int screenNum, Visual *visual, + Colormap colormap, GBool trueColor, int rMul, int gMul, int bMul, int rShift, int gShift, int bShift, Gulong *colors, int numColors) { @@ -636,8 +655,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap, #if HAVE_T1LIB_H if (t1libControl != fontRastNone) { - t1Engine = new T1FontEngine(display, DefaultVisual(display, screenNum), - depth, colormap, + t1Engine = new T1FontEngine(display, visual, depth, colormap, t1libControl == fontRastAALow || t1libControl == fontRastAAHigh, t1libControl == fontRastAAHigh); @@ -656,8 +674,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap, #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) if (freetypeControl != fontRastNone) { - ftEngine = new FTFontEngine(display, DefaultVisual(display, screenNum), - depth, colormap, + ftEngine = new FTFontEngine(display, visual, depth, colormap, freetypeControl == fontRastAALow || freetypeControl == fontRastAAHigh); if (ftEngine->isOk()) { @@ -675,8 +692,7 @@ void XOutputFontCache::startDoc(int screenNum, Colormap colormap, #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) if (freetypeControl != fontRastNone) { - ttEngine = new TTFontEngine(display, DefaultVisual(display, screenNum), - depth, colormap, + ttEngine = new TTFontEngine(display, visual, depth, colormap, freetypeControl == fontRastAALow || freetypeControl == fontRastAAHigh); if (ttEngine->isOk()) { @@ -978,7 +994,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, case displayFontT1: #if HAVE_T1LIB_H if (t1libControl != fontRastNone) { - font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gfxFont, + font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, m11, m12, m21, m22, subst); } @@ -986,7 +1002,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) if (!font) { if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gfxFont, + font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, m11, m12, m21, m22, subst); } @@ -1001,14 +1017,14 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, case displayFontTT: #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gfxFont, + font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, m11, m12, m21, m22, subst); } #endif #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) if (freetypeControl != fontRastNone) { - font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gfxFont, + font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, m11Orig, m12Orig, m21Orig, m22Orig, m11, m12, m21, m22, subst); } @@ -1074,7 +1090,7 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, return NULL; } ff = new Type1CFontFile(fontBuf, fontLen); - ff->convertToType1(f); + ff->convertToType1(outputToFile, f); delete ff; gfree(fontBuf); } else { // fontType1 @@ -1091,17 +1107,19 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, fclose(f); // create the Font - font = tryGetT1FontFromFile(xref, fileName, gfxFont, + font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); - // remove the temporary file + // on systems with Unix hard link semantics, this will remove the + // last link to the temp file unlink(fileName->getCString()); + delete fileName; // check for an external font file } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetT1FontFromFile(xref, fileName, gfxFont, + font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); @@ -1114,6 +1132,7 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref, GString *fileName, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, @@ -1134,13 +1153,18 @@ XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref, error(-1, "Couldn't create t1lib font from '%s'", fileName->getCString()); delete fontFile; + if (deleteFile) { + unlink(fileName->getCString()); + } return NULL; } // add to list id = gfxFont->getID(); t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen, - subst, fontFile)); + subst, fontFile, + deleteFile ? fileName->copy() + : (GString *)NULL)); // create the Font font = new XOutputT1Font(gfxFont->getID(), fontFile, @@ -1236,17 +1260,19 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, fclose(f); // create the Font - font = tryGetFTFontFromFile(xref, fileName, gfxFont, + font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); - // remove the temporary file + // on systems with Unix hard link semantics, this will remove the + // last link to the temp file unlink(fileName->getCString()); + delete fileName; // check for an external font file } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetFTFontFromFile(xref, fileName, gfxFont, + font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); @@ -1259,6 +1285,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, GString *fileName, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, @@ -1289,13 +1316,18 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, error(-1, "Couldn't create FreeType font from '%s'", fileName->getCString()); delete fontFile; + if (deleteFile) { + unlink(fileName->getCString()); + } return NULL; } // add to list id = gfxFont->getID(); ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen, - subst, fontFile)); + subst, fontFile, + deleteFile ? fileName->copy() + : (GString *)NULL)); // create the Font font = new XOutputFTFont(gfxFont->getID(), fontFile, @@ -1363,16 +1395,18 @@ XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref, fclose(f); // create the Font - font = tryGetTTFontFromFile(xref, fileName, gfxFont, + font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); - // remove the temporary file + // on systems with Unix hard link semantics, this will remove the + // last link to the temp file unlink(fileName->getCString()); + delete fileName; } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetTTFontFromFile(xref, fileName, gfxFont, + font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont, m11, m12, m21, m22, m11, m12, m21, m22, gFalse); @@ -1385,6 +1419,7 @@ XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref, XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref, GString *fileName, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, @@ -1412,13 +1447,18 @@ XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref, error(-1, "Couldn't create FreeType font from '%s'", fileName->getCString()); delete fontFile; + if (deleteFile) { + unlink(fileName->getCString()); + } return NULL; } // add to list id = gfxFont->getID(); ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen, - subst, fontFile)); + subst, fontFile, + deleteFile ? fileName->copy() + : (GString *)NULL)); // create the Font font = new XOutputTTFont(gfxFont->getID(), fontFile, @@ -1570,6 +1610,7 @@ struct T3GlyphStack { GC origStrokeGC; GC origFillGC; Region origClipRegion; + double origCTM4, origCTM5; double wx, wy; // untransformed glyph metrics T3GlyphStack *next; }; @@ -1578,53 +1619,63 @@ struct T3GlyphStack { // XOutputDev //------------------------------------------------------------------------ -XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA, - Colormap colormapA, GBool reverseVideoA, - unsigned long paperColor, GBool installCmap, - int rgbCubeSize) { +XOutputDev::XOutputDev(Display *displayA, int screenNumA, + Visual *visualA, Colormap colormapA, + GBool reverseVideoA, unsigned long paperColorA, + GBool installCmap, int rgbCubeSize, + int forceDepth) { XVisualInfo visualTempl; XVisualInfo *visualList; int nVisuals; Gulong mask; - XGCValues gcValues; XColor xcolor; XColor *xcolors; - int r, g, b, n, m, i; + int r, g, b, n, m; GBool ok; + // no document yet xref = NULL; - // get display/pixmap info + // display / screen / visual / colormap display = displayA; - screenNum = DefaultScreen(display); - pixmap = pixmapA; - depth = depthA; + screenNum = screenNumA; + visual = visualA; colormap = colormapA; + // no pixmap yet + pixmapW = pixmapH = 0; + // check for TrueColor visual - trueColor = gFalse; - if (depth == 0) { - depth = DefaultDepth(display, screenNum); - visualList = XGetVisualInfo(display, 0, &visualTempl, &nVisuals); - for (i = 0; i < nVisuals; ++i) { - if (visualList[i].visual == DefaultVisual(display, screenNum)) { - if (visualList[i].c_class == TrueColor) { - trueColor = gTrue; - for (mask = visualList[i].red_mask, rShift = 0; - mask && !(mask & 1); - mask >>= 1, ++rShift) ; - rMul = (int)mask; - for (mask = visualList[i].green_mask, gShift = 0; - mask && !(mask & 1); - mask >>= 1, ++gShift) ; - gMul = (int)mask; - for (mask = visualList[i].blue_mask, bShift = 0; - mask && !(mask & 1); - mask >>= 1, ++bShift) ; - bMul = (int)mask; - } - break; - } + if (forceDepth != 0) { + depth = forceDepth; + trueColor = depth >= 16; + } else { + visualTempl.visualid = XVisualIDFromVisual(visual); + visualList = XGetVisualInfo(display, VisualIDMask, + &visualTempl, &nVisuals); + if (nVisuals < 1) { + // this shouldn't happen + XFree((XPointer)visualList); + visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl, + &nVisuals); + } + depth = visualList->depth; + if (visualList->c_class == TrueColor) { + trueColor = gTrue; + for (mask = visualList->red_mask, rShift = 0; + mask && !(mask & 1); + mask >>= 1, ++rShift) ; + rMul = (int)mask; + for (mask = visualList->green_mask, gShift = 0; + mask && !(mask & 1); + mask >>= 1, ++gShift) ; + gMul = (int)mask; + for (mask = visualList->blue_mask, bShift = 0; + mask && !(mask & 1); + mask >>= 1, ++bShift) ; + bMul = (int)mask; + } else { + trueColor = gFalse; } XFree((XPointer)visualList); } @@ -1710,27 +1761,9 @@ XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA, } } - // reverse video mode + // misc parameters reverseVideo = reverseVideoA; - - // allocate GCs - gcValues.foreground = BlackPixel(display, screenNum); - gcValues.background = WhitePixel(display, screenNum); - gcValues.line_width = 0; - gcValues.line_style = LineSolid; - strokeGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - fillGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - gcValues.foreground = paperColor; - paperGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - - // no clip region yet - clipRegion = NULL; + paperColor = paperColorA; // set up the font cache and fonts gfxFont = NULL; @@ -1755,12 +1788,6 @@ XOutputDev::~XOutputDev() { for (i = 0; i < nT3Fonts; ++i) { delete t3FontCache[i]; } - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - XFreeGC(display, paperGC); - if (clipRegion) { - XDestroyRegion(clipRegion); - } delete text; } @@ -1768,7 +1795,7 @@ void XOutputDev::startDoc(XRef *xrefA) { int i; xref = xrefA; - fontCache->startDoc(screenNum, colormap, trueColor, rMul, gMul, bMul, + fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul, rShift, gShift, bShift, colors, numColors); for (i = 0; i < nT3Fonts; ++i) { delete t3FontCache[i]; @@ -1777,39 +1804,29 @@ void XOutputDev::startDoc(XRef *xrefA) { } void XOutputDev::startPage(int pageNum, GfxState *state) { - XOutputState *s; XGCValues gcValues; XRectangle rect; - // clear state stack - while (save) { - s = save; - save = save->next; - XFreeGC(display, s->strokeGC); - XFreeGC(display, s->fillGC); - XDestroyRegion(s->clipRegion); - delete s; - } - save = NULL; - // default line flatness flatness = 0; - // reset GCs + // allocate GCs gcValues.foreground = BlackPixel(display, screenNum); gcValues.background = WhitePixel(display, screenNum); gcValues.line_width = 0; gcValues.line_style = LineSolid; - XChangeGC(display, strokeGC, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - XChangeGC(display, fillGC, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - - // clear clipping region - if (clipRegion) - XDestroyRegion(clipRegion); + strokeGC = XCreateGC(display, pixmap, + GCForeground | GCBackground | GCLineWidth | GCLineStyle, + &gcValues); + fillGC = XCreateGC(display, pixmap, + GCForeground | GCBackground | GCLineWidth | GCLineStyle, + &gcValues); + gcValues.foreground = paperColor; + paperGC = XCreateGC(display, pixmap, + GCForeground | GCBackground | GCLineWidth | GCLineStyle, + &gcValues); + + // initialize clip region clipRegion = XCreateRegion(); rect.x = rect.y = 0; rect.width = pixmapW; @@ -1830,7 +1847,23 @@ void XOutputDev::startPage(int pageNum, GfxState *state) { } void XOutputDev::endPage() { + XOutputState *s; + text->coalesce(); + + // clear state stack, free all GCs, free the clip region + while (save) { + s = save; + save = save->next; + XFreeGC(display, s->strokeGC); + XFreeGC(display, s->fillGC); + XDestroyRegion(s->clipRegion); + delete s; + } + XFreeGC(display, strokeGC); + XFreeGC(display, fillGC); + XFreeGC(display, paperGC); + XDestroyRegion(clipRegion); } void XOutputDev::drawLink(Link *link, Catalog *catalog) { @@ -2026,6 +2059,8 @@ void XOutputDev::updateStrokeColor(GfxState *state) { void XOutputDev::updateFont(GfxState *state) { double m11, m12, m21, m22; + text->updateFont(state); + if (!(gfxFont = state->getFont())) { font = NULL; return; @@ -2042,8 +2077,6 @@ void XOutputDev::updateFont(GfxState *state) { font->updateGC(fillGC); font->updateGC(strokeGC); } - - text->updateFont(state); } void XOutputDev::stroke(GfxState *state) { @@ -2450,7 +2483,7 @@ void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) { } void XOutputDev::beginString(GfxState *state, GString *s) { - text->beginString(state); + text->beginString(state, state->getCurX(), state->getCurY()); } void XOutputDev::endString(GfxState *state) { @@ -2625,9 +2658,7 @@ GBool XOutputDev::beginType3Char(GfxState *state, (int)floor(yMin - yt), (int)ceil(xMax) - (int)floor(xMin) + 3, (int)ceil(yMax) - (int)floor(yMin) + 3, - display, - DefaultVisual(display, screenNum), - depth, pixmap); + display, visual, depth, pixmap); } } t3Font = t3FontCache[0]; @@ -2676,6 +2707,7 @@ void XOutputDev::endType3Char(GfxState *state) { Gulong pixel; double alpha; T3GlyphStack *t3gs; + double *ctm; if (t3GlyphStack->cacheable) { image = t3GlyphStack->cache->image; @@ -2716,6 +2748,11 @@ void XOutputDev::endType3Char(GfxState *state) { drawType3Glyph(t3GlyphStack->cache, t3GlyphStack->cacheTag, t3GlyphStack->cacheData, t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color); + // the CTM must be restored here in order for TextPage::addChar to + // work correctly + ctm = state->getCTM(); + state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], + t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); } text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy, t3GlyphStack->u, t3GlyphStack->uLen); @@ -2878,6 +2915,8 @@ void XOutputDev::type3D1(GfxState *state, double wx, double wy, XSetRegion(display, strokeGC, clipRegion); XSetRegion(display, fillGC, clipRegion); ctm = state->getCTM(); + t3GlyphStack->origCTM4 = ctm[4]; + t3GlyphStack->origCTM5 = ctm[5]; state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY); } @@ -3118,8 +3157,7 @@ void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); // allocate XImage and read from page pixmap - image = XCreateImage(display, DefaultVisual(display, screenNum), - depth, ZPixmap, 0, NULL, bw, bh, 8, 0); + image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); image->data = (char *)gmalloc(bh * image->bytes_per_line); XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap, image, cx1, cy1); @@ -3167,13 +3205,13 @@ void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, if (n > 0) { p = pixBuf; for (i = 0; i < n; ++i) { - for (j = 0; j < width; ++j) { - imgStr->getPixel(p); - if (invert) { - *p ^= 1; + memcpy(p, imgStr->getLine(), width); + if (invert) { + for (j = 0; j < width; ++j) { + p[j] ^= 1; } - ++p; } + p += width; } } lastYStep = yStep; @@ -3279,7 +3317,7 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, double r0, g0, b0, alpha, mul; Gulong pix; GfxRGB *p; - Guchar *q; + Guchar *q, *p2; GBool oneBitMode; GfxRGB oneBitRGB[2]; int x, y, x1, y1, x2, y2; @@ -3321,6 +3359,14 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, } tx = xoutRound(ctm[2] + ctm[4]); ty = xoutRound(ctm[3] + ctm[5]); + if (xScale < 0) { + // this is the right edge which needs to be (left + width - 1) + --tx; + } + if (yScale < 0) { + // this is the bottom edge which needs to be (top + height - 1) + --ty; + } // use ceil() to avoid gaps between "striped" images scaledWidth = (int)ceil(fabs(xScale)); xSign = (xScale < 0) ? -1 : 1; @@ -3425,8 +3471,7 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, } // allocate XImage - image = XCreateImage(display, DefaultVisual(display, screenNum), - depth, ZPixmap, 0, NULL, bw, bh, 8, 0); + image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); image->data = (char *)gmalloc(bh * image->bytes_per_line); // if the transform is anything other than a 0/90/180/270 degree @@ -3484,26 +3529,27 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, p = pixBuf; q = alphaBuf; for (i = 0; i < n; ++i) { - for (j = 0; j < width; ++j) { - imgStr->getPixel(pixBuf2); - if (oneBitMode) { - *p++ = oneBitRGB[pixBuf2[0]]; - } else { - colorMap->getRGB(pixBuf2, p); - ++p; - } - if (q) { - *q = 1; - for (k = 0; k < nComps; ++k) { - if (pixBuf2[k] < maskColors[2*k] || - pixBuf2[k] > maskColors[2*k]) { - *q = 0; - break; - } - } - ++q; - } - } + p2 = imgStr->getLine(); + for (j = 0; j < width; ++j) { + if (oneBitMode) { + *p = oneBitRGB[*p2]; + } else { + colorMap->getRGB(p2, p); + } + ++p; + if (q) { + *q = 1; + for (k = 0; k < nComps; ++k) { + if (p2[k] < maskColors[2*k] || + p2[k] > maskColors[2*k]) { + *q = 0; + break; + } + } + ++q; + } + p2 += nComps; + } } } lastYStep = yStep; diff --git a/pdf/xpdf/XOutputDev.h b/pdf/xpdf/XOutputDev.h index dc6af01..149fd6e 100644 --- a/pdf/xpdf/XOutputDev.h +++ b/pdf/xpdf/XOutputDev.h @@ -9,7 +9,9 @@ #ifndef XOUTPUTDEV_H #define XOUTPUTDEV_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -328,36 +330,45 @@ private: #if HAVE_T1LIB_H class XOutputT1FontFile { public: - XOutputT1FontFile(int numA, int genA, GBool substA, T1FontFile *fontFileA) - { num = numA; gen = genA; subst = substA; fontFile = fontFileA; } + XOutputT1FontFile(int numA, int genA, GBool substA, + T1FontFile *fontFileA, GString *tmpFileNameA) + { num = numA; gen = genA; subst = substA; + fontFile = fontFileA; tmpFileName = tmpFileNameA; } ~XOutputT1FontFile(); int num, gen; GBool subst; T1FontFile *fontFile; + GString *tmpFileName; }; #endif #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) class XOutputFTFontFile { public: - XOutputFTFontFile(int numA, int genA, GBool substA, FTFontFile *fontFileA) - { num = numA; gen = genA; subst = substA; fontFile = fontFileA; } + XOutputFTFontFile(int numA, int genA, GBool substA, + FTFontFile *fontFileA, GString *tmpFileNameA) + { num = numA; gen = genA; subst = substA; + fontFile = fontFileA; tmpFileName = tmpFileNameA; } ~XOutputFTFontFile(); int num, gen; GBool subst; FTFontFile *fontFile; + GString *tmpFileName; }; #endif #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) class XOutputTTFontFile { public: - XOutputTTFontFile(int numA, int genA, GBool substA, TTFontFile *fontFileA) - { num = numA; gen = genA; subst = substA; fontFile = fontFileA; } + XOutputTTFontFile(int numA, int genA, GBool substA, + TTFontFile *fontFileA, GString *tmpFileNameA) + { num = numA; gen = genA; subst = substA; + fontFile = fontFileA; tmpFileName = tmpFileNameA; } ~XOutputTTFontFile(); int num, gen; GBool subst; TTFontFile *fontFile; + GString *tmpFileName; }; #endif @@ -374,8 +385,8 @@ public: ~XOutputFontCache(); // Initialize (or re-initialize) the font cache for a new document. - void startDoc(int screenNum, Colormap colormap, - GBool trueColor, + void startDoc(int screenNum, Visual *visual, + Colormap colormap, GBool trueColor, int rMul, int gMul, int bMul, int rShift, int gShift, int bShift, Gulong *colors, int numColors); @@ -397,7 +408,7 @@ private: XOutputFont *tryGetT1Font(XRef *xref, GfxFont *gfxFont, double m11, double m12, double m21, double m22); XOutputFont *tryGetT1FontFromFile(XRef *xref, GString *fileName, - GfxFont *gfxFont, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, double m21Orig, double m22Orig, double m11, double m12, @@ -407,7 +418,7 @@ private: XOutputFont *tryGetFTFont(XRef *xref, GfxFont *gfxFont, double m11, double m12, double m21, double m22); XOutputFont *tryGetFTFontFromFile(XRef *xref, GString *fileName, - GfxFont *gfxFont, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, double m21Orig, double m22Orig, double m11, double m12, @@ -417,7 +428,7 @@ private: XOutputFont *tryGetTTFont(XRef *xref, GfxFont *gfxFont, double m11, double m12, double m21, double m22); XOutputFont *tryGetTTFontFromFile(XRef *xref, GString *fileName, - GfxFont *gfxFont, + GBool deleteFile, GfxFont *gfxFont, double m11Orig, double m12Orig, double m21Orig, double m22Orig, double m11, double m12, @@ -480,10 +491,11 @@ class XOutputDev: public OutputDev { public: // Constructor. - XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA, - Colormap colormapA, GBool reverseVideoA, - unsigned long paperColor, GBool installCmap, - int rgbCubeSize); + XOutputDev(Display *displayA, int screenNumA, + Visual *visualA, Colormap colormapA, + GBool reverseVideoA, unsigned long paperColorA, + GBool installCmap, int rgbCubeSize, + int forceDepth = 0); // Destructor. virtual ~XOutputDev(); @@ -583,11 +595,18 @@ public: GBool isReverseVideo() { return reverseVideo; } -protected: - // Update pixmap ID after a page change. - void setPixmap(Pixmap pixmap1, int pixmapW1, int pixmapH1) - { pixmap = pixmap1; pixmapW = pixmapW1; pixmapH = pixmapH1; } + void setPixmap(Pixmap pixmapA, int pixmapWA, int pixmapHA) + { pixmap = pixmapA; pixmapW = pixmapWA; pixmapH = pixmapHA; } + + // Get the off-screen pixmap, its size, various display info. + Pixmap getPixmap() { return pixmap; } + int getPixmapWidth() { return pixmapW; } + int getPixmapHeight() { return pixmapH; } + Display *getDisplay() { return display; } + Guint getDepth() { return depth; } + + Gulong findColor(GfxRGB *rgb); private: @@ -597,6 +616,7 @@ private: Pixmap pixmap; // pixmap to draw into int pixmapW, pixmapH; // size of pixmap Guint depth; // pixmap depth + Visual *visual; // X visual Colormap colormap; // X colormap int flatness; // line flatness GC paperGC; // GC for background @@ -608,6 +628,7 @@ private: int rShift, gShift, bShift; // RGB shifts (for TrueColor) Gulong // color cube colors[maxRGBCube * maxRGBCube * maxRGBCube]; + unsigned long paperColor; // paper color (pixel value) int numColors; // size of color cube double redMap[256]; // map pixel (from color cube) to red value GBool reverseVideo; // reverse video mode @@ -642,7 +663,6 @@ private: void drawType3Glyph(T3FontCache *t3Font, T3FontCacheTag *tag, Guchar *data, double x, double y, GfxRGB *color); - Gulong findColor(GfxRGB *rgb); Gulong findColor(GfxRGB *x, GfxRGB *err); }; diff --git a/pdf/xpdf/XRef.cc b/pdf/xpdf/XRef.cc index 0e1bbc9..901caa5 100644 --- a/pdf/xpdf/XRef.cc +++ b/pdf/xpdf/XRef.cc @@ -6,11 +6,12 @@ // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif -#include #include #include #include @@ -454,6 +455,7 @@ GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { ret = gFalse; permFlags = defPermFlags; + ownerPasswordOk = gFalse; trailerDict.dictLookup("Encrypt", &encrypt); if ((encrypted1 = encrypt.isDict())) { ret = gTrue; diff --git a/pdf/xpdf/XRef.h b/pdf/xpdf/XRef.h index 7876fa6..ebe5b54 100644 --- a/pdf/xpdf/XRef.h +++ b/pdf/xpdf/XRef.h @@ -9,7 +9,9 @@ #ifndef XREF_H #define XREF_H -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma interface #endif @@ -81,6 +83,11 @@ public: // Returns false if unknown or file is not damaged. GBool getStreamEnd(Guint streamStart, Guint *streamEnd); + // Direct access. + int getSize() { return size; } + XRefEntry *getEntry(int i) { return &entries[i]; } + Object *getTrailerDict() { return &trailerDict; } + private: BaseStream *str; // input stream diff --git a/pdf/xpdf/pdfimages.cc b/pdf/xpdf/pdfimages.cc index 898ad00..5e35bfb 100644 --- a/pdf/xpdf/pdfimages.cc +++ b/pdf/xpdf/pdfimages.cc @@ -72,6 +72,9 @@ int main(int argc, char *argv[]) { GString *ownerPW, *userPW; ImageOutputDev *imgOut; GBool ok; + int exitCode; + + exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -81,7 +84,7 @@ int main(int argc, char *argv[]) { if (!printVersion) { printUsage("pdfimages", " ", argDesc); } - exit(1); + goto err0; } fileName = new GString(argv[1]); imgRoot = argv[2]; @@ -111,13 +114,15 @@ int main(int argc, char *argv[]) { delete ownerPW; } if (!doc->isOk()) { - goto err; + exitCode = 1; + goto err1; } // check for copy permission if (!doc->okToCopy()) { error(-1, "Copying of images from this document is not allowed."); - goto err; + exitCode = 3; + goto err1; } // get page range @@ -128,18 +133,22 @@ int main(int argc, char *argv[]) { // write image files imgOut = new ImageOutputDev(imgRoot, dumpJPEG); - if (imgOut->isOk()) + if (imgOut->isOk()) { doc->displayPages(imgOut, firstPage, lastPage, 72, 0, gFalse); + } delete imgOut; + exitCode = 0; + // clean up - err: + err1: delete doc; delete globalParams; + err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return 0; + return exitCode; } diff --git a/pdf/xpdf/pdfinfo.cc b/pdf/xpdf/pdfinfo.cc index ea70afe..f1df095 100644 --- a/pdf/xpdf/pdfinfo.cc +++ b/pdf/xpdf/pdfinfo.cc @@ -76,6 +76,9 @@ int main(int argc, char *argv[]) { FILE *f; GString *metadata; GBool ok; + int exitCode; + + exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -85,7 +88,7 @@ int main(int argc, char *argv[]) { if (!printVersion) { printUsage("pdfinfo", "", argDesc); } - exit(1); + goto err0; } fileName = new GString(argv[1]); @@ -121,6 +124,7 @@ int main(int argc, char *argv[]) { delete ownerPW; } if (!doc->isOk()) { + exitCode = 1; goto err2; } @@ -179,7 +183,10 @@ int main(int argc, char *argv[]) { f = fopen(fileName->getCString(), "rb"); #endif if (f) { -#if HAVE_FSEEK64 +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + printf("File size: %u bytes\n", (Guint)ftello(f)); +#elif HAVE_FSEEK64 fseek64(f, 0, SEEK_END); printf("File size: %u bytes\n", (Guint)ftell64(f)); #else @@ -203,18 +210,21 @@ int main(int argc, char *argv[]) { delete metadata; } + exitCode = 0; + // clean up err2: uMap->decRefCnt(); delete doc; err1: delete globalParams; + err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return 0; + return exitCode; } static void printInfoString(Dict *infoDict, char *key, char *text, @@ -278,8 +288,9 @@ static void printInfoDate(Dict *infoDict, char *key, char *text) { tmStruct.tm_wday = -1; tmStruct.tm_yday = -1; tmStruct.tm_isdst = -1; - mktime(&tmStruct); // compute the tm_wday and tm_yday fields - if (strftime(buf, sizeof(buf), "%c", &tmStruct)) { + // compute the tm_wday and tm_yday fields + if (mktime(&tmStruct) != (time_t)-1 && + strftime(buf, sizeof(buf), "%c", &tmStruct)) { fputs(buf, stdout); } else { fputs(s, stdout); diff --git a/pdf/xpdf/pdftopbm.cc b/pdf/xpdf/pdftopbm.cc index 460377f..76f60a6 100644 --- a/pdf/xpdf/pdftopbm.cc +++ b/pdf/xpdf/pdftopbm.cc @@ -72,6 +72,9 @@ int main(int argc, char *argv[]) { GString *ownerPW, *userPW; PBMOutputDev *pbmOut; GBool ok; + int exitCode; + + exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -81,7 +84,7 @@ int main(int argc, char *argv[]) { if (!printVersion) { printUsage("pdftopbm", " ", argDesc); } - exit(1); + goto err0; } fileName = new GString(argv[1]); pbmRoot = argv[2]; @@ -111,7 +114,8 @@ int main(int argc, char *argv[]) { delete ownerPW; } if (!doc->isOk()) { - goto err; + exitCode = 1; + goto err1; } // get page range @@ -126,14 +130,17 @@ int main(int argc, char *argv[]) { doc->displayPages(pbmOut, firstPage, lastPage, resolution, 0, gFalse); PBMOutputDev::killPBMOutputDev(pbmOut); + exitCode = 0; + // clean up - err: + err1: delete doc; delete globalParams; + err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return 0; + return exitCode; } diff --git a/pdf/xpdf/pdftops.cc b/pdf/xpdf/pdftops.cc index 7f60be0..d5d2de8 100644 --- a/pdf/xpdf/pdftops.cc +++ b/pdf/xpdf/pdftops.cc @@ -127,6 +127,9 @@ int main(int argc, char *argv[]) { PSOutputDev *psOut; GBool ok; char *p; + int exitCode; + + exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -178,7 +181,7 @@ int main(int argc, char *argv[]) { if (paperSize[0]) { if (!globalParams->setPSPaperSize(paperSize)) { fprintf(stderr, "Invalid paper size\n"); - exit(1); + goto err0; } } else { if (paperWidth) { @@ -234,12 +237,14 @@ int main(int argc, char *argv[]) { delete ownerPW; } if (!doc->isOk()) { + exitCode = 1; goto err1; } // check for print permission if (!doc->okToPrint()) { error(-1, "Printing this document is not allowed."); + exitCode = 3; goto err1; } @@ -276,19 +281,26 @@ int main(int argc, char *argv[]) { doc->getCatalog(), firstPage, lastPage, mode); if (psOut->isOk()) { doc->displayPages(psOut, firstPage, lastPage, 72, 0, gFalse); + } else { + delete psOut; + exitCode = 2; + goto err2; } delete psOut; + exitCode = 0; + // clean up err2: delete psFileName; err1: delete doc; delete globalParams; + err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return 0; + return exitCode; } diff --git a/pdf/xpdf/pdftotext.cc b/pdf/xpdf/pdftotext.cc index f4b39ce..150954f 100644 --- a/pdf/xpdf/pdftotext.cc +++ b/pdf/xpdf/pdftotext.cc @@ -91,6 +91,9 @@ int main(int argc, char *argv[]) { Object info; GBool ok; char *p; + int exitCode; + + exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -100,7 +103,7 @@ int main(int argc, char *argv[]) { if (!printVersion) { printUsage("pdftotext", " []", argDesc); } - exit(1); + goto err0; } fileName = new GString(argv[1]); @@ -144,12 +147,14 @@ int main(int argc, char *argv[]) { delete ownerPW; } if (!doc->isOk()) { + exitCode = 1; goto err2; } // check for copy permission if (!doc->okToCopy()) { error(-1, "Copying of text from this document is not allowed."); + exitCode = 3; goto err2; } @@ -182,6 +187,7 @@ int main(int argc, char *argv[]) { } else { if (!(f = fopen(textFileName->getCString(), "wb"))) { error(-1, "Couldn't open text file '%s'", textFileName->getCString()); + exitCode = 2; goto err3; } } @@ -219,6 +225,10 @@ int main(int argc, char *argv[]) { textOut = new TextOutputDev(textFileName->getCString(), rawOrder, htmlMeta); if (textOut->isOk()) { doc->displayPages(textOut, firstPage, lastPage, 72, 0, gFalse); + } else { + delete textOut; + exitCode = 2; + goto err3; } delete textOut; @@ -229,6 +239,7 @@ int main(int argc, char *argv[]) { } else { if (!(f = fopen(textFileName->getCString(), "ab"))) { error(-1, "Couldn't open text file '%s'", textFileName->getCString()); + exitCode = 2; goto err3; } } @@ -240,6 +251,8 @@ int main(int argc, char *argv[]) { } } + exitCode = 0; + // clean up err3: delete textFileName; @@ -248,12 +261,13 @@ int main(int argc, char *argv[]) { uMap->decRefCnt(); err1: delete globalParams; + err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return 0; + return exitCode; } static void printInfoString(FILE *f, Dict *infoDict, char *key, diff --git a/pdf/xpdf/postscript.xbm b/pdf/xpdf/postscript.xbm deleted file mode 100644 index 016e126..0000000 --- a/pdf/xpdf/postscript.xbm +++ /dev/null @@ -1,6 +0,0 @@ -#define postscript_width 15 -#define postscript_height 15 -static unsigned char postscript_bits[] = { - 0xf0, 0x7f, 0x10, 0x40, 0x10, 0x40, 0xc8, 0x23, 0x08, 0x20, 0x68, 0x23, - 0x04, 0x10, 0x34, 0x10, 0x04, 0x10, 0xff, 0x7f, 0x55, 0x55, 0xab, 0x6a, - 0x55, 0x55, 0xab, 0x6a, 0xfe, 0x3f}; diff --git a/pdf/xpdf/vms_make.com b/pdf/xpdf/vms_make.com index c46f50f..35cc7c1 100644 --- a/pdf/xpdf/vms_make.com +++ b/pdf/xpdf/vms_make.com @@ -15,19 +15,21 @@ $ if f$search("COMMON.OLB").eqs."" then lib/create common.olb $! $ COMMON_OBJS = "Annot.obj,Array.obj,BuiltinFont.obj," + - "BuiltinFontTables.obj,Catalog.obj,CharCodeToUnicode.obj," + - - "CMap.obj,Decrypt.obj,Dict.obj,Error.obj," + - + "CMap.obj,Decrypt.obj,Dict.obj,Error.obj," + - "FontEncodingTables.obj,FontFile.obj," + - "Function.obj,Gfx.obj,GfxFont.obj,GfxState.obj,"+ - - "GlobalParams.obj,Lexer.obj," + - - "Link.obj,NameToCharCode.obj,Object.obj,OutputDev.obj," + - - "Page.obj,Parser.obj,PDFdoc.obj,PSTokenizer.obj," + - - "Stream.obj,UnicodeMap.obj,XRef.obj" + "GlobalParams.obj,JBIG2Stream.obj,Lexer.obj," + - + "Link.obj,NameToCharCode.obj,Object.obj,Outline.obj,"+ - + "OutputDev.obj,Page.obj,Parser.obj,PDFdoc.obj," + - + "PDFDocEncoding.obj,PSTokenizer.obj,Stream.obj," + - + "UnicodeMap.obj,XRef.obj" $ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib" $! -$ XPDF_OBJS = "xpdf.obj,FTFont.obj,LTKOutputDev.obj,PSOutputDev.obj," + - +$ XPDF_OBJS = "xpdf.obj,FTFont.obj,PSOutputDev.obj," + - "SFont.obj,T1Font.obj,TextOutputDev.obj,TTFont.obj," + - - "XOutputDev.obj" -$ XPDF_LIBS = "[-.ltk]libltk.olb/lib" + "XOutputDev.obj,XPDFApp.o,XPDFCore.o,XPDFTree.o," + - + "XPDFViewer.o,XPixmapOutputDev.o" +$ XPDF_LIBS = "" $! $ PDFTOPS_OBJS = "pdftops.obj,PSOutputDev.obj" $ PDFTOPS_LIBS = "" @@ -47,11 +49,6 @@ $ PDFIMAGES_LIBS = "" $! $ PDFFONTS_OBJS = "pdffonts.obj" $ PDFFONTS_LIBS = "" -$! Build xpdf-ltk.h -$ close sys$input -$ define/user sys$input xpdf.ltk -$ define/user sys$output xpdf-ltk.h -$ run [-.ltk]ltkbuild $! $COMPILE_CXX_LOOP: $ file = f$element(i, ",",COMMON_OBJS) diff --git a/pdf/xpdf/xpdf-flip.ltk b/pdf/xpdf/xpdf-flip.ltk deleted file mode 100644 index 4a249f8..0000000 --- a/pdf/xpdf/xpdf-flip.ltk +++ /dev/null @@ -1,253 +0,0 @@ -#======================================================================== -# -# xpdf-flip.ltk -# -# Copyright 1997-2002 Glyph & Cog, LLC -# -#======================================================================== - -#------------------------------------------------------------------------ -# main window -#------------------------------------------------------------------------ - -Window(func:makeWindow title:"xpdf" icon:xpdfIcon) { - Box(x:2 y:1 xfill:1 yfill:1) { - - # canvas, scrollbars, page number - Box(x:2 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1 sunken) { - ScrollingCanvas(name:"canvas" w:100 h:100) - } - Box1(yfill:1) { - Scrollbar(name:"vScrollbar" vert min:0 max:100 move:&scrollVertCbk) - } - Box(x:4 y:1) { - Box1() { - Label(text:"Page" - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box1(sunken left:4 right:4) { - TextIn(name:"pageNum" mw:6 done:&pageNumCbk - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box1() { - Label(name:"numPages" length:9 - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box(x:1 y:2 xfill:1) { - Box1(xfill:1) { - Scrollbar(name:"hScrollbar" horiz min:0 max:100 - move:&scrollHorizCbk) - } - Box1(xfill:1 yfill:1) { Empty() } - } - } - Box1() { Empty() } - } - - # buttons - Box(x:1 y:12 yfill:1) { - Box1() { - IconButton(bitmap:leftArrow_bits w:leftArrow_width - h:leftArrow_height press:&prevPageCbk) - } - Box1() { - IconButton(bitmap:rightArrow_bits w:rightArrow_width - h:rightArrow_height press:&nextPageCbk) - } - Box1() { - IconButton(bitmap:dblLeftArrow_bits w:dblLeftArrow_width - h:dblLeftArrow_height press:&prevTenPageCbk) - } - Box1() { - IconButton(bitmap:dblRightArrow_bits w:dblRightArrow_width - h:dblRightArrow_height press:&nextTenPageCbk) - } - Box1(yfill:1) { Empty() } - Box1() { - IconButton(bitmap:zoomIn_bits w:zoomIn_width - h:zoomIn_height press:&zoomInCbk) - } - Box1() { - IconButton(bitmap:zoomOut_bits w:zoomOut_width - h:zoomOut_height press:&zoomOutCbk) - } - Box1(yfill:1) { Empty() } - Box1() { - IconButton(bitmap:postscript_bits w:postscript_width - h:postscript_height press:&postScriptCbk) - } - Box1() { - IconButton(bitmap:about_bits w:about_width h:about_height - press:&aboutCbk) - } - Box1(yfill:1) { Empty() } - Box1() { Button(label:"Quit" press:&quitCbk) } - } - } -} - -#------------------------------------------------------------------------ -# menu for main window -#------------------------------------------------------------------------ - -Menu(func:makeMenu title:"xpdf" n:9) { - MenuItem(text:"Open..." shortcut:"O" num:menuOpen - select:&menuCbk) - MenuItem(text:"Save PDF..." num:menuSavePDF - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Find" shortcut:"F" num:menuFind - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Rotate counterclockwise" num:menuRotateCCW - select:&menuCbk) - MenuItem(text:"Rotate clockwise" num:menuRotateCW - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Quit" shortcut:"Q" num:menuQuit - select:&menuCbk) -} - -#------------------------------------------------------------------------ -# "PostScript output" dialog -#------------------------------------------------------------------------ - -Window(func:makePostScriptDialog dialog:gTrue defWidget:"ok" - title:"xpdf: PostScript output") { - Box(x:1 y:3) { - Box(x:4 y:1) { - Box1() { Label(text:"Pages:") } - Box1(sunken) { - TextIn(name:"firstPage" mw:6 tab:"lastPage" - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box1() { Label(text:"to") } - Box1(sunken) { - TextIn(name:"lastPage" mw:6 tab:"fileName" - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - } - Box(x:2 y:1) { - Box1() { Label(text:"File:") } - Box1(sunken xfill:1) { - TextIn(name:"fileName" mw:32 - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - } - Box(x:3 y:1 top:8) { - Box1(left:8) { Button(name:"ok" label:"Ok" press:&psButtonCbk num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&psButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "open" dialog -#------------------------------------------------------------------------ - -Window(func:makeOpenDialog dialog:gTrue defWidget:"open" - title:"xpdf: Open...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:openSelectCbk - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"open" label:"Open" press:&openButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&openButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "save" dialog -#------------------------------------------------------------------------ - -Window(func:makeSaveDialog dialog:gTrue defWidget:"save" - title:"xpdf: Save as...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:saveSelectCbk - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"save" label:"Save" press:&saveButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&saveButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "find" window -#------------------------------------------------------------------------ - -Window(func:makeFindWindow defWidget:"find" title:"xpdf: Find") { - Box(x:1 y:3 xfill:1 yfill:1) { - Box(x:2 y:1 xfill:1) { - Box1() { Label(text:"Text:") } - Box1(xfill:1 sunken) { - TextIn(name:"text" mw:32 - font:"-*-courier-medium-r-*-*-14-*-*-*-*-*-*-*") - } - } - Box1(xfill:1 yfill:1) { Empty() } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"find" label:"Find" press:&findButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Close" press:&findButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "about" window -#------------------------------------------------------------------------ - -Window(func:makeAboutWindow defWidget:"close" title:"About xpdf") { - Box(x:1 y:2) { - Box(x:1 y:10 left:2 right:2 top:2 bottom:2 sunken) { - Box1(bottom:0) { - Label(text:"xpdf" - font:"-*-times-bold-i-*-*-24-*-*-*-*-*-*-*") - } - Box1(bottom:12) { - Label(text:["Version " xpdfVersion]) - } - Box1(bottom:0) { - Label(text:xpdfCopyright) - } - Box1(bottom:12) { - Label(text:"derekn@foolabs.com") - } - Box1(bottom:0) { - Label(text:["Supports PDF version " pdfVersion "."]) - } - Box1(bottom:0) { - Label(text:"The PDF data structures, operators, and specification") - } - Box1(bottom:12) { - Label(text:"are copyright 1995 Adobe Systems Inc.") - } - Box1(bottom:0) { - Label(text:"Mouse button 1: select text / follow link") - } - Box1(bottom:12) { - Label(text:"Mouse button 3: menu") - } - Box1(bottom:12) { - Label(text:"http://www.foolabs.com/xpdf/") - } - } - Box(x:2 y:1) { - Box1(xfill:1) { Empty() } - Box1() { Button(name:"close" label:"Close" press:&closeAboutCbk) } - } - } -} diff --git a/pdf/xpdf/xpdf-ltk.h b/pdf/xpdf/xpdf-ltk.h deleted file mode 100644 index 5665ee7..0000000 --- a/pdf/xpdf/xpdf-ltk.h +++ /dev/null @@ -1,252 +0,0 @@ -// This file was generated by ltkbuild 1.01 - -LTKWindow *makeWindow(LTKApp *a) { - return new LTKWindow(a, gFalse, "xpdf", xpdfIcon, NULL, - new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 2, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 1, - new LTKScrollingCanvas("canvas", 0, 100, 100, 32, 32) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 1, - new LTKScrollbar("vScrollbar", 0, gTrue, 0, 100, &scrollVertCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKScrollbar("hScrollbar", 0, gFalse, 0, 100, &scrollHorizCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKEmpty() - ) - ), - new LTKBox(NULL, 15, 1, 0, 0, 0, 0, ltkBorderNone, 1, 0, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, backArrow_bits, backArrow_width, backArrow_height, ltkButtonClick, &backCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, dblLeftArrow_bits, dblLeftArrow_width, dblLeftArrow_height, ltkButtonClick, &prevTenPageCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, leftArrow_bits, leftArrow_width, leftArrow_height, ltkButtonClick, &prevPageCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, rightArrow_bits, rightArrow_width, rightArrow_height, ltkButtonClick, &nextPageCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, dblRightArrow_bits, dblRightArrow_width, dblRightArrow_height, ltkButtonClick, &nextTenPageCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, forwardArrow_bits, forwardArrow_width, forwardArrow_height, ltkButtonClick, &forwardCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel(NULL, 0, ltkLabelStatic, 8, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", "Page") - ), - new LTKBox(NULL, 1, 1, 4, 4, 2, 2, ltkBorderSunken, 0, 0, - new LTKTextIn("pageNum", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", &pageNumCbk, NULL) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel("numPages", 0, ltkLabelMaxLength, 9, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKMenuButton("zoom", 0, zoomMenu) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, find_bits, find_width, find_height, ltkButtonClick, &findCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, postscript_bits, postscript_width, postscript_height, ltkButtonClick, &postScriptCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, about_bits, about_width, about_height, ltkButtonClick, &aboutCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKLabel("link", 0, ltkLabelFixedWidth, 8, "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*", NULL) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, "Quit", ltkButtonClick, &quitCbk) - ) - ) - ) - ); -} - -LTKWindow *makeFullScreenWindow(LTKApp *a) { - return new LTKWindow(a, gFalse, "xpdf", xpdfIcon, NULL, - new LTKBox(NULL, 1, 1, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKScrollingCanvas("canvas", 0, 100, 100, 32, 32) - ) - ); -} - -LTKMenu *makeMenu() { - return new LTKMenu("xpdf", 8, - new LTKMenuItem("Open...", "O", menuOpen, &menuCbk, NULL), - new LTKMenuItem("Reload", "R", menuReload, &menuCbk, NULL), - new LTKMenuItem("Save as...", NULL, menuSavePDF, &menuCbk, NULL), - new LTKMenuItem(NULL, NULL, 0, NULL, NULL), - new LTKMenuItem("Rotate counterclockwise", NULL, menuRotateCCW, &menuCbk, NULL), - new LTKMenuItem("Rotate clockwise", NULL, menuRotateCW, &menuCbk, NULL), - new LTKMenuItem(NULL, NULL, 0, NULL, NULL), - new LTKMenuItem("Quit", "Q", menuQuit, &menuCbk, NULL) - - ); -} - -LTKMenu *makeZoomMenu() { - return new LTKMenu("zoom", 14, - new LTKMenuItem("-5", NULL, -5, &zoomMenuCbk, NULL), - new LTKMenuItem("-4", NULL, -4, &zoomMenuCbk, NULL), - new LTKMenuItem("-3", NULL, -3, &zoomMenuCbk, NULL), - new LTKMenuItem("-2", NULL, -2, &zoomMenuCbk, NULL), - new LTKMenuItem("-1", NULL, -1, &zoomMenuCbk, NULL), - new LTKMenuItem("0", NULL, 0, &zoomMenuCbk, NULL), - new LTKMenuItem("+1", NULL, 1, &zoomMenuCbk, NULL), - new LTKMenuItem("+2", NULL, 2, &zoomMenuCbk, NULL), - new LTKMenuItem("+3", NULL, 3, &zoomMenuCbk, NULL), - new LTKMenuItem("+4", NULL, 4, &zoomMenuCbk, NULL), - new LTKMenuItem("+5", NULL, 5, &zoomMenuCbk, NULL), - new LTKMenuItem(NULL, NULL, 0, NULL, NULL), - new LTKMenuItem("fit page", "z", 100, &zoomMenuCbk, NULL), - new LTKMenuItem("fit width", "w", 101, &zoomMenuCbk, NULL) - - ); -} - -LTKWindow *makePostScriptDialog(LTKApp *a) { - return new LTKWindow(a, gTrue, "xpdf: PostScript output", NULL, "ok", - new LTKBox(NULL, 1, 3, 0, 0, 0, 0, ltkBorderNone, 0, 0, - new LTKBox(NULL, 4, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Pages:") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 0, 0, - new LTKTextIn("firstPage", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, "lastPage") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "to") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 0, 0, - new LTKTextIn("lastPage", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, "fileName") - ) - ), - new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "File:") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 0, - new LTKTextIn("fileName", 0, 32, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, NULL) - ) - ), - new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 0, 0, - new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton("ok", 1, "Ok", ltkButtonClick, &psButtonCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKEmpty() - ), - new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &psButtonCbk) - ) - ) - ) - ); -} - -LTKWindow *makeOpenDialog(LTKApp *a) { - return new LTKWindow(a, gTrue, "xpdf: Open...", NULL, "open", - new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, - new LTKFileReq("fileReq", 0, openSelectCbk, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - ), - new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, - new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton("open", 1, "Open", ltkButtonClick, &openButtonCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKEmpty() - ), - new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &openButtonCbk) - ) - ) - ) - ); -} - -LTKWindow *makeSaveDialog(LTKApp *a) { - return new LTKWindow(a, gTrue, "xpdf: Save as...", NULL, "save", - new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, - new LTKFileReq("fileReq", 0, saveSelectCbk, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - ), - new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, - new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton("save", 1, "Save", ltkButtonClick, &saveButtonCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKEmpty() - ), - new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &saveButtonCbk) - ) - ) - ) - ); -} - -LTKWindow *makeFindWindow(LTKApp *a) { - return new LTKWindow(a, gFalse, "xpdf: Find", NULL, "find", - new LTKBox(NULL, 1, 3, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 1, 0, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Text:") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 0, - new LTKTextIn("text", 0, 32, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, NULL) - ) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, - new LTKEmpty() - ), - new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, - new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton("find", 1, "Find", ltkButtonClick, &findButtonCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKEmpty() - ), - new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, - new LTKButton(NULL, 0, "Close", ltkButtonClick, &findButtonCbk) - ) - ) - ) - ); -} - -LTKWindow *makeAboutWindow(LTKApp *a) { - return new LTKWindow(a, gFalse, "About xpdf", NULL, "close", - new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 2, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 1, - new LTKList("list", 0, 400, 30, gFalse, "-*-courier-medium-r-normal-*-12-*-*-*-*-*-*-*") - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 1, - new LTKScrollbar("vScrollbar", 0, gTrue, 0, 100, &aboutScrollVertCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKScrollbar("hScrollbar", 0, gFalse, 0, 100, &aboutScrollHorizCbk) - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKEmpty() - ) - ), - new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, - new LTKEmpty() - ), - new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, - new LTKButton("close", 0, "Close", ltkButtonClick, &closeAboutCbk) - ) - ) - ) - ); -} - diff --git a/pdf/xpdf/xpdf-top.ltk b/pdf/xpdf/xpdf-top.ltk deleted file mode 100644 index e00a385..0000000 --- a/pdf/xpdf/xpdf-top.ltk +++ /dev/null @@ -1,252 +0,0 @@ -#======================================================================== -# -# xpdf-top.ltk -# -# Copyright 1996-2002 Glyph & Cog, LLC -# -#======================================================================== - -#------------------------------------------------------------------------ -# main window -#------------------------------------------------------------------------ - -Window(func:makeWindow title:"xpdf" icon:xpdfIcon) { - Box(x:1 y:2 xfill:1 yfill:1) { - - # buttons, page number, etc. - Box(x:14 y:1 xfill:1 top:2) { - Box1() { - IconButton(bitmap:dblLeftArrow_bits w:dblLeftArrow_width - h:dblLeftArrow_height press:&prevTenPageCbk) - } - Box1() { - IconButton(bitmap:leftArrow_bits w:leftArrow_width - h:leftArrow_height press:&prevPageCbk) - } - Box1() { - IconButton(bitmap:rightArrow_bits w:rightArrow_width - h:rightArrow_height press:&nextPageCbk) - } - Box1() { - IconButton(bitmap:dblRightArrow_bits w:dblRightArrow_width - h:dblRightArrow_height press:&nextTenPageCbk) - } - Box1() { - Label(text:"Page" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1(sunken left:4 right:4) { - TextIn(name:"pageNum" mw:6 done:&pageNumCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { - Label(name:"numPages" maxLength length:9 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { - IconButton(bitmap:zoomIn_bits w:zoomIn_width - h:zoomIn_height press:&zoomInCbk) - } - Box1() { - IconButton(bitmap:zoomOut_bits w:zoomOut_width - h:zoomOut_height press:&zoomOutCbk) - } - Box1() { - IconButton(bitmap:find_bits w:find_width - h:find_height press:&findCbk) - } - Box1() { - IconButton(bitmap:postscript_bits w:postscript_width - h:postscript_height press:&postScriptCbk) - } - Box1() { - IconButton(bitmap:about_bits w:about_width h:about_height - press:&aboutCbk) - } - Box1(xfill:1) { - Label(name:"link" fixedWidth - font:"-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*") - } - Box1() { Button(label:"Quit" press:&quitCbk) } - } - - # canvas and scrollbars - Box(x:2 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1 sunken) { - ScrollingCanvas(name:"canvas" w:100 h:100) - } - Box1(yfill:1) { - Scrollbar(name:"vScrollbar" vert min:0 max:100 move:&scrollVertCbk) - } - Box1(xfill:1) { - Scrollbar(name:"hScrollbar" horiz min:0 max:100 move:&scrollHorizCbk) - } - Box1() { Empty() } - } - } -} - -#------------------------------------------------------------------------ -# menu for main window -#------------------------------------------------------------------------ - -Menu(func:makeMenu title:"xpdf" n:7) { - MenuItem(text:"Open..." shortcut:"O" num:menuOpen - select:&menuCbk) - MenuItem(text:"Save as..." num:menuSavePDF - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Rotate counterclockwise" num:menuRotateCCW - select:&menuCbk) - MenuItem(text:"Rotate clockwise" num:menuRotateCW - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Quit" shortcut:"Q" num:menuQuit - select:&menuCbk) -} - -#------------------------------------------------------------------------ -# "PostScript output" dialog -#------------------------------------------------------------------------ - -Window(func:makePostScriptDialog dialog:gTrue defWidget:"ok" - title:"xpdf: PostScript output") { - Box(x:1 y:3) { - Box(x:4 y:1) { - Box1() { Label(text:"Pages:") } - Box1(sunken) { - TextIn(name:"firstPage" mw:6 tab:"lastPage" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { Label(text:"to") } - Box1(sunken) { - TextIn(name:"lastPage" mw:6 tab:"fileName" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box(x:2 y:1) { - Box1() { Label(text:"File:") } - Box1(sunken xfill:1) { - TextIn(name:"fileName" mw:32 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box(x:3 y:1 top:8) { - Box1(left:8) { Button(name:"ok" label:"Ok" press:&psButtonCbk num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&psButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "open" dialog -#------------------------------------------------------------------------ - -Window(func:makeOpenDialog dialog:gTrue defWidget:"open" - title:"xpdf: Open...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:openSelectCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"open" label:"Open" press:&openButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&openButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "save" dialog -#------------------------------------------------------------------------ - -Window(func:makeSaveDialog dialog:gTrue defWidget:"save" - title:"xpdf: Save as...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:saveSelectCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"save" label:"Save" press:&saveButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&saveButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "find" window -#------------------------------------------------------------------------ - -Window(func:makeFindWindow defWidget:"find" title:"xpdf: Find") { - Box(x:1 y:3 xfill:1 yfill:1) { - Box(x:2 y:1 xfill:1) { - Box1() { Label(text:"Text:") } - Box1(xfill:1 sunken) { - TextIn(name:"text" mw:32 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box1(xfill:1 yfill:1) { Empty() } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"find" label:"Find" press:&findButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Close" press:&findButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "about" window -#------------------------------------------------------------------------ - -Window(func:makeAboutWindow defWidget:"close" title:"About xpdf") { - Box(x:1 y:2) { - Box(x:1 y:11 left:2 right:2 top:2 bottom:2 sunken) { - Box1(bottom:0) { - Label(text:"xpdf" - font:"-*-times-bold-i-normal-*-24-*-*-*-*-*-*-*") - } - Box1(bottom:12) { - Label(text:["Version " xpdfVersion]) - } - Box1(bottom:0) { - Label(text:xpdfCopyright) - } - Box1(bottom:12) { - Label(text:"derekn@foolabs.com") - } - Box1(bottom:2) { - Label(text:["Supports PDF version " pdfVersion "."]) - } - Box1(bottom:0) { - Label(text:"The PDF data structures, operators, and specification") - } - Box1(bottom:12) { - Label(text:"are copyright 1995 Adobe Systems Inc.") - } - Box1(bottom:0) { - Label(text:"Mouse button 1: select text / follow link") - } - Box1(bottom:0) { - Label(text:"Mouse button 2: pan window") - } - Box1(bottom:12) { - Label(text:"Mouse button 3: menu") - } - Box1(bottom:12) { - Label(text:"http://www.foolabs.com/xpdf/") - } - } - Box(x:2 y:1) { - Box1(xfill:1) { Empty() } - Box1() { Button(name:"close" label:"Close" press:&closeAboutCbk) } - } - } -} diff --git a/pdf/xpdf/xpdf.cc b/pdf/xpdf/xpdf.cc index ff54550..ef47fb6 100644 --- a/pdf/xpdf/xpdf.cc +++ b/pdf/xpdf/xpdf.cc @@ -7,252 +7,20 @@ //======================================================================== #include -#include -#include -#include -#include -#include -#include -#include -#include #include "gtypes.h" #include "GString.h" #include "parseargs.h" #include "gfile.h" #include "gmem.h" #include "GlobalParams.h" -#include "LTKAll.h" #include "Object.h" -#include "Stream.h" -#include "Array.h" -#include "Dict.h" -#include "XRef.h" -#include "Catalog.h" -#include "Page.h" -#include "Link.h" -#include "PDFDoc.h" -#include "XOutputDev.h" -#include "LTKOutputDev.h" -#include "PSOutputDev.h" -#include "TextOutputDev.h" -#include "Error.h" +#include "XPDFApp.h" #include "config.h" -#ifdef XlibSpecificationRelease -#if XlibSpecificationRelease < 5 -typedef char *XPointer; -#endif -#else -typedef char *XPointer; -#endif - -// hack around old X includes which are missing these symbols -#ifndef XK_Page_Up -#define XK_Page_Up 0xFF55 -#endif -#ifndef XK_Page_Down -#define XK_Page_Down 0xFF56 -#endif -#ifndef XK_KP_Home -#define XK_KP_Home 0xFF95 -#endif -#ifndef XK_KP_Left -#define XK_KP_Left 0xFF96 -#endif -#ifndef XK_KP_Up -#define XK_KP_Up 0xFF97 -#endif -#ifndef XK_KP_Right -#define XK_KP_Right 0xFF98 -#endif -#ifndef XK_KP_Down -#define XK_KP_Down 0xFF99 -#endif -#ifndef XK_KP_Prior -#define XK_KP_Prior 0xFF9A -#endif -#ifndef XK_KP_Page_Up -#define XK_KP_Page_Up 0xFF9A -#endif -#ifndef XK_KP_Next -#define XK_KP_Next 0xFF9B -#endif -#ifndef XK_KP_Page_Down -#define XK_KP_Page_Down 0xFF9B -#endif -#ifndef XK_KP_End -#define XK_KP_End 0xFF9C -#endif -#ifndef XK_KP_Begin -#define XK_KP_Begin 0xFF9D -#endif -#ifndef XK_KP_Insert -#define XK_KP_Insert 0xFF9E -#endif -#ifndef XK_KP_Delete -#define XK_KP_Delete 0xFF9F -#endif - -//------------------------------------------------------------------------ -// misc constants / enums -//------------------------------------------------------------------------ - -#define remoteCmdLength 512 - -enum XpdfMenuItem { - menuOpen, - menuReload, - menuSavePDF, - menuRotateCCW, - menuRotateCW, - menuQuit -}; - -//------------------------------------------------------------------------ -// prototypes -//------------------------------------------------------------------------ - -// loadFile / displayPage -static GBool loadFile(GString *fileName); -static void displayPage(int page1, int zoomA, int rotateA, GBool addToHist); -static void displayDest(LinkDest *dest, int zoomA, int rotateA, - GBool addToHist); - -// key press and menu callbacks -static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, - char *s, int n); -static void menuCbk(LTKMenuItem *item); - -// mouse callbacks -static void buttonPressCbk(LTKWidget *canvas1, int n, - int mx, int my, int button, GBool dblClick); -static void buttonReleaseCbk(LTKWidget *canvas1, int n, - int mx, int my, int button, GBool click); -static void doLink(int mx, int my); -static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my); -static void mouseDragCbk(LTKWidget *widget, int widgetNum, - int mx, int my, int button); - -// button callbacks -static void nextPageCbk(LTKWidget *button, int n, GBool on); -static void nextTenPageCbk(LTKWidget *button, int n, GBool on); -static void gotoNextPage(int inc, GBool top); -static void prevPageCbk(LTKWidget *button, int n, GBool on); -static void prevTenPageCbk(LTKWidget *button, int n, GBool on); -static void gotoPrevPage(int dec, GBool top, GBool bottom); -static void backCbk(LTKWidget *button, int n, GBool on); -static void forwardCbk(LTKWidget *button, int n, GBool on); -static void pageNumCbk(LTKWidget *textIn, int n, GString *text); -static void zoomMenuCbk(LTKMenuItem *item); -static void postScriptCbk(LTKWidget *button, int n, GBool on); -static void aboutCbk(LTKWidget *button, int n, GBool on); -static void quitCbk(LTKWidget *button, int n, GBool on); - -// scrollbar callbacks -static void scrollVertCbk(LTKWidget *scrollbar, int n, int val); -static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val); - -// misc callbacks -static void layoutCbk(LTKWindow *win1); -static void updateScrollbars(); -static void propChangeCbk(LTKWindow *win1, Atom atom); - -// selection -static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax); - -// "Open" dialog -static void mapOpenDialog(); -static void openButtonCbk(LTKWidget *button, int n, GBool on); -static void openSelectCbk(LTKWidget *widget, int n, GString *name); - -// "Reload" -static void reloadCbk(); - -// "Save PDF" dialog -static void mapSaveDialog(); -static void saveButtonCbk(LTKWidget *button, int n, GBool on); -static void saveSelectCbk(LTKWidget *widget, int n, GString *name); - -// "PostScript" dialog -static void mapPSDialog(); -static void psButtonCbk(LTKWidget *button, int n, GBool on); - -// "About" window -static void mapAboutWin(); -static void closeAboutCbk(LTKWidget *button, int n, GBool on); -static void aboutLayoutCbk(LTKWindow *winA); -static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val); -static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val); - -// "Find" window -static void findCbk(LTKWidget *button, int n, GBool on); -static void mapFindWin(); -static void findButtonCbk(LTKWidget *button, int n, GBool on); -static void doFind(char *s); - -// app kill callback -static void killCbk(LTKWindow *win1); - -//------------------------------------------------------------------------ -// "About" window text -//------------------------------------------------------------------------ - -static char *aboutWinText[] = { - "X X d fff", - " X X d f f", - " X X d f", - " X pppp dddd ffff", - " X X p p d d f", - " X X p p d d f", - "X X pppp dddd f Version " xpdfVersion, - " p", - " p", - " p", - "", - xpdfCopyright, - "", - "http://www.foolabs.com/xpdf/", - "derekn@foolabs.com", - "", - "Licensed under the GNU General Public License (GPL).", - "See the 'COPYING' file for details.", - "", - "Supports PDF version " supportedPDFVersionStr ".", - "", - "The PDF data structures, operators, and specification", - "are copyright 1985-2001 Adobe Systems Inc.", - "", - "Mouse bindings:", - " button 1: select text / follow link", - " button 2: pan window", - " button 3: menu", - "", - "Key bindings:", - " o = open file", - " r = reload", - " f = find text", - " n = = next page", - " p = = previous page", - " = scroll down", - " = = scroll up", - " v = forward (history path)", - " b = backward (history path)", - " 0 / + / - = zoom zero / in / out", - " z / w = zoom page / page width", - " ctrl-L = redraw", - " q = quit", - " / = top / bottom of page", - " = scroll", - "", - "For more information, please read the xpdf(1) man page.", - NULL -}; - //------------------------------------------------------------------------ // command line options //------------------------------------------------------------------------ -static char initialZoomStr[32] = ""; static char t1libControlStr[16] = ""; static char freetypeControlStr[16] = ""; static char psFileArg[256]; @@ -273,7 +41,6 @@ static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; -static GBool viKeys = gFalse; static ArgDesc argDesc[] = { {"-g", argStringDummy, NULL, 0, @@ -290,7 +57,7 @@ static ArgDesc argDesc[] = { "reverse video"}, {"-papercolor", argStringDummy, NULL, 0, "color of paper background"}, - {"-z", argString, initialZoomStr, sizeof(initialZoomStr), + {"-z", argStringDummy, NULL, 0, "initial zoom level (-5..5, page, width)"}, #if HAVE_T1LIB_H {"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr), @@ -345,154 +112,19 @@ static ArgDesc argDesc[] = { {NULL} }; -static XrmOptionDescRec opts[] = { - {"-display", ".display", XrmoptionSepArg, NULL}, - {"-foreground", ".foreground", XrmoptionSepArg, NULL}, - {"-fg", ".foreground", XrmoptionSepArg, NULL}, - {"-background", ".background", XrmoptionSepArg, NULL}, - {"-bg", ".background", XrmoptionSepArg, NULL}, - {"-geometry", ".geometry", XrmoptionSepArg, NULL}, - {"-g", ".geometry", XrmoptionSepArg, NULL}, - {"-font", ".font", XrmoptionSepArg, NULL}, - {"-fn", ".font", XrmoptionSepArg, NULL}, - {"-title", ".title", XrmoptionSepArg, NULL}, - {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"}, - {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL}, - {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"}, - {"-papercolor", ".paperColor", XrmoptionSepArg, NULL}, - {NULL} -}; - -//------------------------------------------------------------------------ -// global variables -//------------------------------------------------------------------------ - -// zoom factor is 1.2 (similar to DVI magsteps) -#define minZoom -5 -#define maxZoom 5 -#define zoomPage 100 -#define zoomWidth 101 -#define defZoom 1 -static int zoomDPI[maxZoom - minZoom + 1] = { - 29, 35, 42, 50, 60, - 72, - 86, 104, 124, 149, 179 -}; - -static PDFDoc *doc; - -static LTKOutputDev *out; - -static int page; -static int zoom; -static int rotate; -static GBool quit; - -static time_t modTime; // last modification time of PDF file - -static LinkAction *linkAction; // mouse pointer is over this link -static int // coordinates of current selection: - selectXMin, selectYMin, // (xMin==xMax || yMin==yMax) means there - selectXMax, selectYMax; // is no selection -static GBool lastDragLeft; // last dragged selection edge was left/right -static GBool lastDragTop; // last dragged selection edge was top/bottom -static int panMX, panMY; // last mouse position for pan - -struct History { - GString *fileName; - int page; -}; -#define historySize 50 -static History // page history queue - history[historySize]; -static int historyCur; // currently displayed page -static int historyBLen; // number of valid entries backward from - // current entry -static int historyFLen; // number of valid entries forward from - // current entry - -static GString *psFileName; -static int psFirstPage, psLastPage; - -static GString *fileReqDir; // current directory for file requesters - -static GString *urlCommand; // command to execute for URI links - -static GString *windowTitle; // window title string - -static LTKApp *app; -static Display *display; -static LTKWindow *win; -static LTKMenu *zoomMenu; -static LTKScrollingCanvas *canvas; -static LTKScrollbar *hScrollbar, *vScrollbar; -static LTKTextIn *pageNumText; -static LTKLabel *numPagesLabel; -static LTKLabel *linkLabel; -static LTKMenuButton *zoomMenuBtn; -static LTKWindow *aboutWin; -static LTKList *aboutList; -static LTKScrollbar *aboutHScrollbar, *aboutVScrollbar; -static LTKWindow *psDialog; -static LTKWindow *openDialog; -static LTKWindow *saveDialog; -static LTKWindow *findWin; -static LTKTextIn *findTextIn; -static Atom remoteAtom; -static GC selectGC; - -//------------------------------------------------------------------------ -// GUI includes -//------------------------------------------------------------------------ - -#include "xpdfIcon.xpm" -#include "leftArrow.xbm" -#include "dblLeftArrow.xbm" -#include "rightArrow.xbm" -#include "dblRightArrow.xbm" -#include "backArrow.xbm" -#include "forwardArrow.xbm" -#include "find.xbm" -#include "postscript.xbm" -#include "about.xbm" -#include "xpdf-ltk.h" - -//------------------------------------------------------------------------ -// main program //------------------------------------------------------------------------ int main(int argc, char *argv[]) { - Window xwin; - XGCValues gcValues; - char cmd[remoteCmdLength]; - LTKMenu *menu; - GString *name; - GString *title; - GString *initialZoom; - GBool reverseVideo; - unsigned long paperColor; - GBool installCmap; - int rgbCubeSize; + XPDFApp *app; + GString *fileName; int pg; GString *destName; - LinkDest *dest; - int x, y; - Guint width, height; - double width1, height1; + GString *userPasswordStr, *ownerPasswordStr; GBool ok; - char s[20]; - int i; - int ret; + int exitCode; - // initialize - app = NULL; - win = NULL; - out = NULL; - remoteAtom = None; - doc = NULL; - psFileName = NULL; - fileReqDir = getCurrentDir(); - ret = 0; + exitCode = 0; + userPasswordStr = ownerPasswordStr = NULL; // parse args ok = parseArgs(argDesc, &argc, argv); @@ -525,9 +157,6 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Bad '-eol' value on command line\n"); } } - if (initialZoomStr[0]) { - globalParams->setInitialZoom(initialZoomStr); - } if (t1libControlStr[0]) { if (!globalParams->setT1libControl(t1libControlStr)) { fprintf(stderr, "Bad '-t1lib' value on command line\n"); @@ -538,35 +167,43 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Bad '-freetype' value on command line\n"); } } + if (printCommands) { + globalParams->setPrintCommands(printCommands); + } if (quiet) { globalParams->setErrQuiet(quiet); } - // create LTKApp (and parse X-related args) - app = new LTKApp("xpdf", "Xpdf", opts, &argc, argv); - app->setKillCbk(&killCbk); - display = app->getDisplay(); + // create the XPDFApp object + app = new XPDFApp(&argc, argv); + + // the initialZoom parameter can be set in either the config file or + // as an X resource (or command line arg) + if (app->getInitialZoom()) { + globalParams->setInitialZoom(app->getInitialZoom()->getCString()); + } // check command line - if (doRemoteRaise) + if (doRemoteRaise) { ok = ok && remoteName[5] && !doRemoteQuit && argc >= 1 && argc <= 3; - else if (doRemoteQuit) + } else if (doRemoteQuit) { ok = ok && remoteName[5] && argc == 1; - else + } else { ok = ok && argc >= 1 && argc <= 3; + } if (!ok || printVersion || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("xpdf", "[ [ | +]]", argDesc); } - ret = 1; - goto done2; + exitCode = 99; + goto done1; } if (argc >= 2) { - name = new GString(argv[1]); + fileName = new GString(argv[1]); } else { - name = NULL; + fileName = NULL; } pg = 1; destName = NULL; @@ -578,1953 +215,75 @@ int main(int argc, char *argv[]) { } } - // look for already-running remote server + // handle remote server stuff if (remoteName[5]) { - remoteAtom = XInternAtom(display, remoteName, False); - xwin = XGetSelectionOwner(display, remoteAtom); - if (xwin != None) { - if (name) { + app->setRemoteName(remoteName); + if (app->remoteServerRunning()) { + if (fileName) { if (destName) { - sprintf(cmd, "%c +%.256s %.200s", doRemoteRaise ? 'D' : 'd', - destName->getCString(), name->getCString()); - delete destName; + app->remoteOpenAtDest(fileName, destName, doRemoteRaise); } else { - sprintf(cmd, "%c %d %.200s", doRemoteRaise ? 'D' : 'd', - pg, name->getCString()); + app->remoteOpen(fileName, pg, doRemoteRaise); } - XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8, - PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1); - delete name; } else if (doRemoteRaise) { - XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8, - PropModeReplace, (Guchar *)"r", 2); + app->remoteRaise(); } else if (doRemoteQuit) { - XChangeProperty(display, xwin, remoteAtom, remoteAtom, 8, - PropModeReplace, (Guchar *)"q", 2); + app->remoteQuit(); } goto done2; } if (doRemoteQuit) { - if (destName) { - delete destName; - } goto done2; } } - // no history yet - historyCur = historySize - 1; - historyBLen = historyFLen = 0; - for (i = 0; i < historySize; ++i) - history[i].fileName = NULL; - - // open PDF file - if (name) { - if (!loadFile(name)) { - ret = 1; - goto done1; - } - delete fileReqDir; - fileReqDir = makePathAbsolute(grabPath(name->getCString())); - } + // set options + app->setFullScreen(fullScreen); - // check for legal page number - if (doc && (pg < 1 || pg > doc->getNumPages())) { - pg = 1; - } - - // create window - menu = makeMenu(); - if (fullScreen) { - zoomMenu = NULL; - win = makeFullScreenWindow(app); - win->setDecorated(gFalse); - } else { - zoomMenu = makeZoomMenu(); - win = makeWindow(app); - } - win->setMenu(menu); - canvas = (LTKScrollingCanvas *)win->findWidget("canvas"); - hScrollbar = (LTKScrollbar *)win->findWidget("hScrollbar"); - vScrollbar = (LTKScrollbar *)win->findWidget("vScrollbar"); - pageNumText = (LTKTextIn *)win->findWidget("pageNum"); - numPagesLabel = (LTKLabel *)win->findWidget("numPages"); - linkLabel = (LTKLabel *)win->findWidget("link"); - zoomMenuBtn = (LTKMenuButton *)win->findWidget("zoom"); - win->setKeyCbk(&keyPressCbk); - win->setLayoutCbk(&layoutCbk); - canvas->setButtonPressCbk(&buttonPressCbk); - canvas->setButtonReleaseCbk(&buttonReleaseCbk); - canvas->setMouseMoveCbk(&mouseMoveCbk); - canvas->setMouseDragCbk(&mouseDragCbk); - if (!fullScreen) { - hScrollbar->setRepeatPeriod(0); - vScrollbar->setRepeatPeriod(0); - } - - // get parameters - urlCommand = globalParams->getURLCommand(); - - // get X resources - windowTitle = app->getStringResource("title", NULL); - installCmap = app->getBoolResource("installCmap", gFalse); - if (installCmap) { - win->setInstallCmap(gTrue); - } - rgbCubeSize = app->getIntResource("rgbCubeSize", defaultRGBCube); - reverseVideo = app->getBoolResource("reverseVideo", gFalse); - paperColor = app->getColorResource( - "paperColor", - reverseVideo ? (char *)"black" : (char *)"white", - reverseVideo ? BlackPixel(display, app->getScreenNum()) - : WhitePixel(display, app->getScreenNum()), - NULL); - if (fullScreen) { - zoom = zoomPage; - } else { - initialZoom = globalParams->getInitialZoom(); - if (!initialZoom->cmp("page")) { - zoom = zoomPage; - i = maxZoom - minZoom + 2; - } else if (!initialZoom->cmp("width")) { - zoom = zoomWidth; - i = maxZoom - minZoom + 3; - } else { - zoom = atoi(initialZoom->getCString()); - if (zoom < minZoom) { - zoom = minZoom; - } else if (zoom > maxZoom) { - zoom = maxZoom; - } - i = zoom - minZoom; - } - zoomMenuBtn->setInitialMenuItem(zoomMenu->getItem(i)); - } - viKeys = app->getBoolResource("viKeys", gFalse); - - // get geometry - if (fullScreen) { - x = y = 0; - width = app->getDisplayWidth(); - height = app->getDisplayHeight(); - } else { - x = y = -1; - width = height = 0; - app->getGeometryResource("geometry", &x, &y, &width, &height); - if (width == 0 || height == 0) { - if (!doc || doc->getNumPages() == 0) { - width1 = 612; - height1 = 792; - } else if (doc->getPageRotate(pg) == 90 || - doc->getPageRotate(pg) == 270) { - width1 = doc->getPageHeight(pg); - height1 = doc->getPageWidth(pg); - } else { - width1 = doc->getPageWidth(pg); - height1 = doc->getPageHeight(pg); - } - if (zoom == zoomPage || zoom == zoomWidth) { - width = (int)((width1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); - height = (int)((height1 * zoomDPI[defZoom - minZoom]) / 72 + 0.5); - } else { - width = (int)((width1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); - height = (int)((height1 * zoomDPI[zoom - minZoom]) / 72 + 0.5); - } - width += 28; - height += 56; - if (width > (Guint)app->getDisplayWidth() - 100) { - width = app->getDisplayWidth() - 100; - } - if (height > (Guint)app->getDisplayHeight() - 100) { - height = app->getDisplayHeight() - 100; - } - } - } + // check for password string(s) + ownerPasswordStr = ownerPassword[0] ? new GString(ownerPassword) + : (GString *)NULL; + userPasswordStr = userPassword[0] ? new GString(userPassword) + : (GString *)NULL; - // finish setting up window - if (!fullScreen) { - sprintf(s, "of %d", doc ? doc->getNumPages() : 0); - numPagesLabel->setText(s); - } - if (windowTitle) { - title = windowTitle->copy(); - } else if (name) { - title = new GString("xpdf: "); - title->append(name); - } else { - title = new GString("xpdf"); - } - win->setTitle(title); - win->layout(x, y, width, height); - win->map(); - aboutWin = NULL; - psDialog = NULL; - openDialog = NULL; - saveDialog = NULL; - findWin = NULL; - gcValues.foreground = BlackPixel(display, win->getScreenNum()) ^ - WhitePixel(display, win->getScreenNum()); - gcValues.function = GXxor; - selectGC = XCreateGC(display, win->getXWindow(), - GCForeground | GCFunction, &gcValues); - - // set up remote server - if (remoteAtom != None) { - win->setPropChangeCbk(&propChangeCbk); - xwin = win->getXWindow(); - XSetSelectionOwner(display, remoteAtom, xwin, CurrentTime); - } - - // create output device - out = new LTKOutputDev(win, reverseVideo, paperColor, - installCmap, rgbCubeSize, !fullScreen); - out->startDoc(doc ? doc->getXRef() : (XRef *)NULL); - - // display first page + // open the file and run the main loop if (destName) { - if (doc) { - if ((dest = doc->findDest(destName))) { - displayDest(dest, zoom, 0, gTrue); - delete dest; - } else { - error(-1, "Unknown named destination '%s'", destName->getCString()); - displayPage(1, zoom, 0, gTrue); - } + if (!app->openAtDest(fileName, destName, + ownerPasswordStr, userPasswordStr)) { + exitCode = 1; + goto done2; } - delete destName; } else { - displayPage(pg, zoom, 0, gTrue); + if (!app->open(fileName, pg, ownerPasswordStr, userPasswordStr)) { + exitCode = 1; + goto done2; + } } + app->run(); - // event loop - quit = gFalse; - do { - app->doEvent(gTrue); - } while (!quit); - - done1: - // release remote control atom - if (remoteAtom != None) - XSetSelectionOwner(display, remoteAtom, None, CurrentTime); + exitCode = 0; + // clean up done2: - // free stuff - if (out) { - delete out; - } - if (win) { - delete win; - } - if (aboutWin) { - delete aboutWin; - } - if (findWin) { - delete findWin; + if (userPasswordStr) { + delete userPasswordStr; } - if (app) { - delete app; + if (ownerPasswordStr) { + delete ownerPasswordStr; } - if (doc) { - delete doc; - } - if (psFileName) { - delete psFileName; - } - if (fileReqDir) { - delete fileReqDir; + if (destName) { + delete destName; } - if (windowTitle) { - delete windowTitle; - } - for (i = 0; i < historySize; ++i) { - if (history[i].fileName) { - delete history[i].fileName; - } + if (fileName) { + delete fileName; } + done1: + delete app; delete globalParams; // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); - return ret; -} - -//------------------------------------------------------------------------ -// loadFile / displayPage / displayDest -//------------------------------------------------------------------------ - -static GBool loadFile(GString *fileName) { - GString *title; - PDFDoc *newDoc; - GString *ownerPW, *userPW; - char s[20]; - char *p; - - // busy cursor - if (win) - win->setBusyCursor(gTrue); - - // open PDF file - if (ownerPassword[0]) { - ownerPW = new GString(ownerPassword); - } else { - ownerPW = NULL; - } - if (userPassword[0]) { - userPW = new GString(userPassword); - } else { - userPW = NULL; - } - newDoc = new PDFDoc(fileName, ownerPW, userPW, printCommands); - if (userPW) { - delete userPW; - } - if (ownerPW) { - delete ownerPW; - } - if (!newDoc->isOk()) { - delete newDoc; - if (win) - win->setBusyCursor(gFalse); - return gFalse; - } - - // replace old document - if (doc) - delete doc; - doc = newDoc; - if (out) { - out->startDoc(doc->getXRef()); - } - - // nothing displayed yet - page = -99; - - // save the modification time - modTime = getModTime(fileName->getCString()); - - // init PostScript output params - if (psFileName) - delete psFileName; - if (globalParams->getPSFile()) { - psFileName = globalParams->getPSFile()->copy(); - } else { - p = fileName->getCString() + fileName->getLength() - 4; - if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) - psFileName = new GString(fileName->getCString(), - fileName->getLength() - 4); - else - psFileName = fileName->copy(); - psFileName->append(".ps"); - } - psFirstPage = 1; - psLastPage = doc->getNumPages(); - - // set up title, number-of-pages display; back to normal cursor - if (win) { - if (!windowTitle) { - title = new GString("xpdf: "); - title->append(fileName); - win->setTitle(title); - } - if (!fullScreen) { - sprintf(s, "of %d", doc->getNumPages()); - numPagesLabel->setText(s); - } - win->setBusyCursor(gFalse); - } - - // done - return gTrue; -} - -static void displayPage(int pageA, int zoomA, int rotateA, GBool addToHist) { - time_t modTime1; - double hDPI, vDPI, dpi; - int rot; - char s[20]; - History *h; - - // check for document - if (!doc || doc->getNumPages() == 0) - return; - - // check for changes to the file - modTime1 = getModTime(doc->getFileName()->getCString()); - if (modTime1 != modTime) { - if (loadFile(doc->getFileName()->copy())) { - if (pageA > doc->getNumPages()) { - pageA = doc->getNumPages(); - } - } - modTime = modTime1; - } - - // busy cursor - if (win) - win->setBusyCursor(gTrue); - - // new page/zoom/rotate values - page = pageA; - zoom = zoomA; - rotate = rotateA; - - // initialize mouse-related stuff - linkAction = NULL; - win->setDefaultCursor(); - if (!fullScreen) { - linkLabel->setText(NULL); - } - selectXMin = selectXMax = 0; - selectYMin = selectYMax = 0; - lastDragLeft = lastDragTop = gTrue; - - // draw the page - rot = rotate + doc->getPageRotate(page); - if (rot >= 360) - rot -= 360; - else if (rotate < 0) - rot += 360; - if (fullScreen) { - if (rot == 90 || rot == 270) { - hDPI = (win->getWidth() / doc->getPageHeight(page)) * 72; - vDPI = (win->getHeight() / doc->getPageWidth(page)) * 72; - } else { - hDPI = (win->getWidth() / doc->getPageWidth(page)) * 72; - vDPI = (win->getHeight() / doc->getPageHeight(page)) * 72; - } - dpi = (hDPI < vDPI) ? hDPI : vDPI; - } else if (zoom == zoomPage) { - if (rot == 90 || rot == 270) { - hDPI = (canvas->getWidth() / doc->getPageHeight(page)) * 72; - vDPI = (canvas->getHeight() / doc->getPageWidth(page)) * 72; - } else { - hDPI = (canvas->getWidth() / doc->getPageWidth(page)) * 72; - vDPI = (canvas->getHeight() / doc->getPageHeight(page)) * 72; - } - dpi = (hDPI < vDPI) ? hDPI : vDPI; - } else if (zoom == zoomWidth) { - if (rot == 90 || rot == 270) { - dpi = (canvas->getWidth() / doc->getPageHeight(page)) * 72; - } else { - dpi = (canvas->getWidth() / doc->getPageWidth(page)) * 72; - } - } else { - dpi = zoomDPI[zoom - minZoom]; - } - doc->displayPage(out, page, dpi, rotate, gTrue); - updateScrollbars(); - - // update page number display - if (!fullScreen) { - sprintf(s, "%d", page); - pageNumText->setText(s); - } - - // add to history - if (addToHist) { - if (++historyCur == historySize) - historyCur = 0; - h = &history[historyCur]; - if (h->fileName) - delete h->fileName; - h->fileName = doc->getFileName()->copy(); - h->page = page; - if (historyBLen < historySize) - ++historyBLen; - historyFLen = 0; - } - - // back to regular cursor - win->setBusyCursor(gFalse); -} - -static void displayDest(LinkDest *dest, int zoomA, int rotateA, - GBool addToHist) { - Ref pageRef; - int pg; - int dx, dy; - - if (dest->isPageRef()) { - pageRef = dest->getPageRef(); - pg = doc->findPage(pageRef.num, pageRef.gen); - } else { - pg = dest->getPageNum(); - } - if (pg <= 0 || pg > doc->getNumPages()) { - pg = 1; - } - if (pg != page) { - displayPage(pg, zoomA, rotateA, addToHist); - } - - if (fullScreen) { - return; - } - switch (dest->getKind()) { - case destXYZ: - out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); - if (dest->getChangeLeft() || dest->getChangeTop()) { - if (dest->getChangeLeft()) { - hScrollbar->setPos(dx, canvas->getWidth()); - } - if (dest->getChangeTop()) { - vScrollbar->setPos(dy, canvas->getHeight()); - } - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - //~ what is the zoom parameter? - break; - case destFit: - case destFitB: - //~ do fit - hScrollbar->setPos(0, canvas->getWidth()); - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitH: - case destFitBH: - //~ do fit - out->cvtUserToDev(0, dest->getTop(), &dx, &dy); - hScrollbar->setPos(0, canvas->getWidth()); - vScrollbar->setPos(dy, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitV: - case destFitBV: - //~ do fit - out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy); - hScrollbar->setPos(dx, canvas->getWidth()); - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case destFitR: - //~ do fit - out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy); - hScrollbar->setPos(dx, canvas->getWidth()); - vScrollbar->setPos(dy, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - } -} - -//------------------------------------------------------------------------ -// key press and menu callbacks -//------------------------------------------------------------------------ - -static void keyPressCbk(LTKWindow *win1, KeySym key, Guint modifiers, - char *s, int n) { - if (n > 0) { - switch (s[0]) { - case 'O': - case 'o': - mapOpenDialog(); - break; - case 'R': - case 'r': - reloadCbk(); - break; - case 'F': - case 'f': - mapFindWin(); - break; - case 'N': - case 'n': - gotoNextPage(1, !(modifiers & Mod5Mask)); - break; - case 'P': - case 'p': - gotoPrevPage(1, !(modifiers & Mod5Mask), gFalse); - break; - case ' ': - if (fullScreen || - vScrollbar->getPos() >= - canvas->getRealHeight() - canvas->getHeight()) { - gotoNextPage(1, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case '\b': // bs - case '\177': // del - if (fullScreen) { - gotoPrevPage(1, gTrue, gFalse); - } else if (vScrollbar->getPos() == 0) { - gotoPrevPage(1, gFalse, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 'v': - forwardCbk(NULL, 0, gTrue); - break; - case 'b': - backCbk(NULL, 0, gTrue); - break; - case 'g': - if (fullScreen) { - break; - } - pageNumText->selectAll(); - pageNumText->activate(gTrue); - break; - case 'h': // vi-style left - if (fullScreen) { - break; - } - if (viKeys) { - hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 'l': // vi-style right - if (fullScreen) { - break; - } - if (viKeys) { - hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 'k': // vi-style up - if (fullScreen) { - break; - } - if (viKeys) { - vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 'j': // vi-style down - if (fullScreen) { - break; - } - if (viKeys) { - vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case '0': - if (fullScreen) { - break; - } - if (zoom != defZoom) { - zoomMenuBtn->setMenuItem(zoomMenu->getItem(defZoom - minZoom)); - } - break; - case '+': - if (fullScreen) { - break; - } - if (zoom >= minZoom && zoom < maxZoom) { - zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom + 1 - minZoom)); - } - break; - case '-': - if (fullScreen) { - break; - } - if (zoom > minZoom && zoom <= maxZoom) { - zoomMenuBtn->setMenuItem(zoomMenu->getItem(zoom - 1 - minZoom)); - } - break; - case 'z': - if (fullScreen) { - break; - } - zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 2)); - break; - case 'w': - if (fullScreen) { - break; - } - zoomMenuBtn->setMenuItem(zoomMenu->getItem(maxZoom - minZoom + 3)); - break; - case '\014': // ^L - win->redraw(); - displayPage(page, zoom, rotate, gFalse); - break; - case 'Q': - case 'q': - quitCbk(NULL, 0, gTrue); - break; - } - } else { - switch (key) { - case XK_Home: - case XK_KP_Home: - if (fullScreen) { - break; - } - hScrollbar->setPos(0, canvas->getWidth()); - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case XK_End: - case XK_KP_End: - if (fullScreen) { - break; - } - hScrollbar->setPos(canvas->getRealWidth() - canvas->getWidth(), - canvas->getWidth()); - vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case XK_Page_Up: - case XK_KP_Page_Up: - if (fullScreen) { - gotoPrevPage(1, gTrue, gFalse); - } else if (vScrollbar->getPos() == 0) { - gotoPrevPage(1, gFalse, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() - canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case XK_Page_Down: - case XK_KP_Page_Down: - if (fullScreen || - vScrollbar->getPos() >= - canvas->getRealHeight() - canvas->getHeight()) { - gotoNextPage(1, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() + canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case XK_Left: - case XK_KP_Left: - if (fullScreen) { - break; - } - hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case XK_Right: - case XK_KP_Right: - if (fullScreen) { - break; - } - hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case XK_Up: - case XK_KP_Up: - if (fullScreen) { - break; - } - vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case XK_Down: - case XK_KP_Down: - if (fullScreen) { - break; - } - vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - } - } -} - -static void menuCbk(LTKMenuItem *item) { - int r; - - switch (item->getItemNum()) { - case menuOpen: - mapOpenDialog(); - break; - case menuReload: - reloadCbk(); - break; - case menuSavePDF: - if (doc) - mapSaveDialog(); - break; - case menuRotateCCW: - if (doc) { - r = (rotate == 0) ? 270 : rotate - 90; - displayPage(page, zoom, r, gFalse); - } - break; - case menuRotateCW: - if (doc) { - r = (rotate == 270) ? 0 : rotate + 90; - displayPage(page, zoom, r, gFalse); - } - break; - case menuQuit: - quit = gTrue; - break; - } -} - -//------------------------------------------------------------------------ -// mouse callbacks -//------------------------------------------------------------------------ - -static void buttonPressCbk(LTKWidget *canvas1, int n, - int mx, int my, int button, GBool dblClick) { - if (!doc || doc->getNumPages() == 0) { - return; - } - switch (button) { - case 1: - setSelection(mx, my, mx, my); - break; - case 2: - if (!fullScreen) { - panMX = mx - hScrollbar->getPos(); - panMY = my - vScrollbar->getPos(); - } - break; - case 4: // mouse wheel up - if (fullScreen) { - gotoPrevPage(1, gTrue, gFalse); - } else if (vScrollbar->getPos() == 0) { - gotoPrevPage(1, gFalse, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() - 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 5: // mouse wheel down - if (fullScreen || - vScrollbar->getPos() >= - canvas->getRealHeight() - canvas->getHeight()) { - gotoNextPage(1, gTrue); - } else { - vScrollbar->setPos(vScrollbar->getPos() + 16, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - break; - case 6: // second mouse wheel right - if (fullScreen) { - return; - } - hScrollbar->setPos(hScrollbar->getPos() + 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - case 7: // second mouse wheel left - if (fullScreen) { - return; - } - hScrollbar->setPos(hScrollbar->getPos() - 16, canvas->getWidth()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - break; - } -} - -static void buttonReleaseCbk(LTKWidget *canvas1, int n, - int mx, int my, int button, GBool click) { - GString *s; - - if (!doc || doc->getNumPages() == 0) - return; - - if (button == 1) { - // selection - if (selectXMin < selectXMax && selectYMin < selectYMax) { -#ifndef NO_TEXT_SELECT - if (doc->okToCopy()) { - s = out->getText(selectXMin, selectYMin, selectXMax, selectYMax); - win->setSelection(NULL, s); - } else { - error(-1, "Copying of text from this document is not allowed."); - } -#endif - - // link - } else { - setSelection(mx, my, mx, my); - doLink(mx, my); - } - } -} - -static void doLink(int mx, int my) { - LinkActionKind kind; - LinkAction *action = NULL; - LinkDest *dest; - GString *namedDest; - char *s; - GString *fileName; - GString *actionName; - double x, y; - LTKButtonDialog *dialog; - int i; - - // look for a link - out->cvtDevToUser(mx, my, &x, &y); - if ((action = doc->findLink(x, y))) { - switch (kind = action->getKind()) { - - // GoTo / GoToR action - case actionGoTo: - case actionGoToR: - if (kind == actionGoTo) { - dest = NULL; - namedDest = NULL; - if ((dest = ((LinkGoTo *)action)->getDest())) - dest = dest->copy(); - else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) - namedDest = namedDest->copy(); - } else { - dest = NULL; - namedDest = NULL; - if ((dest = ((LinkGoToR *)action)->getDest())) - dest = dest->copy(); - else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) - namedDest = namedDest->copy(); - s = ((LinkGoToR *)action)->getFileName()->getCString(); - //~ translate path name for VMS (deal with '/') - if (isAbsolutePath(s)) - fileName = new GString(s); - else - fileName = appendToPath( - grabPath(doc->getFileName()->getCString()), s); - if (!loadFile(fileName)) { - if (dest) - delete dest; - if (namedDest) - delete namedDest; - return; - } - } - if (namedDest) { - dest = doc->findDest(namedDest); - delete namedDest; - } - if (dest) { - displayDest(dest, zoom, rotate, gTrue); - delete dest; - } else { - if (kind == actionGoToR) { - displayPage(1, zoom, 0, gTrue); - } - } - break; - - // Launch action - case actionLaunch: - fileName = ((LinkLaunch *)action)->getFileName(); - s = fileName->getCString(); - if (!strcmp(s + fileName->getLength() - 4, ".pdf") || - !strcmp(s + fileName->getLength() - 4, ".PDF")) { - //~ translate path name for VMS (deal with '/') - if (isAbsolutePath(s)) - fileName = fileName->copy(); - else - fileName = appendToPath( - grabPath(doc->getFileName()->getCString()), s); - if (!loadFile(fileName)) - return; - displayPage(1, zoom, rotate, gTrue); - } else { - fileName = fileName->copy(); - if (((LinkLaunch *)action)->getParams()) { - fileName->append(' '); - fileName->append(((LinkLaunch *)action)->getParams()); - } -#ifdef VMS - fileName->insert(0, "spawn/nowait "); -#elif defined(__EMX__) - fileName->insert(0, "start /min /n "); -#else - fileName->append(" &"); -#endif - dialog = new LTKButtonDialog(win, "xpdf: Launch", - "Execute the command:", - fileName->getCString(), - NULL, "Ok", "Cancel"); - if (dialog->go()) - system(fileName->getCString()); - delete dialog; - delete fileName; - } - break; - - // URI action - case actionURI: - if (urlCommand) { - for (s = urlCommand->getCString(); *s; ++s) { - if (s[0] == '%' && s[1] == 's') { - break; - } - } - if (s) { - fileName = ((LinkURI *)action)->getURI()->copy(); - // filter out any quote marks (' or ") to avoid a potential - // security hole - i = 0; - while (i < fileName->getLength()) { - if (fileName->getChar(i) == '"') { - fileName->del(i); - fileName->insert(i, "%22"); - i += 3; - } else if (fileName->getChar(i) == '\'') { - fileName->del(i); - fileName->insert(i, "%27"); - i += 3; - } else { - ++i; - } - } - fileName->insert(0, urlCommand->getCString(), - s - urlCommand->getCString()); - fileName->append(s+2); - } else { - fileName = urlCommand->copy(); - } -#ifdef VMS - fileName->insert(0, "spawn/nowait "); -#elif defined(__EMX__) - fileName->insert(0, "start /min /n "); -#else - fileName->append(" &"); -#endif - system(fileName->getCString()); - delete fileName; - } else { - printf("URI: %s\n", ((LinkURI *)action)->getURI()->getCString()); - } - break; - - // Named action - case actionNamed: - actionName = ((LinkNamed *)action)->getName(); - if (!actionName->cmp("NextPage")) { - gotoNextPage(1, gTrue); - } else if (!actionName->cmp("PrevPage")) { - gotoPrevPage(1, gTrue, gFalse); - } else if (!actionName->cmp("FirstPage")) { - if (page != 1) { - displayPage(1, zoom, rotate, gTrue); - } - } else if (!actionName->cmp("LastPage")) { - if (page != doc->getNumPages()) { - displayPage(doc->getNumPages(), zoom, rotate, gTrue); - } - } else if (!actionName->cmp("GoBack")) { - backCbk(NULL, 0, gTrue); - } else if (!actionName->cmp("GoForward")) { - forwardCbk(NULL, 0, gTrue); - } else if (!actionName->cmp("Quit")) { - quitCbk(NULL, 0, gTrue); - } else { - error(-1, "Unknown named action: '%s'", actionName->getCString()); - } - break; - - // unknown action type - case actionUnknown: - error(-1, "Unknown link action type: '%s'", - ((LinkUnknown *)action)->getAction()->getCString()); - break; - } - } -} - -static void mouseMoveCbk(LTKWidget *widget, int widgetNum, int mx, int my) { - double x, y; - LinkAction *action; - char *s; - - if (!doc || doc->getNumPages() == 0) - return; - out->cvtDevToUser(mx, my, &x, &y); - if ((action = doc->findLink(x, y))) { - if (action != linkAction) { - if (!linkAction) { - win->setCursor(XC_hand2); - } - linkAction = action; - if (!fullScreen) { - s = NULL; - switch (linkAction->getKind()) { - case actionGoTo: - s = "[internal link]"; - break; - case actionGoToR: - s = ((LinkGoToR *)linkAction)->getFileName()->getCString(); - break; - case actionLaunch: - s = ((LinkLaunch *)linkAction)->getFileName()->getCString(); - break; - case actionURI: - s = ((LinkURI *)action)->getURI()->getCString(); - break; - case actionNamed: - s = ((LinkNamed *)linkAction)->getName()->getCString(); - break; - case actionUnknown: - s = "[unknown link]"; - break; - } - linkLabel->setText(s); - } - } - } else { - if (linkAction) { - linkAction = NULL; - win->setDefaultCursor(); - if (!fullScreen) { - linkLabel->setText(NULL); - } - } - } -} - -static void mouseDragCbk(LTKWidget *widget, int widgetNum, - int mx, int my, int button) { - int x, y; - int xMin, yMin, xMax, yMax; - - // button 1: select - if (button == 1) { - - // clip mouse coords - x = mx; - if (x < 0) - x = 0; - else if (x >= canvas->getRealWidth()) - x = canvas->getRealWidth() - 1; - y = my; - if (y < 0) - y = 0; - else if (y >= canvas->getRealHeight()) - y = canvas->getRealHeight() - 1; - - // move appropriate edges of selection - if (lastDragLeft) { - if (x < selectXMax) { - xMin = x; - xMax = selectXMax; - } else { - xMin = selectXMax; - xMax = x; - lastDragLeft = gFalse; - } - } else { - if (x > selectXMin) { - xMin = selectXMin; - xMax = x; - } else { - xMin = x; - xMax = selectXMin; - lastDragLeft = gTrue; - } - } - if (lastDragTop) { - if (y < selectYMax) { - yMin = y; - yMax = selectYMax; - } else { - yMin = selectYMax; - yMax = y; - lastDragTop = gFalse; - } - } else { - if (y > selectYMin) { - yMin = selectYMin; - yMax = y; - } else { - yMin = y; - yMax = selectYMin; - lastDragTop = gTrue; - } - } - - // redraw the selection - setSelection(xMin, yMin, xMax, yMax); - - // button 2: pan - } else if (!fullScreen && button == 2) { - mx -= hScrollbar->getPos(); - my -= vScrollbar->getPos(); - hScrollbar->setPos(hScrollbar->getPos() - (mx - panMX), - canvas->getWidth()); - vScrollbar->setPos(vScrollbar->getPos() - (my - panMY), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - panMX = mx; - panMY = my; - } -} - -//------------------------------------------------------------------------ -// button callbacks -//------------------------------------------------------------------------ - -static void nextPageCbk(LTKWidget *button, int n, GBool on) { - gotoNextPage(1, gTrue); -} - -static void nextTenPageCbk(LTKWidget *button, int n, GBool on) { - gotoNextPage(10, gTrue); -} - -static void gotoNextPage(int inc, GBool top) { - int pg; - - if (!doc || doc->getNumPages() == 0) { - return; - } - if (page < doc->getNumPages()) { - if (top && !fullScreen) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos()); - } - if ((pg = page + inc) > doc->getNumPages()) { - pg = doc->getNumPages(); - } - displayPage(pg, zoom, rotate, gTrue); - } else { - XBell(display, 0); - } -} - -static void prevPageCbk(LTKWidget *button, int n, GBool on) { - gotoPrevPage(1, gTrue, gFalse); -} - -static void prevTenPageCbk(LTKWidget *button, int n, GBool on) { - gotoPrevPage(10, gTrue, gFalse); -} - -static void gotoPrevPage(int dec, GBool top, GBool bottom) { - int pg; - - if (!doc || doc->getNumPages() == 0) { - return; - } - if (page > 1) { - if (top && !fullScreen) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->setScrollPos(hScrollbar->getPos(), vScrollbar->getPos()); - } else if (bottom && !fullScreen) { - vScrollbar->setPos(canvas->getRealHeight() - canvas->getHeight(), - canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - if ((pg = page - dec) < 1) { - pg = 1; - } - displayPage(pg, zoom, rotate, gTrue); - } else { - XBell(display, 0); - } -} - -static void backCbk(LTKWidget *button, int n, GBool on) { - if (historyBLen <= 1) { - XBell(display, 0); - return; - } - if (--historyCur < 0) - historyCur = historySize - 1; - --historyBLen; - ++historyFLen; - if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { - if (!loadFile(history[historyCur].fileName->copy())) { - XBell(display, 0); - return; - } - } - displayPage(history[historyCur].page, zoom, rotate, gFalse); -} - -static void forwardCbk(LTKWidget *button, int n, GBool on) { - if (historyFLen == 0) { - XBell(display, 0); - return; - } - if (++historyCur == historySize) - historyCur = 0; - --historyFLen; - ++historyBLen; - if (history[historyCur].fileName->cmp(doc->getFileName()) != 0) { - if (!loadFile(history[historyCur].fileName->copy())) { - XBell(display, 0); - return; - } - } - displayPage(history[historyCur].page, zoom, rotate, gFalse); -} - -static void pageNumCbk(LTKWidget *textIn, int n, GString *text) { - int page1; - char s[20]; - - if (!doc || doc->getNumPages() == 0) - return; - page1 = atoi(text->getCString()); - if (page1 >= 1 && page1 <= doc->getNumPages()) { - if (page1 != page) - displayPage(page1, zoom, rotate, gTrue); - } else { - XBell(display, 0); - sprintf(s, "%d", page); - pageNumText->setText(s); - } -} - -static void zoomMenuCbk(LTKMenuItem *item) { - int z; - - if (!doc || doc->getNumPages() == 0) { - return; - } - z = item->getItemNum(); - if (z != zoom) { - displayPage(page, z, rotate, gFalse); - } -} - -static void postScriptCbk(LTKWidget *button, int n, GBool on) { - if (!doc) - return; - mapPSDialog(); -} - -static void aboutCbk(LTKWidget *button, int n, GBool on) { - mapAboutWin(); -} - -static void quitCbk(LTKWidget *button, int n, GBool on) { - quit = gTrue; -} - -//------------------------------------------------------------------------ -// scrollbar callbacks -//------------------------------------------------------------------------ - -static void scrollVertCbk(LTKWidget *scrollbar, int n, int val) { - canvas->scroll(hScrollbar->getPos(), val); - XSync(display, False); -} - -static void scrollHorizCbk(LTKWidget *scrollbar, int n, int val) { - canvas->scroll(val, vScrollbar->getPos()); - XSync(display, False); -} - -//------------------------------------------------------------------------ -// misc callbacks -//------------------------------------------------------------------------ - -static void layoutCbk(LTKWindow *win1) { - if (page >= 0 && (zoom == zoomPage || zoom == zoomWidth)) { - displayPage(page, zoom, rotate, gFalse); - } else { - updateScrollbars(); - } -} - -static void updateScrollbars() { - if (fullScreen) { - return; - } - hScrollbar->setLimits(0, canvas->getRealWidth() - 1); - hScrollbar->setPos(hScrollbar->getPos(), canvas->getWidth()); - hScrollbar->setScrollDelta(16); - vScrollbar->setLimits(0, canvas->getRealHeight() - 1); - vScrollbar->setPos(vScrollbar->getPos(), canvas->getHeight()); - vScrollbar->setScrollDelta(16); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); -} - -static void propChangeCbk(LTKWindow *win1, Atom atom) { - Window xwin; - char *cmd; - Atom type; - int format; - Gulong size, remain; - char *p, *q; - GString *newFileName; - int newPage; - GString *destName; - LinkDest *dest; - - // get command - xwin = win1->getXWindow(); - if (XGetWindowProperty(display, xwin, remoteAtom, - 0, remoteCmdLength/4, True, remoteAtom, - &type, &format, &size, &remain, - (Guchar **)&cmd) != Success) { - return; - } - if (size == 0) { - return; - } - - // raise window - if (cmd[0] == 'D' || cmd[0] == 'r'){ - win->raise(); - XFlush(display); - } - - // display file / page - if (cmd[0] == 'd' || cmd[0] == 'D') { - p = cmd + 2; - q = strchr(p, ' '); - if (!q) { - return; - } - *q++ = '\0'; - newPage = 1; - destName = NULL; - if (*p == '+') { - destName = new GString(p + 1); - } else { - newPage = atoi(p); - } - if (!q) { - return; - } - newFileName = new GString(q); - XFree((XPointer)cmd); - if (!doc || newFileName->cmp(doc->getFileName())) { - if (!loadFile(newFileName)) - return; - } else { - delete newFileName; - } - if (destName) { - if ((dest = doc->findDest(destName))) { - displayDest(dest, zoom, rotate, gTrue); - delete dest; - } - delete destName; - } else if (newPage != page && - newPage >= 1 && newPage <= doc->getNumPages()) { - displayPage(newPage, zoom, rotate, gTrue); - } - - // quit - } else if (cmd[0] == 'q') { - quit = gTrue; - } -} - -//------------------------------------------------------------------------ -// selection -//------------------------------------------------------------------------ - -static void setSelection(int newXMin, int newYMin, int newXMax, int newYMax) { - int x, y, w, h; - GBool needRedraw, needScroll; - GBool moveLeft, moveRight, moveTop, moveBottom; - - // erase old selection on canvas pixmap - needRedraw = gFalse; - if (selectXMin < selectXMax && selectYMin < selectYMax) { - XFillRectangle(canvas->getDisplay(), canvas->getPixmap(), - selectGC, selectXMin, selectYMin, - selectXMax - selectXMin, selectYMax - selectYMin); - needRedraw = gTrue; - } - - // draw new selection on canvas pixmap - if (newXMin < newXMax && newYMin < newYMax) { - XFillRectangle(canvas->getDisplay(), canvas->getPixmap(), - selectGC, newXMin, newYMin, - newXMax - newXMin, newYMax - newYMin); - needRedraw = gTrue; - } - - // check which edges moved - moveLeft = newXMin != selectXMin; - moveTop = newYMin != selectYMin; - moveRight = newXMax != selectXMax; - moveBottom = newYMax != selectYMax; - - // redraw currently visible part of canvas - if (needRedraw) { - if (moveLeft) { - canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin, - (newYMin < selectYMin) ? newYMin : selectYMin, - (newXMin > selectXMin) ? newXMin : selectXMin, - (newYMax > selectYMax) ? newYMax : selectYMax); - } - if (moveRight) { - canvas->redrawRect((newXMax < selectXMax) ? newXMax : selectXMax, - (newYMin < selectYMin) ? newYMin : selectYMin, - (newXMax > selectXMax) ? newXMax : selectXMax, - (newYMax > selectYMax) ? newYMax : selectYMax); - } - if (moveTop) { - canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin, - (newYMin < selectYMin) ? newYMin : selectYMin, - (newXMax > selectXMax) ? newXMax : selectXMax, - (newYMin > selectYMin) ? newYMin : selectYMin); - } - if (moveBottom) { - canvas->redrawRect((newXMin < selectXMin) ? newXMin : selectXMin, - (newYMax < selectYMax) ? newYMax : selectYMax, - (newXMax > selectXMax) ? newXMax : selectXMax, - (newYMax > selectYMax) ? newYMax : selectYMax); - } - } - - // switch to new selection coords - selectXMin = newXMin; - selectXMax = newXMax; - selectYMin = newYMin; - selectYMax = newYMax; - - // scroll canvas if necessary - if (fullScreen) { - return; - } - needScroll = gFalse; - w = canvas->getWidth(); - h = canvas->getHeight(); - x = hScrollbar->getPos(); - y = vScrollbar->getPos(); - if (moveLeft && selectXMin < x) { - x = selectXMin; - needScroll = gTrue; - } else if (moveRight && selectXMax >= x + w) { - x = selectXMax - w; - needScroll = gTrue; - } else if (moveLeft && selectXMin >= x + w) { - x = selectXMin - w; - needScroll = gTrue; - } else if (moveRight && selectXMax < x) { - x = selectXMax; - needScroll = gTrue; - } - if (moveTop && selectYMin < y) { - y = selectYMin; - needScroll = gTrue; - } else if (moveBottom && selectYMax >= y + h) { - y = selectYMax - h; - needScroll = gTrue; - } else if (moveTop && selectYMin >= y + h) { - y = selectYMin - h; - needScroll = gTrue; - } else if (moveBottom && selectYMax < y) { - y = selectYMax; - needScroll = gTrue; - } - if (needScroll) { - hScrollbar->setPos(x, w); - vScrollbar->setPos(y, h); - canvas->scroll(x, y); - } -} - -//------------------------------------------------------------------------ -// "Open" dialog -//------------------------------------------------------------------------ - -static void mapOpenDialog() { - openDialog = makeOpenDialog(app); - ((LTKFileReq *)openDialog->findWidget("fileReq"))->setDir(fileReqDir); - openDialog->layoutDialog(win, -1, -1); - openDialog->map(); -} - -static void openButtonCbk(LTKWidget *button, int n, GBool on) { - LTKFileReq *fileReq; - GString *sel; - - sel = NULL; - if (n == 1) { - fileReq = (LTKFileReq *)openDialog->findWidget("fileReq"); - if (!(sel = fileReq->getSelection())) { - return; - } - openSelectCbk(fileReq, 0, sel); - } - if (openDialog) { - if (sel) { - delete fileReqDir; - fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir(); - } - delete openDialog; - openDialog = NULL; - } -} - -static void openSelectCbk(LTKWidget *widget, int n, GString *name) { - GString *name1; - - name1 = name->copy(); - if (openDialog) { - delete fileReqDir; - fileReqDir = ((LTKFileReq *)openDialog->findWidget("fileReq"))->getDir(); - delete openDialog; - openDialog = NULL; - } - if (loadFile(name1)) { - if (!fullScreen) { - vScrollbar->setPos(0, canvas->getHeight()); - canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos()); - } - displayPage(1, zoom, rotate, gTrue); - } -} - -//------------------------------------------------------------------------ -// "Reload" -//------------------------------------------------------------------------ - -static void reloadCbk() { - int pg; - - if (!doc) { - return; - } - pg = page; - if (loadFile(doc->getFileName()->copy())) { - if (pg > doc->getNumPages()) { - pg = doc->getNumPages(); - } - displayPage(pg, zoom, rotate, gFalse); - } -} - -//------------------------------------------------------------------------ -// "Save PDF" dialog -//------------------------------------------------------------------------ - -static void mapSaveDialog() { - saveDialog = makeSaveDialog(app); - ((LTKFileReq *)saveDialog->findWidget("fileReq"))->setDir(fileReqDir); - saveDialog->layoutDialog(win, -1, -1); - saveDialog->map(); -} - -static void saveButtonCbk(LTKWidget *button, int n, GBool on) { - LTKFileReq *fileReq; - GString *sel; - - if (!doc) - return; - sel = NULL; - if (n == 1) { - fileReq = (LTKFileReq *)saveDialog->findWidget("fileReq"); - if (!(sel = fileReq->getSelection())) { - return; - } - saveSelectCbk(fileReq, 0, sel); - } - if (saveDialog) { - if (sel) { - delete fileReqDir; - fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir(); - } - delete saveDialog; - saveDialog = NULL; - } -} - -static void saveSelectCbk(LTKWidget *widget, int n, GString *name) { - GString *name1; - - name1 = name->copy(); - if (saveDialog) { - delete fileReqDir; - fileReqDir = ((LTKFileReq *)saveDialog->findWidget("fileReq"))->getDir(); - delete saveDialog; - saveDialog = NULL; - } - win->setBusyCursor(gTrue); - doc->saveAs(name1); - delete name1; - win->setBusyCursor(gFalse); -} - -//------------------------------------------------------------------------ -// "PostScript" dialog -//------------------------------------------------------------------------ - -static void mapPSDialog() { - LTKTextIn *widget; - char s[20]; - - psDialog = makePostScriptDialog(app); - sprintf(s, "%d", psFirstPage); - widget = (LTKTextIn *)psDialog->findWidget("firstPage"); - widget->setText(s); - sprintf(s, "%d", psLastPage); - widget = (LTKTextIn *)psDialog->findWidget("lastPage"); - widget->setText(s); - widget = (LTKTextIn *)psDialog->findWidget("fileName"); - widget->setText(psFileName->getCString()); - psDialog->layoutDialog(win, -1, -1); - psDialog->map(); -} - -static void psButtonCbk(LTKWidget *button, int n, GBool on) { - PSOutputDev *psOut; - LTKTextIn *widget; - - if (!doc) - return; - - // "Ok" button - if (n == 1) { - // extract params and close the dialog - widget = (LTKTextIn *)psDialog->findWidget("firstPage"); - psFirstPage = atoi(widget->getText()->getCString()); - if (psFirstPage < 1) - psFirstPage = 1; - widget = (LTKTextIn *)psDialog->findWidget("lastPage"); - psLastPage = atoi(widget->getText()->getCString()); - if (psLastPage < psFirstPage) - psLastPage = psFirstPage; - else if (psLastPage > doc->getNumPages()) - psLastPage = doc->getNumPages(); - widget = (LTKTextIn *)psDialog->findWidget("fileName"); - if (psFileName) - delete psFileName; - psFileName = widget->getText()->copy(); - if (!(psFileName->getChar(0) == '|' || - psFileName->cmp("-") == 0)) - makePathAbsolute(psFileName); - - // do the PostScript output - psDialog->setBusyCursor(gTrue); - win->setBusyCursor(gTrue); - if (doc->okToPrint()) { - psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(), - doc->getCatalog(), psFirstPage, psLastPage, - psModePS); - if (psOut->isOk()) { - doc->displayPages(psOut, psFirstPage, psLastPage, 72, 0, gFalse); - } - delete psOut; - } else { - error(-1, "Printing this document is not allowed."); - } - - delete psDialog; - win->setBusyCursor(gFalse); - - // "Cancel" button - } else { - delete psDialog; - } -} - -//------------------------------------------------------------------------ -// "About" window -//------------------------------------------------------------------------ - -static void mapAboutWin() { - int i; - - if (aboutWin) { - aboutWin->raise(); - } else { - aboutWin = makeAboutWindow(app); - aboutWin->setLayoutCbk(&aboutLayoutCbk); - aboutList = (LTKList *)aboutWin->findWidget("list"); - aboutHScrollbar = (LTKScrollbar *)aboutWin->findWidget("hScrollbar"); - aboutVScrollbar = (LTKScrollbar *)aboutWin->findWidget("vScrollbar"); - for (i = 0; aboutWinText[i]; ++i) { - aboutList->addLine(aboutWinText[i]); - } - aboutWin->layout(-1, -1, -1, -1); - aboutWin->map(); - } -} - -static void closeAboutCbk(LTKWidget *button, int n, GBool on) { - delete aboutWin; - aboutWin = NULL; -} - -static void aboutLayoutCbk(LTKWindow *winA) { - aboutHScrollbar->setLimits(0, aboutList->getMaxWidth() - 1); - aboutHScrollbar->setPos(aboutHScrollbar->getPos(), aboutList->getWidth()); - aboutVScrollbar->setLimits(0, aboutList->getNumLines() - 1); - aboutVScrollbar->setPos(aboutVScrollbar->getPos(), - aboutList->getDisplayedLines()); -} - -static void aboutScrollVertCbk(LTKWidget *scrollbar, int n, int val) { - aboutList->scrollTo(val, aboutHScrollbar->getPos()); - XSync(display, False); -} - -static void aboutScrollHorizCbk(LTKWidget *scrollbar, int n, int val) { - aboutList->scrollTo(aboutVScrollbar->getPos(), val); - XSync(display, False); -} - -//------------------------------------------------------------------------ -// "Find" window -//------------------------------------------------------------------------ - -static void findCbk(LTKWidget *button, int n, GBool on) { - if (!doc || doc->getNumPages() == 0) - return; - mapFindWin(); -} - -static void mapFindWin() { - if (findWin) { - findWin->raise(); - } else { - findWin = makeFindWindow(app); - findWin->layout(-1, -1, -1, -1); - findWin->map(); - findTextIn = (LTKTextIn *)findWin->findWidget("text"); - } - findTextIn->activate(gTrue); -} - -static void findButtonCbk(LTKWidget *button, int n, GBool on) { - if (!doc || doc->getNumPages() == 0) - return; - if (n == 1) { - doFind(findTextIn->getText()->getCString()); - } else { - delete findWin; - findWin = NULL; - } -} - -static void doFind(char *s) { - Unicode *u; - TextOutputDev *textOut; - int xMin, yMin, xMax, yMax; - double xMin1, yMin1, xMax1, yMax1; - int pg; - GBool top; - GString *s1; - int len, i; - - // check for zero-length string - if (!s[0]) { - XBell(display, 0); - return; - } - - // set cursors to watch - win->setBusyCursor(gTrue); - findWin->setBusyCursor(gTrue); - - // convert to Unicode -#if 1 //~ should do something more intelligent here - len = strlen(s); - u = (Unicode *)gmalloc(len * sizeof(Unicode)); - for (i = 0; i < len; ++i) { - u[i] = (Unicode)(s[i] & 0xff); - } -#endif - - // search current page starting at current selection or top of page - xMin = yMin = xMax = yMax = 0; - if (selectXMin < selectXMax && selectYMin < selectYMax) { - xMin = selectXMax; - yMin = (selectYMin + selectYMax) / 2; - top = gFalse; - } else { - top = gTrue; - } - if (out->findText(u, len, top, gTrue, &xMin, &yMin, &xMax, &yMax)) { - goto found; - } - - // search following pages - textOut = new TextOutputDev(NULL, gFalse, gFalse); - if (!textOut->isOk()) { - delete textOut; - goto done; - } - for (pg = page+1; pg <= doc->getNumPages(); ++pg) { - doc->displayPage(textOut, pg, 72, 0, gFalse); - if (textOut->findText(u, len, gTrue, gTrue, - &xMin1, &yMin1, &xMax1, &yMax1)) { - goto foundPage; - } - } - - // search previous pages - for (pg = 1; pg < page; ++pg) { - doc->displayPage(textOut, pg, 72, 0, gFalse); - if (textOut->findText(u, len, gTrue, gTrue, - &xMin1, &yMin1, &xMax1, &yMax1)) { - goto foundPage; - } - } - delete textOut; - - // search current page ending at current selection - if (selectXMin < selectXMax && selectYMin < selectYMax) { - xMax = selectXMin; - yMax = (selectYMin + selectYMax) / 2; - if (out->findText(u, len, gTrue, gFalse, &xMin, &yMin, &xMax, &yMax)) { - goto found; - } - } - - // not found - XBell(display, 0); - goto done; - - // found on a different page - foundPage: - delete textOut; - displayPage(pg, zoom, rotate, gTrue); - if (!out->findText(u, len, gTrue, gTrue, &xMin, &yMin, &xMax, &yMax)) { - // this can happen if coalescing is bad - goto done; - } - - // found: change the selection - found: - setSelection(xMin, yMin, xMax, yMax); -#ifndef NO_TEXT_SELECT - if (doc->okToCopy()) { - s1 = out->getText(selectXMin, selectYMin, selectXMax, selectYMax); - win->setSelection(NULL, s1); - } -#endif - - done: - gfree(u); - - // reset cursors to normal - win->setBusyCursor(gFalse); - findWin->setBusyCursor(gFalse); -} - -//------------------------------------------------------------------------ -// app kill callback -//------------------------------------------------------------------------ - -static void killCbk(LTKWindow *win1) { - if (win1 == win) { - quit = gTrue; - } else if (win1 == aboutWin) { - delete aboutWin; - aboutWin = NULL; - } else if (win1 == psDialog) { - delete psDialog; - psDialog = NULL; - } else if (win1 == openDialog) { - delete openDialog; - openDialog = NULL; - } else if (win1 == saveDialog) { - delete saveDialog; - saveDialog = NULL; - } else if (win1 == findWin) { - delete findWin; - findWin = NULL; - } + return exitCode; } diff --git a/pdf/xpdf/xpdf.ltk b/pdf/xpdf/xpdf.ltk deleted file mode 100644 index 1e21032..0000000 --- a/pdf/xpdf/xpdf.ltk +++ /dev/null @@ -1,267 +0,0 @@ -#======================================================================== -# -# xpdf.ltk -# -# Copyright 1996-2002 Glyph & Cog, LLC -# -#======================================================================== - -#------------------------------------------------------------------------ -# main window -#------------------------------------------------------------------------ - -Window(func:makeWindow title:"xpdf" icon:xpdfIcon) { - Box(x:1 y:2 xfill:1 yfill:1) { - - # canvas and scrollbars - Box(x:2 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1 sunken) { - ScrollingCanvas(name:"canvas" w:100 h:100) - } - Box1(yfill:1) { - Scrollbar(name:"vScrollbar" vert min:0 max:100 move:&scrollVertCbk) - } - Box1(xfill:1) { - Scrollbar(name:"hScrollbar" horiz min:0 max:100 move:&scrollHorizCbk) - } - Box1() { Empty() } - } - - # buttons, page number, etc. - Box(x:15 y:1 xfill:1) { - Box1() { - IconButton(bitmap:backArrow_bits w:backArrow_width - h:backArrow_height press:&backCbk) - } - Box1() { - IconButton(bitmap:dblLeftArrow_bits w:dblLeftArrow_width - h:dblLeftArrow_height press:&prevTenPageCbk) - } - Box1() { - IconButton(bitmap:leftArrow_bits w:leftArrow_width - h:leftArrow_height press:&prevPageCbk) - } - Box1() { - IconButton(bitmap:rightArrow_bits w:rightArrow_width - h:rightArrow_height press:&nextPageCbk) - } - Box1() { - IconButton(bitmap:dblRightArrow_bits w:dblRightArrow_width - h:dblRightArrow_height press:&nextTenPageCbk) - } - Box1() { - IconButton(bitmap:forwardArrow_bits w:forwardArrow_width - h:forwardArrow_height press:&forwardCbk) - } - Box1() { - Label(text:"Page" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1(sunken left:4 right:4) { - TextIn(name:"pageNum" mw:6 done:&pageNumCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { - Label(name:"numPages" maxLength length:9 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { - MenuButton(name:"zoom" menu:zoomMenu) - } - Box1() { - IconButton(bitmap:find_bits w:find_width - h:find_height press:&findCbk) - } - Box1() { - IconButton(bitmap:postscript_bits w:postscript_width - h:postscript_height press:&postScriptCbk) - } - Box1() { - IconButton(bitmap:about_bits w:about_width h:about_height - press:&aboutCbk) - } - Box1(xfill:1) { - Label(name:"link" fixedWidth - font:"-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*") - } - Box1() { Button(label:"Quit" press:&quitCbk) } - } - } -} - -#------------------------------------------------------------------------ -# full-screen main window -#------------------------------------------------------------------------ - -Window(func:makeFullScreenWindow title:"xpdf" icon:xpdfIcon) { - Box(x:1 y:1 xfill:1 yfill:1) { - ScrollingCanvas(name:"canvas" w:100 h:100) - } -} - -#------------------------------------------------------------------------ -# menu for main window -#------------------------------------------------------------------------ - -Menu(func:makeMenu title:"xpdf" n:8) { - MenuItem(text:"Open..." shortcut:"O" num:menuOpen - select:&menuCbk) - MenuItem(text:"Reload" shortcut:"R" num:menuReload - select:&menuCbk) - MenuItem(text:"Save as..." num:menuSavePDF - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Rotate counterclockwise" num:menuRotateCCW - select:&menuCbk) - MenuItem(text:"Rotate clockwise" num:menuRotateCW - select:&menuCbk) - MenuItem(text:NULL) - MenuItem(text:"Quit" shortcut:"Q" num:menuQuit - select:&menuCbk) -} - -#------------------------------------------------------------------------ -# popup zoom menu -#------------------------------------------------------------------------ - -Menu(func:makeZoomMenu title:"zoom" n:14) { - MenuItem(text:"-5" num:-5 select:&zoomMenuCbk) - MenuItem(text:"-4" num:-4 select:&zoomMenuCbk) - MenuItem(text:"-3" num:-3 select:&zoomMenuCbk) - MenuItem(text:"-2" num:-2 select:&zoomMenuCbk) - MenuItem(text:"-1" num:-1 select:&zoomMenuCbk) - MenuItem(text:"0" num: 0 select:&zoomMenuCbk) - MenuItem(text:"+1" num: 1 select:&zoomMenuCbk) - MenuItem(text:"+2" num: 2 select:&zoomMenuCbk) - MenuItem(text:"+3" num: 3 select:&zoomMenuCbk) - MenuItem(text:"+4" num: 4 select:&zoomMenuCbk) - MenuItem(text:"+5" num: 5 select:&zoomMenuCbk) - MenuItem(text:NULL) - MenuItem(text:"fit page" shortcut:"z" num:100 select:&zoomMenuCbk) - MenuItem(text:"fit width" shortcut:"w" num:101 select:&zoomMenuCbk) -} - -#------------------------------------------------------------------------ -# "PostScript output" dialog -#------------------------------------------------------------------------ - -Window(func:makePostScriptDialog dialog:gTrue defWidget:"ok" - title:"xpdf: PostScript output") { - Box(x:1 y:3) { - Box(x:4 y:1) { - Box1() { Label(text:"Pages:") } - Box1(sunken) { - TextIn(name:"firstPage" mw:6 tab:"lastPage" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box1() { Label(text:"to") } - Box1(sunken) { - TextIn(name:"lastPage" mw:6 tab:"fileName" - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box(x:2 y:1) { - Box1() { Label(text:"File:") } - Box1(sunken xfill:1) { - TextIn(name:"fileName" mw:32 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box(x:3 y:1 top:8) { - Box1(left:8) { Button(name:"ok" label:"Ok" press:&psButtonCbk num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&psButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "open" dialog -#------------------------------------------------------------------------ - -Window(func:makeOpenDialog dialog:gTrue defWidget:"open" - title:"xpdf: Open...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:openSelectCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"open" label:"Open" press:&openButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&openButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "save" dialog -#------------------------------------------------------------------------ - -Window(func:makeSaveDialog dialog:gTrue defWidget:"save" - title:"xpdf: Save as...") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1) { - FileReq(name:"fileReq" select:saveSelectCbk - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"save" label:"Save" press:&saveButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Cancel" press:&saveButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "find" window -#------------------------------------------------------------------------ - -Window(func:makeFindWindow defWidget:"find" title:"xpdf: Find") { - Box(x:1 y:3 xfill:1 yfill:1) { - Box(x:2 y:1 xfill:1) { - Box1() { Label(text:"Text:") } - Box1(xfill:1 sunken) { - TextIn(name:"text" mw:32 - font:"-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") - } - } - Box1(xfill:1 yfill:1) { Empty() } - Box(x:3 y:1 top:8 xfill:1) { - Box1(left:8) { Button(name:"find" label:"Find" press:&findButtonCbk - num:1) } - Box1(xfill:1) { Empty() } - Box1(right:8) { Button(label:"Close" press:&findButtonCbk num:0) } - } - } -} - -#------------------------------------------------------------------------ -# "about" window -#------------------------------------------------------------------------ - -Window(func:makeAboutWindow defWidget:"close" title:"About xpdf") { - Box(x:1 y:2 xfill:1 yfill:1) { - Box(x:2 y:2 xfill:1 yfill:1) { - Box1(xfill:1 yfill:1 sunken) { - List(name:"list" w:400 h:30 - font:"-*-courier-medium-r-normal-*-12-*-*-*-*-*-*-*") - } - Box1(yfill:1) { - Scrollbar(name:"vScrollbar" vert min:0 max:100 - move:&aboutScrollVertCbk) - } - Box1(xfill:1) { - Scrollbar(name:"hScrollbar" horiz min:0 max:100 - move:&aboutScrollHorizCbk) - } - Box1() { Empty() } - } - Box(x:2 y:1) { - Box1(xfill:1) { Empty() } - Box1() { Button(name:"close" label:"Close" press:&closeAboutCbk) } - } - } -} diff --git a/pdf/xpdf/xpdfconfig.h b/pdf/xpdf/xpdfconfig.h index c814b88..bb6eab9 100644 --- a/pdf/xpdf/xpdfconfig.h +++ b/pdf/xpdf/xpdfconfig.h @@ -14,8 +14,11 @@ //------------------------------------------------------------------------ // xpdf version - -#define xpdfVersion "1.01.1" +#define xpdfVersion "2.00" +#define xpdfVersionNum 2.00 +#define xpdfMajorVersion 2 +#define xpdfMinorVersion 0 +#define xpdfMajorVersionStr "2" // supported PDF version #define supportedPDFVersionStr "1.4" @@ -24,6 +27,10 @@ // copyright notice #define xpdfCopyright "Copyright 1996-2002 Glyph & Cog, LLC" +// Windows resource file stuff +#define winxpdfVersion "WinXpdf 2.00" +#define xpdfCopyrightAmp "Copyright 1996-2002 Glyph && Cog, LLC" + //------------------------------------------------------------------------ // paper size //------------------------------------------------------------------------ @@ -79,41 +86,13 @@ #define pclose _pclose #endif -#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32__) || defined(MACOS) +#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) #define POPEN_READ_MODE "rb" #else #define POPEN_READ_MODE "r" #endif //------------------------------------------------------------------------ -// uncompress program -//------------------------------------------------------------------------ - -#ifdef HAVE_POPEN - -// command to uncompress to stdout -# ifdef USE_GZIP -# define uncompressCmd "gzip -d -c -q" -# else -# ifdef __EMX__ -# define uncompressCmd "compress -d -c" -# else -# define uncompressCmd "uncompress -c" -# endif // __EMX__ -# endif // USE_GZIP - -#else // HAVE_POPEN - -// command to uncompress a file -# ifdef USE_GZIP -# define uncompressCmd "gzip -d -q" -# else -# define uncompressCmd "uncompress" -# endif // USE_GZIP - -#endif // HAVE_POPEN - -//------------------------------------------------------------------------ // Win32 stuff //------------------------------------------------------------------------ -- cgit v0.9.1