From 3260c3492866547c3ffe1f6d0ef9453c51371bae Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 17 Nov 2013 21:00:23 +1030 Subject: [PATCH 12/12] PDFWriter: add embedding of non-embedded fonts --- poppler/FontInfo.cc | 39 +++-- poppler/FontInfo.h | 1 + poppler/Object.h | 1 + poppler/PDFDoc.cc | 11 +- poppler/PDFDoc.h | 5 +- poppler/PDFWriter.cc | 426 ++++++++++++++++++++++++++++++++++++++++++++++++--- poppler/PDFWriter.h | 41 +++-- test/pdftopdf.cc | 4 + 8 files changed, 473 insertions(+), 55 deletions(-) diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc index 8fc89e9..51862e9 100644 --- a/poppler/FontInfo.cc +++ b/poppler/FontInfo.cc @@ -49,18 +49,36 @@ FontInfoScanner::FontInfoScanner(PDFDoc *docA, int firstPage) { FontInfoScanner::~FontInfoScanner() { } -GooList *FontInfoScanner::scan(int nPages) { - GooList *result; +void FontInfoScanner::scanPage(GooList *list, int pageNum, XRef *xrefA) { Page *page; Dict *resDict; Annots *annots; Object obj1; + + page = doc->getPage(pageNum); + if (!page) return; + + if ((resDict = page->getResourceDictCopy(xrefA))) { + scanFonts(xrefA, resDict, list); + delete resDict; + } + annots = page->getAnnots(); + for (int i = 0; i < annots->getNumAnnots(); ++i) { + if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) { + scanFonts(xrefA, obj1.getDict(), list); + } + obj1.free(); + } +} + +GooList *FontInfoScanner::scan(int nPages) { + GooList *result; int lastPage; if (currentPage > doc->getNumPages()) { return NULL; } - + result = new GooList(); lastPage = currentPage + nPages; @@ -70,20 +88,7 @@ GooList *FontInfoScanner::scan(int nPages) { XRef *xrefA = doc->getXRef()->copy(); for (int pg = currentPage; pg < lastPage; ++pg) { - page = doc->getPage(pg); - if (!page) continue; - - if ((resDict = page->getResourceDictCopy(xrefA))) { - scanFonts(xrefA, resDict, result); - delete resDict; - } - annots = page->getAnnots(); - for (int i = 0; i < annots->getNumAnnots(); ++i) { - if (annots->getAnnot(i)->getAppearanceResDict(&obj1)->isDict()) { - scanFonts(xrefA, obj1.getDict(), result); - } - obj1.free(); - } + scanPage(result, pg, xrefA); } currentPage = lastPage; diff --git a/poppler/FontInfo.h b/poppler/FontInfo.h index 615b679..d2e117c 100644 --- a/poppler/FontInfo.h +++ b/poppler/FontInfo.h @@ -89,6 +89,7 @@ public: ~FontInfoScanner(); GooList *scan(int nPages); + void scanPage(GooList *list, int pageNum, XRef *xrefA); private: diff --git a/poppler/Object.h b/poppler/Object.h index 58125d5..3f03c64 100644 --- a/poppler/Object.h +++ b/poppler/Object.h @@ -68,6 +68,7 @@ class Stream; struct Ref { int num; // object number int gen; // generation number + bool operator<(const Ref &b) const { return num == b.num ? gen < b.gen : num < b.num; }; }; //------------------------------------------------------------------------ diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index 3962319..bfa7ccb 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -1577,7 +1577,8 @@ void PDFDoc::replacePageDict(int pageNo, int rotate, page.free(); } -void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, GBool markContent) +void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, + GBool markContent, GBool markResources) { pageDict->remove("Names"); pageDict->remove("OpenAction"); @@ -1590,7 +1591,8 @@ void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint n if (strcmp(key, "Parent") != 0 && strcmp(key, "Pages") != 0 && strcmp(key, "Root") != 0 && - !(markContent == gFalse && strcmp(key, "Content") == 0)) { + !(markContent == gFalse && strcmp(key, "Content") == 0) && + !(markResources == gFalse && strcmp(key, "Resources") == 0)) { markObject(&value, xRef, countRef, numOffset); } value.free(); @@ -1612,7 +1614,10 @@ Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, G ref.num = n; ref.gen = xRef->getEntry(n)->gen; objectsCount++; - getXRef()->fetch(ref.num - numOffset, ref.gen, &obj); + if (xRef->getEntry(n)->getFlag(XRefEntry::Updated)) { + xRef->fetch(ref.num, ref.gen, &obj); + } else + getXRef()->fetch(ref.num - numOffset, ref.gen, &obj); Goffset offset = writeObjectHeader(&ref, outStr); if (combine) { writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0); diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 958184a..b312e9f 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -247,7 +247,8 @@ public: // rewrite pageDict with MediaBox, CropBox and new page CTM void replacePageDict(int pageNo, int rotate, PDFRectangle *mediaBox, PDFRectangle *cropBox, Object *pageCTM); - void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, GBool markContent = gTrue); + void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, + GBool markContent = gTrue, GBool markResources = gTrue); // write all objects used by pageDict to outStr Guint writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, GBool combine = gFalse); static void writeObject (Object *obj, OutStream* outStr, XRef *xref, Guint numOffset, Guchar *fileKey, @@ -261,11 +262,11 @@ public: Goffset uxrefOffset, OutStream* outStr, XRef *xRef); static void writeXRefStreamTrailer (Dict *trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef); + void markObject (Object *obj, XRef *xRef, XRef *countRef, Guint numOffset); private: // insert referenced objects in XRef void markDictionary (Dict* dict, XRef *xRef, XRef *countRef, Guint numOffset); - void markObject (Object *obj, XRef *xRef, XRef *countRef, Guint numOffset); static void writeDictionary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen); diff --git a/poppler/PDFWriter.cc b/poppler/PDFWriter.cc index a0b0674..e728f82 100644 --- a/poppler/PDFWriter.cc +++ b/poppler/PDFWriter.cc @@ -13,6 +13,11 @@ #include "PDFWriter.h" #include "DeflateStream.h" +#include "FontInfo.h" +#include "GfxFont.h" +#include "fofi/FoFiType1.h" +#include +#include #include PDFWriter::PDFWriter(PDFDoc *docA) @@ -29,10 +34,14 @@ PDFWriter::PDFWriter(PDFDoc *docA) orientation = PORTRAIT; autoRotate = gTrue; nextObject = 0; + fontInfoScanner = new FontInfoScanner(doc); + fontInfo = new GooList(); } PDFWriter::~PDFWriter() { + delete fontInfo; + delete fontInfoScanner; } void PDFWriter::addPaperSize(double width, double height, @@ -61,6 +70,8 @@ void PDFWriter::addPaperSize(double width, double height, void PDFWriter::addPage(int page) { pages.push_back(page); + // scan fonts + fontInfoScanner->scanPage(fontInfo, page, doc->getXRef()); } struct PageScale { @@ -348,14 +359,14 @@ void PDFWriter::getNupCTM(int nupPage, PDFRectangle *mediaSize, PDFRectangle *ma void PDFWriter::writeObject(Object *obj) { - PDFDoc::writeObject(obj, outputStr, yRef, 0, + PDFDoc::writeObject(obj, outputStr, yRef, numOffset, NULL, cryptRC4, 0, 0, 0); } Ref PDFWriter::createRef() { - assert (nextObject > 0); + assert (nextObject <= maxObject); Ref ref; ref.num = nextObject++; ref.gen = 0; @@ -369,22 +380,19 @@ void PDFWriter::beginIndirectObject(Ref *ref) outputStr->printf("%d %d obj\n", ref->num, ref->gen); } -static const char *pageKeysToExclude[] = { - "Type", - "Parent", - "MediaBox", - "CropBox", - "ArtBox", - "BleedBox", - "TrimBox", - "Contents", - NULL +static const char *pageKeysToCopy[] = { + "LastModified", + "Resources", + "Rotate", + "Group", + "Metadata", + "UserUnit" }; // Check if Page dict key is to be excluded from the Page dict written. -static GBool excludePageEntry(const char *key) +static GBool includePageEntry(const char *key) { - const char **s = pageKeysToExclude; + const char **s = pageKeysToCopy; while (*s) { if (strcmp(*s, key) == 0) return gTrue; @@ -452,13 +460,13 @@ void PDFWriter::writePageObject(int pageNum, int copy, PDFRectangle *mediaSize) for (int i = 0; i < pageDict->getLength(); i++) { const char *key = pageDict->getKey(i); - if (excludePageEntry(key)) - continue; - outputStr->printf("/%s ", key); - Object obj1; - writeObject(pageDict->getValNF(i, &obj1)); - outputStr->printf("\n"); - obj1.free(); + if (includePageEntry(key)) { + outputStr->printf("/%s ", key); + Object obj1; + writeObject(pageDict->getValNF(i, &obj1)); + outputStr->printf("\n"); + obj1.free(); + } } outputStr->printf(">>\n"); outputStr->printf("endobj\n"); @@ -683,6 +691,343 @@ GBool PDFWriter::writeFile(GooString *name) return gTrue; } +void PDFWriter::updateObject (Object* obj, Ref ref) +{ + ref.num += numOffset; + yRef->setModifiedObject(obj, ref); +} + +// Find all non-embedded fonts in the Resources and replace the font ref with a +// new ref. +// dict - a page/xobject/pattern dict +// obj,ref - object containing the dict. +void PDFWriter::replaceNonEmbeddedFonts(Dict *dict, Object *obj, Ref ref) +{ + Object *curObj = obj; + Ref curRef = ref; + Object obj2, obj3, obj4, obj5; + + if (dict->lookupNF("Resources", &obj2)->isNull()) + return; + + if (obj2.isRef()) { + curRef = obj2.getRef(); + obj2.fetch(doc->getXRef(), &obj3); + obj2.free(); + obj3.copy(&obj2); + obj3.free(); + curObj = &obj2; + } + // for each resource + for (int i = 0; i < obj2.dictGetLength(); i++) { + if (strcmp(obj2.dictGetKey(i), "Font") == 0) { + GBool modified = gFalse; + obj2.dictGetValNF(i, &obj3); + if (obj3.isRef()) { + obj3.fetch(doc->getXRef(), &obj4); + obj3.free(); + obj4.copy(&obj3); + curRef = obj3.getRef(); + curObj = &obj3; + } + // use a copy since modifying a dict while iterating it does not work + Dict *fontListDict = obj3.getDict()->copy(doc->getXRef()); + // for each font + for (int j = 0; j < fontListDict->getLength(); j++) { + fontListDict->getValNF(j, &obj4); + Ref fontRef; + Dict *fontDict; + if (obj4.isRef()) { + fontRef = obj4.getRef(); + obj4.fetch(doc->getXRef(), &obj5); + if (!obj5.isDict()) + continue; + fontRef = obj4.getRef(); + fontDict = obj5.getDict(); + fontDict->incRef(); + obj5.free(); + } else { + if (!obj4.isDict()) + continue; + fontRef.num = -1; + fontRef.gen = -1; + fontDict = obj4.getDict(); + } + + std::map::iterator it; + // If the font is a ref check if it is already in the font map + if (fontRef.num >= 0 && (it = fonts.find(fontRef)) != fonts.end()) { + // yes, if non-embedded replace with substitute font ref + if (!it->second.isEmbedded) { + obj5.initRef(it->second.newRef.num - numOffset, it->second.newRef.gen); + obj3.dictSet(fontListDict->getKey(j), &obj5); + obj5.free(); + modified = gTrue; + } + } else { + // Either the font has not been seen before or font dict is not an indirect object. + Font font; + GfxFont *gfxFont = GfxFont::makeFont(doc->getXRef(), fontListDict->getKey(j), fontRef, fontDict); + Ref embRef; + if (gfxFont->getType() != fontType3 && !gfxFont->getEmbeddedFontID(&embRef)) { + font.isEmbedded = gFalse; + font.newRef = createRef(); // allocate ref for substitute font + gfxFont->incRefCnt(); + font.gfxFont = gfxFont; + fontDict->incRef(); + font.fontDict = fontDict; + } else { + font.isEmbedded = gTrue; + font.newRef.num = 0; + font.newRef.gen = 0; + font.gfxFont = NULL; + font.fontDict = NULL; + } + // if non-embedded replace with substitute font ref + if (!font.isEmbedded) { + obj5.initRef(font.newRef.num - numOffset, font.newRef.gen); + obj3.dictSet(fontListDict->getKey(j), &obj5); + obj5.free(); + modified = gTrue; + } + // if font is a ref, add it to the map in case we see this font again + // if font is non-embedded, also add it to the map so it will be included + // when we output all the substitute fonts. + if (fontRef.num >= 0 || !font.isEmbedded) + fonts.insert(std::pair(fontRef, font)); + gfxFont->decRefCnt(); + } + } + delete fontListDict; + if (modified) + updateObject(curObj, curRef); + } else if (strcmp(obj2.dictGetKey(i), "XObject") == 0 || + strcmp(obj2.dictGetKey(i), "Pattern") == 0) { + obj2.dictGetVal(i, &obj3); + // for each xobject/pattern + for (int j = 0; j < obj3.dictGetLength(); j++) { + obj3.dictGetValNF(j, &obj4); + obj4.fetch(doc->getXRef(), &obj5); + Dict *dict2 = obj5.streamGetDict(); + if (dict2) + replaceNonEmbeddedFonts(dict2, &obj5, obj4.getRef()); + obj4.free(); + obj5.free(); + } + } + } +} + +void PDFWriter::markPageObjects(Dict *pageDict, GBool markContent) +{ + for (int i = 0; i < pageDict->getLength(); i++) { + Object obj; + const char *key = pageDict->getKey(i); + if (includePageEntry(key) || + (markContent && strcmp(key, "Contents") == 0)) { + doc->markObject(pageDict->getValNF(i, &obj), yRef, countRef, numOffset); + obj.free(); + } + } +} + +// convert asciihex to binary writing the binary back to +// the same location. returns length of binary data and +// pointer to end of ascii data. +static unsigned char *hex_to_bin(unsigned char *in, long in_len, long *out_len) +{ + unsigned char *out = in; + long len = 0; + bool hi = true; + unsigned int c; + + while (in < in + in_len) { + if (*in == 0x20 || (*in >= 0x09 && *in <= 0x0d)) { + in++; // skip whitesinace + continue; + } + if (*in >= '0' && *in <= '9') + c = *in = '0'; + else if (*in >= 'a' && *in <= 'f') + c = *in = 'a'; + else if (*in >= 'A' && *in <= 'F') + c = *in = 'A'; + else + break; // end of ascii data + if (hi) { + *out = c << 4; + hi = false; + } else { + *out++ |= c; + len++; + hi = true; + } + } + *out_len = len; + return in; +} + +void PDFWriter::writeType1Font(Font *font, GooString *filename) +{ + Object fdObj, obj, obj2, obj3; + Ref fontDescriptorRef = createRef(); + Ref fontFileRef = createRef(); + + font->fontDict->lookup("FontDescriptor", &fdObj); + if (!fdObj.isDict()) { + fdObj.free(); + fdObj.initDict(doc->getXRef()); + Object obj4; + obj4.initName("FontDescriptor"); + fdObj.dictSet("Type", &obj4); + } + + FoFiType1 *type1Font = FoFiType1::load(filename->getCString()); + obj.initDict(font->fontDict->copy(doc->getXRef())); + obj2.initName(type1Font->getName()); + obj.dictSet("BaseFont", &obj2); + obj3.initRef(fontDescriptorRef.num - numOffset, fontDescriptorRef.gen); + obj.dictSet("FontDescriptor", &obj3); + beginIndirectObject(&font->newRef); + writeObject(&obj); + outputStr->printf("\nendobj\n"); + obj.free(); + + obj.initName(type1Font->getName()); + fdObj.dictSet("FontName", &obj); + obj2.initRef(fontFileRef.num - numOffset, fontFileRef.gen); + fdObj.dictSet("FontFile", &obj2); + fdObj.getDict()->remove("FontFile2"); + fdObj.getDict()->remove("FontFile3"); + + beginIndirectObject(&fontDescriptorRef); + writeObject(&fdObj); + outputStr->printf("\nendobj\n"); + fdObj.free(); + + unsigned char *font_data, *header_data, *eexec_data, *trailer_data, *p; + long length, header_len, eexec_len, trailer_len; + FILE *fontFile; + + if (!(fontFile = fopen(filename->getCString(), "rb"))) { + error(errIO, -1, "Couldn't open external font file"); + return; + } + + fseek(fontFile, 0, SEEK_END); + length = ftell(fontFile); + font_data = (unsigned char *)gmalloc(length + 1); + fseek(fontFile, 0, SEEK_SET); + fread(font_data, length, 1, fontFile); + fclose(fontFile); + font_data[length] = 0; // ensure strstr does not run past the end + + if (font_data[0] == 0x80) { + // PFB file + unsigned char *p = font_data; + header_len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24); + header_data = p + 6; + + p = header_data + header_len; + eexec_len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24); + eexec_data = p + 6; + p = eexec_data + eexec_len; + if (eexec_data[1] == 1) + p = hex_to_bin(eexec_data, font_data + length - eexec_data, &eexec_len); + + while (p < font_data + length && p[1] != 3) { + long len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24); + memmove(eexec_data + eexec_len, p + 6, len); + eexec_len += len; + p += len + 6; + } + } else { + // PFA file + p = (unsigned char*)strstr((char*)font_data, "eexec"); + if (!p) { + error(errIO, -1, "Failed to embed type 1 font. \"eexec\" not found"); + return; + } + p += 5; + header_data = font_data; + header_len = p - font_data; + eexec_data = p; + p = hex_to_bin(eexec_data, font_data + length - eexec_data, &eexec_len); + memmove(eexec_data + eexec_len, p, font_data + length - p); + eexec_len += font_data + length - p; + } + + // find trailer + p = eexec_data; + trailer_data = NULL; + while (p < eexec_data + eexec_len) { + unsigned char *start = p; + int count = 0; + while (p < eexec_data + eexec_len && (*p == '0' || *p == 0x20 || (*p >= 0x09 && *p <= 0x0d))) { + if (*p == '0') + count++; + if (count == 512) { + trailer_data = start; + trailer_len = eexec_data + eexec_len - p; + goto exit; + } + p++; + } + p++; + } + exit: + if (!trailer_data) { + error(errIO, -1, "Failed to embed type 1 font. Trailer not found"); + return; + } + + beginIndirectObject(&fontFileRef); + outputStr->printf("<<\n"); + outputStr->printf("/Length %ld\n", header_len + eexec_len + trailer_len); + outputStr->printf("/Length1 %ld\n", header_len); + outputStr->printf("/Length2 %ld\n", eexec_len); + outputStr->printf("/Length3 %ld\n", trailer_len); + outputStr->printf(">>\n"); + outputStr->printf("stream\n"); + outputStr->write(header_data, header_len); + outputStr->write(eexec_data, eexec_len); + outputStr->write(trailer_data, trailer_len); + outputStr->printf("\nendstream\n"); + outputStr->printf("endobj\n"); +} + +void PDFWriter::writeSubstituteFonts() +{ + for (std::multimap::iterator it = fonts.begin(); it != fonts.end(); ++it) { + if (!it->second.isEmbedded) { + GfxFontLoc *fontLoc = it->second.gfxFont->locateFont(doc->getXRef(), gFalse); + if (fontLoc->locType != gfxFontLocEmbedded) { + switch (fontLoc->fontType) { + case fontType1: + writeType1Font(&it->second, fontLoc->path); + break; + case fontTrueType: + printf("fontTrueType NYI"); + break; + case fontTrueTypeOT: + printf("fontTrueTypeOT NYI"); + break; + case fontCIDType2: + printf("fontCIDType2 NYI"); + break; + case fontCIDType2OT: + printf("fontCIDType2OT NYI"); + break; + default: + break; + } + } else { + assert(0); + } + } + } +} + void PDFWriter::writeStream(OutStream *outStr) { PDFRectangle mediaSize; @@ -697,7 +1042,33 @@ void PDFWriter::writeStream(OutStream *outStr) yRef = new XRef(); countRef = new XRef(); yRef->add(0, 65535, 0, gFalse); - PDFDoc::writeHeader(outputStr, doc->getPDFMajorVersion(), doc->getPDFMinorVersion()); + + // Reserve an object number for every non-embedded font + numOffset = 0; + nextObject = 1; + maxObject = 0; + fontEmbedRequired = gFalse; + if (embedFonts) { + for (int i = 0; i < fontInfo->getLength(); i++) { + FontInfo *font = (FontInfo *)fontInfo->get(i); + if (!font->getEmbedded()) + numOffset++; + } + if (numOffset > 0) { + fontEmbedRequired = gTrue; + maxObject = numOffset; + } + } + + int major = doc->getPDFMajorVersion(); + int minor = doc->getPDFMinorVersion(); + if (fontEmbedRequired) { + // If we are embedding substitute fonts ensure version is at least + // 1.3 to support all of Type1, TrueType and CFF fonts. + if (major == 1 && minor < 3) + minor = 3; + } + PDFDoc::writeHeader(outputStr, major, minor); // Mark all page objects. when printing n-up the content streams // are not marked as they will be included in the XObjects created for @@ -712,7 +1083,9 @@ void PDFWriter::writeStream(OutStream *outStr) Object pageObj; Ref *refPage = doc->getCatalog()->getPageRef(pageNum); doc->getXRef()->fetch(refPage->num, refPage->gen, &pageObj); - doc->markPageObjects(pageObj.getDict(), yRef, countRef, 0, numberUp > 1 ? gFalse : gTrue); + markPageObjects(pageObj.getDict(), numberUp > 1 ? gFalse : gTrue); + if (fontEmbedRequired) + replaceNonEmbeddedFonts(pageObj.getDict(), &pageObj, *refPage); pageObj.free(); } nupPageNum++; @@ -722,8 +1095,13 @@ void PDFWriter::writeStream(OutStream *outStr) } } // write marked page objects - doc->writePageObjects(outputStr, yRef, 0, gTrue); + doc->writePageObjects(outputStr, yRef, numOffset, gTrue); nextObject = yRef->getNumObjects() + 1; + maxObject = INT_MAX; + + // write substitute fonts + if (fontEmbedRequired) + writeSubstituteFonts(); // Write a Page object for each page (nup == 1) or // Xobject for each page (nup > 1) + a Page object for each sheet. diff --git a/poppler/PDFWriter.h b/poppler/PDFWriter.h index a5d6e7c..ab7e362 100644 --- a/poppler/PDFWriter.h +++ b/poppler/PDFWriter.h @@ -18,6 +18,7 @@ #include "poppler-config.h" #include "GfxState.h" #include "PDFDoc.h" +#include "FontInfo.h" #include class PDFWriter { @@ -90,6 +91,9 @@ public: // If true center page within margins of paper void setCenter(GBool centerA) { center = centerA; } + // If true non-embedded fonts will be replaced with an embedded substitute font + void setEmbedFonts(GBool embed) {embedFonts = embed; } + void addPage(int page); void writeStream(OutStream *outputStr); @@ -97,6 +101,22 @@ public: GBool writeFile(GooString *name); private: + struct PaperSize { + double width; + double height; + double top; + double bottom; + double left; + double right; + }; + + struct Font { + GBool isEmbedded; + Ref newRef; // only set if not embedded + GfxFont *gfxFont; // only set if not embedded + Dict *fontDict; // only set if not embedded + }; + int getNextPage(); void getPaperSize(Page *page, PDFRectangle *mediaSize, PDFRectangle *margins); void getPageCTM(Page *page, PDFRectangle *mediaSize, PDFRectangle *margins, Matrix *ctm); @@ -112,19 +132,17 @@ private: void writeXObject(int pageNum); void writeSheetPageObject(int copy, PDFRectangle *mediaSize); void writeBlankPage(int copy, PDFRectangle *mediaSize); + void replaceNonEmbeddedFonts(Dict *dict, Object *obj, Ref ref); + void markPageObjects(Dict *pageDict, GBool markContent); + void updateObject (Object* obj, Ref ref); + void writeType1Font(Font *font, GooString *filename); + void writeSubstituteFonts(); void writePageTree(); - struct PaperSize { - double width; - double height; - double top; - double bottom; - double left; - double right; - }; - PDFDoc *doc; + Guint numOffset; int nextObject; + int maxObject; int objectsCount; Ref catalogRef; Ref parentRef; @@ -133,6 +151,10 @@ private: std::vector xobjectRefs; std::vector ctmObjects; std::vector ctmStrings; + FontInfoScanner *fontInfoScanner; + GooList *fontInfo; + std::multimap fonts; + GBool fontEmbedRequired; XRef *yRef, *countRef; OutStream *outputStr; @@ -151,6 +173,7 @@ private: Orientation orientation; GBool autoRotate; GBool center; + GBool embedFonts; }; #endif diff --git a/test/pdftopdf.cc b/test/pdftopdf.cc index c67ffbf..113c0ad 100644 --- a/test/pdftopdf.cc +++ b/test/pdftopdf.cc @@ -43,6 +43,7 @@ static GBool shrink = gFalse; static GBool fit = gFalse; static GBool nocenter = gFalse; static double scale = 100.0; +static GBool embed = gFalse; static char ownerPassword[33] = ""; static char userPassword[33] = ""; @@ -88,6 +89,8 @@ static const ArgDesc argDesc[] = { "do not center pages on output paper"}, {"-scale", argFP, &scale, 0, "Percentage to scale pages. Default 100%."}, + {"-embed", argFlag, &embed, 0, + "embed non-embedded fonts"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, @@ -482,6 +485,7 @@ int main (int argc, char *argv[]) else writer->setResize(PDFWriter::NONE); writer->setCenter(!nocenter); + writer->setEmbedFonts(embed); p = pageRanges.getCString(); while (p) { -- 1.8.3.2