From af3daa01f6b0d82b11c476cc26bcfbbc4735739b Mon Sep 17 00:00:00 2001 From: "edisonn@google.com" Date: Wed, 12 Jun 2013 19:07:45 +0000 Subject: Code generator for dinamic generation of podofo wrappers Review URL: https://codereview.chromium.org/16838002 git-svn-id: http://skia.googlecode.com/svn/trunk@9544 2bbb7eff-a529-9590-31e7-b0007b416f81 --- experimental/PdfViewer/generate_code.py | 299 +++++++++++++++++++++---- experimental/PdfViewer/pdf_viewer_main.cpp | 343 +++++++++++++++++++++++------ 2 files changed, 533 insertions(+), 109 deletions(-) (limited to 'experimental') diff --git a/experimental/PdfViewer/generate_code.py b/experimental/PdfViewer/generate_code.py index d453cd24b4..1ac6bba4f5 100644 --- a/experimental/PdfViewer/generate_code.py +++ b/experimental/PdfViewer/generate_code.py @@ -4,23 +4,45 @@ class PdfName: def __init__(self, name, abr=''): self.fName = name self.fAbr = abr + + def toCpp(self): + return '\"' + self.fName + '\"' + +class PdfString: + def __init__(self, value): + self.fValue = value + + def toCpp(self): + return '\"' + self.fValue + '\"' class PdfInteger: def __init__(self, value): self.fValue = value + def toCpp(self): + return str(self.fValue) + class PdfReal: def __init__(self, value): self.fValue = value + def toCpp(self): + return str(self.fValue) + class PdfString: def __init__(self, value): self.fValue = value + def toCpp(self): + return self.fValue + class PdfBoolean: def __init__(self, value): self.fValue = value + def toCpp(self): + return self.fValue + class PdfField: def __init__(self, parent, name, abr): self.fParent = parent @@ -29,37 +51,59 @@ class PdfField: self.fDefault = '' self.fType = '' + self.fCppName = '' + self.fCppType = '' + self.fCppReader = '' + self.fValidOptions = [] + self.fHasMust = False + self.fMustBe = '' def must(self, value): - return self.fParent + self.fHasMust = True + self.fMustBe = value + return self def default(self, value): self.fDefault = value return self - def number(self): + def number(self, name): self.fType = 'number' + self.fCppName = name + self.fCppType = 'double' + self.fCppReader = 'DoubleFromDictionary' return self - def integer(self): + def integer(self, name): self.fType = 'integer' + self.fCppName = name + self.fCppType = 'long' + self.fCppReader = 'LongFromDictionary' return self - def real(self): + def real(self, name): self.fType = 'real' + self.fCppName = name + self.fCppType = 'double' + self.fCppReader = 'DoubleFromDictionary' return self - def name(self): + def name(self, name): self.fType = 'name' + self.fCppName = name + self.fCppType = 'std::string' + self.fCppReader = 'NameFromDictionary' return self - def string(self): + def string(self, name): self.fType = 'string' + self.fCppName = name + self.fCppType = 'std::string' + self.fCppReader = 'StringFromDictionary' return self - def multiple(self, options): - self.fType = 'multiple' - self.fOptions = options + def multiple(self, validOptions): + self.fValidOptions = validOptions return self def done(self): @@ -68,14 +112,13 @@ class PdfField: class PdfClassField: def __init__(self, parent, required): - self.fFields = [] - self.fIncludes = [] - self.fCC = [] + #self.fProp = '' self.fParent = parent self.fRequired = required - def hasField(self, name, abr=''): - return PdfField(self, name, abr) + def field(self, name, abr=''): + self.fProp = PdfField(self, name, abr) + return self.fProp def done(self): return self.fParent @@ -84,7 +127,8 @@ class PdfClass: def __init__(self, name, base): self.fFields = [] self.fIncludes = [] - self.fCC = [] + self.fCCPublic = [] + self.fCCPrivate = [] self.fName = name self.fBase = base @@ -93,8 +137,9 @@ class PdfClass: self.fEnum = '!UNDEFINED' self.fEnumEnd = '!UNDEFINED' - def required(self): + def required(self, badDefault): field = PdfClassField(self, True) + field.fBadDefault = badDefault self.fFields.append(field) return field @@ -107,17 +152,26 @@ class PdfClass: self.fIncludes.append(path) return self - def carbonCopy(self, cc): - self.fCC.append(cc) + def carbonCopyPublic(self, cc): + self.fCCPublic.append(cc) + return self + + def carbonCopyPrivate(self, cc): + self.fCCPrivate.append(cc) return self class PdfClassManager: def __init__(self): self.fClasses = {} + self.fClassesNamesInOrder = [] - def addClass(self, name, base=''): - cls = PdfClass(name, base) + def addClass(self, name, base='Object'): + if name == 'Object': + cls = PdfClass(name, '') + else: + cls = PdfClass(name, base) self.fClasses[name] = cls + self.fClassesNamesInOrder.append(name) return cls def longName(self, name): @@ -142,6 +196,45 @@ class PdfClassManager: if cnt != 0: print(' ' + cls.fEnumEnd + ',') + + + def writeAsNull(self, cls, enumToCls): + print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return NULL;}') + print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return NULL;}') + print + + cnt = 0 + for sub in cls.fEnumSubclasses: + self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls) + cnt = cnt + 1 + + + def writeAsFoo(self, cls, enumToCls): + # TODO(edisonn): add a container, with sections, public, private, default, ... + # the end code will be grouped + + # me + print('public:') + print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return this;}') + print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return this;}') + print + + if cls.fName == 'Object': + cnt = 0 + for sub in cls.fEnumSubclasses: + self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls) + cnt = cnt + 1 + + if cls.fName != 'Object': + print('private:') + base = self.fClasses[cls.fBase] + cnt = 0 + for sub in base.fEnumSubclasses: + if enumToCls[base.fEnumSubclasses[cnt]].fName != cls.fName: + self.writeAsNull(enumToCls[base.fEnumSubclasses[cnt]], enumToCls) + cnt = cnt + 1 + + def write(self): # generate enum @@ -152,8 +245,8 @@ class PdfClassManager: for name in self.fClasses: cls = self.fClasses[name] enum = self.longName(name) - cls.fEnum = 'k' + enum + '_PdfObjectType' - cls.fEnumEnd = 'k' + enum + '__End_PdfObjectType' + cls.fEnum = 'k' + enum + '_SkPdfObjectType' + cls.fEnumEnd = 'k' + enum + '__End_SkPdfObjectType' if cls.fBase != '': self.fClasses[cls.fBase].fEnumSubclasses.append(cls.fEnum) @@ -165,14 +258,138 @@ class PdfClassManager: enumsRoot.sort() + + # TODO(edisonn): move each .h in it's own file + # write imports + # write enums - print('enum PdfObjectType {') + print('enum SkPdfObjectType {') for enum in enumsRoot: self.writeEnum(enum, enumToCls) print('};') + print + + # write forward class declaration + for name in self.fClassesNamesInOrder: + print('class SkPdf' + name + ';') + print + + for name in self.fClassesNamesInOrder: + cls = self.fClasses[name] + enum = cls.fEnum + + if cls.fBase == '': + print('class SkPdf' + cls.fName + ' {') + else: + print('class SkPdf' + cls.fName + ' : public SkPdf' + cls.fBase + ' {') + + print('public:') + print(' virtual SkPdfObjectType getType() const { return ' + cls.fEnum + ';}') + if len(cls.fEnumSubclasses) == 0: + print(' virtual SkPdfObjectType getTypeEnd() const { return (SkPdfObjectType)(' + cls.fEnum + ' + 1);}') + else: + print(' virtual SkPdfObjectType getTypeEnd() const { return ' + cls.fEnumEnd + ';}') + + + self.writeAsFoo(cls, enumToCls) + + print('public:') + for cc in cls.fCCPublic: + print(' ' + cc) + + print('private:') + for cc in cls.fCCPrivate: + print(' ' + cc) + + if cls.fBase == '': + print('protected:') + print(' const PdfMemDocument* fPodofoDoc;') + print(' const PdfObject* fPodofoObj;') + print + print('public:') + print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : fPodofoDoc(podofoDoc), fPodofoObj(podofoObj) {}') + print(' const PdfObject* podofo() const { return fPodofoObj;}') + else: + print('public:') + print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : SkPdf' + cls.fBase + '(podofoDoc, podofoObj) {}') + + #check required fieds, also, there should be an internal_valid() manually wrote for complex + # situations + # right now valid return true + print(' virtual bool valid() const {return true;}') + + for field in cls.fFields: + prop = field.fProp + if prop.fCppName != '': + print(' ' + prop.fCppType + ' ' + prop.fCppName + '() const {') + print(' ' + prop.fCppType + ' ret;') + print(' if (' + prop.fCppReader + '(fPodofoDoc, fPodofoObj->GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &ret)) return ret;') + if field.fRequired == False: + print(' return ' + prop.fDefault.toCpp() + ';'); + if field.fRequired == True: + print(' // TODO(edisonn): warn about missing required field, assert for known good pdfs') + print(' return ' + field.fBadDefault + ';'); + print(' }') + print + + print('};') + print + print + + + + # generate constructor when knowing the type + # later, p2, generate constructor when not knowing the type - very similar with parsing? - # generate each class # generate parser + + # TODO(edisonn): fast recognition based on must attributes. + print('class PodofoMapper {') + print('public:') + for name in self.fClassesNamesInOrder: + cls = self.fClasses[name] + + print(' static bool map' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj, SkPdfObject** out) {') + print(' if (!isA' + name + '(podofoDoc, podofoObj)) return false;') + print + + for sub in cls.fEnumSubclasses: + print(' if (map' + enumToCls[sub].fName + '(podofoDoc, podofoObj, out)) return true;') + + print + + print(' *out = new SkPdf' + name + '(&podofoDoc, &podofoObj);') + print(' return true;') + print(' }') + print + + for name in self.fClassesNamesInOrder: + cls = self.fClasses[name] + + print(' static bool isA' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj) {') + + cntMust = 0 + for field in cls.fFields: + prop = field.fProp + if prop.fHasMust: + cntMust = cntMust + 1 + print(' ' + prop.fCppType + ' ' + prop.fCppName + ';') + print(' if (!' + prop.fCppReader + '(&podofoDoc, podofoObj.GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &' + prop.fCppName + ')) return false;') + print(' if (' + prop.fCppName + ' != ' + prop.fMustBe.toCpp() + ') return false;') + print + + # hack, we only care about dictionaries now, so ret tru only if there is a match + if cntMust != 0 or name == 'Object' or name == 'Dictionary': + print(' return true;') + else: + print(' return false;') + + print(' }') + print + + print('};') + print + return def generateCode(): @@ -189,22 +406,28 @@ def generateCode(): all.addClass('Array') all.addClass('Dictionary') - all.addClass('XObject', 'Dictionary').required().hasField('/Type').must('/XObject') + all.addClass('XObject', 'Dictionary').required('""').field('Type').must(PdfName('XObject')).name('t') - all.addClass('Image', 'XObject').required().hasField('/Type').must('/XObject').done()\ - .required().hasField('/Subtype').must('/Image').done()\ - .required().hasField('/Width', '/W').integer().done().done()\ - .required().hasField('/Height', '/H').integer().done().done()\ - .required().hasField('/ColorSpace').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')])\ + all.addClass('Image', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\ + .done()\ + .required('""').field('Subtype').must(PdfName('Image')).name('s').done()\ + .done()\ + .required('-1').field('Width', 'W').integer('w').done()\ + .done()\ + .required('-1').field('Height', 'H').integer('h').done()\ + .done()\ + .required('""').field('ColorSpace').name('cs').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')]).done()\ + .done()\ + .optional().field('BitsPerComponent', 'BPC').integer('bpc').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\ + .default(PdfInteger(1)).done()\ .done()\ - .done()\ - .optional().hasField('/BitsPerComponent', '/BPC').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\ - .default(PdfInteger(1))\ - .done().done()\ - .carbonCopy('SkBitmap bitmap;') - - all.addClass('Form', 'XObject').required().hasField('/Type').must('/XObject').done()\ - .required().hasField('/Subtype').must('/Form').done() + .carbonCopyPrivate('SkBitmap bitmap;') + + all.addClass('Form', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\ + .done()\ + .required('""').field('Subtype').must(PdfName('Form')).name('s').done()\ + .done()\ + .carbonCopyPublic('void test() {}') all.write() diff --git a/experimental/PdfViewer/pdf_viewer_main.cpp b/experimental/PdfViewer/pdf_viewer_main.cpp index 9f4c009a40..1b2ae2b47e 100644 --- a/experimental/PdfViewer/pdf_viewer_main.cpp +++ b/experimental/PdfViewer/pdf_viewer_main.cpp @@ -22,6 +22,29 @@ #include #include "podofo.h" +using namespace PoDoFo; + +bool LongFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + long* data); + +bool BoolFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + bool* data); + +bool NameFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + std::string* data); + + + +#include "pdf_auto_gen.h" /* * TODO(edisonn): ASAP so skp -> pdf -> png looks greap @@ -31,7 +54,7 @@ * - load font for youtube.pdf */ -//#define PDF_TRACE +#define PDF_TRACE //#define PDF_TRACE_DIFF_IN_PNG //#define PDF_DEBUG_NO_CLIPING //#define PDF_DEBUG_NO_PAGE_CLIPING @@ -78,9 +101,9 @@ int GetColorSpaceComponents(const std::string& colorSpace) { } } -PdfObject* resolveReferenceObject(PdfMemDocument* pdfDoc, - PdfObject* obj, - bool resolveOneElementArrays = false) { +const PdfObject* resolveReferenceObject(const PdfMemDocument* pdfDoc, + const PdfObject* obj, + bool resolveOneElementArrays = false) { while (obj && (obj->IsReference() || (resolveOneElementArrays && obj->IsArray() && obj->GetArray().GetSize() == 1))) { @@ -152,7 +175,7 @@ struct PdfGraphicsState { double fWordSpace; double fCharSpace; - PdfObject* fObjectWithResources; + const PdfObject* fObjectWithResources; SkBitmap fSMask; @@ -562,7 +585,7 @@ PdfEncoding* FixPdfFont(PdfContext* pdfContext, PdfFont* fCurFont) { if (fCurFont->GetObject()->IsDictionary() && fCurFont->GetObject()->GetDictionary().HasKey(PdfName("ToUnicode"))) { PdfCMapEncoding* enc = new PdfCMapEncoding( fCurFont->GetObject(), - resolveReferenceObject(pdfContext->fPdfDoc, + (PdfObject*)resolveReferenceObject(pdfContext->fPdfDoc, fCurFont->GetObject()->GetDictionary().GetKey(PdfName("ToUnicode"))), PdfCMapEncoding::eBaseEncoding_Identity); // todo, read the base encoding gFontsFixed[fCurFont] = enc; @@ -728,12 +751,12 @@ PdfResult PdfOp_Tc(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo // TODO(edisonn): deal with synonyms (/BPC == /BitsPerComponent), here or in GetKey? // Always pass long form in key, and have a map of long -> short key -bool LongFromDictionary(PdfContext* pdfContext, - PdfDictionary& dict, +bool LongFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, const char* key, long* data) { - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, - dict.GetKey(PdfName(key))); + const PdfObject* value = resolveReferenceObject(pdfDoc, + dict.GetKey(PdfName(key))); if (value == NULL || !value->IsNumber()) { return false; @@ -743,12 +766,22 @@ bool LongFromDictionary(PdfContext* pdfContext, return true; } -bool BoolFromDictionary(PdfContext* pdfContext, - PdfDictionary& dict, +bool LongFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + long* data) { + if (LongFromDictionary(pdfDoc, dict, key, data)) return true; + if (abr == NULL || *abr == '\0') return false; + return LongFromDictionary(pdfDoc, dict, abr, data); +} + +bool BoolFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, const char* key, bool* data) { - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, - dict.GetKey(PdfName(key))); + const PdfObject* value = resolveReferenceObject(pdfDoc, + dict.GetKey(PdfName(key))); if (value == NULL || !value->IsBool()) { return false; @@ -758,13 +791,23 @@ bool BoolFromDictionary(PdfContext* pdfContext, return true; } -bool NameFromDictionary(PdfContext* pdfContext, - PdfDictionary& dict, +bool BoolFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + bool* data) { + if (BoolFromDictionary(pdfDoc, dict, key, data)) return true; + if (abr == NULL || *abr == '\0') return false; + return BoolFromDictionary(pdfDoc, dict, abr, data); +} + +bool NameFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, const char* key, std::string* data) { - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, - dict.GetKey(PdfName(key)), - true); + const PdfObject* value = resolveReferenceObject(pdfDoc, + dict.GetKey(PdfName(key)), + true); if (value == NULL || !value->IsName()) { return false; } @@ -773,6 +816,16 @@ bool NameFromDictionary(PdfContext* pdfContext, return true; } +bool NameFromDictionary(const PdfMemDocument* pdfDoc, + const PdfDictionary& dict, + const char* key, + const char* abr, + std::string* data) { + if (NameFromDictionary(pdfDoc, dict, key, data)) return true; + if (abr == NULL || *abr == '\0') return false; + return NameFromDictionary(pdfDoc, dict, abr, data); +} + // TODO(edisonn): perf!!! static SkColorTable* getGrayColortable() { @@ -899,14 +952,81 @@ bool transferImageStreamToARGB(unsigned char* uncompressedStream, pdf_long uncom // this functions returns the image, it does not look at the smask. -SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transparencyMask) { +SkBitmap getImageFromObject(PdfContext* pdfContext, const SkPdfImage* image, bool transparencyMask) { + if (image == NULL || !image->valid()) { + // TODO(edisonn): report warning to be used in testing. + return SkBitmap(); + } + + // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ... +// PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, +// obj.GetDictionary().GetKey(PdfName("Filter"))); +// if (value && value->IsArray() && value->GetArray().GetSize() == 1) { +// value = resolveReferenceObject(pdfContext->fPdfDoc, +// &value->GetArray()[0]); +// } +// if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") { +// SkStream stream = SkStream:: +// SkImageDecoder::Factory() +// } + + long bpc = image->bpc(); + long width = image->w(); + long height = image->h(); + std::string colorSpace = image->cs(); + +/* + bool imageMask = image->imageMask(); + + if (imageMask) { + if (bpc != 0 && bpc != 1) { + // TODO(edisonn): report warning to be used in testing. + return SkBitmap(); + } + bpc = 1; + } +*/ + + const PdfObject* obj = image->podofo(); + + char* uncompressedStream = NULL; + pdf_long uncompressedStreamLength = 0; + + PdfResult ret = kPartial_PdfResult; + // TODO(edisonn): get rid of try/catch exceptions! We should not throw on user data! + try { + obj->GetStream()->GetFilteredCopy(&uncompressedStream, &uncompressedStreamLength); + } catch (PdfError& e) { + // TODO(edisonn): report warning to be used in testing. + return SkBitmap(); + } + + int bytesPerLine = uncompressedStreamLength / height; +#ifdef PDF_TRACE + if (uncompressedStreamLength % height != 0) { + printf("Warning uncompressedStreamLength % height != 0 !!!\n"); + } +#endif + + SkBitmap bitmap = transferImageStreamToBitmap( + (unsigned char*)uncompressedStream, uncompressedStreamLength, + width, height, bytesPerLine, + bpc, colorSpace, + transparencyMask); + + free(uncompressedStream); + + return bitmap; +} + +SkBitmap getImageFromObjectOld(PdfContext* pdfContext, const PdfObject& obj, bool transparencyMask) { if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 || !obj.IsDictionary()) { // TODO(edisonn): report warning to be used in testing. return SkBitmap(); } - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("Filter"))); if (value && value->IsArray() && value->GetArray().GetSize() == 1) { @@ -924,10 +1044,10 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa // translate long bpc = 0; - LongFromDictionary(pdfContext, obj.GetDictionary(), "BitsPerComponent", &bpc); + LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "BitsPerComponent", "BPC", &bpc); bool imageMask = false; - BoolFromDictionary(pdfContext, obj.GetDictionary(), "ImageMask", &imageMask); + BoolFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ImageMask", "", &imageMask); if (imageMask) { if (bpc != 0 && bpc != 1) { @@ -938,19 +1058,19 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa } long width; - if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Width", &width)) { + if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Width", &width)) { // TODO(edisonn): report warning to be used in testing. return SkBitmap(); } long height; - if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Height", &height)) { + if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Height", &height)) { // TODO(edisonn): report warning to be used in testing. return SkBitmap(); } std::string colorSpace; // TODO(edisonn): load others than names, for more complicated - if (!NameFromDictionary(pdfContext, obj.GetDictionary(), "ColorSpace", &colorSpace)) { + if (!NameFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ColorSpace", &colorSpace)) { // TODO(edisonn): report warning to be used in testing. return SkBitmap(); } @@ -985,8 +1105,29 @@ SkBitmap getImageFromObject(PdfContext* pdfContext, PdfObject& obj, bool transpa return bitmap; } -SkBitmap getSmaskFromObject(PdfContext* pdfContext, PdfObject& obj) { - PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc, +SkBitmap getSmaskFromObject(PdfContext* pdfContext, const SkPdfImage* obj) { + const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc, + obj->podofo()->GetDictionary().GetKey(PdfName("SMask"))); + +#ifdef PDF_TRACE + std::string str; + if (sMask) { + sMask->ToString(str); + printf("/SMask of /Subtype /Image: %s\n", str.c_str()); + } +#endif + + if (sMask) { + SkPdfImage skxobjmask(pdfContext->fPdfDoc, sMask); + return getImageFromObject(pdfContext, &skxobjmask, true); + } + + // TODO(edisonn): implement GS SMask. Default to empty right now. + return pdfContext->fGraphicsState.fSMask; +} + +SkBitmap getSmaskFromObjectOld(PdfContext* pdfContext, const PdfObject& obj) { + const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("SMask"))); #ifdef PDF_TRACE @@ -998,21 +1139,50 @@ SkBitmap getSmaskFromObject(PdfContext* pdfContext, PdfObject& obj) { #endif if (sMask) { - return getImageFromObject(pdfContext, *sMask, true); + return getImageFromObjectOld(pdfContext, *sMask, true); } // TODO(edisonn): implement GS SMask. Default to empty right now. return pdfContext->fGraphicsState.fSMask; } -PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { + +PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfImage* skpdfimage) { + if (skpdfimage == NULL || !skpdfimage->valid()) { + return kIgnoreError_PdfResult; + } + + SkBitmap image = getImageFromObject(pdfContext, skpdfimage, false); + SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage); + + canvas->save(); + canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); + SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), SkDoubleToScalar(1.0), SkDoubleToScalar(1.0)); + + if (sMask.empty()) { + canvas->drawBitmapRect(image, dst, NULL); + } else { + canvas->saveLayer(&dst, NULL); + canvas->drawBitmapRect(image, dst, NULL); + SkPaint xfer; + xfer.setXfermodeMode(SkXfermode::kSrcOut_Mode); // SkXfermode::kSdtOut_Mode + canvas->drawBitmapRect(sMask, dst, &xfer); + canvas->restore(); + } + + canvas->restore(); + + return kPartial_PdfResult; +} + +PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 || !obj.IsDictionary()) { return kIgnoreError_PdfResult; } - SkBitmap image = getImageFromObject(pdfContext, obj, false); - SkBitmap sMask = getSmaskFromObject(pdfContext, obj); + SkBitmap image = getImageFromObjectOld(pdfContext, obj, false); + SkBitmap sMask = getSmaskFromObjectOld(pdfContext, obj); canvas->save(); canvas->setMatrix(pdfContext->fGraphicsState.fMatrix); @@ -1034,13 +1204,14 @@ PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& o return kPartial_PdfResult; } -PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { + +PdfResult doXObject_ImageOld2(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0 || !obj.IsDictionary()) { return kIgnoreError_PdfResult; } - PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* sMask = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("SMask"))); // TODO(edisonn): else get smask from graphi state // TODO(edisonn): add utility, SkBitmap loadBitmap(PdfObject& obj, bool no_smask); @@ -1054,6 +1225,8 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject } #endif +/* + // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ... PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("Filter"))); @@ -1062,20 +1235,19 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject &value->GetArray()[0]); } - // TODO (edisonn): Fast Jpeg(DCTDecode) draw, or fast PNG(FlateDecode) draw ... -// if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") { -// SkStream stream = SkStream:: -// SkImageDecoder::Factory() -// } - + if (value && value->IsName() && value->GetName().GetName() == "DCTDecode") { + SkStream stream = SkStream:: + SkImageDecoder::Factory() + } +*/ // Get color space // trasnlate long bpc = 0; - LongFromDictionary(pdfContext, obj.GetDictionary(), "BitsPerComponent", &bpc); + LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "BitsPerComponent", "BPC", &bpc); bool imageMask = false; - BoolFromDictionary(pdfContext, obj.GetDictionary(), "ImageMask", &imageMask); + BoolFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ImageMask", "", &imageMask); if (imageMask) { if (bpc != 0 && bpc != 1) { @@ -1085,17 +1257,17 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject } long width; - if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Width", &width)) { + if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Width", "W", &width)) { return kIgnoreError_PdfResult; } long height; - if (!LongFromDictionary(pdfContext, obj.GetDictionary(), "Height", &height)) { + if (!LongFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "Height", "H", &height)) { return kIgnoreError_PdfResult; } std::string colorSpace; // TODO(edisonn): load others than names, for more complicated - if (!NameFromDictionary(pdfContext, obj.GetDictionary(), "ColorSpace", &colorSpace)) { + if (!NameFromDictionary(pdfContext->fPdfDoc, obj.GetDictionary(), "ColorSpace", "", &colorSpace)) { return kIgnoreError_PdfResult; } @@ -1146,10 +1318,10 @@ PdfResult doXObject_ImageOld(PdfContext* pdfContext, SkCanvas* canvas, PdfObject } bool SkMatrixFromDictionary(PdfContext* pdfContext, - PdfDictionary& dict, + const PdfDictionary& dict, const char* key, SkMatrix* matrix) { - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, dict.GetKey(PdfName(key))); if (value == NULL || !value->IsArray()) { @@ -1162,7 +1334,7 @@ bool SkMatrixFromDictionary(PdfContext* pdfContext, double array[6]; for (int i = 0; i < 6; i++) { - PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]); + const PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]); if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) { return false; } @@ -1174,10 +1346,10 @@ bool SkMatrixFromDictionary(PdfContext* pdfContext, } bool SkRectFromDictionary(PdfContext* pdfContext, - PdfDictionary& dict, + const PdfDictionary& dict, const char* key, SkRect* rect) { - PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, dict.GetKey(PdfName(key))); if (value == NULL || !value->IsArray()) { @@ -1190,7 +1362,7 @@ bool SkRectFromDictionary(PdfContext* pdfContext, double array[4]; for (int i = 0; i < 4; i++) { - PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]); + const PdfObject* elem = resolveReferenceObject(pdfContext->fPdfDoc, &value->GetArray()[i]); if (elem == NULL || (!elem->IsReal() && !elem->IsNumber())) { return false; } @@ -1204,7 +1376,7 @@ bool SkRectFromDictionary(PdfContext* pdfContext, return true; } -PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { +PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { if (!obj.HasStream() || obj.GetStream() == NULL || obj.GetStream()->GetLength() == 0) { return kOK_PdfResult; } @@ -1261,17 +1433,17 @@ PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& ob return ret; } -PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { +PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { return kNYI_PdfResult; } // TODO(edisonn): faster, have the property on the PdfObject itself. -std::set gInRendering; +std::set gInRendering; class CheckRecursiveRendering { - PdfObject& fObj; + const PdfObject& fObj; public: - CheckRecursiveRendering(PdfObject& obj) : fObj(obj) { + CheckRecursiveRendering(const PdfObject& obj) : fObj(obj) { gInRendering.insert(&obj); } @@ -1280,12 +1452,41 @@ public: gInRendering.erase(&fObj); } - static bool IsInRendering(PdfObject& obj) { + static bool IsInRendering(const PdfObject& obj) { return gInRendering.find(&obj) != gInRendering.end(); } }; -PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { +PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { + if (CheckRecursiveRendering::IsInRendering(obj)) { + // Oops, corrupt PDF! + return kIgnoreError_PdfResult; + } + + CheckRecursiveRendering checkRecursion(obj); + + // TODO(edisonn): check type + SkPdfObject* skobj = NULL; + if (!PodofoMapper::mapObject(*pdfContext->fPdfDoc, obj, &skobj)) return kIgnoreError_PdfResult; + + if (!skobj || !skobj->valid()) return kIgnoreError_PdfResult; + + PdfResult ret = kIgnoreError_PdfResult; + switch (skobj->getType()) + { + case kObjectDictionaryXObjectImage_SkPdfObjectType: + ret = doXObject_Image(pdfContext, canvas, skobj->asImage()); + //case kObjectDictionaryXObjectForm_SkPdfObjectType: + //return doXObject_Form(skxobj.asForm()); + //case kObjectDictionaryXObjectPS_SkPdfObjectType: + //return doXObject_PS(skxobj.asPS()); + } + + delete skobj; + return ret; +} + +PdfResult doXObjectOld(PdfContext* pdfContext, SkCanvas* canvas, const PdfObject& obj) { if (CheckRecursiveRendering::IsInRendering(obj)) { // Oops, corrupt PDF! return kIgnoreError_PdfResult; @@ -1297,7 +1498,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { return kIgnoreError_PdfResult; } - PdfObject* type = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* type = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("Type"))); if (type == NULL || !type->IsName()) { @@ -1308,7 +1509,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { return kIgnoreError_PdfResult; } - PdfObject* subtype = + const PdfObject* subtype = resolveReferenceObject(pdfContext->fPdfDoc, obj.GetDictionary().GetKey(PdfName("Subtype"))); @@ -1317,7 +1518,7 @@ PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, PdfObject& obj) { } if (subtype->GetName().GetName() == "Image") { - return doXObject_Image(pdfContext, canvas, obj); + return doXObject_ImageOld(pdfContext, canvas, obj); } else if (subtype->GetName().GetName() == "Form") { return doXObject_Form(pdfContext, canvas, obj); } else if (subtype->GetName().GetName() == "PS") { @@ -2058,8 +2259,8 @@ PdfResult PdfOp_i(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** loo PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { PdfName name = pdfContext->fVarStack.top().GetName(); pdfContext->fVarStack.pop(); - PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary(); - PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary(); + const PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc, pageDict.GetKey("Resources")); if (resources == NULL) { @@ -2082,9 +2283,9 @@ PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo return kIgnoreError_PdfResult; } - PdfDictionary& resourceDict = resources->GetDictionary(); + const PdfDictionary& resourceDict = resources->GetDictionary(); //Next, get the ExtGState Dictionary from the Resource Dictionary: - PdfObject* extGStateDictionary = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* extGStateDictionary = resolveReferenceObject(pdfContext->fPdfDoc, resourceDict.GetKey("ExtGState")); if (extGStateDictionary == NULL) { @@ -2101,7 +2302,7 @@ PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo return kIgnoreError_PdfResult; } - PdfObject* value = + const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, extGStateDictionary->GetDictionary().GetKey(name)); @@ -2200,8 +2401,8 @@ PdfResult PdfOp_sh(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { PdfName name = pdfContext->fVarStack.top().GetName(); pdfContext->fVarStack.pop(); - PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary(); - PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfDictionary& pageDict = pdfContext->fGraphicsState.fObjectWithResources->GetDictionary(); + const PdfObject* resources = resolveReferenceObject(pdfContext->fPdfDoc, pageDict.GetKey("Resources")); if (resources == NULL) { @@ -2224,9 +2425,9 @@ PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo return kIgnoreError_PdfResult; } - PdfDictionary& resourceDict = resources->GetDictionary(); + const PdfDictionary& resourceDict = resources->GetDictionary(); //Next, get the XObject Dictionary from the Resource Dictionary: - PdfObject* xObjectDictionary = resolveReferenceObject(pdfContext->fPdfDoc, + const PdfObject* xObjectDictionary = resolveReferenceObject(pdfContext->fPdfDoc, resourceDict.GetKey("XObject")); if (xObjectDictionary == NULL) { @@ -2243,7 +2444,7 @@ PdfResult PdfOp_Do(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** lo return kIgnoreError_PdfResult; } - PdfObject* value = + const PdfObject* value = resolveReferenceObject(pdfContext->fPdfDoc, xObjectDictionary->GetDictionary().GetKey(name)); -- cgit v1.2.3