首页 > Skia > Skia-相关资料
2013五月15

Skia-相关资料

[隐藏]

在线文档:https://sites.google.com/site/skiadocs/user-documentation/quick-start-guides/windows

1.SkPaint

SkPaint 保存绘制几何形状、文本、位图 的风格和颜色信息。

setAntiAlias: 设置画笔的锯齿效果。
setColor:     设置画笔颜色
setARGB:      设置画笔的a,r,p,g值。
setAlpha:     设置Alpha值
setTextSize:  设置字体尺寸。
setStyle:     设置画笔风格,空心或者实心。
setStrokeWidth: 设置空心的边框宽度。
getColor:    得到画笔的颜色
getAlpha:    得到画笔的Alpha值。

2.SkBitmap和DIB互转

SkBitmap转换成DIB的示例代码:(来自src\views\win\SkOSWindow_win)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        const SkBitmap& bitmap = this->getBitmap();
 
        BITMAPINFO bmi;
        memset(&bmi, 0, sizeof(bmi));
        bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth       = bitmap.width();
        bmi.bmiHeader.biHeight      = -bitmap.height(); // top-down image
        bmi.bmiHeader.biPlanes      = 1;
        bmi.bmiHeader.biBitCount    = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
        bmi.bmiHeader.biSizeImage   = 0;
 
        //
        // Do the SetDIBitsToDevice.
        //
        // TODO(wjmaclean):
        //       Fix this call to handle SkBitmaps that have rowBytes != width,
        //       i.e. may have padding at the end of lines. The SkASSERT below
        //       may be ignored by builds, and the only obviously safe option
        //       seems to be to copy the bitmap to a temporary (contiguous)
        //       buffer before passing to SetDIBitsToDevice().
        SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
        bitmap.lockPixels();
        int ret = SetDIBitsToDevice(hdc,
            0, 0,
            bitmap.width(), bitmap.height(),
            0, 0,
            0, bitmap.height(),
            bitmap.getPixels(),
            &bmi,
            DIB_RGB_COLORS);
        (void)ret; // we're ignoring potential failures for now.
        bitmap.unlockPixels();

DIB转Skia代码:(纯手敲,未测试)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  BITMAPINFO bmi;
  memset(&bmi, 0, sizeof(bmi));
  bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  bmi.bmiHeader.biWidth       = nWid;
  bmi.bmiHeader.biHeight      = -nHei; // top-down image
  bmi.bmiHeader.biPlanes      = 1;
  bmi.bmiHeader.biBitCount    = 32;
  bmi.bmiHeader.biCompression = BI_RGB;
  bmi.bmiHeader.biSizeImage   = 0;
  BYTE *pPixelBits = NULL;
  CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pPixelBits, 0, 0);
  SkBitmap bitmap;
  bitmap.setInfo(SkImageInfo::Make(nWid,nHei,kN32_SkColorType,kPremul_SkAlphaType));
  bitmap.setPixels(pPixelBits);// SkBitmap关联像素阵列

更多代码可以参看:http://code.google.com/p/skia/wiki/SkPaint

3.fRefCnt引用计数

SkShder 继承于 SkFlattenable,SkFlattenable继承于SkRefCnt

引用计数fRefCnt在SkRefCnt中定义

SkRefCnt 的成员函数 ref()和unref() 分别将fRefCnt递增1,递减1

void ref() const
{
     SkASSERT(fRefCnt > 0);
     sk_atomic_inc(&fRefCnt);  //递增1
 }
void unref() const
{
    SkASSERT(fRefCnt > 0);
    if (sk_atomic_dec(&fRefCnt) == 1)   //递减1
{
        fRefCnt = 1;    // so our destructor won't complain
        SkDELETE(this);  //delete this
    }
}

sk_atomic_dec(&fRefCnt) 返回的是递减前fRefCnt的值,也就是如果对象的引用计数已经是1,再调用unref(),则删除对象。

skRefCnt在构造函数中将fRefCnt赋值为1.(即使此时没有paint这种对象引用它)

SkRefCnt() : fRefCnt(1) {}

示例:

SkShader *shader =NULL;
shader =SkGradientShader::CreateLinear(..);    
paint.setShader(shader);        // fRefCnt+1 = 2
shader->unref();                // fRefCnt-1 = 1
shader->unref();                // fRefCnt-1 = 0,自动删除shader对象
printf("shader =%d\n",shader);  // unref删除shader对象的时候,并没有将this指空,此时shader仍是原来的地址值
SkRect r = {0,0,SkIntToScalar(800),SkIntToScalar(100)};
pskCanvas->drawRect(r,paint);   // 已经删除shader所指向的对象,所以drawRect没有效果

4.SkinRegion

Regions – set operations with rectangles

Regions are a highly compressed way to represent (integer) areas. Skia uses them to represent (internally) the current clip on the canvas. Regions take their inspiration from the data type with the same name on the original Macintosh (thank you Bill). Regions are opaque structures, but they can be queried via iterators. Best of all, they can be combined with other regions and with rectangles (which can be thought of as "simple" regions. If you remember Set operations from math class (intersection, union, difference, etc.), then you're all ready to use regions.

bool SkRegion::isEmpty();
bool SkRegion::isRect();
bool SkRegion::isComplex();

  Regions can be classified into one of three types: empty, rectangular, or complex. Empty regions are just that, empty. All empty regions are equal (using operator==). Compare this to rectangles (SkRect or SkIRect). Any rectangle with fLeft >= fRight or fTop >= fBottom is consider empty, but clearly there are different empty rectangles that are not equal.

SkRect a = { 0, 0, 0, 0 };
SkRect b = { 1, 1, 1, 1 };

Both a and b are empty, but they are definitely not equal to each other. However, with regions, all empty regions are equal. If you query its bounds, you will always get { 0, 0, 0, 0 }. Even if you translate it, it will still be all zeros. //这意思只要SkRegion为空,它们就相等,但SKRect就不行了

SkRegion a, b;   // regions default to empty
assert(a == b);
a.offset(10, 20);
assert(a == b);
assert(a.getBounds() == { 0, 0, 0, 0 });   // not legal C++, but you get the point
assert(b.getBounds() == { 0, 0, 0, 0 });

To initialize a region to something more interesting, use one of the set() methods

SkRegion a, b;
a.setRect(10, 10, 50, 50);
b.setRect(rect);    // see SkIRect
c.setPath(path);   // see SkPath

This is the first step that SkCanvas performs when one of its clip…() methods are called. The clip data is first transformed into device coordinates (see SkMatrix), and then a region is build from the data (either a rect or a path). The final step is to combine this new region with the existing clip using the specified operator. //操作和HRGN何其相似

enum Op {
    kUnion_Op,
    kIntersect_Op,
    kDifference_Op,
    kXor_Op,
    kReverseDifference_Op,
    kReplace_Op
};

By default, intersect op is used when a clip call is made, but the other operators are equally valid.

// returns true if the resulting clip is non-empty (i.e. drawing can still occur)

bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
    SkRegion rgn;
    // peek at the CTM (current transformation matrix on the canvas)
    const SkMatrix& m = this->getTotalMatrix();
    if (m.rectStaysRect()) {    // check if a transformed rect can be represented as another rect
        SkRect deviceRect;
        m.mapRect(&deviceRect, rect);
        SkIRect intRect;
        deviceRect.round(&intRect);
        rgn.setRect(intRect);
    } else {  // matrix rotates or skew (or is perspective)
        SkPath path;
        path.addRect(rect);
        path.transform(m);
        rgn.setPath(path);
    }
    // now combine the new region with the current one, using the specified *op*
    return fCurrentClip.op(rgn, op);
}

5.SkRect

SkRect

Rectangles

SkRect is basic to many drawing and measuring operations. It can be drawn using canvas.drawRect(), but it is also used to return the bounds of objects like paths and text characters. It is specified using SkScalar values.

// SkIRect就一32位整型SKRect

SkIRect is the integer counter part to SkRect, but is specified using 32bit integers.

struct SkRect {
      SkScalar fLeft;
      SkScalar fTop;
      SkScalar fRight;
      SkScalar fBottom;
   };

SkRect has the usual getters, to return width(), height(), centerX(), etc. It also has methods to compute unions and intersections between rectangles.

Converting between SkRect and SkIRect is asymetric. Short of overflow issues when SkScalar is an int, converting from SkIRect to SkRect is straight forward:

kRect::set(const SkIRect&);

However, convert from SkRect to SkIRect needs to know how to go from fractional values to integers.

 SkRect::round(SkIRect*) const;      // round each coordinate
   SkRect::roundOut(SkIRect*) const;  // apply floor to left/top, and ceil to right/bottom

n Skia, rectangle coordinates describe the boundary of what is drawn, such that an empty rectangle encloses zero pixels:

bool SkRect::isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
 
SkScalar SkRect::width() const { return fRight - fLeft; }
 
SkScalar SkRect::height() const { return fBottom - fTop; }
 
bool SkRect::contains(SkScalar x, SkScalar y) const {
    return fLeft <= x && x < fRight && fTop <= y && y < fBottom;
}

Thus, to draw a single pixel (assuming no matrix on the canvas), the rectangle should be initialized as follows:

SkRect r;
r.fLeft = x;
r.fTop = y;
r.fRight = x + SkIntToScalar(1);
r.fBottom = y + SkIntToScalar(1);

The same conventions hold for the integer counterpart: SkIRect. This also dovetails with SkRegion, which has the same model for set membership, and which uses SkIRect.

文章作者:hgy413
本文地址:https://hgy413.com/1832.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

本文的评论功能被关闭了.