SkDocument base for pdf, xps, etc.
R=scroggo@google.com Review URL: https://codereview.chromium.org/16660002 git-svn-id: http://skia.googlecode.com/svn/trunk@9476 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
99d43ffcfb
commit
99ac02bb70
@ -186,6 +186,8 @@
|
||||
'<(skia_src_path)/core/SkWriter32.cpp',
|
||||
'<(skia_src_path)/core/SkXfermode.cpp',
|
||||
|
||||
'<(skia_src_path)/doc/SkDocument.cpp',
|
||||
|
||||
'<(skia_src_path)/image/SkDataPixelRef.cpp',
|
||||
'<(skia_src_path)/image/SkImage.cpp',
|
||||
'<(skia_src_path)/image/SkImagePriv.cpp',
|
||||
|
@ -47,6 +47,8 @@
|
||||
'../src/pdf/SkPDFUtils.cpp',
|
||||
'../src/pdf/SkPDFUtils.h',
|
||||
'../src/pdf/SkTSet.h',
|
||||
|
||||
'../src/doc/SkDocument_PDF.cpp',
|
||||
],
|
||||
# This section makes all targets that depend on this target
|
||||
# #define SK_SUPPORT_PDF and have access to the pdf header files.
|
||||
|
@ -64,6 +64,7 @@
|
||||
],
|
||||
'dependencies': [
|
||||
'skia_lib.gyp:skia_lib',
|
||||
'pdf.gyp:pdf',
|
||||
'flags.gyp:flags',
|
||||
],
|
||||
},
|
||||
|
94
include/core/SkDocument.h
Normal file
94
include/core/SkDocument.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDocument_DEFINED
|
||||
#define SkDocument_DEFINED
|
||||
|
||||
#include "SkRect.h"
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class SkCanvas;
|
||||
class SkWStream;
|
||||
|
||||
/**
|
||||
* High-level API for creating a document-based canvas. To use..
|
||||
*
|
||||
* 1. Create a document, specifying a stream to store the output.
|
||||
* 2. For each "page" of content:
|
||||
* a. canvas = doc->beginPage(...)
|
||||
* b. draw_my_content(canvas);
|
||||
* c. doc->endPage();
|
||||
* 3. Close the document with doc->close().
|
||||
*/
|
||||
class SkDocument : public SkRefCnt {
|
||||
public:
|
||||
/**
|
||||
* Create a PDF-backed document, writing the results into a file.
|
||||
* If there is an error trying to create the doc, returns NULL.
|
||||
*/
|
||||
static SkDocument* CreatePDF(const char filename[]);
|
||||
|
||||
/**
|
||||
* Create a PDF-backed document, writing the results into a stream.
|
||||
* If there is an error trying to create the doc, returns NULL.
|
||||
*
|
||||
* The document may write to the stream at anytime during its lifetime,
|
||||
* until either close() is called or the document is deleted. Once close()
|
||||
* has been called, and all of the data has been written to the stream,
|
||||
* if there is a Done proc provided, it will be called with the stream.
|
||||
* The proc can delete the stream, or whatever it needs to do.
|
||||
*/
|
||||
static SkDocument* CreatePDF(SkWStream*, void (*Done)(SkWStream*) = NULL);
|
||||
|
||||
/**
|
||||
* Begin a new page for the document, returning the canvas that will draw
|
||||
* into the page. The document owns this canvas, and it will go out of
|
||||
* scope when endPage() or close() is called, or the document is deleted.
|
||||
*/
|
||||
SkCanvas* beginPage(SkScalar width, SkScalar height,
|
||||
const SkRect* content = NULL);
|
||||
|
||||
/**
|
||||
* Call endPage() when the content for the current page has been drawn
|
||||
* (into the canvas returned by beginPage()). After this call the canvas
|
||||
* returned by beginPage() will be out-of-scope.
|
||||
*/
|
||||
void endPage();
|
||||
|
||||
/**
|
||||
* Call close() when all pages have been drawn. This will close the file
|
||||
* or stream holding the document's contents. After close() the document
|
||||
* can no longer add new pages. Deleting the document will automatically
|
||||
* call close() if need be.
|
||||
*/
|
||||
void close();
|
||||
|
||||
protected:
|
||||
SkDocument(SkWStream*, void (*)(SkWStream*));
|
||||
// note: subclasses must call close() in their destructor, as the base class
|
||||
// cannot do this for them.
|
||||
virtual ~SkDocument();
|
||||
|
||||
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
|
||||
const SkRect& content) = 0;
|
||||
virtual void onEndPage() = 0;
|
||||
virtual void onClose(SkWStream*) = 0;
|
||||
|
||||
enum State {
|
||||
kBetweenPages_State,
|
||||
kInPage_State,
|
||||
kClosed_State
|
||||
};
|
||||
State getState() const { return fState; }
|
||||
|
||||
private:
|
||||
SkWStream* fStream;
|
||||
void (*fDoneProc)(SkWStream*);
|
||||
State fState;
|
||||
};
|
||||
|
||||
#endif
|
83
src/doc/SkDocument.cpp
Normal file
83
src/doc/SkDocument.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkDocument.h"
|
||||
#include "SkStream.h"
|
||||
|
||||
SkDocument::SkDocument(SkWStream* stream, void (*doneProc)(SkWStream*)) {
|
||||
fStream = stream; // we do not own this object.
|
||||
fDoneProc = doneProc;
|
||||
fState = kBetweenPages_State;
|
||||
}
|
||||
|
||||
SkDocument::~SkDocument() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
SkCanvas* SkDocument::beginPage(SkScalar width, SkScalar height,
|
||||
const SkRect* content) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SkRect outer = SkRect::MakeWH(width, height);
|
||||
SkRect inner;
|
||||
if (content) {
|
||||
inner = *content;
|
||||
if (!inner.intersect(outer)) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
inner = outer;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
switch (fState) {
|
||||
case kBetweenPages_State:
|
||||
fState = kInPage_State;
|
||||
return this->onBeginPage(width, height, inner);
|
||||
case kInPage_State:
|
||||
this->endPage();
|
||||
break;
|
||||
case kClosed_State:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
SkASSERT(!"never get here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SkDocument::endPage() {
|
||||
if (kInPage_State == fState) {
|
||||
fState = kBetweenPages_State;
|
||||
this->onEndPage();
|
||||
}
|
||||
}
|
||||
|
||||
void SkDocument::close() {
|
||||
for (;;) {
|
||||
switch (fState) {
|
||||
case kBetweenPages_State:
|
||||
fState = kClosed_State;
|
||||
this->onClose(fStream);
|
||||
|
||||
if (fDoneProc) {
|
||||
fDoneProc(fStream);
|
||||
}
|
||||
// we don't own the stream, but we mark it NULL since we can
|
||||
// no longer write to it.
|
||||
fStream = NULL;
|
||||
return;
|
||||
case kInPage_State:
|
||||
this->endPage();
|
||||
break;
|
||||
case kClosed_State:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
92
src/doc/SkDocument_PDF.cpp
Normal file
92
src/doc/SkDocument_PDF.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkDocument.h"
|
||||
#include "SkPDFDocument.h"
|
||||
#include "SkPDFDevice.h"
|
||||
|
||||
class SkDocument_PDF : public SkDocument {
|
||||
public:
|
||||
SkDocument_PDF(SkWStream* stream, void (*doneProc)(SkWStream*))
|
||||
: SkDocument(stream, doneProc) {
|
||||
fDoc = SkNEW(SkPDFDocument);
|
||||
fCanvas = NULL;
|
||||
fDevice = NULL;
|
||||
}
|
||||
|
||||
virtual ~SkDocument_PDF() {
|
||||
// subclasses must call close() in their destructors
|
||||
this->close();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
|
||||
const SkRect& content) SK_OVERRIDE {
|
||||
SkASSERT(NULL == fCanvas);
|
||||
SkASSERT(NULL == fDevice);
|
||||
|
||||
SkISize pageS, contentS;
|
||||
SkMatrix matrix;
|
||||
|
||||
pageS.set(SkScalarRoundToInt(width), SkScalarRoundToInt(height));
|
||||
contentS.set(SkScalarRoundToInt(content.width()),
|
||||
SkScalarRoundToInt(content.height()));
|
||||
matrix.setTranslate(content.fLeft, content.fTop);
|
||||
|
||||
fDevice = SkNEW_ARGS(SkPDFDevice, (pageS, contentS, matrix));
|
||||
fCanvas = SkNEW_ARGS(SkCanvas, (fDevice));
|
||||
return fCanvas;
|
||||
}
|
||||
|
||||
virtual void onEndPage() SK_OVERRIDE {
|
||||
SkASSERT(fCanvas);
|
||||
SkASSERT(fDevice);
|
||||
|
||||
fCanvas->flush();
|
||||
fDoc->appendPage(fDevice);
|
||||
|
||||
fCanvas->unref();
|
||||
fDevice->unref();
|
||||
|
||||
fCanvas = NULL;
|
||||
fDevice = NULL;
|
||||
}
|
||||
|
||||
virtual void onClose(SkWStream* stream) SK_OVERRIDE {
|
||||
SkASSERT(NULL == fCanvas);
|
||||
SkASSERT(NULL == fDevice);
|
||||
|
||||
fDoc->emitPDF(stream);
|
||||
SkDELETE(fDoc);
|
||||
fDoc = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
SkPDFDocument* fDoc;
|
||||
SkPDFDevice* fDevice;
|
||||
SkCanvas* fCanvas;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkDocument* SkDocument::CreatePDF(SkWStream* stream, void (*done)(SkWStream*)) {
|
||||
return stream ? SkNEW_ARGS(SkDocument_PDF, (stream, done)) : NULL;
|
||||
}
|
||||
|
||||
static void delete_wstream(SkWStream* stream) {
|
||||
SkDELETE(stream);
|
||||
}
|
||||
|
||||
SkDocument* SkDocument::CreatePDF(const char path[]) {
|
||||
SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (path));
|
||||
if (!stream->isValid()) {
|
||||
SkDELETE(stream);
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(SkDocument_PDF, (stream, delete_wstream));
|
||||
}
|
||||
|
@ -8,22 +8,62 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkCommandLineFlags.h"
|
||||
#include "SkData.h"
|
||||
#include "SkDocument.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkSurface.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkString.h"
|
||||
|
||||
DEFINE_string2(outFile, o, "skhello.png", "The filename to write the image.");
|
||||
DEFINE_string2(outFile, o, "skhello", "The filename to write the image.");
|
||||
DEFINE_string2(text, t, "Hello", "The string to write.");
|
||||
|
||||
static void doDraw(SkCanvas* canvas, const SkPaint& paint, const char text[]) {
|
||||
SkRect bounds;
|
||||
canvas->getClipBounds(&bounds);
|
||||
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
canvas->drawText(text, strlen(text),
|
||||
bounds.centerX(), bounds.centerY(),
|
||||
paint);
|
||||
}
|
||||
|
||||
static bool do_surface(int w, int h, const char path[], const char text[],
|
||||
const SkPaint& paint) {
|
||||
SkImage::Info info = {
|
||||
w, h, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
|
||||
};
|
||||
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
|
||||
doDraw(surface->getCanvas(), paint, text);
|
||||
|
||||
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
|
||||
SkAutoDataUnref data(image->encode());
|
||||
if (NULL == data.get()) {
|
||||
return false;
|
||||
}
|
||||
SkFILEWStream stream(path);
|
||||
return stream.write(data->data(), data->size());
|
||||
}
|
||||
|
||||
static bool do_document(int w, int h, const char path[], const char text[],
|
||||
const SkPaint& paint) {
|
||||
SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path));
|
||||
if (doc.get()) {
|
||||
SkScalar width = SkIntToScalar(w);
|
||||
SkScalar height = SkIntToScalar(h);
|
||||
doDraw(doc->beginPage(width, height, NULL), paint, text);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int tool_main(int argc, char** argv);
|
||||
int tool_main(int argc, char** argv) {
|
||||
SkCommandLineFlags::SetUsage("");
|
||||
SkCommandLineFlags::Parse(argc, argv);
|
||||
|
||||
SkAutoGraphics ag;
|
||||
SkString path("skhello.png");
|
||||
SkString path("skhello");
|
||||
SkString text("Hello");
|
||||
|
||||
if (!FLAGS_outFile.isEmpty()) {
|
||||
@ -44,24 +84,23 @@ int tool_main(int argc, char** argv) {
|
||||
int w = SkScalarRound(width) + 30;
|
||||
int h = SkScalarRound(spacing) + 30;
|
||||
|
||||
SkImage::Info info = {
|
||||
w, h, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
|
||||
static const struct {
|
||||
bool (*fProc)(int w, int h, const char path[], const char text[],
|
||||
const SkPaint&);
|
||||
const char* fSuffix;
|
||||
} gRec[] = {
|
||||
{ do_surface, ".png" },
|
||||
{ do_document, ".pdf" },
|
||||
};
|
||||
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
canvas->drawText(text.c_str(), text.size(),
|
||||
SkIntToScalar(w)/2, SkIntToScalar(h)*2/3,
|
||||
paint);
|
||||
|
||||
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
|
||||
SkAutoDataUnref data(image->encode());
|
||||
if (NULL == data.get()) {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
|
||||
SkString file;
|
||||
file.printf("%s%s", path.c_str(), gRec[i].fSuffix);
|
||||
if (!gRec[i].fProc(w, h, file.c_str(), text.c_str(), paint)) {
|
||||
return -1;
|
||||
}
|
||||
SkFILEWStream stream(path.c_str());
|
||||
return stream.write(data->data(), data->size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined SK_BUILD_FOR_IOS
|
||||
|
Loading…
Reference in New Issue
Block a user