| Index: site/user/api/canvas.md
|
| diff --git a/site/user/api/canvas.md b/site/user/api/canvas.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..eacd1ccbd4ec9234cb14218ca5f05fd3628dc372
|
| --- /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");
|
| + }
|
|
|