1

我遇到了这个 ActionScript 示例,该示例演示了使用波形通过循环一次一行地绘制色谱图。

但是,每个 RGB 通道的波形位置会创建一个缺少颜色(纯黄色、青色和品红色)的色谱,因此该光谱是不完整的。

我该如何解决这个问题,以便绘制的色谱显示所有颜色?

// Loop through all of the pixels from '0' to the specified width.
for(var i:int = 0; i < nWidth; i++)
    {
    // Calculate the color percentage based on the current pixel.
    nColorPercent = i / nWidth;

    // Calculate the radians of the angle to use for rotating color values.
    nRadians = (-360 * nColorPercent) * (Math.PI / 180);

    // Calculate the RGB channels based on the angle.
    nR = Math.cos(nRadians)                   * 127 + 128 << 16;
    nG = Math.cos(nRadians + 2 * Math.PI / 3) * 127 + 128 << 8;
    nB = Math.cos(nRadians + 4 * Math.PI / 3) * 127 + 128;

    // OR the individual color channels together.
    nColor  = nR | nG | nB;
    }

更新的解决方案


对于任何有兴趣的人,以下是我为解决上述问题而编写的解决方案。RGB 波形不用于创建全色谱。此外,代码很灵活,因此您可以为生成的精灵分配自己的大小和颜色变量。此示例中的颜色变量为红色、黄色、绿色、青色、蓝色、品红色、红色,以生成完整的色谱

/*
//SpectrumGradient Object Call

var spectrum:SpectrumGradient = new SpectrumGradient(stage.stageWidth, stage.stageHeight, 0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFF0000);
this.addChild(spectrum);
*/


package
{
    import flash.display.BitmapData;
    import flash.display.CapsStyle;
    import flash.display.GradientType;
    import flash.display.LineScaleMode;
    import flash.display.Sprite;
    import flash.geom.Matrix;

    public class SpectrumGradient extends Sprite
        {
        public function SpectrumGradient(spriteWidth:Number, spriteHeight:Number, ...spriteColors)
            {
            //Setup spectrum sprite
            var spectrum:Sprite = new Sprite();
            var spectrumAlphas:Array = new Array();
            var spectrumRatios:Array = new Array();
            var spectrumPartition:Number = 255 / (spriteColors.length - 1);

            for (var pushLoop:int = 0; pushLoop < spriteColors.length; pushLoop++)
                {
                spectrumAlphas.push(1);
                spectrumRatios.push(pushLoop * spectrumPartition);
                }

            //Create spectrum sprite as evenly distributed linear gradient using supplied spriteColors
            var spectrumMatrix:Matrix = new Matrix();
            spectrumMatrix.createGradientBox(spriteWidth, spriteHeight);
            spectrum.graphics.lineStyle();
            spectrum.graphics.beginGradientFill(GradientType.LINEAR, spriteColors, spectrumAlphas, spectrumRatios, spectrumMatrix);
            spectrum.graphics.drawRect(0, 0, spriteWidth, 1);
            spectrum.graphics.endFill();

            //Assign bitmapData to the spectrum sprite
            var bitmapData:BitmapData = new BitmapData(spectrum.width, spectrum.height, true, 0);
            bitmapData.draw(spectrum);

            var pixelColor:Number;

            for (var i:int = 0; i < spriteWidth; i++)
                {
                //Retrieve the color number for each pixel of the spectrum sprite
                pixelColor = bitmapData.getPixel(i, 0);

                //Create new matrices for the white and black gradient lines
                var matrixWhite:Matrix = new Matrix();
                matrixWhite.createGradientBox(1, spriteHeight / 2, Math.PI * 0.5, 0, 0);
                var matrixBlack = new Matrix();
                matrixBlack.createGradientBox(1, spriteHeight / 2, Math.PI * 0.5, 0, spriteHeight / 2);

                //Each slice of the sprite is composed of two vertical lines:  the first fades from white to the pixelColor, the second fades from pixelColor to black
                graphics.lineStyle(1, 0, 1, false, LineScaleMode.NONE, CapsStyle.NONE);
                graphics.lineGradientStyle(GradientType.LINEAR, [0xFFFFFF, pixelColor], [100, 100], [0, 255], matrixWhite);
                graphics.moveTo(i, 0);
                graphics.lineTo(i, spriteHeight / 2);
                graphics.lineGradientStyle(GradientType.LINEAR, [pixelColor, 0], [100, 100], [0, 255], matrixBlack);
                graphics.moveTo(i, spriteHeight / 2);
                graphics.lineTo(i, spriteHeight);
                }

            }
        }
}
4

1 回答 1

4

你不能一次拥有所有颜色。所有 RGB 颜色,即 256 x 256 x 256,因此您需要 4096 x 4096 像素才能显示所有颜色。

此外,没有“自然”/明智的方式来显示它们。至少到目前为止,还没有人提出真正有意义的二维色彩空间。为了显示颜色,您总是必须选择 2。这就是为什么常见的颜色选择器要么使用色调滑块和亮度/饱和度平面,要么使用色调/饱和度平面和亮度滑块

另请注意,第一个(矩形)光谱可以很容易地用 2 个叠加梯度绘制。一个水平的色调,一个垂直的(半透明的)亮度。它更快且完全平滑(如果放大,则看不到单独的线条)。

编辑:这是一个工作示例,说明如何使用单个渐变来实现这一点,出于显而易见的原因,这是更可取的:

package  {
    import flash.display.*;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;

    public class GradientTest extends Sprite {

        public function GradientTest() {
            var colors:Array = [0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFF0000];
            var part:Number = 0xFF / (colors.length-1);
            var ratios:Array = [], alphas:Array = [];
            var m:Matrix = new Matrix();
            m.createGradientBox(500, 20);
            for (var i:int = 0; i < colors.length; i++) {
                ratios.push(part * i);
                alphas.push(100);
            }

            this.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, m);
            this.graphics.drawRect(0, 0, 500, 20);

            //just to get the RGB values under the mouse:
            var b:BitmapData = new BitmapData(this.width, this.height, true, 0);
            b.draw(this);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, function (e:Event):void {
                if (hitTestPoint(mouseX, mouseY)) {
                    var s:String = b.getPixel(mouseX, mouseY).toString(16);
                    while (s.length < 6) s = "0" + s;
                    trace("#" + s);                 
                }
            });
        }   
    }
}

使用波形的方法有点像寻找钉子的锤子。仅仅因为位运算和三角函数是很好的工具,并不意味着您应该更喜欢它们而不是更简单的解决方案。

于 2010-03-29T07:54:49.013 回答