aboutsummaryrefslogtreecommitdiffhomepage
path: root/site/user/api/canvas.md
diff options
context:
space:
mode:
Diffstat (limited to 'site/user/api/canvas.md')
-rw-r--r--site/user/api/canvas.md250
1 files changed, 250 insertions, 0 deletions
diff --git a/site/user/api/canvas.md b/site/user/api/canvas.md
new file mode 100644
index 0000000000..eacd1ccbd4
--- /dev/null
+++ b/site/user/api/canvas.md
@@ -0,0 +1,250 @@
+Creating SkCanvas Objects
+=========================
+
+First, read about [the SkCanvas API](skcanvas).
+
+Skia has multiple backends which receive SkCanvas drawing commands,
+including:
+
+- [Raster](#raster) - CPU-only.
+- [Ganesh](#ganesh) - Skia's GPU-accelerated backend.
+- [SkPDF](#skpdf) - PDF document creation.
+- [SkPicture](#skpicture) - Skia's display list format.
+- [NullCanvas](#nullcanvas) - Useful for testing only.
+- [SkXPS](#skxps) - Experimental XPS backend.
+- [SkSVG](#sksvg) - Experimental XPS backend.
+
+Each backend has a unique way of creating a SkCanvas. This page gives
+an example for each:
+
+<span id="raster"></span>
+Raster
+------
+
+The raster backend draws to a block of memory. This memory can be
+managed by Skia or by the client.
+
+The recommended way of creating a canvas for the Raster and Ganesh
+backends is to use a `SkSurface`, which is an object that manages
+the memory into which the canvas commands are drawn.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkData.h"
+ #include "SkImage.h"
+ #include "SkStream.h"
+ #include "SkSurface.h"
+ void raster(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ SkAutoTUnref<SkSurface> rasterSurface(
+ SkSurface::NewRasterN32Premul(width, height));
+ SkCanvas* rasterCanvas = rasterSurface->getCanvas();
+ draw(rasterCanvas);
+ SkAutoTUnref<SkImage> img(s->newImageSnapshot());
+ if (!img) { return; }
+ SkAutoTUnref<SkData> png(img->encode());
+ if (!png) { return; }
+ SkFILEWStream out(path);
+ (void)out.write(png->data(), png->size());
+ }
+
+Alternatively, we could have specified the memory for the surface
+explicitly, instead of asking Skia to manage it.
+
+<!--?prettify lang=cc?-->
+
+ std::vector<char> raster_direct(int width, int height,
+ void(*draw)(SkCanvas*)) {
+ SkImageInfo info = SkImageInfo::MakeN32(width, height);
+ size_t rowBytes = info.minRowBytes();
+ size_t size = info.getSafeSize(rowBytes);
+ std::vector<char> pixelMemory(size); // allocate memory
+ SkAutoTUnref<SkSurface> surface(
+ SkSurface::NewRasterDirect(
+ info, &pixelMemory[0], rowBytes));
+ SkCanvas* canvas = surface.getCanvas();
+ draw(canvas);
+ return std::move(pixelMemory);
+ }
+
+<span id="ganesh"></span>
+Ganesh
+------
+
+Ganesh Surfaces must have a `GrContext` object which manages the
+GPU context, and related caches for textures and fonts. In this
+example, we use a `GrContextFactory` to create a context.
+
+<!--?prettify lang=cc?-->
+
+ #include "GrContextFactory.h"
+ #include "SkData.h"
+ #include "SkImage.h"
+ #include "SkStream.h"
+ #include "SkSurface.h"
+ void ganesh(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ GrContextFactory grFactory;
+ GrContext* context = grFactory.get(GrContextFactory::kNative_GLContextType);
+ SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height);
+ SkAutoTUnref<SkSurface> gpuSurface(
+ SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info));
+ if (!gpuSurface) {
+ SkDebugf("SkSurface::NewRenderTarget returned null\n");
+ return;
+ }
+ SkCanvas* gpuCanvas = gpuSurface->getCanvas();
+ draw(gpuCanvas);
+ SkAutoTUnref<SkImage> img(s->newImageSnapshot());
+ if (!img) { return; }
+ SkAutoTUnref<SkData> png(img->encode());
+ if (!png) { return; }
+ SkFILEWStream out(path);
+ (void)out.write(png->data(), png->size());
+ }
+
+<span id="skpdf"></span>
+SkPDF
+-----
+
+The SkPDF backend uses `SkDocument` instead of `SkSurface`, since
+a document must include multiple pages.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkDocument.h"
+ #include "SkStream.h"
+ void skpdf(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ SkFILEWStream pdfStream(path);
+ SkAutoTUnref<SkDocument> pdfDoc(SkDocument::CreatePDF(&pdfStream));
+ SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width),
+ SkIntToScalar(height));
+ draw(pdfCanvas);
+ pdfDoc->close();
+ }
+
+<span id="skpicture"></span>
+SkPicture
+---------
+
+The SkPicture backend uses SkPictureRecorder instead of SkSurface.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkPictureRecorder"
+ #include "SkPicture"
+ #include "SkStream.h"
+ void picture(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ SkPictureRecorder recorder;
+ SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
+ SkIntToScalar(height));
+ draw(recordingCanvas);
+ SkAutoTUnref<SkPicture> picture(recorder.endRecordingAsPicture());
+ SkFILEWStream skpStream(path);
+ // Open SKP files with `SampleApp --picture SKP_FILE`
+ picture->serialize(&skpStream);
+ }
+
+<span id="nullcanvas"></span>
+NullCanvas
+----------
+
+The null canvas is a canvas that ignores all drawing commands and does
+nothing.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkNullCanvas.h"
+ void picture(int, int, void(*draw)(SkCanvas*), const char*) {
+ SkAutoTDelete<SkCanvas> nullCanvas(SkCreateNullCanvas());
+ draw(nullCanvas); // NoOp
+ }
+
+<span id="skxps"></span>
+SkXPS
+-----
+
+The (*still experimental*) SkXPS canvas writes into an XPS document.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkDocument.h"
+ #include "SkStream.h"
+ void skxps(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ SkFILEWStream xpsStream(path);
+ SkAutoTUnref<SkDocument> xpsDoc(SkDocument::CreateXPS(&pdfStream));
+ SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width),
+ SkIntToScalar(height));
+ draw(xpsCanvas);
+ xpsDoc->close();
+ }
+
+<span id="sksvg"></span>
+SkSVG
+-----
+
+The (*still experimental*) SkSVG canvas writes into an SVG document.
+
+<!--?prettify lang=cc?-->
+
+ #include "SkStream.h"
+ #include "SkSVGCanvas.h"
+ #include "SkXMLWriter.h"
+ void sksvg(int width, int height,
+ void(*draw)(SkCanvas*),
+ const char* path) {
+ SkFILEWStream svgStream(path);
+ SkAutoTDelete<SkXMLWriter> xmlWriter(SkNEW_ARGS(SkXMLStreamWriter, (&svgStream)));
+ SkAutoTUnref<SkCanvas> svgCanvas(SkSVGCanvas::Create(
+ SkRect::MakeWH(SkIntToScalar(src.size().width()),
+ SkIntToScalar(src.size().height())),
+ xmlWriter));
+ draw(svgCanvas);
+ }
+
+<span id="example"></span>
+Example
+-------
+
+To try this code out, make a [new unit test using instructions
+here](/dev/testing/tests) and wrap these funtions together:
+
+<!--?prettify lang=cc?-->
+
+ #include "SkCanvas.h"
+ #include "SkPath.h"
+ #include "Test.h"
+ void example(SkCanvas* canvas) {
+ const SkScalar scale = 256.0f;
+ const SkScalar R = 0.45f * scale;
+ const SkScalar TAU = 6.2831853f;
+ SkPath path;
+ for (int i = 0; i < 5; ++i) {
+ SkScalar theta = 2 * i * TAU / 5;
+ if (i == 0) {
+ path.moveTo(R * cos(theta), R * sin(theta));
+ } else {
+ path.lineTo(R * cos(theta), R * sin(theta));
+ }
+ }
+ path.close();
+ SkPaint p;
+ p.setAntiAlias(true);
+ canvas->clear(SK_ColorWHITE);
+ canvas->translate(0.5f * scale, 0.5f * scale);
+ canvas->drawPath(path, p);
+ }
+ DEF_TEST(FourBackends, r) {
+ raster( 256, 256, example, "out_raster.png" );
+ ganesh( 256, 256, example, "out_ganesh.png" );
+ skpdf( 256, 256, example, "out_skpdf.pdf" );
+ picture(256, 256, example, "out_picture.skp");
+ }