aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/PdfViewer
diff options
context:
space:
mode:
authorGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 15:56:19 +0000
committerGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-24 15:56:19 +0000
commit147adb10f7f80ae721879e08474fd575e719487c (patch)
treeaf415230b5536e7638f3990c22c58cc2ee73d351 /experimental/PdfViewer
parentc172cf4faad2e7b0518f988d26bd12aafc761acb (diff)
pdfviewer: remove dependency on picture_utils. add utility function to render SkStream into bitmap.
Review URL: https://codereview.chromium.org/20087003 git-svn-id: http://skia.googlecode.com/svn/trunk@10314 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental/PdfViewer')
-rw-r--r--experimental/PdfViewer/SkPdfRenderer.cpp41
-rw-r--r--experimental/PdfViewer/SkPdfRenderer.h14
-rw-r--r--experimental/PdfViewer/pdf_viewer_main.cpp59
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp36
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h8
5 files changed, 146 insertions, 12 deletions
diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp
index 33798cb343..c51c2390f8 100644
--- a/experimental/PdfViewer/SkPdfRenderer.cpp
+++ b/experimental/PdfViewer/SkPdfRenderer.cpp
@@ -2030,6 +2030,20 @@ bool SkPdfRenderer::load(const SkString inputFileName) {
return fPdfDoc != NULL;
}
+bool SkPdfRenderer::load(SkStream* stream) {
+ unload();
+
+ // TODO(edisonn): create static function that could return NULL if there are errors
+ fPdfDoc = new SkNativeParsedPDF(stream);
+ if (fPdfDoc->pages() == 0) {
+ delete fPdfDoc;
+ fPdfDoc = NULL;
+ }
+
+ return fPdfDoc != NULL;
+}
+
+
int SkPdfRenderer::pages() const {
return fPdfDoc != NULL ? fPdfDoc->pages() : 0;
}
@@ -2047,3 +2061,30 @@ SkRect SkPdfRenderer::MediaBox(int page) const {
size_t SkPdfRenderer::bytesUsed() const {
return fPdfDoc ? fPdfDoc->bytesUsed() : 0;
}
+
+bool SkPDFNativeRenderToBitmap(SkStream* stream,
+ SkBitmap* output,
+ int page,
+ SkPdfContent content,
+ double dpi) {
+ SkASSERT(page >= 0);
+ SkPdfRenderer renderer;
+ renderer.load(stream);
+ if (!renderer.loaded() || page >= renderer.pages() || page < 0) {
+ return false;
+ }
+
+ SkRect rect = renderer.MediaBox(page < 0 ? 0 :page);
+
+ SkScalar width = SkScalarMul(rect.width(), SkDoubleToScalar(sqrt(dpi / 72.0)));
+ SkScalar height = SkScalarMul(rect.height(), SkDoubleToScalar(sqrt(dpi / 72.0)));
+
+ rect = SkRect::MakeWH(width, height);
+
+ setup_bitmap(output, (int)SkScalarToDouble(width), (int)SkScalarToDouble(height));
+
+ SkAutoTUnref<SkDevice> device(SkNEW_ARGS(SkDevice, (*output)));
+ SkCanvas canvas(device);
+
+ return renderer.renderPage(page, &canvas, rect);
+}
diff --git a/experimental/PdfViewer/SkPdfRenderer.h b/experimental/PdfViewer/SkPdfRenderer.h
index 8bbc4f1eb2..b3c4ae3e89 100644
--- a/experimental/PdfViewer/SkPdfRenderer.h
+++ b/experimental/PdfViewer/SkPdfRenderer.h
@@ -9,9 +9,16 @@
#ifndef SkPdfRenderer_DEFINED
#define SkPdfRenderer_DEFINED
+class SkBitmap;
class SkCanvas;
class SkNativeParsedPDF;
class SkRect;
+class SkStream;
+
+enum SkPdfContent {
+ kNoForms_SkPdfContent,
+ kAll_SkPdfContent,
+};
// TODO(edisonn): move in another file
class SkPdfRenderer : public SkRefCnt {
@@ -24,6 +31,7 @@ public:
bool renderPage(int page, SkCanvas* canvas, const SkRect& dst) const;
bool load(const SkString inputFileName);
+ bool load(SkStream* stream);
bool loaded() const {return fPdfDoc != NULL;}
int pages() const;
void unload();
@@ -33,4 +41,10 @@ public:
void reportPdfRenderStats();
+bool SkPDFNativeRenderToBitmap(SkStream* stream,
+ SkBitmap* output,
+ int page = 0,
+ SkPdfContent content = kAll_SkPdfContent,
+ double dpi = 72.0);
+
#endif // SkPdfRenderer_DEFINED
diff --git a/experimental/PdfViewer/pdf_viewer_main.cpp b/experimental/PdfViewer/pdf_viewer_main.cpp
index 7541cdfae6..cfea97411d 100644
--- a/experimental/PdfViewer/pdf_viewer_main.cpp
+++ b/experimental/PdfViewer/pdf_viewer_main.cpp
@@ -9,7 +9,6 @@
#include "SkStream.h"
#include "SkTypeface.h"
#include "SkTArray.h"
-#include "picture_utils.h"
#include "SkNulCanvas.h"
#include "SkPdfRenderer.h"
@@ -74,6 +73,56 @@ static bool add_page_and_replace_filename_extension(SkString* path, int page,
return false;
}
+void make_filepath(SkString* path, const SkString& dir, const SkString& name) {
+ size_t len = dir.size();
+ path->set(dir);
+ if (0 < len && '/' != dir[len - 1]) {
+ path->append("/");
+ }
+ path->append(name);
+}
+
+bool is_path_seperator(const char chr) {
+#if defined(SK_BUILD_FOR_WIN)
+ return chr == '\\' || chr == '/';
+#else
+ return chr == '/';
+#endif
+}
+
+void get_basename(SkString* basename, const SkString& path) {
+ if (path.size() == 0) {
+ basename->reset();
+ return;
+ }
+
+ size_t end = path.size() - 1;
+
+ // Paths pointing to directories often have a trailing slash,
+ // we remove it so the name is not empty
+ if (is_path_seperator(path[end])) {
+ if (end == 0) {
+ basename->reset();
+ return;
+ }
+
+ end -= 1;
+ }
+
+ size_t i = end;
+ do {
+ --i;
+ if (is_path_seperator(path[i])) {
+ const char* basenameStart = path.c_str() + i + 1;
+ size_t basenameLength = end - i;
+ basename->set(basenameStart, basenameLength);
+ return;
+ }
+ } while (i > 0);
+
+ basename->set(path.c_str(), end + 1);
+}
+
/** Builds the output filename. path = dir/name, and it replaces expected
* .skp extension with .pdf extention.
* @param path Output filename.
@@ -81,12 +130,10 @@ static bool add_page_and_replace_filename_extension(SkString* path, int page,
* @returns false if the file did not has the expected extension.
* if false is returned, contents of path are undefined.
*/
-
-
static bool make_output_filepath(SkString* path, const SkString& dir,
const SkString& name,
int page) {
- sk_tools::make_filepath(path, dir, name);
+ make_filepath(path, dir, name);
return add_page_and_replace_filename_extension(path, page,
PDF_FILE_EXTENSION,
PNG_FILE_EXTENSION);
@@ -167,7 +214,7 @@ static bool process_pdf(const SkString& inputPath, const SkString& outputDir,
SkDebugf("Loading PDF: %s\n", inputPath.c_str());
SkString inputFilename;
- sk_tools::get_basename(&inputFilename, inputPath);
+ get_basename(&inputFilename, inputPath);
SkFILEStream inputStream;
inputStream.setPath(inputPath.c_str());
@@ -241,7 +288,7 @@ static int process_input(const char* input, const SkString& outputDir,
SkString inputPath;
SkString _input;
_input.append(input);
- sk_tools::make_filepath(&inputPath, _input, inputFilename);
+ make_filepath(&inputPath, _input, inputFilename);
if (!process_pdf(inputPath, outputDir, renderer)) {
++failures;
}
diff --git a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp
index 4fb7f8895b..8f92a0fcfe 100644
--- a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp
+++ b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.cpp
@@ -14,6 +14,7 @@
#include "SkPdfPageTreeNodeDictionary_autogen.h"
#include "SkPdfMapper_autogen.h"
+#include "SkStream.h"
static long getFileSize(const char* filename)
@@ -67,25 +68,48 @@ SkNativeParsedPDF* gDoc = NULL;
// 1) run on a lot of file
// 2) recoverable corupt file: remove endobj, endsteam, remove other keywords, use other white spaces, insert comments randomly, ...
// 3) irrecoverable corrupt file
+
+SkNativeParsedPDF::SkNativeParsedPDF(SkStream* stream)
+ : fAllocator(new SkPdfAllocator())
+ , fFileContent(NULL)
+ , fContentLength(0)
+ , fRootCatalogRef(NULL)
+ , fRootCatalog(NULL) {
+ size_t size = stream->getLength();
+ void* ptr = sk_malloc_throw(size);
+ stream->read(ptr, size);
+
+ init(ptr, size);
+}
+
SkNativeParsedPDF::SkNativeParsedPDF(const char* path)
: fAllocator(new SkPdfAllocator())
+ , fFileContent(NULL)
+ , fContentLength(0)
, fRootCatalogRef(NULL)
, fRootCatalog(NULL) {
gDoc = this;
FILE* file = fopen(path, "r");
- fContentLength = getFileSize(path);
- unsigned char* content = new unsigned char[fContentLength + 1];
- bool ok = (0 != fread(content, fContentLength, 1, file));
- content[fContentLength] = '\0';
- fFileContent = content;
+ size_t size = getFileSize(path);
+ void* content = sk_malloc_throw(size);
+ bool ok = (0 != fread(content, size, 1, file));
fclose(file);
file = NULL;
if (!ok) {
+ sk_free(content);
// TODO(edisonn): report read error
+ // TODO(edisonn): not nice to return like this from constructor, create a static
+ // function that can report NULL for failures.
return; // Doc will have 0 pages
}
+ init(content, size);
+}
+
+void SkNativeParsedPDF::init(const void* bytes, size_t length) {
+ fFileContent = (const unsigned char*)bytes;
+ fContentLength = length;
const unsigned char* eofLine = lineHome(fFileContent, fFileContent + fContentLength - 1);
const unsigned char* xrefByteOffsetLine = previousLineHome(fFileContent, eofLine);
const unsigned char* xrefstartKeywordLine = previousLineHome(fFileContent, xrefByteOffsetLine);
@@ -126,7 +150,7 @@ SkNativeParsedPDF::SkNativeParsedPDF(const char* path)
// TODO(edisonn): NYI
SkNativeParsedPDF::~SkNativeParsedPDF() {
- delete[] fFileContent;
+ sk_free((void*)fFileContent);
delete fAllocator;
}
diff --git a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h
index c520b0394a..d55d808a2c 100644
--- a/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h
+++ b/experimental/PdfViewer/pdfparser/native/SkNativeParsedPDF.h
@@ -19,6 +19,8 @@ class SkPdfPageTreeNodeDictionary;
class SkPdfNativeTokenizer;
+class SkStream;
+
class SkNativeParsedPDF {
private:
struct PublicObjectEntry {
@@ -35,7 +37,10 @@ public:
// TODO(edisonn): read page N asap, read all file
// TODO(edisonn): allow corruptions of file (e.g. missing endobj, missing stream length, ...)
// TODO(edisonn): encryption
+
SkNativeParsedPDF(const char* path);
+ SkNativeParsedPDF(SkStream* stream);
+
~SkNativeParsedPDF();
int pages() const;
@@ -65,6 +70,9 @@ public:
private:
+ // Takes ownership of bytes.
+ void init(const void* bytes, size_t length);
+
const unsigned char* readCrossReferenceSection(const unsigned char* xrefStart, const unsigned char* trailerEnd);
long readTrailer(const unsigned char* trailerStart, const unsigned char* trailerEnd, bool storeCatalog);