如何制作涂抹工具算法?

How to make smudge tool algorithm?

我正在为涂抹工具创建一个算法,但它必须逐个像素地完成。

涂抹工具的概念很简单

onMouseMove - 使用画笔模板将旧点的像素复制到新点

我在按位运算中遇到问题。该算法未正确绘制像素。(我是从头开始创建此算法,因此可能会出现一些愚蠢的错误)

diameter = brush.size;
_bitData = _canvas.bitmapData;
_bitwidth = _bitData.rect.width;//width of canvas

_bitVector = _bitData.getVector();//1d vector of uint

_brushVector = brush.bitmapData.getVector();//1d vector of uint

brushVectorIndex = 0;
for(yIndex = 0; yIndex < diameter; yIndex++)
{
    for(xIndex = 0; xIndex < diameter; xIndex++)
    {
        yCor = yIndex + oldY;
        xCor = xIndex + oldX;

        if(_bitData.rect.contains(xCor,yCor))
        {
            bitVectorIndex_old      = (yCor * _bitWidth)        + xCor;
            bitVectorIndex_new      = ((Y+yIndex) * _bitWidth)  + X+xIndex;

            //Creating alpha map of brush and old mouse point's pixel
            brushPixelAlpha = (_brushVector[brushVectorIndex] & _bitVector[bitVectorIndex_old] & 0xFF000000);

            //Adding colors to the aplha map according to old mouse point's pixel
            brushPixel = brushPixelAlpha | (_bitVector[bitVectorIndex_old] & 0x00FFFFFF);

            //Create alpha map for new pixel
            pixelAlpha = ((brushPixel | _bitVector[bitVectorIndex_new]) & 0xFF000000)

            //Adding color to pixel alpha map using brush's stamp 
            pixel =  pixelAlpha | (brushPixel & 0x00FFFFFF);

            _bitVector[bitVectorIndex_new] = pixel;
        }
        brushVectorIndex++;
    }
}
_bitData.setVector(_bitVector);

如果您能建议如何优化这段代码,那也会很有帮助,因为这段代码每帧 运行 10000 秒。

编辑:制定了一个有效的解决方案。上面的位运算是非常错误的。下面的代码没有优化,但可以工作。

private function smudgeIt(brush:uint,oldMouse:uint,newMouse:uint):uint
        {
            var pixel:uint;
            var bA:uint = (brush>>24)&0xff;
            var oA:uint = (oldMouse>>24)&0xff;

            var oldAlpha:uint = oA<bA?oA:bA;

            var rOld:uint,gOld:uint,bOld:uint;
            var rNew:uint,gNew:uint,bNew:uint;

            rOld = (oldMouse >>16) & 0xff;
            gOld = (oldMouse >>8)  & 0xff;
            bOld = (oldMouse       & 0xff);

            rNew = (newMouse >>16) & 0xff;
            gNew = (newMouse >>8)  & 0xff;
            bNew = (newMouse       & 0xff);

            var newAlpha:uint = ((newMouse>>24)&0xff)-oldAlpha;
            newAlpha = newAlpha<0?0:newAlpha;

            rNew = (rNew*newAlpha + rOld*oldAlpha)/255;
            gNew = (gNew*newAlpha + gOld*oldAlpha)/255;
            bNew = (bNew*newAlpha + bOld*oldAlpha)/255;

            var finalAlpha:uint = ((newMouse >> 24) & 0xff)+oldAlpha;
            finalAlpha = finalAlpha>255?255:finalAlpha;

            pixel = finalAlpha<<24 | rNew << 16 | gNew << 8 | bNew;

            return pixel;
        }

Alpha 通道的含义有些混淆。
如果用旧的和刷子的混合物覆盖新位置的 RGB 通道,您显示的代码:

RGB_new = RGB_old | RGB_brush;
alpha_new = alpha_new | (alpha_old & alpha_brush);

这不是你想要的,你丢失了新位置的所有颜色信息(因此没有混合它),更糟糕的是,如果画笔真的有RGB信息,你会饱和所有通道直到你获得纯白.
让我们暂时忘掉 alpha 通道,让我们从普通的不透明 RGB 形式开始。
正如您所描述的那样,画笔作为位掩码运行:如果某个位设置为 1,则从旧位置获取像素,否则将像素从新位置保留。假设一个8位mask8 = mask1*16rFF),应用于1个像素的1-8位通道:

R_new = (R_new & (256-mask8)) | (R_old & mask8);

现在假设一个 24 位掩码(8 位掩码重复 3 次,(mask8<<16)|(mask8<<8)|mask8mask8*0x10100mask1*16rFFFFFF),这可以同时应用于 3 个通道:

RGB_new = (RGB_new & (~mask24)) | (R_old & mask24);

如果你想用 alpha 通道使事情复杂化(这是某种逐渐透明而不是全有或全无),那么你将不得不描述如何混合新旧位,但我认为然后画笔将成为 alpha 通道本身。

一种经典算法(alpha 混合)具有 R_new = R_new * (1-alpha) + R_old * alpha,其中 alpha 是 0 到 1 之间的分数。它可以在 alpha 介于 0(透明)和 0xFF(不透明)之间的整数算法中执行:

R_new = (R_new * (255-alpha) + R_old*alpha) / 255;

通过一些小技巧,您可以在 R_B 通道和 A_G_ 通道上进行多路复用操作。您可以在此站点上找到其中一些 alpha 混合位技巧。我确实将其中一些应用于 Squeak VM http://bugs.squeak.org/view.php?id=7803, after all BitBlt operations where invented by Dan Ingalls in the Smalltalk context https://en.wikipedia.org/wiki/Bit_blit,所以我们必须回馈凯撒。

在这里,我们没有考虑新旧像素的固有透明度,我们可以定义更复杂的操作来考虑这些,但这意味着什么?如果它们是透明的,我们看到后面是什么?