Android下Skia遮罩特效的达成
发布时间:2021-11-25 18:28:36 所属栏目:教程 来源:互联网
导读:大体需求是,有一个文字点阵,叫glyph,为单色点阵,有笔画的地方为黑色,1;无笔画的地方为白色,0; 现在要把这个字画到屏幕,还有一个要求,要用当前颜色画; 分析来分析去,这就是一个简单的rop3操作,或者简单一点,就是一个遮罩特效:使用glyph当遮罩
大体需求是,有一个文字点阵,叫glyph,为单色点阵,有笔画的地方为黑色,1;无笔画的地方为白色,0; 现在要把这个字画到屏幕,还有一个要求,要用当前颜色画; 分析来分析去,这就是一个简单的rop3操作,或者简单一点,就是一个遮罩特效:使用glyph当遮罩,使用当前颜色画矩形,仅此而以。 但是,目前没有在Skia中找到类似的操作,只找到SkXformode里有这样的定义: enum Mode { kClear_Mode, //!< [0, 0] kSrc_Mode, //!< [Sa, Sc] kDst_Mode, //!< [Da, Dc] kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc] kDstOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc] kSrcIn_Mode, //!< [Sa * Da, Sc * Da] kDstIn_Mode, //!< [Sa * Da, Sa * Dc] kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)] kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc] kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1-Sa)* Dc] ...... 基本上看不懂,光看公式,没法知道到底是个什么效果;看来只有使用这些东西来模拟遮罩效果了。 试验来试验去,下面的代码可以实现: 1 首先,把单色位图转换成32位 static void depth1to32(const uint16 * data, uint8 * out, uint8 * end) { uint16 pixel; uint32 value; ...... // glyph : src SkBitmap // bitmap : dst SkBitmap int width; int height; width = glyph->width(); height = glyph->height(); uint8 *sbits; sbits = (uint8 *)data; int sstride; sstride = (width + 7) / 8; uint8 *sline; sline = sbits; // check format uint8 *dbits; dbits = (uint8 *)out; int dstride; dstride = bitmap->rowBytes(); int dbpp; // bytes per pixel dbpp = bitmap->bytesPerPixel(); uint8 *dline; dline = dbits; while (height--) { int w = width; uint8 *dline1 = dline; uint8 *sline1 = sline; while(w > 0) { uint8 pixel8; pixel8 = *(sline1++); for(int i = 0; i < (w < 8 ? w : 8); i++) { uint8 c = 1 < < (7 - i); if(pixel8 & c) { *(dline1++) = 0; *(dline1++) = 0; *(dline1++) = 0; // 这个地方,如果最高两个字节是0,则表示透明 *(dline1++) = 0xFF; } else { *(dline1++) = 0xff; *(dline1++) = 0xff; *(dline1++) = 0xff; // 这个地方,如果最高两个字节是0,则表示透明 *(dline1++) = 0; } } w -= 8; } dline += dstride; sline += sstride; } } ...... 2 使用当前颜色转换遮罩 SkBitmap *srcbmp = (SkBitmap*)(bitmap); SkPaint paint; SkCanvas canvas(*srcbmp); paint.setXfermodeMode(SkXfermode::kSrcIn_Mode); paint.setColor(display->foreColor); SkRect rect = { 0, 0, srcbmp->width(), srcbmp->height()}; canvas.drawRect(rect, paint); 自此,srcbmp已经变成了当前颜色表示的字符点阵 3 把字符画到屏幕 SkShader* s = SkShader::CreateBitmapShader(*srcbmp, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); SkMatrix matrix; matrix.reset(); matrix.postTranslate(x, y); SkShader *shader = (SkShader *)s; shader->setLocalMatrix(matrix); // 设置原点 SkPaint *paint = (SkPaint *)paint; paint->setShader(shader)->unref(); paint->setXfermodeMode(SkXfermode::kSrcOver_Mode); paint->setColor(display->foreColor); SkRect rect = { x, y, x + w, y + h}; canvas->drawRect(rect, *paint); 这段代码,相当于把一个部分区域透明的pattern画到屏幕上 这样,我们就实现了字符遮罩的功能,使用当前颜色把字符画到屏幕上了。 当然,我们只是画了一个单色字符,其实也可以画很复杂的图案,类似于PS和Flash里的遮罩层的效果。 以上代码是示意代码,因此有些地方明显无法编译,有些地方明显多此一举,请注意。 另,Skia有类似Mask的概念,但看来看去,好像没有我们这里说的遮罩功能。 如果大家有更好的实现方法,也请告诉我一下。 ![]() (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |