aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-08-05 16:23:23 +0000
committerGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-08-05 16:23:23 +0000
commitb0145ce60ea1a3bacc786ec1285218c6fe70c8a3 (patch)
tree0a8e85c026d4c55867cc483d4a39e1d689d1fb6e
parent2f683ba958488f29fdf117a7fab7d04390b4836d (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.h3
-rw-r--r--experimental/PdfViewer/SkPdfFont.cpp6
-rw-r--r--experimental/PdfViewer/SkPdfFont.h2
-rw-r--r--experimental/PdfViewer/SkPdfRenderer.cpp104
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp8
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h4
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp5
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfObject.cpp21
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfObject.h39
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");
}