1Creating SkCanvas Objects
2=========================
3
4First, read about [the SkCanvas API](skcanvas).
5
6Skia has multiple backends which receive SkCanvas drawing commands,
7including:
8
9-   [Raster](#raster) - CPU-only.
10-   [Ganesh](#ganesh) - Skia's GPU-accelerated backend.
11-   [SkPDF](#skpdf) - PDF document creation.
12-   [SkPicture](#skpicture) - Skia's display list format.
13-   [NullCanvas](#nullcanvas)  - Useful for testing only.
14-   [SkXPS](#skxps) - Experimental XPS backend.
15-   [SkSVG](#sksvg) - Experimental XPS backend.
16
17Each backend has a unique way of creating a SkCanvas.  This page gives
18an example for each:
19
20<span id="raster"></span>
21Raster
22------
23
24The raster backend draws to a block of memory. This memory can be
25managed by Skia or by the client.
26
27The recommended way of creating a canvas for the Raster and Ganesh
28backends is to use a `SkSurface`, which is an object that manages
29the memory into which the canvas commands are drawn.
30
31<!--?prettify lang=cc?-->
32
33    #include "SkData.h"
34    #include "SkImage.h"
35    #include "SkStream.h"
36    #include "SkSurface.h"
37    void raster(int width, int height,
38                void(*draw)(SkCanvas*),
39                const char* path) {
40        SkAutoTUnref<SkSurface> rasterSurface(
41                SkSurface::NewRasterN32Premul(width, height));
42        SkCanvas* rasterCanvas = rasterSurface->getCanvas();
43        draw(rasterCanvas);
44        SkAutoTUnref<SkImage> img(s->newImageSnapshot());
45        if (!img) { return; }
46        SkAutoTUnref<SkData> png(img->encode());
47        if (!png) { return; }
48        SkFILEWStream out(path);
49        (void)out.write(png->data(), png->size());
50    }
51
52Alternatively, we could have specified the memory for the surface
53explicitly, instead of asking Skia to manage it.
54
55<!--?prettify lang=cc?-->
56
57    std::vector<char> raster_direct(int width, int height,
58                                    void(*draw)(SkCanvas*)) {
59        SkImageInfo info = SkImageInfo::MakeN32(width, height);
60        size_t rowBytes = info.minRowBytes();
61        size_t size = info.getSafeSize(rowBytes);
62        std::vector<char> pixelMemory(size);  // allocate memory
63        SkAutoTUnref<SkSurface> surface(
64                SkSurface::NewRasterDirect(
65                        info, &pixelMemory[0], rowBytes));
66        SkCanvas* canvas = surface.getCanvas();
67        draw(canvas);
68        return std::move(pixelMemory);
69    }
70
71<span id="ganesh"></span>
72Ganesh
73------
74
75Ganesh Surfaces must have a `GrContext` object which manages the
76GPU context, and related caches for textures and fonts.  In this
77example, we use a `GrContextFactory` to create a context.
78
79<!--?prettify lang=cc?-->
80
81    #include "GrContextFactory.h"
82    #include "SkData.h"
83    #include "SkImage.h"
84    #include "SkStream.h"
85    #include "SkSurface.h"
86    void ganesh(int width, int height,
87                void(*draw)(SkCanvas*),
88                const char* path) {
89        GrContextFactory grFactory;
90        GrContext* context = grFactory.get(GrContextFactory::kNative_GLContextType);
91        SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height);
92        SkAutoTUnref<SkSurface> gpuSurface(
93                SkSurface::NewRenderTarget(context, SkBudgeted::kNo, info));
94        if (!gpuSurface) {
95            SkDebugf("SkSurface::NewRenderTarget returned null\n");
96            return;
97        }
98        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
99        draw(gpuCanvas);
100        SkAutoTUnref<SkImage> img(s->newImageSnapshot());
101        if (!img) { return; }
102        SkAutoTUnref<SkData> png(img->encode());
103        if (!png) { return; }
104        SkFILEWStream out(path);
105        (void)out.write(png->data(), png->size());
106    }
107
108<span id="skpdf"></span>
109SkPDF
110-----
111
112The SkPDF backend uses `SkDocument` instead of `SkSurface`, since
113a document must include multiple pages.
114
115<!--?prettify lang=cc?-->
116
117    #include "SkDocument.h"
118    #include "SkStream.h"
119    void skpdf(int width, int height,
120               void(*draw)(SkCanvas*),
121               const char* path) {
122        SkFILEWStream pdfStream(path);
123        SkAutoTUnref<SkDocument> pdfDoc(SkDocument::CreatePDF(&pdfStream));
124        SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width),
125                                                SkIntToScalar(height));
126        draw(pdfCanvas);
127        pdfDoc->close();
128    }
129
130<span id="skpicture"></span>
131SkPicture
132---------
133
134The SkPicture backend uses SkPictureRecorder instead of SkSurface.
135
136<!--?prettify lang=cc?-->
137
138    #include "SkPictureRecorder"
139    #include "SkPicture"
140    #include "SkStream.h"
141    void picture(int width, int height,
142                 void(*draw)(SkCanvas*),
143                 const char* path) {
144        SkPictureRecorder recorder;
145        SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
146                                                            SkIntToScalar(height));
147        draw(recordingCanvas);
148        SkAutoTUnref<SkPicture> picture(recorder.endRecordingAsPicture());
149        SkFILEWStream skpStream(path);
150        // Open SKP files with `SampleApp --picture SKP_FILE`
151        picture->serialize(&skpStream);
152    }
153
154<span id="nullcanvas"></span>
155NullCanvas
156----------
157
158The null canvas is a canvas that ignores all drawing commands and does
159nothing.
160
161<!--?prettify lang=cc?-->
162
163    #include "SkNullCanvas.h"
164    void picture(int, int, void(*draw)(SkCanvas*), const char*) {
165        SkAutoTDelete<SkCanvas> nullCanvas(SkCreateNullCanvas());
166        draw(nullCanvas);  // NoOp
167    }
168
169<span id="skxps"></span>
170SkXPS
171-----
172
173The (*still experimental*) SkXPS canvas writes into an XPS document.
174
175<!--?prettify lang=cc?-->
176
177    #include "SkDocument.h"
178    #include "SkStream.h"
179    void skxps(int width, int height,
180               void(*draw)(SkCanvas*),
181               const char* path) {
182        SkFILEWStream xpsStream(path);
183        SkAutoTUnref<SkDocument> xpsDoc(SkDocument::CreateXPS(&pdfStream));
184        SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width),
185                                                SkIntToScalar(height));
186        draw(xpsCanvas);
187        xpsDoc->close();
188    }
189
190<span id="sksvg"></span>
191SkSVG
192-----
193
194The (*still experimental*) SkSVG canvas writes into an SVG document.
195
196<!--?prettify lang=cc?-->
197
198    #include "SkStream.h"
199    #include "SkSVGCanvas.h"
200    #include "SkXMLWriter.h"
201    void sksvg(int width, int height,
202               void(*draw)(SkCanvas*),
203               const char* path) {
204        SkFILEWStream svgStream(path);
205        SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(&svgStream));
206        SkAutoTUnref<SkCanvas> svgCanvas(SkSVGCanvas::Create(
207                SkRect::MakeWH(SkIntToScalar(src.size().width()),
208                               SkIntToScalar(src.size().height())),
209                xmlWriter));
210        draw(svgCanvas);
211    }
212
213<span id="example"></span>
214Example
215-------
216
217To try this code out, make a [new unit test using instructions
218here](/dev/testing/tests) and wrap these funtions together:
219
220<!--?prettify lang=cc?-->
221
222    #include "SkCanvas.h"
223    #include "SkPath.h"
224    #include "Test.h"
225    void example(SkCanvas* canvas) {
226        const SkScalar scale = 256.0f;
227        const SkScalar R = 0.45f * scale;
228        const SkScalar TAU = 6.2831853f;
229        SkPath path;
230        for (int i = 0; i < 5; ++i) {
231            SkScalar theta = 2 * i * TAU / 5;
232            if (i == 0) {
233                path.moveTo(R * cos(theta), R * sin(theta));
234            } else {
235                path.lineTo(R * cos(theta), R * sin(theta));
236            }
237        }
238        path.close();
239        SkPaint p;
240        p.setAntiAlias(true);
241        canvas->clear(SK_ColorWHITE);
242        canvas->translate(0.5f * scale, 0.5f * scale);
243        canvas->drawPath(path, p);
244    }
245    DEF_TEST(FourBackends, r) {
246        raster( 256, 256, example, "out_raster.png" );
247        ganesh( 256, 256, example, "out_ganesh.png" );
248        skpdf(  256, 256, example, "out_skpdf.pdf"  );
249        picture(256, 256, example, "out_picture.skp");
250    }
251