Skia引擎API整理介紹


http://code.google.com/p/skia/

svn checkout http://skia.googlecode.com/svn/trunk/ skia-read-only

 

 

Skia引擎重要類簡介
(PS: 注意是簡介了,觀眾不要要求太高,我也是在摸索中整理的文檔)
1. SkCanvas
     這個類是Skia引擎的一個核心類,他封裝了所有對設備進行的畫圖操作。這個類自身包含了一個設備的引用,以及一個矩陣和裁剪棧。所有的畫圖操作, 都是在經過棧內存放的矩陣變幻之后才進行的(這點和OpenGL類似)。當然,最終顯示給用戶的圖像,還必須經過裁剪堆棧的運算。
     SkCanvas記錄着整個設備的繪畫狀態,而設備上面繪制的對象的狀態又是由SkPaint類來記錄的,SkPaint類作為參數,傳遞給不同 SkCanvas類的成員函數drawXXXX().(比如:drawPoints, drawLine, drawRect, drawCircle)。SkPaint類里記錄着如顏色(color), 字體(typeface), 文字大小(textSize), 文字粗細(strokeWidth), 漸變(gradients, patterns)等。
     SkCanvas類的主要成員函數:
         > 構造函數,給定一個Bitmap或者Device,在給定的這個對象上進行畫圖,Device可以為空。
            SkCanvas(const SkBitmap& bitmap);
            SkCanvas(SkDevice* device = NULL);
         > setViewport, getViewport, 這2個函數只有在支持OpenGL視圖時才有效。
         > save, saveLayer, saveLayerAlpha, restore, 這4個函數用於保存和恢復顯示矩陣,剪切,過濾堆棧,不同函數有不同的附加功能。
         > 移位,縮放,旋轉,變形函數。
            translate(SkiaScalar dx, SkiaScalar dy);
            scale(SkScalar sx, SkScalar sy);
            rotate(SkScalar degrees);
            skew(SkScalar sx, SkScalar sy);
         > 指定具體矩陣,進行相應的變換的函數,以上4個方法都可以通過定義特定的矩陣,再調用此函數實現。
            cancat(const SkMatrix& matrix);
         > 圖像剪輯,把指定的區域顯示出來。
            clipRect(SkRect&...);
            clipPath(SkPath&...);
            clipRegion(SkRegion&...);
         > 在當前畫布內畫圖,有以下多種畫圖方式:
            drawARGB(u8 a, u8 r, u8 g, u8 b....) 給定透明度以及紅,綠,蘭3色,填充整個可繪制區域。
            drawColor(SkColor color...) 給定顏色color, 填充整個繪制區域。
            drawPaint(SkPaint& paint) 用指定的畫筆填充整個區域。
            drawPoint(...)/drawPoints(...) 根據各種不同參數繪制不同的點。
            drawLine(x0, y0, x1, y1, paint) 畫線,起點(x0, y0), 終點(x1, y1), 使用paint作為畫筆。
            drawRect(rect, paint) 畫矩形,矩形大小由rect指定,畫筆由paint指定。
            drawRectCoords(left, top, right, bottom, paint), 給定4個邊界畫矩陣。
            drawOval(SkRect& oval, SkPaint& paint) 畫橢圓,橢圓大小由oval矩形指定。
            drawCicle(cx, cy, radius, paint), 給定圓心坐標和半徑畫圓。
            drawArcSkRect& oval...) 畫弧線,用法類似於畫橢圓。
            drawRoundRect(rect, rx, ry, paint) 畫圓角矩形,x, y方向的弧度用rx, ry指定。
            drawPath(path, paint) 路徑繪制,根據path指定的路徑繪制路徑。
            drawBitmap(SkBitmap& bitmap, left, top, paint = NULL) 繪制指定的位圖, paint可以為空。
            drawBitmapRect(bitmap, src, dest, paint=NULL), 繪制給定位圖的一部分區域,此區域由src指定,然后把截取的部分位圖繪制到dest指定的區域,可能進行縮放。
            drawBitmapMatrix(bitmap, matrix, paint=NULL), 功效同上,可以通過給定矩陣來進行裁剪和縮放變換。
            drawSprite(bitmap, left, top, paint=NULL), 繪制位圖,不受當前變換矩陣影響。
            drawText(void* text, byteLength, x, y, paint), 以(x,y)為起始點寫文字,文字存儲在text指針內,長度有byteLength指定。
            drawPosText(...) 功能同上,不過每個文字可以單獨指定位置。
            drawPosTextH(...) 功能同上,不過由一個變量指定了當前所有文字的統一Y坐標,即在同一條水平線上以不同的間隔寫字。
            drawTextOnPathHV, drawTextOnPath, drawTextOnPath, 以不同方式在給點定的path上面繪制文字。
            drawPicture(SkPicture& picture) 在畫布上繪制圖片,比較高效的繪圖函數。
            drawShape(SkShape*) 在畫布上繪制指定形狀的圖像。
            drawVertices(...) 繪制點,可以有紋理,顏色,等附加選項。


 

1 Skia 繪圖概述

Skia 是 Google 一個底層的圖形、文本、圖像、動畫等多方面的圖形庫,是 Android 中圖形系統的引擎。 Skia 作為第三方軟件放在 external 目錄下: external/skia/ 。 skia 的源文件及部分頭文件都在 src 目錄下,導出的頭文件在 include 目錄下。

使用 Skia 的 API 進行圖形繪制時主要會用到一下幾個類:

SkBitmap

SkCanvas

SkPaint

SkRect

其中

SkBitmap 用來設置像素,

SkCanvas 寫入位圖,

SkPaint 設置顏色和樣式,

SkRect 用來繪制矩形。

其實現代碼主要在 src/core 目錄下。

 

 

2 使用 Skia 繪圖的步驟

a) 定義一個位圖 32 位像素並初始化
SkBitmap bitmap;

bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200);

其中 setConfig 為設置位圖的格式,原型為 void setConfig(Config, int width, int height, int rowBytes = 0)
Config 為一個數據結構
enum Config {
kNo_Config, // 不確定的位圖格式
kA1_Config, //1 位 ( 黑 , 白 ) 位圖
kA8_Config, //8 位 ( 黑 , 白 ) 位圖
kIndex8_Config, // 類似 windows 下的顏色索引表,具體請查看 SkColorTable 類結構
kRGB_565_Config, //16 位象素 565 格式位圖,詳情請查看 SkColorPriv.h 文件
kARGB_4444_Config, //16 位象素 4444 格式位圖,詳情請查看 SkColorPriv.h 文件
kARGB_8888_Config, //32 位象素 8888 格式位圖,詳情請查看 SkColorPriv.h 文件
kRLE_Index8_Config,
kConfigCount
};

b) 分配位圖所占的空間

bitmap.allocPixels()
其實 allocPixels 為重載函數,原型為 bool allocPixels(SkColorTable* ctable = NULL)
參數 ctable 為顏色索引表,一般情況下為 NULL 。

c) 指定輸出設備

SkCanvas canvas(new SkDevice(bitmap));
其中 canvas 為一個多構造函數,原型為

explicit SkCanvas(const SkBitmap& bitmap) ,

explicit SkCanvas(SkDevice* device = NULL)
explicit 關健字的意思為:不允許類型轉換
輸出設備可以為一個上下文 Device, 也可以指定為一張位圖。

d) 設備繪制的風格
Paint paint;
SkRect r;
paint.setARGB(255, 255, 0, 0);
r.set(25, 25, 145, 145);
canvas.drawRect(r, paint);
paint 可以指定繪圖的顏色,文本的大小及對齊方式,編碼格式等等,因為以前位圖的格式設置為 kARGB_8888_Config ,所以這里要設置繪制的顏色 setARGB(255, 255, 0, 0) ,第一位參數為透明顏色通道,其它三位分別為 R 、 G 、 B 。 r 設置要繪制的范圍,最后通過 drawRect 繪制出指定區域的一個方形。

這樣,一個紅色的矩形就繪制成功了。

SkCanvas 主要完成三種繪制功能:

a 基本圖形繪制 ( 如 drawARGB,drawLine 函數 )

b 圖像文件繪制( drawBitmap 函數)

c 文本繪制( drawText 函數)

相關 API 有:

canvas.drawRect(rect, paint);
         canvas.drawOval(oval, paint);
         canvas.drawCircle(x, y, radius, paint);
         canvas.drawRoundRect(rect, rx, ry, paint);
         canvas.drawPath(path, paint);
         canvas.drawBitmap(bitmap, x, y, &paint);
         canvas.drawBitmapRect(bitmap, &srcRect, dstRect, &paint);
         canvas.drawBitmapMatrix(bitmap, matrix, &paint);
         canvas.drawText(text, length, x, y, paint);
         canvas.drawPosText(text, length, pos[], paint);
         canvas.drawTextOnPath(text, length, path, paint);

e)

例程

i )畫點、線、圓、文字

#include "SkBitmap.h"

#include "SkDevice.h"

#include "SkPaint.h"

#include "SkRect.h"

#include "SkImageEncoder.h"

#include "SkTypeface.h"

using namespace std;

int main()

{

SkBitmap bitmap;

bitmap.setConfig(SkBitmap::kARGB_8888_Config,320,240);

bitmap.allocPixels();

SkCanvas canvas(new SkDevice(bitmap));

SkPaint paint;

// draw points with red.

paint.setARGB(255, 255, 0, 0);

paint.setStrokeWidth(4);

canvas.drawPoint(40,30, paint);

canvas.drawPoint(80,60, paint);

canvas.drawPoint(120,90, paint);

//draw a line with green.

paint.setARGB(255, 0, 255, 0);

paint.setStrokeWidth(4);

canvas.drawLine(160,10,320,110,paint);

//draw a circle with bule.

paint.setARGB(255, 0, 0, 255);

canvas.drawCircle(80,180,50,paint);

//draw text with red

SkTypeface *font = SkTypeface::CreateFromFile("simkai.ttf");

if ( font )

{

paint.setARGB(255, 255, 0, 0);

paint.setTypeface( font );

paint.setTextSize(24);

canvas.drawText("HELLO!:)", 8, 200, 180, paint);

}

SkImageEncoder::EncodeFile("snapshot.png", bitmap,SkImageEncoder::kPNG_Type,100);

return 0;

}

程序執行后,得到如下輸出結果:

ii) 圖像的編解碼

該例程目前測試只支持 .png 格式的圖片, .jpg 還不支持,還未找到原因。

#include "SkBitmap.h"

#include "SkDevice.h"

#include "SkPaint.h"

#include "SkRect.h"

#include "SkImageEncoder.h"

#include "SkImageDecoder.h"

#include <iostream>

using namespace std;

int main()

{

int ret = -1;

SkBitmap bitmap;

//SkImageDecoder

ret = SkImageDecoder::DecodeFile("./old.png", &bitmap);

cout<< "get the decode type = "<< bitmap.config() << endl;

//SkImageEncoder

ret = SkImageEncoder::EncodeFile("new1.png",bitmap,SkImageEncoder::kPNG_Type,100);

cout<< "encode data to png result = "<< ret<< endl;

return 0;

}

SkImageDecoder::DecodeFile("./old.png", &bitmap);

 

將 png 轉換成位圖格式,並將數據放到 bitmap 變量中
SkImageEncoder::EncodeFile("snapshot.png", bitmap,SkImageEncoder::kPNG_Type,/* Quality ranges from 0..100 */ 100);

將 bitmap 中的數據編碼輸出為 .png 格式,第一位參數為 png 文件路徑,第二位為指定的輸出位圖,第三位為文件的類型,第四位參數指定了輸出位圖的質量,范圍為 0..100 ,默認為 80 。

3 圖形圖像特效

src/effects 目錄的文件主要實現一些圖形圖像的特效,包括 遮罩、浮雕、模糊、濾鏡、漸變色、離散、透明以及 PATH 的各種特效等。

4 動畫

src/animator 目錄的文件主要實現了 Skia 的動畫效果,Android不支持。

5 界面 UI 庫

src/view 目錄 構建了一套界面 UI 庫。
組件包括 Window,Menu, TextBox, ListView, ProgressBar, Widget, ScrollBar,TagList,Image 等。

6 其它

a) src/gl 目錄: 這部分是 skia 調用 OpenGL 或 OpenGL ES 來實現 3D 效果。
如果定義了 MAC ,則使用 OpenGL ,如果定義了 Android ,則使用嵌入式 系統 上的 esgl 三維圖形庫。

b)src/images 目錄: 主要是 SkImageDecoder 和 SkImageEncoder 以及 SkMovie 。主要是用來處理 images 的,能處理的圖像類型包括: BMP 、 JPEG/PVJPEG 、 PNG 、 ICO ,而 SkMovie 是用來處理 gif 動畫的。

c) src/opts 目錄:性能優化的代碼。

d) src/pdf 目錄: 處理 PDF 文檔,用了一個 fpdfemb 庫。

e) src/ports 目錄: 這部分是 skia 的一些接口在不同系統上的實現,平台相關的代碼,比如字體、線程、時間等,主要包括幾個部分: Font , Event , File , Thread , Time , XMLParser

這些與 Skia 的接口,需要針對不同的 操作系統 實現。

f) src/svg 目錄: 矢量圖像,Android不支持。
SkSVGPath, SkSVGPolyline, SkSVGRect, SkSVGText, SkSVGLine, SkSVGImage, SkSVGEllipse 等等。

g) src/text 目錄:???

h) src/utils 目錄: 是一些輔助工具類。
SkCamera, SkColorMatrix,SkOSFile,SkProxyCanvas,SkInterpolator 等文件。

i) src/xml : 這是處理 xml 數據的部分, skia 在這里只是對 xml 解析器做了一層包裝,具體的 xml 解析器的實現需要根據不同的操作系統及宿主程序來實現。

j) Third-party library

除了自身的所有文件外, skia 還使用了一些 third-party library 以及包含了不少 linux 上的頭文件。

通過分析 skia 源程序,發現 skia 主要使用以下幾個第三方庫:
Zlib ,處理數據的壓縮和解壓縮
Jpeglib ,處理 jpeg 圖像的編碼解碼
Pnglib ,處理 png 圖像的編碼解碼
giflib ,處理 gif 圖像
fpdfemb ,處理 pdf 文檔

skia 還需要一些 linux/unix 下的頭文件(可能還需要更多):
stdint.h
unistd.h
features.h
cdefs.h
stubs.h
posix_opt.h
types.h
wordsize.h
typesizes.h
confname.h
getopt.h
mman.h

 

 

3D圖片旋轉,旋轉窗口我看行

SkBitmap *pskBitmap;

SkCanvas *pskCanvas;

BITMAPINFO *lpbmi;

HWND g_hWnd;

SkBitmap *bkBitmap;//背景圖片

SkRect   g_rtImg;// 圖片最初按鈕。

SkRect   g_rtClip;//矩陣裁剪用 ,做圖片旋轉時,每次旋轉時的裁剪會用到上一次的裁剪范圍。

//g_rtClip是共用裁剪范圍,多個不同的位置共用,每次旋轉前初始化為要旋轉圖片的原始位置

//初始化背景圖片,

void MyInitBkImage(char *filename)

{

    SkFILEStream stream(filename);

    SkImageDecoder * coder = SkImageDecoder::Factory(&stream);

    if (coder)

    {

        bkBitmap = new SkBitmap();

        coder->decode(&stream,bkBitmap,SkBitmap::kRGB_565_Config,SkImageDecoder::kDecodePixels_Mode);

    }

}

//整體初始化

void MyInit()

{

    pskBitmap = new SkBitmap();

    pskBitmap->setConfig(SkBitmap::kRGB_565_Config,800,480);

    pskBitmap->allocPixels();//分配位圖所占空間

    pskCanvas = new SkCanvas();

    pskCanvas->setBitmapDevice(*pskBitmap);

    lpbmi  = (BITMAPINFO*)malloc( sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(2) );

    //printf("%d,%d\n",sizeof(BITMAPINFOHEADER),sizeof(BITMAPINFO));40,44

    memset( lpbmi, 0, sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(2) );//必須同上方一直

    lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);//位圖信息頭大小 40字節

    lpbmi->bmiHeader.biWidth = 800;

    lpbmi->bmiHeader.biHeight = -480;

    lpbmi->bmiHeader.biPlanes = 1;

    lpbmi->bmiHeader.biBitCount = 16;              //16位位圖  565模式0xF800、0x07E0、0x001F

    lpbmi->bmiHeader.biCompression = BI_BITFIELDS; //壓縮參數  BI_RGB=0表示無壓縮,

    lpbmi->bmiHeader.biSizeImage = 0;

    lpbmi->bmiColors[0].rgbBlue = 0; 

    lpbmi->bmiColors[0].rgbGreen = 0xF8;  //248?

    lpbmi->bmiColors[0].rgbRed = 0; 

    lpbmi->bmiColors[0].rgbReserved = 0; 

    lpbmi->bmiColors[1].rgbBlue = 0xE0;  //224

    lpbmi->bmiColors[1].rgbGreen = 0x07;  //7

    lpbmi->bmiColors[1].rgbRed = 0; 

    lpbmi->bmiColors[1].rgbReserved = 0; 

    lpbmi->bmiColors[2].rgbBlue = 0x1F;  //31

    lpbmi->bmiColors[2].rgbGreen = 0; 

    lpbmi->bmiColors[2].rgbRed = 0; 

    lpbmi->bmiColors[2].rgbReserved = 0;

    MyInitBkImage("\\USER\\skia\\bk.png");

    g_rtImg.setLTRB(151,214,249,346); //初始化圖片位置

    //g_rtClip 在每次旋轉前初始化

}

//畫圖片filename,rt為其范圍,圖片沒有保存,每次臨時加載

void DrawImage(char * filename,SkCanvas *canvas, SkRect rt, SkPaint *paint)

{

    int ti = GetTickCount();

    SkFILEStream stream(filename);

    SkImageDecoder* coder = SkImageDecoder::Factory(&stream);

    SkBitmap *bitmap;

    if (coder)

    {

        //printf(" file %s code success\n",filename);

        bitmap = new SkBitmap();

        coder->decode(&stream, bitmap, SkBitmap::kRGB_565_Config,

            SkImageDecoder::kDecodePixels_Mode);

    }

    else

    {

        printf(" file %s code fail\n",filename);

        return;

    }

    //printf("24bit800*480png,code time =%d\n",GetTickCount()-ti);//367

    ti = GetTickCount();

    canvas->drawBitmap(*bitmap,rt.fLeft, rt.fTop);

    //printf("24bit800*480png,draw time =%d\n",GetTickCount()-ti);//12

    delete bitmap;

    return;

}

//畫背景

void DrawBKImage()

{

    SkIRect rt;

    rt.setXYWH(0,0,800,480);

    int ti = GetTickCount();

    pskCanvas->drawBitmap(*bkBitmap,rt.fLeft,rt.fTop);

    printf("--------------time draw bk 24bit800*480=%d\n",GetTickCount()-ti);//11

}

//畫圖片filename,效果使其繞Y軸旋轉rotateY角度,調用DrawImage()

void DrawRotateYImage(char * filename,int rotateY,SkRect rtImg)

{

    SkRect rtClip = g_rtClip;//保留上次裁剪范圍

    pskCanvas->resetMatrix();

    SkMatrix matrix;

    Sk3DView    sk3DView;

    sk3DView.rotateY(rotateY); //繞Y軸旋轉

    sk3DView.getMatrix(&matrix);

    matrix.preTranslate(-(rtImg.fLeft+rtImg.width()/2), 0);

    matrix.postTranslate((rtImg.fLeft+rtImg.width()/2), 0);

    matrix.mapRect(&g_rtClip,rtImg); //兩個參數都是SkRect類型

    //matrix.mapRect 作用:src經過matrix變化,形成dst

    //圖片的最初范圍經過matrix變化(每次繞Y軸旋轉角度不一樣),得出新的裁剪范圍

    rtClip.join(g_rtClip);              //計算最終裁剪范圍

    g_rtClip = rtClip ;                 //保存裁剪范圍,供下次計算最終裁剪范圍

    //DrawBKImage();//此處畫背景,不然會保留不同ratateY角度圖片的痕跡 ,放在此處 畫背景用時多 ,為4或者3,

    pskCanvas->save();

    pskCanvas->clipRect(rtClip);//矩陣裁剪

    DrawBKImage();//此處畫背景,不然會保留不同ratateY角度圖片的痕跡 放在此處畫背景用時小 ,為0或者1,

    //具體畫的內容,與pskCanvas畫布的裁剪有關系?

    //pskCanvas->save(SkCanvas::kMatrix_SaveFlag); 可以去掉,之前已經有pskCanvas->save();

    pskCanvas->concat(matrix);  

    DrawImage(filename,pskCanvas,rtImg,NULL);

    //此處的位置參數須是圖片原始位置,不能是裁剪范圍,否則顯示的位置偏離

    //pskCanvas->restore();     與save對應

    pskCanvas->restore();

    //pskCanvas->resetMatrix();

}

//觸發圖片旋轉函數

void MyLButtonDown()

{

    g_rtClip = g_rtImg; //初始裁剪范圍為要畫圖片的正常范圍。

    for (int i =0;i<=10;i++)

    {

        DrawRotateYImage("\\user\\skia\\music-n.png",36*(i+0),g_rtImg);

        HDC dc = GetDC(g_hWnd);

        SetDIBitsToDevice(dc, 0, 0, 800, 480, 0, 0, 0, 800, pskBitmap->getPixels(), lpbmi, DIB_RGB_COLORS);

        //將數據顯示到屏幕上

        ReleaseDC(g_hWnd,dc);

    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM