diff options
author | edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-08-05 16:23:23 +0000 |
---|---|---|
committer | edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-08-05 16:23:23 +0000 |
commit | b0145ce60ea1a3bacc786ec1285218c6fe70c8a3 (patch) | |
tree | 0a8e85c026d4c55867cc483d4a39e1d689d1fb6e | |
parent | 2f683ba958488f29fdf117a7fab7d04390b4836d (diff) |
pdfviewer: add indexed rbg image support, enhanche caching(setData) for SkPdfObject
Review URL: https://codereview.chromium.org/21738005
git-svn-id: http://skia.googlecode.com/svn/trunk@10534 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | experimental/PdfViewer/SkPdfBasics.h | 3 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfFont.cpp | 6 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfFont.h | 2 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfRenderer.cpp | 104 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp | 8 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h | 4 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp | 5 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp | 21 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfObject.h | 39 |
9 files changed, 148 insertions, 44 deletions
diff --git a/experimental/PdfViewer/SkPdfBasics.h b/experimental/PdfViewer/SkPdfBasics.h index a681eca710..662e745583 100644 --- a/experimental/PdfViewer/SkPdfBasics.h +++ b/experimental/PdfViewer/SkPdfBasics.h @@ -221,7 +221,8 @@ soft mask dictionary (PDF 1.4) A soft-mask dictionary (see “Soft-Ma Group XObjects”). Initial value: None. */ SkPdfSoftMaskDictionary* fSoftMaskDictionary; - SkBitmap fSMask; + // TODO(edisonn): make sMask private, add setter and getter, ref/unref/..., at the moment we most likely leask + SkBitmap* fSMask; /* diff --git a/experimental/PdfViewer/SkPdfFont.cpp b/experimental/PdfViewer/SkPdfFont.cpp index ac96f02efa..5d8cfe6d9a 100644 --- a/experimental/PdfViewer/SkPdfFont.cpp +++ b/experimental/PdfViewer/SkPdfFont.cpp @@ -255,10 +255,10 @@ SkPdfFont* SkPdfFont::fontFromPdfDictionary(SkNativeParsedPDF* doc, SkPdfFontDic return NULL; // TODO(edisonn): report default one? } - if (dict->data() == NULL) { - dict->setData(fontFromPdfDictionaryOnce(doc, dict)); + if (!dict->hasData(SkPdfObject::kFont_Data)) { + dict->setData(fontFromPdfDictionaryOnce(doc, dict), SkPdfObject::kFont_Data); } - return (SkPdfFont*)dict->data(); + return (SkPdfFont*)dict->data(SkPdfObject::kFont_Data); } diff --git a/experimental/PdfViewer/SkPdfFont.h b/experimental/PdfViewer/SkPdfFont.h index 58c91b6271..c484727345 100644 --- a/experimental/PdfViewer/SkPdfFont.h +++ b/experimental/PdfViewer/SkPdfFont.h @@ -315,7 +315,7 @@ CIDToGIDMap* fCidToGid; class SkPdfType3Font : public SkPdfFont { struct Type3FontChar { - const SkPdfObject* fObj; + SkPdfObject* fObj; double fWidth; }; diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp index 5b8edc3ee3..50b48a057b 100644 --- a/experimental/PdfViewer/SkPdfRenderer.cpp +++ b/experimental/PdfViewer/SkPdfRenderer.cpp @@ -435,11 +435,11 @@ static SkColorTable* getGrayColortable() { return grayColortable; } -static SkBitmap transferImageStreamToBitmap(const unsigned char* uncompressedStream, size_t uncompressedStreamLength, +static SkBitmap* transferImageStreamToBitmap(const unsigned char* uncompressedStream, size_t uncompressedStreamLength, int width, int height, int bytesPerLine, int bpc, const std::string& colorSpace, bool transparencyMask) { - SkBitmap bitmap; + SkBitmap* bitmap = new SkBitmap(); //int components = GetColorSpaceComponents(colorSpace); //#define MAX_COMPONENTS 10 @@ -462,8 +462,8 @@ static SkBitmap transferImageStreamToBitmap(const unsigned char* uncompressedStr uncompressedStream += bytesPerLine; } - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - bitmap.setPixels(uncompressedStreamArgb); + bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); + bitmap->setPixels(uncompressedStreamArgb); } else if ((colorSpace == "DeviceGray" || colorSpace == "Gray") && bpc == 8) { unsigned char* uncompressedStreamA8 = (unsigned char*)malloc(width * height); @@ -478,9 +478,9 @@ static SkBitmap transferImageStreamToBitmap(const unsigned char* uncompressedStr uncompressedStream += bytesPerLine; } - bitmap.setConfig(transparencyMask ? SkBitmap::kA8_Config : SkBitmap::kIndex8_Config, + bitmap->setConfig(transparencyMask ? SkBitmap::kA8_Config : SkBitmap::kIndex8_Config, width, height); - bitmap.setPixels(uncompressedStreamA8, transparencyMask ? NULL : getGrayColortable()); + bitmap->setPixels(uncompressedStreamA8, transparencyMask ? NULL : getGrayColortable()); } // TODO(edisonn): Report Warning, NYI, or error @@ -496,10 +496,10 @@ static SkBitmap transferImageStreamToBitmap(const unsigned char* uncompressedStr // this functions returns the image, it does not look at the smask. -static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* image, bool transparencyMask) { +static SkBitmap* getImageFromObjectCore(PdfContext* pdfContext, SkPdfImageDictionary* image, bool transparencyMask) { if (image == NULL || !image->hasStream()) { // TODO(edisonn): report warning to be used in testing. - return SkBitmap(); + return NULL; } int64_t bpc = image->BitsPerComponent(pdfContext->fPdfDoc); @@ -507,9 +507,37 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* int64_t height = image->Height(pdfContext->fPdfDoc); std::string colorSpace = "DeviceRGB"; + bool indexed = false; + SkPMColor colors[256]; + int cnt = 0; + // TODO(edisonn): color space can be an array too! if (image->isColorSpaceAName(pdfContext->fPdfDoc)) { colorSpace = image->getColorSpaceAsName(pdfContext->fPdfDoc); + } else if (image->isColorSpaceAArray(pdfContext->fPdfDoc)) { + SkPdfArray* array = image->getColorSpaceAsArray(pdfContext->fPdfDoc); + if (array && array->size() == 4 && array->objAtAIndex(0)->isName("Indexed") && + (array->objAtAIndex(1)->isName("DeviceRGB") || array->objAtAIndex(1)->isName("RGB")) && + array->objAtAIndex(2)->isInteger() && + array->objAtAIndex(3)->isHexString() + ) { + // TODO(edisonn): suport only DeviceRGB for now. + indexed = true; + cnt = array->objAtAIndex(2)->intValue() + 1; + if (cnt > 256) { + // TODO(edionn): report NYIs + return NULL; + } + SkColorTable colorTable(cnt); + NotOwnedString data = array->objAtAIndex(3)->strRef(); + if (data.fBytes != (unsigned int)cnt * 3) { + // TODO(edionn): report error/warning + return NULL; + } + for (int i = 0 ; i < cnt; i++) { + colors[i] = SkPreMultiplyARGB(0xff, data.fBuffer[3 * i], data.fBuffer[3 * i + 1], data.fBuffer[3 * i + 2]); + } + } } /* @@ -532,7 +560,7 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* if (!stream || !stream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) || uncompressedStream == NULL || uncompressedStreamLength == 0) { // TODO(edisonn): report warning to be used in testing. - return SkBitmap(); + return NULL; } SkPdfStreamCommonDictionary* streamDict = (SkPdfStreamCommonDictionary*)stream; @@ -543,8 +571,8 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* streamDict->getFilterAsArray(NULL)->size() > 0 && streamDict->getFilterAsArray(NULL)->objAtAIndex(0)->isName() && streamDict->getFilterAsArray(NULL)->objAtAIndex(0)->nameValue2() == "DCTDecode"))) { - SkBitmap bitmap; - SkImageDecoder::DecodeMemory(uncompressedStream, uncompressedStreamLength, &bitmap); + SkBitmap* bitmap = new SkBitmap(); + SkImageDecoder::DecodeMemory(uncompressedStream, uncompressedStreamLength, bitmap); return bitmap; } @@ -562,6 +590,15 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* // SkImageDecoder::Factory() // } + // TODO(edisonn): assumes RGB for now, since it is the only onwe implemented + if (indexed) { + SkBitmap* bitmap = new SkBitmap(); + bitmap->setConfig(SkBitmap::kIndex8_Config, width, height); + SkColorTable* colorTable = new SkColorTable(colors, cnt); + bitmap->setPixels((void*)uncompressedStream, colorTable); + return bitmap; + } + int bytesPerLine = (int)(uncompressedStreamLength / height); #ifdef PDF_TRACE if (uncompressedStreamLength % height != 0) { @@ -569,7 +606,7 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* } #endif - SkBitmap bitmap = transferImageStreamToBitmap( + SkBitmap* bitmap = transferImageStreamToBitmap( (unsigned char*)uncompressedStream, uncompressedStreamLength, (int)width, (int)height, bytesPerLine, (int)bpc, colorSpace, @@ -578,7 +615,19 @@ static SkBitmap getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* return bitmap; } -static SkBitmap getSmaskFromObject(PdfContext* pdfContext, SkPdfImageDictionary* obj) { +static SkBitmap* getImageFromObject(PdfContext* pdfContext, SkPdfImageDictionary* image, bool transparencyMask) { + if (!transparencyMask) { + if (!image->hasData(SkPdfObject::kBitmap_Data)) { + SkBitmap* bitmap = getImageFromObjectCore(pdfContext, image, transparencyMask); + image->setData(bitmap, SkPdfObject::kBitmap_Data); + } + return (SkBitmap*) image->data(SkPdfObject::kBitmap_Data); + } else { + return getImageFromObjectCore(pdfContext, image, transparencyMask); + } +} + +static SkBitmap* getSmaskFromObject(PdfContext* pdfContext, SkPdfImageDictionary* obj) { SkPdfImageDictionary* sMask = obj->SMask(pdfContext->fPdfDoc); if (sMask) { @@ -594,8 +643,8 @@ static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf return kIgnoreError_PdfResult; } - SkBitmap image = getImageFromObject(pdfContext, skpdfimage, false); - SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage); + SkBitmap* image = getImageFromObject(pdfContext, skpdfimage, false); + SkBitmap* sMask = getSmaskFromObject(pdfContext, skpdfimage); canvas->save(); canvas->setMatrix(pdfContext->fGraphicsState.fCTM); @@ -616,16 +665,16 @@ static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), SkDoubleToScalar(1.0), SkDoubleToScalar(1.0)); // TODO(edisonn): soft mask type? alpha/luminosity. - if (sMask.empty()) { - canvas->drawBitmapRect(image, dst, NULL); + if (!sMask || sMask->empty()) { + canvas->drawBitmapRect(*image, dst, NULL); } else { canvas->saveLayer(&dst, NULL); - canvas->drawBitmapRect(image, dst, NULL); + canvas->drawBitmapRect(*image, dst, NULL); SkPaint xfer; pdfContext->fGraphicsState.applyGraphicsState(&xfer, false); // TODO(edisonn): is the blend mode specified already implicitly/explicitly in pdf? xfer.setXfermodeMode(SkXfermode::kSrcOut_Mode); // SkXfermode::kSdtOut_Mode - canvas->drawBitmapRect(sMask, dst, &xfer); + canvas->drawBitmapRect(*sMask, dst, &xfer); canvas->restore(); } @@ -1255,14 +1304,19 @@ static PdfResult PdfOp_fillAndStroke(PdfContext* pdfContext, SkCanvas* canvas, b // TODO(edisonn): constants // TODO(edisonn): colored if (pattern->PaintType(pdfContext->fPdfDoc) == 1) { - int xStep = (int)pattern->XStep(pdfContext->fPdfDoc); - int yStep = (int)pattern->YStep(pdfContext->fPdfDoc); + // TODO(edisonn): don't use abs, iterate as asked, if the cells intersect + // it will change the result iterating in reverse + int xStep = abs((int)pattern->XStep(pdfContext->fPdfDoc)); + int yStep = abs((int)pattern->YStep(pdfContext->fPdfDoc)); SkRect bounds = path.getBounds(); - SkScalar x; - SkScalar y; // TODO(edisonn): xstep and ystep can be negative, and we need to iterate in reverse + // TODO(edisonn): don't do that! + bounds.sort(); + + SkScalar x; + SkScalar y; y = bounds.top(); int totalx = 0; @@ -1961,7 +2015,7 @@ void skpdfGraphicsStateApplySMask_dict(PdfContext* pdfContext, SkPdfDictionary* void skpdfGraphicsStateApplySMask_name(PdfContext* pdfContext, const std::string& sMask) { if (sMask == "None") { pdfContext->fGraphicsState.fSoftMaskDictionary = NULL; - pdfContext->fGraphicsState.fSMask = SkBitmap(); + pdfContext->fGraphicsState.fSMask = NULL; return; } @@ -1983,7 +2037,7 @@ void skpdfGraphicsStateApplySMask_name(PdfContext* pdfContext, const std::string } pdfContext->fGraphicsState.fSoftMaskDictionary = NULL; - pdfContext->fGraphicsState.fSMask = SkBitmap(); + pdfContext->fGraphicsState.fSMask = NULL; skpdfGraphicsStateApplySMask_dict(pdfContext, obj->asDictionary()); } diff --git a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp index 306bf0716b..6386f988e3 100644 --- a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp @@ -306,7 +306,7 @@ const unsigned char* SkNativeParsedPDF::readTrailer(const unsigned char* trailer } if (storeCatalog) { - const SkPdfObject* ref = trailer->Root(NULL); + SkPdfObject* ref = trailer->Root(NULL); if (ref == NULL || !ref->isReference()) { // TODO(edisonn): oops, we have to fix the corrup pdf file return current; @@ -384,7 +384,7 @@ SkPdfObject* SkNativeParsedPDF::readObject(int id/*, int expectedGeneration*/) { } void SkNativeParsedPDF::fillPages(SkPdfPageTreeNodeDictionary* tree) { - const SkPdfArray* kids = tree->Kids(this); + SkPdfArray* kids = tree->Kids(this); if (kids == NULL) { *fPages.append() = (SkPdfPageObjectDictionary*)tree; return; @@ -392,7 +392,7 @@ void SkNativeParsedPDF::fillPages(SkPdfPageTreeNodeDictionary* tree) { int cnt = kids->size(); for (int i = 0; i < cnt; i++) { - const SkPdfObject* obj = resolveReference(kids->objAtAIndex(i)); + SkPdfObject* obj = resolveReference(kids->objAtAIndex(i)); if (fMapper->mapPageObjectDictionary(obj) != kPageObjectDictionary_SkPdfObjectType) { *fPages.append() = (SkPdfPageObjectDictionary*)obj; } else { @@ -506,7 +506,7 @@ SkPdfAllocator* SkNativeParsedPDF::allocator() const { // TODO(edisonn): fix infinite loop if ref to itself! // TODO(edisonn): perf, fix refs at load, and resolve will simply return fResolvedReference? -SkPdfObject* SkNativeParsedPDF::resolveReference(const SkPdfObject* ref) { +SkPdfObject* SkNativeParsedPDF::resolveReference(SkPdfObject* ref) { if (ref && ref->isReference()) { int id = ref->referenceId(); // TODO(edisonn): generation/updates not supported now diff --git a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h index d073f00a30..de71bf6e80 100644 --- a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h +++ b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h @@ -64,7 +64,7 @@ public: // the string does not own the char* SkPdfString* createString(const unsigned char* sz, size_t len) const; - SkPdfObject* resolveReference(const SkPdfObject* ref); + SkPdfObject* resolveReference(SkPdfObject* ref); // Reports an approximation of all the memory usage. size_t bytesUsed() const; @@ -95,7 +95,7 @@ private: SkPdfMapper* fMapper; const unsigned char* fFileContent; size_t fContentLength; - const SkPdfObject* fRootCatalogRef; + SkPdfObject* fRootCatalogRef; SkPdfCatalogDictionary* fRootCatalog; mutable SkTDArray<PublicObjectEntry> fObjects; diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp index 8dd5d30c5c..637eb4dda6 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp @@ -32,9 +32,11 @@ static char* strrstrk(char* hayStart, char* hayEnd, const char* needle) { static void TRACE_INDENT(int level, const char* type) { static int id = 0; id++; +#if 0 if (478613 == id) { printf("break;\n"); } +#endif // all types should have 2 letters, so the text is alligned nicely printf("\n%10i %15s: ", id, type); for (int i = 0 ; i < level; i++) { @@ -158,7 +160,6 @@ static const unsigned char* readArray(int level, const unsigned char* start, con } array->appendInArray(newObj); } - printf("break;\n"); // DO NOT SUBMIT! // TODO(edisonn): report not reached, we should never get here // TODO(edisonn): there might be a bug here, enable an assert and run it on files // or it might be that the files were actually corrupted @@ -954,9 +955,11 @@ bool SkPdfNativeTokenizer::readTokenCore(PdfToken* token) { #ifdef PDF_TRACE_READ_TOKEN static int read_op = 0; read_op++; +#if 0 if (548 == read_op) { printf("break;\n"); } +#endif printf("%i READ %s %s\n", read_op, token->fType == kKeyword_TokenType ? "Keyword" : "Object", token->fKeyword ? std::string(token->fKeyword, token->fKeywordLength).c_str() : token->fObject->toString().c_str()); #endif diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp index eb342af730..a02d789854 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp @@ -6,6 +6,9 @@ #include "SkStream.h" #include "SkPdfNativeTokenizer.h" +#include "SkBitmap.h" +#include "SkPdfFont.h" + SkPdfObject SkPdfObject::kNull = SkPdfObject::makeNull(); bool SkPdfObject::applyFlateDecodeFilter() { @@ -86,3 +89,21 @@ bool SkPdfObject::filterStream() { return true; } + +void SkPdfObject::releaseData() { + if (fData) { + switch (fDataType) { + case kFont_Data: + delete (SkPdfFont*)fData; + break; + case kBitmap_Data: + delete (SkBitmap*)fData; + break; + default: + SkASSERT(false); + break; + } + } + fData = NULL; + fDataType = kEmpty_Data; +} diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h index 29780d07cc..1fb4e1fccb 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h +++ b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h @@ -49,6 +49,12 @@ class SkPdfObject { kUndefined_PdfObjectType, // per 1.4 spec, if the same key appear twice in the dictionary, the value is undefined }; + enum DataType { + kEmpty_Data, + kFont_Data, + kBitmap_Data, + }; + private: struct Reference { unsigned int fId; @@ -76,21 +82,33 @@ private: Reference fRef; }; SkTDict<SkPdfObject*>* fMap; + + // TODO(edisonn): rename data with cache void* fData; + DataType fDataType; public: - SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL) {} + SkPdfObject() : fObjectType(kInvalid_PdfObjectType), fMap(NULL), fData(NULL), fDataType(kEmpty_Data) {} + + + inline bool hasData(DataType type) { + return type == fDataType; + } - inline void* data() { - return fData; + inline void* data(DataType type) { + return type == fDataType ? fData : NULL; } - inline void setData(void* data) { + inline void setData(void* data, DataType type) { + releaseData(); + fDataType = type; fData = data; } + void releaseData(); + // ~SkPdfObject() { // //reset(); must be called manually! // } @@ -114,6 +132,7 @@ public: break; } fObjectType = kInvalid_PdfObjectType; + releaseData(); } ObjectType type() { return fObjectType; } @@ -604,6 +623,10 @@ public: return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType; } + bool isHexString() const { + return fObjectType == kHexString_PdfObjectType; + } + bool isMatrix() const { return fObjectType == kArray_PdfObjectType && fArray->count() == 6; // NYI + and elems are numbers } @@ -867,7 +890,9 @@ public: case kHexString_PdfObjectType: str.append("<"); - str.append((const char*)fStr.fBuffer, fStr.fBytes); + for (unsigned int i = 0 ; i < fStr.fBytes; i++) { + str.appendf("%02x", (unsigned int)fStr.fBuffer[i]); + } str.append(">"); break; @@ -908,9 +933,9 @@ public: const unsigned char* stream = NULL; size_t length = 0; if (GetFilteredStreamRef(&stream, &length)) { - str.append("stream"); + str.append("stream\n"); str.append((const char*)stream, length > 256 ? 256 : length); - str.append("endstream"); + str.append("\nendstream"); } else { str.append("stream STREAM_ERROR endstream"); } |