OLD | NEW |
(Empty) | |
| 1 Creating SkCanvas Objects |
| 2 ========================= |
| 3 |
| 4 First, read about [the SkCanvas API](skcanvas). |
| 5 |
| 6 Skia has multiple backends which receive SkCanvas drawing commands, |
| 7 including: |
| 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 |
| 17 Each backend has a unique way of creating a SkCanvas. This page gives |
| 18 an example for each: |
| 19 |
| 20 <span id="raster"></span> |
| 21 Raster |
| 22 ------ |
| 23 |
| 24 The raster backend draws to a block of memory. This memory can be |
| 25 managed by Skia or by the client. |
| 26 |
| 27 The recommended way of creating a canvas for the Raster and Ganesh |
| 28 backends is to use a `SkSurface`, which is an object that manages |
| 29 the 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 |
| 52 Alternatively, we could have specified the memory for the surface |
| 53 explicitly, 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> |
| 72 Ganesh |
| 73 ------ |
| 74 |
| 75 Ganesh Surfaces must have a `GrContext` object which manages the |
| 76 GPU context, and related caches for textures and fonts. In this |
| 77 example, 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_GLContextTy
pe); |
| 91 SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height); |
| 92 SkAutoTUnref<SkSurface> gpuSurface( |
| 93 SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, inf
o)); |
| 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> |
| 109 SkPDF |
| 110 ----- |
| 111 |
| 112 The SkPDF backend uses `SkDocument` instead of `SkSurface`, since |
| 113 a 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> |
| 131 SkPicture |
| 132 --------- |
| 133 |
| 134 The 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> |
| 155 NullCanvas |
| 156 ---------- |
| 157 |
| 158 The null canvas is a canvas that ignores all drawing commands and does |
| 159 nothing. |
| 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> |
| 170 SkXPS |
| 171 ----- |
| 172 |
| 173 The (*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> |
| 191 SkSVG |
| 192 ----- |
| 193 |
| 194 The (*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(SkNEW_ARGS(SkXMLStreamWriter, (&svg
Stream))); |
| 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> |
| 214 Example |
| 215 ------- |
| 216 |
| 217 To try this code out, make a [new unit test using instructions |
| 218 here](/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 } |
OLD | NEW |