1--- 2title: 'SkCanvas Creation' 3linkTitle: 'SkCanvas Creation' 4 5weight: 250 6--- 7 8First, read about [the SkCanvas API](../skcanvas_overview). 9 10Skia has multiple backends which receive SkCanvas drawing commands, including: 11 12- [Raster](#raster) - CPU-only. 13- [GPU](#gpu) - Skia's GPU-accelerated backend. 14- [SkPDF](#skpdf) - PDF document creation. 15- [SkPicture](#skpicture) - Skia's display list format. 16- [NullCanvas](#nullcanvas) - Useful for testing only. 17- [SkXPS](#skxps) - Experimental XPS backend. 18- [SkSVG](#sksvg) - Experimental SVG backend. 19 20Each backend has a unique way of creating a SkCanvas. This page gives an example 21for each: 22 23<span id="raster"></span> Raster 24 25--- 26 27The raster backend draws to a block of memory. This memory can be managed by 28Skia or by the client. 29 30The recommended way of creating a canvas for the Raster and Ganesh backends is 31to use a `SkSurface`, which is an object that manages the memory into which the 32canvas commands are drawn. 33 34<!--?prettify lang=cc?--> 35 36 #include "SkData.h" 37 #include "SkImage.h" 38 #include "SkStream.h" 39 #include "SkSurface.h" 40 void raster(int width, int height, 41 void (*draw)(SkCanvas*), 42 const char* path) { 43 sk_sp<SkSurface> rasterSurface = 44 SkSurface::MakeRasterN32Premul(width, height); 45 SkCanvas* rasterCanvas = rasterSurface->getCanvas(); 46 draw(rasterCanvas); 47 sk_sp<SkImage> img(rasterSurface->makeImageSnapshot()); 48 if (!img) { return; } 49 sk_sp<SkData> png(img->encode()); 50 if (!png) { return; } 51 SkFILEWStream out(path); 52 (void)out.write(png->data(), png->size()); 53 } 54 55Alternatively, we could have specified the memory for the surface explicitly, 56instead of asking Skia to manage it. 57 58<!--?prettify lang=cc?--> 59 60 #include <vector> 61 #include "SkSurface.h" 62 std::vector<char> raster_direct(int width, int height, 63 void (*draw)(SkCanvas*)) { 64 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 65 size_t rowBytes = info.minRowBytes(); 66 size_t size = info.getSafeSize(rowBytes); 67 std::vector<char> pixelMemory(size); // allocate memory 68 sk_sp<SkSurface> surface = 69 SkSurface::MakeRasterDirect( 70 info, &pixelMemory[0], rowBytes); 71 SkCanvas* canvas = surface->getCanvas(); 72 draw(canvas); 73 return pixelMemory; 74 } 75 76<span id="gpu"></span> GPU 77 78--- 79 80GPU Surfaces must have a `GrContext` object which manages the GPU context, and 81related caches for textures and fonts. GrContexts are matched one to one with 82OpenGL contexts or Vulkan devices. That is, all SkSurfaces that will be rendered 83to using the same OpenGL context or Vulkan device should share a GrContext. Skia 84does not create a OpenGL context or Vulkan device for you. In OpenGL mode it 85also assumes that the correct OpenGL context has been made current to the 86current thread when Skia calls are made. 87 88<!--?prettify lang=cc?--> 89 90 #include "GrDirectContext.h" 91 #include "gl/GrGLInterface.h" 92 #include "SkData.h" 93 #include "SkImage.h" 94 #include "SkStream.h" 95 #include "SkSurface.h" 96 97 void gl_example(int width, int height, void (*draw)(SkCanvas*), const char* path) { 98 // You've already created your OpenGL context and bound it. 99 const GrGLInterface* interface = nullptr; 100 // Leaving interface as null makes Skia extract pointers to OpenGL functions for the current 101 // context in a platform-specific way. Alternatively, you may create your own GrGLInterface and 102 // initialize it however you like to attach to an alternate OpenGL implementation or intercept 103 // Skia's OpenGL calls. 104 sk_sp<GrContext> context = GrContext::MakeGL(interface); 105 SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height); 106 sk_sp<SkSurface> gpuSurface( 107 SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info)); 108 if (!gpuSurface) { 109 SkDebugf("SkSurface::MakeRenderTarget returned null\n"); 110 return; 111 } 112 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 113 draw(gpuCanvas); 114 sk_sp<SkImage> img(gpuSurface->makeImageSnapshot()); 115 if (!img) { return; } 116 sk_sp<SkData> png(img->encode()); 117 if (!png) { return; } 118 SkFILEWStream out(path); 119 (void)out.write(png->data(), png->size()); 120 } 121 122<span id="skpdf"></span> SkPDF 123 124--- 125 126The SkPDF backend uses `SkDocument` instead of `SkSurface`, since a document 127must include multiple pages. 128 129<!--?prettify lang=cc?--> 130 131 #include "SkPDFDocument.h" 132 #include "SkStream.h" 133 void skpdf(int width, int height, 134 void (*draw)(SkCanvas*), 135 const char* path) { 136 SkFILEWStream pdfStream(path); 137 auto pdfDoc = SkPDF::MakeDocument(&pdfStream); 138 SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width), 139 SkIntToScalar(height)); 140 draw(pdfCanvas); 141 pdfDoc->close(); 142 } 143 144<span id="skpicture"></span> SkPicture 145 146--- 147 148The SkPicture backend uses SkPictureRecorder instead of SkSurface. 149 150<!--?prettify lang=cc?--> 151 152 #include "SkPictureRecorder.h" 153 #include "SkPicture.h" 154 #include "SkStream.h" 155 void picture(int width, int height, 156 void (*draw)(SkCanvas*), 157 const char* path) { 158 SkPictureRecorder recorder; 159 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width), 160 SkIntToScalar(height)); 161 draw(recordingCanvas); 162 sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); 163 SkFILEWStream skpStream(path); 164 // Open SKP files with `viewer --skps PATH_TO_SKP --slide SKP_FILE` 165 picture->serialize(&skpStream); 166 } 167 168<span id="nullcanvas"></span> NullCanvas 169 170--- 171 172The null canvas is a canvas that ignores all drawing commands and does nothing. 173 174<!--?prettify lang=cc?--> 175 176 #include "SkNullCanvas.h" 177 void null_canvas_example(int, int, void (*draw)(SkCanvas*), const char*) { 178 std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); 179 draw(nullCanvas.get()); // NoOp 180 } 181 182<span id="skxps"></span> SkXPS 183 184--- 185 186The (_still experimental_) SkXPS canvas writes into an XPS document. 187 188<!--?prettify lang=cc?--> 189 190 #include "SkDocument.h" 191 #include "SkStream.h" 192 #ifdef SK_BUILD_FOR_WIN 193 void skxps(IXpsOMObjectFactory* factory; 194 int width, int height, 195 void (*draw)(SkCanvas*), 196 const char* path) { 197 SkFILEWStream xpsStream(path); 198 sk_sp<SkDocument> xpsDoc = SkDocument::MakeXPS(&pdfStream, factory); 199 SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width), 200 SkIntToScalar(height)); 201 draw(xpsCanvas); 202 xpsDoc->close(); 203 } 204 #endif 205 206<span id="sksvg"></span> SkSVG 207 208--- 209 210The (_still experimental_) SkSVG canvas writes into an SVG document. 211 212<!--?prettify lang=cc?--> 213 214 #include "SkStream.h" 215 #include "SkSVGCanvas.h" 216 #include "SkXMLWriter.h" 217 void sksvg(int width, int height, 218 void (*draw)(SkCanvas*), 219 const char* path) { 220 SkFILEWStream svgStream(path); 221 std::unique_ptr<SkXMLWriter> xmlWriter( 222 new SkXMLStreamWriter(&svgStream)); 223 SkRect bounds = SkRect::MakeIWH(width, height); 224 std::unique_ptr<SkCanvas> svgCanvas = 225 SkSVGCanvas::Make(bounds, xmlWriter.get()); 226 draw(svgCanvas.get()); 227 } 228 229<span id="example"></span> Example 230 231--- 232 233To try this code out, make a 234[new unit test using instructions here](/docs/dev/testing/tests) and wrap these 235functions together: 236 237<!--?prettify lang=cc?--> 238 239 #include "SkCanvas.h" 240 #include "SkPath.h" 241 #include "Test.h" 242 void example(SkCanvas* canvas) { 243 const SkScalar scale = 256.0f; 244 const SkScalar R = 0.45f * scale; 245 const SkScalar TAU = 6.2831853f; 246 SkPath path; 247 for (int i = 0; i < 5; ++i) { 248 SkScalar theta = 2 * i * TAU / 5; 249 if (i == 0) { 250 path.moveTo(R * cos(theta), R * sin(theta)); 251 } else { 252 path.lineTo(R * cos(theta), R * sin(theta)); 253 } 254 } 255 path.close(); 256 SkPaint p; 257 p.setAntiAlias(true); 258 canvas->clear(SK_ColorWHITE); 259 canvas->translate(0.5f * scale, 0.5f * scale); 260 canvas->drawPath(path, p); 261 } 262 DEF_TEST(FourBackends, r) { 263 raster( 256, 256, example, "out_raster.png" ); 264 gl_example( 256, 256, example, "out_gpu.png" ); 265 skpdf( 256, 256, example, "out_skpdf.pdf" ); 266 picture( 256, 256, example, "out_picture.skp"); 267 } 268