Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/TextOutputDev.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/TextOutputDev.cc | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc index aa9366a..d3b0137 100644 --- a/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc +++ b/noncore/unsupported/qpdf/xpdf/TextOutputDev.cc @@ -1,17 +1,17 @@ //======================================================================== // // TextOutputDev.cc // -// Copyright 1997 Derek B. Noonburg +// Copyright 1997-2002 Glyph & Cog, LLC // //======================================================================== #ifdef __GNUC__ #pragma implementation #endif #include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <math.h> @@ -39,24 +39,30 @@ TextString::TextString(GfxState *state, fouble fontSize) { fouble x, y; state->transform(state->getCurX(), state->getCurY(), &x, &y); if ((font = state->getFont())) { yMin = y - font->getAscent() * fontSize; yMax = y - font->getDescent() * fontSize; } else { // this means that the PDF file draws text without a current font, // which should never happen yMin = y - 0.95 * fontSize; yMax = y + 0.35 * fontSize; } + if (yMin == yMax) { + // this is a sanity check for a case that shouldn't happen -- but + // if it does happen, we want to avoid dividing by zero later + yMin = y; + yMax = y + 1; + } col = 0; text = NULL; xRight = NULL; len = size = 0; yxNext = NULL; xyNext = NULL; } TextString::~TextString() { gfree(text); gfree(xRight); } @@ -90,43 +96,47 @@ TextPage::TextPage(GBool rawOrderA) { nest = 0; } TextPage::~TextPage() { clear(); } void TextPage::updateFont(GfxState *state) { GfxFont *font; fouble *fm; char *name; int code; + fouble w; // adjust the font size fontSize = state->getTransformedFontSize(); if ((font = state->getFont()) && font->getType() == fontType3) { // This is a hack which makes it possible to deal with some Type 3 // fonts. The problem is that it's impossible to know what the // base coordinate system used in the font is without actually // 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'). for (code = 0; code < 256; ++code) { if ((name = ((Gfx8BitFont *)font)->getCharName(code)) && name[0] == 'm' && name[1] == '\0') { break; } } if (code < 256) { - // 600 is a generic average 'm' width -- yes, this is a hack - fontSize *= ((Gfx8BitFont *)font)->getWidth(code) / 0.6; + w = ((Gfx8BitFont *)font)->getWidth(code); + if (w != 0) { + // 600 is a generic average 'm' width -- yes, this is a hack + fontSize *= w / 0.6; + } } fm = font->getFontMatrix(); if (fm[0] != 0) { fontSize *= fabs(fm[3] / fm[0]); } } } void TextPage::beginString(GfxState *state) { // This check is needed because Type 3 characters can contain // text-drawing operations. if (curStr) { @@ -145,26 +155,28 @@ void TextPage::addChar(GfxState *state, fouble x, fouble y, 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); } state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(), 0, &dx2, &dy2); dx -= dx2; dy -= dy2; state->transformDelta(dx, dy, &w1, &h1); - w1 /= uLen; - h1 /= uLen; + if (uLen != 0) { + w1 /= uLen; + h1 /= uLen; + } for (i = 0; i < uLen; ++i) { curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]); } } void TextPage::endString() { TextString *p1, *p2; fouble h, y1, y2; // This check is needed because Type 3 characters can contain // text-drawing operations. if (nest > 0) { @@ -420,25 +432,25 @@ GString *TextPage::getText(fouble xMin, fouble yMin, } xPrev = x2; yPrev = str1->yMax; } } if (multiLine) { s->append(eol, eolLen); } uMap->decRefCnt(); return s; } -void TextPage::dump(FILE *f) { +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; fouble yMin, yMax; int col1, col2, d, i; // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { return; } spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); @@ -489,74 +501,74 @@ void TextPage::dump(FILE *f) { col2 = str2->col + (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) * str2->len); if (col2 > col1) { col1 = col2; } } } str1->col = col1; } #if 0 //~ for debugging - fprintf(f, "~~~~~~~~~~\n"); + fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); for (str1 = yxStrings; str1; str1 = str1->yxNext) { - fprintf(f, "(%4d,%4d) - (%4d,%4d) [%3d] '", + 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(f, "~~~~~~~~~~\n"); + fprintf((FILE *)outputStream, "~~~~~~~~~~\n"); #endif // output col1 = 0; yMax = yxStrings ? yxStrings->yMax : fouble(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) { - fwrite(space, 1, spaceLen, f); + (*outputFunc)(outputStream, space, spaceLen); } } // print the string for (i = 0; i < str1->len; ++i) { if ((n = uMap->mapUnicode(str1->text[i], buf, sizeof(buf))) > 0) { - fwrite(buf, 1, n, f); + (*outputFunc)(outputStream, buf, n); } } // 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 - fwrite(eol, 1, eolLen, f); + (*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)) @@ -564,107 +576,122 @@ void TextPage::dump(FILE *f) { } // 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) { - fwrite(eol, 1, eolLen, f); + (*outputFunc)(outputStream, eol, eolLen); } } // set up for next line col1 = 0; yMax = str1->yxNext ? str1->yxNext->yMax : fouble(0); } } // end of page - fwrite(eol, 1, eolLen, f); - fwrite(eop, 1, eopLen, f); - fwrite(eol, 1, eolLen, f); + (*outputFunc)(outputStream, eol, eolLen); + (*outputFunc)(outputStream, eop, eopLen); + (*outputFunc)(outputStream, eol, eolLen); uMap->decRefCnt(); } void TextPage::clear() { TextString *p1, *p2; if (curStr) { delete curStr; curStr = NULL; } for (p1 = yxStrings; p1; p1 = p2) { p2 = p1->yxNext; delete p1; } yxStrings = NULL; xyStrings = NULL; yxCur1 = yxCur2 = NULL; } //------------------------------------------------------------------------ // TextOutputDev //------------------------------------------------------------------------ +static void outputToFile(void *stream, char *text, int len) { + fwrite(text, 1, len, (FILE *)stream); +} + TextOutputDev::TextOutputDev(char *fileName, GBool rawOrderA, GBool append) { text = NULL; rawOrder = rawOrderA; ok = gTrue; // open file needClose = gFalse; if (fileName) { if (!strcmp(fileName, "-")) { - f = stdout; - } else if ((f = fopen(fileName, append ? "a" : "w"))) { + outputStream = stdout; + } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { needClose = gTrue; } else { error(-1, "Couldn't open text file '%s'", fileName); ok = gFalse; return; } + outputFunc = &outputToFile; } else { - f = NULL; + outputStream = NULL; } // set up text object text = new TextPage(rawOrder); } +TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, + GBool rawOrderA) { + outputFunc = func; + outputStream = stream; + needClose = gFalse; + rawOrder = rawOrderA; + text = new TextPage(rawOrder); + ok = gTrue; +} + TextOutputDev::~TextOutputDev() { if (needClose) { #ifdef MACOS - ICS_MapRefNumAndAssign((short)f->handle); + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); #endif - fclose(f); + fclose((FILE *)outputStream); } if (text) { delete text; } } void TextOutputDev::startPage(int pageNum, GfxState *state) { text->clear(); } void TextOutputDev::endPage() { text->coalesce(); - if (f) { - text->dump(f); + if (outputStream) { + text->dump(outputStream, outputFunc); } } void TextOutputDev::updateFont(GfxState *state) { text->updateFont(state); } void TextOutputDev::beginString(GfxState *state, GString *s) { text->beginString(state); } void TextOutputDev::endString(GfxState *state) { |