免費咨詢婦科醫(yī)生在線seo推廣百度百科
創(chuàng)建SkCanvas
首先,閱讀SkCanvasAPI
概述.
Skia
有多個接收SkCanvas
繪圖命令的后端.每個后端都有創(chuàng)建SkCanvas
的獨特方式.本頁給出了每個示例:
光柵化
光柵化
后端將繪畫到可由Skia
或客戶
管理的內存塊
.
推薦用管理畫布命令要繪畫
內存對象的SkSurface
為Raster
和Ganesh
后端創(chuàng)建
畫布.
#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
void raster(int width, int height, void (*draw)(SkCanvas*), const char* path) {sk_sp<SkSurface> rasterSurface = SkSurface::MakeRasterN32Premul(width, height);SkCanvas* rasterCanvas = rasterSurface->getCanvas();draw(rasterCanvas);sk_sp<SkImage> img(rasterSurface->makeImageSnapshot());if (!img) { return; }sk_sp<SkData> png = SkPngEncoder::Encode(nullptr, img, {});if (!png) { return; }SkFILEWStream out(path);(void)out.write(png->data(), png->size());
}
或,可顯式
指定表面
的內存,而不是讓Skia
管理它.
#include <vector>
#include "include/core/SkSurface.h"
std::vector<char> raster_direct(int width, int height, void (*draw)(SkCanvas*)) {SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);size_t rowBytes = info.minRowBytes();size_t size = info.getSafeSize(rowBytes);std::vector<char> pixelMemory(size); // 分配內存sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect( info, &pixelMemory[0], rowBytes);SkCanvas* canvas = surface->getCanvas();draw(canvas);return pixelMemory;
}
GPU
GPU
表面必須有管理GPU
環(huán)境及紋理和字體
相關緩存的GrContext
對象.GrContexts
與OpenGL
環(huán)境或Vulkan
設備一一匹配
.
也即,使用相同的OpenGL
環(huán)境或Vulkan
設備渲染到的所有SkSurfaces
都應共享一個GrContext
.Skia
不會為你創(chuàng)建OpenGL
環(huán)境或Vulkan
設備.
在OpenGL
模式下,還假定在調用Skia
時,已為當前線程的當前環(huán)境
設置了正確的OpenGL
環(huán)境.
#include "include/gpu/GrDirectContext.h"#include "include/gpu/gl/GrGLInterface.h"#include "include/gpu/ganesh/gl/GrGLInterface.h"#include "include/core/SkData.h"#include "include/core/SkImage.h"#include "include/core/SkStream.h"#include "include/core/SkSurface.h"void gl_example(int width, int height, void (*draw)(SkCanvas*), const char* path) {// 已經(jīng)創(chuàng)建了`OpenGL`上下文并綁定了它sk_sp<const GrGLInterface> interface = nullptr;//將`interface`保留為`null`會使`Skia`按特定平臺方式,提取當前上下文的`OpenGL`函數(shù)的指針.或,可創(chuàng)建自己的`GrGLInterface`,并初化它,以附加到備用`OpenGL`實現(xiàn)或攔截`Skia`的`OpenGL`調用sk_sp<GrDirectContext> context = GrDirectContexts::MakeGL(interface);SkImageInfo info = SkImageInfo:: MakeN32Premul(width, height);sk_sp<SkSurface> gpuSurface(SkSurface::MakeRenderTarget(context.get(), skgpu::Budgeted::kNo, info));if (!gpuSurface) {SkDebugf("SkSurface::MakeRenderTarget returned null\n");return;}SkCanvas* gpuCanvas = gpuSurface->getCanvas();draw(gpuCanvas);sk_sp<SkImage> img(gpuSurface->makeImageSnapshot());if (!img) { return; }// 必須傳遞非空上下文,以便可以讀回和編碼`像素`sk_sp<SkData> png = SkPngEncoder::Encode(context.get(), img, {});if (!png) { return; }SkFILEWStream out(path);(void)out.write(png->data(), png->size());}
SKPDF
格式
因為文檔
必須包含多頁,SkPDF
后端使用SkDocument
而不是SkSurface
.
#include "include/docs/SkPDFDocument.h"#include "include/core/SkStream.h"void skpdf(int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream pdfStream(path);auto pdfDoc = SkPDF::MakeDocument(&pdfStream);SkCanvas* pdfCanvas = pdfDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));draw(pdfCanvas);pdfDoc->close();}
SkPicture
SkPicture
后端使用SkPictureRecorder
而不是SkSurface
.
#include "include/core/SkPictureRecorder.h"#include "include/core/SkPicture.h"#include "include/core/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);sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();SkFILEWStream skpStream(path);// 用`viewer --skps PATH_TO_SKP --slide SKP_FILE`,打開SKP文件picture->serialize(&skpStream);}
空畫布
空畫布是忽略
所有繪圖命令
且無操作
的畫布.
#include "include/utils/SkNullCanvas.h"void null_canvas_example(int, int, void (*draw)(SkCanvas*), const char*) {std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();draw(nullCanvas.get()); // 閑著}
SkXPS
(仍在實驗階段)把SkXPS
畫布寫入XPS
文檔.
#include "include/core/SkDocument.h"#include "include/core/SkStream.h"#ifdef SK_BUILD_FOR_WINvoid skxps(IXpsOMObjectFactory* factory; int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream xpsStream(path);sk_sp<SkDocument> xpsDoc = SkDocument::MakeXPS(&pdfStream, factory);SkCanvas* xpsCanvas = xpsDoc->beginPage(SkIntToScalar(width), SkIntToScalar(height));draw(xpsCanvas);xpsDoc->close();}#endif
SkSVG
(仍在實驗階段)把SkSVG
畫布寫入SVG
文檔.
#include "include/core/SkStream.h"#include "include/svg/SkSVGCanvas.h"#include "SkXMLWriter.h"void sksvg(int width, int height, void (*draw)(SkCanvas*), const char* path) {SkFILEWStream svgStream(path);std::unique_ptr<SkXMLWriter> xmlWriter( new SkXMLStreamWriter(&svgStream));SkRect bounds = SkRect::MakeIWH(width, height);std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(bounds, xmlWriter.get());draw(svgCanvas.get());}
例
要試用此代碼,請使用新的單元測試
,并把這些函數(shù)包裝
在一起:
#include "include/core/SkCanvas.h"#include "include/core/SkPath.h"#include "tests/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" );gl_example( 256, 256, example, "out_gpu.png" );skpdf( 256, 256, example, "out_skpdf.pdf" );picture( 256, 256, example, "out_picture.skp");}
畫布概述
繪圖環(huán)境
細節(jié)
SkCanvas
是Skia
的繪圖環(huán)境
.它知道直接在哪繪圖
(即屏幕外像素
的屏幕
位置),并維護一堆矩陣和剪切
.
但注意,與其他API
(如postscript,cairo
或awt
)中的類似環(huán)境不同,Skia
不會在環(huán)境
中存儲其他(如顏色,筆大小
)繪圖屬性
.相反,在每次
繪畫調用中,通過SkPaint
顯式指定它們.
確切地說,畫筆
而不是畫布
,描述繪畫
的顏色和風格
.
首先,可能想要擦除
整個畫布.可繪畫巨大
矩形來完成,但有更簡單
方法.
void draw(SkCanvas* canvas) {SkPaint paint;paint.setColor(SK_ColorWHITE);canvas->drawPaint(paint);}
這(當然,尊重當前剪切)指定
繪畫用的顏色或著色器
(和xfermode
),并填充整個畫布
.如果畫筆
中有個著色器
,則它也會遵循畫布
上的當前矩陣
(見SkShader
).
如果(用可選的xfermode
)只想繪畫
個顏色,你可直接調用drawColor()
,這樣就不必賦值
畫筆了.
void draw(SkCanvas* canvas) {canvas->drawColor(SK_ColorWHITE);}
所有其他繪畫API
類似,都以畫筆
參數(shù)結尾.
在某些
調用中,傳遞畫筆
的指針,而不是引用
.這時,paint
參數(shù)可能為null
.其他時候,必需要有paint
參數(shù).
畫筆概覽
每當你在Skia
中畫筆
某些內容時,想要指定顏色
,或如何與背景
混合,或使用的風格或字體
,都可在畫筆
中指定這些屬性.
與SkCanvas
不同,畫筆
不維護內部狀態(tài)棧
(即畫筆上不保存/恢復
).然而,畫筆
是輕量
的,因此客戶可創(chuàng)建和維護
多個用途不同的畫筆
對象.
從畫布
狀態(tài)中,分解出所有這些顏色和風格
屬性,并轉換為(多個
)畫筆
對象中,因為只需維護矩陣
和剪切
設置棧,可更加高效的保存/恢復畫布
.
可顯示三個不同
畫筆,每種畫筆
都按以不同的風格設置.現(xiàn)在,調用者
可自由地混合
這些畫筆
,可原樣使用它們,也可在繪圖
過程中修改它們.
除了顏色,描邊和文本值
等簡單屬性外,畫筆還支持特效
.它是繪圖管線
不同方面的子類
,引用畫筆
時(每個子類
都按引用計數(shù)
),調用它以覆蓋
繪圖管線的某些部分
.
如,要用漸變
而不是單色
畫筆,請為畫筆
指定SkShader
.
現(xiàn)在,使用該畫筆的內容都使用調用MakeLinear()
中指定的漸變畫筆
.返回的著色器
對象是引用計數(shù)
的.每當賦值著色
器等特效對象
給畫筆
時,畫筆都會增加引用計數(shù)
.
為了平衡,上面賦值給畫筆后,在著色器
上馬上調用unref()
.現(xiàn)在,畫筆
是該著色器的唯一"物主"
,當畫筆
出域或為其賦值另一個著色器(或null
)時,它自動在著色器
上調用unref()
.
有6種類型的特效可賦值
給畫筆:
1,SkPathEffect
,在生成α
掩碼(如破折號)修改幾何路徑
2,SkRasterizer
,合成
自定義掩碼圖層(如陰影
)
3,SkMaskFilter
,在著色及繪畫前修改α
掩碼(如模糊)
4,SkShader
:如漸變
(線性,徑向,掃描
),位圖模式(夾,重復,鏡像
)
5,SkColorFilter
,在混合
前修改源顏色
(如顏色矩陣
)
6,SkBlendMode
:如porter-duff
傳輸模式,混合模式等
畫筆
還有SkTypeface
的引用.字體
表示來測量和繪畫
文本的特定字體風格
.畫筆不僅可繪畫
文本,還可測量
文本.
paint.measureText(...);paint.getTextBounds(...);paint.textToGlyphs(...);paint.getFontMetrics(...);
SkBlend
模式
以下示例演示了Skia
的所有標準混合模式
.此例中,源
是有水平α
漸變的純洋紅色
,目標為有垂直α
漸變的純青色
.
SkShader
定義了幾個著色器(除了已提到的線性漸變):
1,位圖
著色器
2,徑向漸變
著色器
3,兩點錐形
漸變著色器
4,掃描
漸變著色器
5,分形
噪聲著色器
6,湍流
噪聲著色器
7,合成
著色器
SkMask
過濾器
1,模糊
掩碼過濾器
SkColor
過濾器
ColorMatrix
顏色過濾器
顏色表
顏色過濾器
SkPathEffect
1,SkPath2DPathEffect
:用矩陣
定義晶格,標記指定路徑
以填充
形狀.
2,SkLine2DPathEffect
:路徑是要描邊
而不是要填充
的直線路徑的SkPath2DPathEffect
的特例.
3,SkPath1DPathEffect
:通過復制指定路徑
沿著畫筆
路徑,創(chuàng)建
類似破折號
的特效.
4,SkCornerPathEffect
:一個可變形尖角
的特效(如圓角).
5,SkDashPathEffect
:實現(xiàn)破折號
的路徑特效.
6,SkDiscretePathEffect
:此路徑特效把路徑切成離散段
,并隨機替換它們.
7,SkComposePathEffect
:先應用內部pathEffect
,再外部pathEffect
(即outer(inner(path))
)的pathEffect
特效.
8,SkSumPathEffect
:按如下應用兩個特效的pathEffect
特效:
sequence (first(path) + second(path)).