BitmapData.GradientFill()的な何か
...
@author @kndys
package
{
import com.bit101.components.Label;
import com.bit101.components.CheckBox;
import com.bit101.components.ColorChooser;
import com.bit101.components.HSlider;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;
/**
* ...
* @author @kndys
*/
public class Main extends Sprite
{
private var sldrMidSrc:HSlider;
private var sldrMidDst:HSlider;
private var chooser1:ColorChooser;
private var chooser2:ColorChooser;
private var sldrMin:HSlider;
private var sldrMax:HSlider;
private var linearBox:CheckBox;
private var sldrParam:HSlider;
private var sldrRot:HSlider;
private var bmdGrad:BitmapDataGrad;
private var curve:ToneCurve;
private var bmp:Bitmap;
private var bmd:BitmapData;
public function Main()
{
bmd = new BitmapData(258, 258);
bmp = new Bitmap(bmd);
bmp.x = 160;
bmp.y = 5;
addChild(bmp);
bmdGrad = new BitmapDataGrad(bmd);
chooser1 = new ColorChooser(this, 5, 5, 0xff0000, update);
new Label(this, 80, 5, "start color");
chooser2 = new ColorChooser(this, 5, 25, 0xff00, update);
new Label(this, 80, 25, "end color");
sldrMidSrc = new HSlider(this, 5, 65, update);
sldrMidSrc.value = 50.0;
new Label(this, 110, 60, "mid src");
sldrMidDst = new HSlider(this, 5, 85, update);
sldrMidDst.value = 50.0;
new Label(this, 110, 80, "mid dst");
sldrMin = new HSlider(this, 5, 105, update);
sldrMin.value = 50.0;
new Label(this, 110, 100, "start");
sldrMax = new HSlider(this, 5, 125, update);
sldrMax.value = 50.0;
new Label(this, 110, 120, "end");
linearBox = new CheckBox(this, 5, 145, "linearRBG", update);
sldrParam = new HSlider(this, 5, 165, update);
sldrParam.value = 50.0;
new Label(this, 110, 160, "param");
sldrRot = new HSlider(this, 5, 195, update);
sldrRot.value = 25.0;
new Label(this, 110, 190, "rotation");
curve = new ToneCurveQuadric();
update();
}
private function update(e:Event = null):void
{
curve.lock();
curve.parameter = sldrParam.value * 0.02 - 1.0;
curve.inflectionSrc = sldrMidSrc.value * 2.55;
curve.inflectionDst = sldrMidDst.value * 2.55;
curve.interceptMin = sldrMin.value * 0.02 - 1.0;
curve.interceptMax = sldrMax.value * 0.02 - 1.0;
curve.unlock();
bmdGrad.lock();
bmdGrad.ezFill(0xff000000);
bmdGrad.linearGradientFill(new Rectangle(1, 1, 256, 256), chooser1.value | 0xff000000, chooser2.value | 0xff000000, curve, sldrRot.value * 0.02 * Math.PI, linearBox.selected);
bmdGrad.unlock();
}
}
}
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import flash.display.BitmapData;
import flash.display.IBitmapDrawable;
import flash.display.BitmapData;
import flash.filters.BitmapFilter;
import flash.filters.ConvolutionFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Matrix;
class BitmapDataWrapper
{
protected var _target:BitmapData;
public function BitmapDataWrapper(target:BitmapData)
{
_target = target;
}
public function get height():int { return _target.height; }
public function get rect():Rectangle { return _target.rect; }
public function get transparent():Boolean { return _target.transparent; }
public function get width():int { return _target.width; }
public function applyFilter(source:BitmapData, sourceRect:Rectangle, destPoint:Point, filter:BitmapFilter):void
{
_target.applyFilter(source, sourceRect, destPoint, filter);
}
public function colorTransform(rect:Rectangle, colorTransform:ColorTransform):void
{
_target.colorTransform(rect, colorTransform);
}
public function compare(other:BitmapData):Object
{
return _target.compare(other);
}
public function copyChannel(source:BitmapData, sourceRect:Rectangle, destPoint:Point, sourceChannel:uint, destChannel:uint):void
{
_target.copyChannel(source, sourceRect, destPoint, sourceChannel, destChannel);
}
public function copyPixels(source:BitmapData, sourceRect:Rectangle, destPoint:Point, alphaBitmapDataBase:BitmapData = null, alphaPoint:Point = null, mergeAlpha:Boolean = false):void
{
_target.copyPixels(source, sourceRect, destPoint, (alphaBitmapDataBase? alphaBitmapDataBase: null), alphaPoint, mergeAlpha);
}
public function dispose():void
{
_target.dispose();
}
public function draw(source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:String = null, clipRect:Rectangle = null, smoothing:Boolean = false):void
{
_target.draw(source, matrix, colorTransform, blendMode, clipRect, smoothing);
}
public function drawFill(source:IBitmapDrawable, srcClipRect:Rectangle, dstFillRect:Rectangle,
rotation:Number = 0.0, smooothing:Boolean = false, colorTransform:ColorTransform = null, blendMode:String = null):void
{
var cosine:Number = Math.cos(rotation);
var sine:Number = Math.sin(rotation);
var absCos:Number = Math.abs(cosine);
var absSin:Number = Math.abs(sine);
var srcW:Number = srcClipRect.width;
var srcH:Number = srcClipRect.height;
var dstW:Number = dstFillRect.width;
var dstH:Number = dstFillRect.height;
var srcX0:Number = srcClipRect.x + 0.5 * srcW;
var srcY0:Number = srcClipRect.y + 0.5 * srcH;
var dstX0:Number = dstFillRect.x + 0.5 * dstW;
var dstY0:Number = dstFillRect.y + 0.5 * dstH;
var wRatio:Number = (dstW * absCos + dstH * absSin) / srcW;
var hRatio:Number = (dstW * absSin + dstH * absCos) / srcH;
var mat:Matrix = new Matrix();
mat.a = wRatio * cosine;
mat.b = wRatio * sine;
mat.c = - hRatio * sine;
mat.d = hRatio * cosine;
mat.tx = dstX0 - mat.a * srcX0 - mat.c * srcY0;
mat.ty = dstY0 - mat.b * srcX0 - mat.d * srcY0;
draw(source, mat, colorTransform, blendMode, dstFillRect, smooothing);
}
public function fillRect(rect:Rectangle, color:uint):void
{
_target.fillRect(rect, color);
}
public function floodFill(x:int, y:int, color:uint):void
{
_target.floodFill(x, y, color);
}
public function generateFilterRect(sourceRect:Rectangle, filter:BitmapFilter):Rectangle
{
return _target.generateFilterRect(sourceRect, filter);
}
public function getColorBoundsRect(mask:uint, color:uint, findColor:Boolean = true):Rectangle
{
return _target.getColorBoundsRect(mask, color, findColor);
}
public function getPixel24(x:int, y:int):uint
{
return _target.getPixel(x, y);
}
public function getPixel32(x:int, y:int):uint
{
return _target.getPixel32(x, y);
}
public function getPixels(rect:Rectangle):ByteArray
{
return _target.getPixels(rect);
}
public function getVector(rect:Rectangle):Vector.<uint>
{
return _target.getVector(rect);
}
public function histogram(hRect:Rectangle = null):Vector.<Vector.<Number>>
{
return _target.histogram(hRect);
}
public function hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean
{
return _target.hitTest(firstPoint, firstAlphaThreshold, secondObject, secondBitmapDataPoint, secondAlphaThreshold);
}
public function lock():void
{
_target.lock();
}
public function merge(source:BitmapData, sourceRect:Rectangle, destPoint:Point, redMultiplier:uint, greenMultiplier:uint, blueMultiplier:uint, alphaMultiplier:uint):void
{
_target.merge(source, sourceRect, destPoint, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier);
}
public function noise(randomSeed:int, low:uint = 0, high:uint = 255, channelOptions:uint = 7, grayScale:Boolean = false):void
{
_target.noise(randomSeed, low, high, channelOptions, grayScale);
}
public function paletteMap(source:BitmapData, sourceRect:Rectangle, destPoint:Point, redArray:Array = null, greenArray:Array = null, blueArray:Array = null, alphaArray:Array = null):void
{
_target.paletteMap(source, sourceRect, destPoint, redArray, greenArray, blueArray, alphaArray);
}
public function paletteMap2(source:ByteArray, sourceRect:Rectangle, destPoint:Point,
redVector:Vector.<uint> = null, greenVector:Vector.<uint> = null, blueVector:Vector.<uint> = null, alphaVector:Vector.<uint> = null):void
{
if (!redVector) redVector = newVectorUint256();
if (!greenVector) greenVector = newVectorUint256();
if (!blueVector) blueVector = newVectorUint256();
if (!alphaVector) alphaVector = newVectorUint256();
//target
var __tt:BitmapData = _target;
var __txStart:int = destPoint.x;
var __tyStart:int = destPoint.y;
var __tx:int = __txStart;
var __ty:int = __tyStart;
var __txEnd:int = __tx + sourceRect.width;
var __tyEnd:int = __ty + sourceRect.height;
var __tA:uint;
var __tR:uint;
var __tG:uint;
var __tB:uint;
source.position = 0;
__tt.lock();
while (__ty < __tyEnd)
{
while (__tx < __txEnd)
{
__tA = alphaVector[source.readUnsignedByte()];
__tR = redVector[source.readUnsignedByte()];
__tG = greenVector[source.readUnsignedByte()];
__tB = blueVector[source.readUnsignedByte()];
__tt.setPixel32(__tx, __ty, addColor(__tA, __tR, __tG, __tB));
__tx++;
}
__tx = __txStart;
__ty++;
}
__tt.unlock();
}
private function newVectorUint256():Vector.<uint>
{
var vector: Vector.<uint> = new Vector.<uint>();
for (var i:uint = 0; i < 0x100; i++)
{
vector[i] = 0;
}
return vector;
}
private function addColor(color0:uint, color1:uint, color2:uint, color3:uint):uint
{
var sumAG:uint = ((color0 & 0xff00ff00) >> 8) + ((color1 & 0xff00ff00) >> 8) +
((color2 & 0xff00ff00) >> 8) + ((color3 & 0xff00ff00) >> 8);
if ((sumAG & 0xff000000) != 0)
{
sumAG &= 0x00ffffff;
sumAG |= 0x00ff0000;
}
if ((sumAG & 0xff00) != 0)
{
sumAG &= 0xffff00ff;
sumAG |= 0x000000ff;
}
var sumRB:uint = (color0 & 0x00ff00ff) + (color1 & 0x00ff00ff) +
(color2 & 0x00ff00ff) + (color3 & 0x00ff00ff);
if ((sumRB & 0xff000000) != 0)
{
sumRB &= 0x00ffffff;
sumRB |= 0x00ff0000;
}
if ((sumRB & 0xff00) != 0)
{
sumRB &= 0xffff00ff;
sumRB |= 0x000000ff;
}
return (sumAG << 8) | sumRB;
}
public function perlinNoise(baseX:Number, baseY:Number, numOctaves:uint, randomSeed:int, stitch:Boolean, fractalNoise:Boolean, channelOptions:uint = 7, grayScale:Boolean = false, offsets:Array = null):void
{
_target.perlinNoise(baseX, baseY, numOctaves, randomSeed, stitch, fractalNoise, channelOptions, grayScale, offsets);
}
public function pixelDissolve(source:BitmapData, sourceRect:Rectangle, destPoint:Point, randomSeed:int = 0, numPixels:int = 0, fillColor:uint = 0):int
{
return _target.pixelDissolve(source, sourceRect, destPoint, randomSeed, numPixels, fillColor);
}
public function scroll(x:int, y:int):void
{
_target.scroll(x, y);
}
public function setPixel24(x:int, y:int, color:uint):void
{
_target.setPixel(x, y, color);
}
public function setPixel32(x:int, y:int, color:uint):void
{
_target.setPixel32(x, y, color);
}
public function setPixels(rect:Rectangle, inputByteArray:ByteArray):void
{
_target.setPixels(rect, inputByteArray);
}
public function setVector(rect:Rectangle, inputVector:Vector.<uint>):void
{
_target.setVector(rect, inputVector);
}
public function threshold(source:BitmapData, sourceRect:Rectangle, destPoint:Point, operation:String, threshold:uint, color:uint = 0, mask:uint = 4294967295, copySource:Boolean = false):uint
{
return _target.threshold(source, sourceRect, destPoint, operation, threshold, color, mask, copySource);
}
public function unlock(changeRect:Rectangle = null):void
{
_target.unlock(changeRect);
}
}
class BitmapDataEz extends BitmapDataWrapper
{
//private const ONE_THIRD:Number = 1.0 / 3.0;
protected static const POINT_ZERO:Point = new Point(0, 0);
protected const RECTANGLE:Rectangle = new Rectangle();
private var dXFilter:ConvolutionFilter;
private var dYFilter:ConvolutionFilter;
private var tempRect:Rectangle;
private var tempPoint:Point;
public function BitmapDataEz(target:BitmapData)
{
tempRect = new Rectangle();
tempPoint = new Point();
RECTANGLE.width = target.width;
RECTANGLE.height = target.height
super(target);
}
public function ezApplyFilter(source:BitmapDataEz, filter:BitmapFilter):void
{
applyFilter(source._target, source.RECTANGLE, POINT_ZERO, filter);
}
public function ezColorTransform(transform:ColorTransform):void
{
colorTransform(RECTANGLE, transform);
}
public function ezCopyChannel(source:BitmapDataEz, sourceChannel:uint, destChannel:uint):void
{
copyChannel(source._target, source.RECTANGLE, POINT_ZERO, sourceChannel, destChannel);
}
public function ezCopyPixels(source:BitmapDataEz, mergeAlpha:Boolean = false, alphaBitmapData:BitmapData = null):void
{
copyPixels(source._target, source.RECTANGLE, POINT_ZERO, alphaBitmapData, POINT_ZERO, mergeAlpha);
}
public function ezDrawFill(source:BitmapDataEz,
rotation:Number = 0.0, smooothing:Boolean = false, colorTransform:ColorTransform = null, blendMode:String = null):void
{
drawFill(source._target, source.RECTANGLE, RECTANGLE, rotation, smooothing, colorTransform, blendMode);
}
public function ezFill(color:uint):void
{
fillRect(RECTANGLE, color);
}
public function ezGetPixels():ByteArray
{
return getPixels(RECTANGLE);
}
public function ezMerge(source:BitmapDataEz, redMultiplier:uint, greenMultiplier:uint, blueMultiplier:uint, alphaMultiplier:uint):void
{
merge(source._target, source.RECTANGLE, POINT_ZERO, redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier);
}
public function ezPaletteMap(source:BitmapDataEz,
redArray:Array = null, greenArray:Array = null, blueArray:Array = null, alphaArray:Array = null):void
{
paletteMap(source._target, source.RECTANGLE, POINT_ZERO, redArray, greenArray, blueArray, alphaArray);
}
public function ezPaletteMap2(source:BitmapDataEz,
redVector:Vector.<uint> = null, greenVector:Vector.<uint> = null, blueVector:Vector.<uint> = null, alphaVector:Vector.<uint> = null):void
{
paletteMap2(source.getPixels(source.RECTANGLE), source.RECTANGLE, POINT_ZERO, redVector, greenVector, blueVector, alphaVector);
}
public function ezPixelDissolve(source:BitmapDataEz, randomSeed:int = 0, numPixels:int = 0, fillColor:uint = 0):int
{
return pixelDissolve(source._target, source.RECTANGLE, POINT_ZERO, randomSeed, numPixels, fillColor);
}
public function ezSetPixels(bytes:ByteArray):void
{
setPixels(RECTANGLE, bytes);
}
public function ezThreshold(source:BitmapDataEz, operation:String, threshold:uint, color:uint = 0, mask:uint = 4294967295, copySource:Boolean = false):uint
{
return this.threshold(source._target, source.RECTANGLE, POINT_ZERO, operation, threshold, color, mask, copySource);
}
}
class BitmapDataGrad extends BitmapDataEz
{
private var lGradData:ByteArray;
private var lGradRect:Rectangle;
private var cGradData:ByteArray;
private var cGradRect:Rectangle;
private var sqrtTable:Vector.<Number>;
public function BitmapDataGrad(target:BitmapData)
{
super(target);
}
public function linearGradientFill(rectangle:Rectangle, colorStart:uint, colorEnd:uint, curve:ToneCurve, rotation:Number = 0.0, linearRGB:Boolean = false):void
{
var tempData:BitmapData = new BitmapData(512, 1);
for (var i:int = 0; i < 512; i+=1)
{
tempData.setPixel32(i, 0, curve.interpolate(colorStart, colorEnd, (i + 0.5) / 512.0, true, linearRGB));
}
drawFill(tempData, tempData.rect, rectangle, rotation, true);
}
}
class Color
{
private var _a:uint;
private var _r:uint;
private var _g:uint;
private var _b:uint;
public function Color(argb:uint)
{
_a = argb >>> 24;
_r = (argb >>> 16) & 0xff;
_g = (argb >>> 8) & 0xff;
_b = argb & 0xff;
}
public static function interpolate(color1:uint, color2:uint, ratio:Number, useAlpha:Boolean = true, linearRGB:Boolean = false):uint
{
var c1:Color = new Color(color1);
var c2:Color = new Color(color2);
if (ratio < 0.0 && linearRGB) ratio = 0.0;
if (ratio > 1.0 && linearRGB) ratio = 1.0;
var a:uint = useAlpha ? checkChannel((1.0 - ratio) * c1._a + ratio * c2._a): 0xff;
var k1:Number = linearRGB? Math.sqrt(1.0 - ratio): (1.0 - ratio);
var k2:Number = linearRGB? Math.sqrt(ratio): ratio;
var r:uint = checkChannel(k1 * c1._r + k2 * c2._r);
var g:uint = checkChannel(k1 * c1._g + k2 * c2._g);
var b:uint = checkChannel(k1 * c1._b + k2 * c2._b);
return (a << 24) | (r << 16) | (g << 8) | b;
}
private static function checkChannel(ch:Number):uint
{
return ch > 255.0? 0xff: (ch < 0.0? 0x0: (ch | 0));
}
}
class ToneCurve
{
private var colorVector:Vector.<uint>;
protected var param:Number;
protected var minSrc:Number;
protected var minDst:Number;
protected var midSrc:Number;
protected var midDst:Number;
protected var maxSrc:Number;
protected var maxDst:Number;
private var _inflectionSrc:Number;
private var _inflectionDst:Number;
private var _interceptMin:Number;
private var _interceptMax:Number;
private var isLocked:Boolean;
public function ToneCurve(parameter:Number = 0.0, inflectionSrc:uint = 0x80, inflectionDst:uint = 0x80, interceptMin:Number = 0.0, interceptMax:Number = 0.0)
{
colorVector = new Vector.<uint>();
_inflectionSrc = inflectionSrc;
_inflectionDst = inflectionDst;
_interceptMin = interceptMin;
_interceptMax = interceptMax;
init();
param = parameter;
create();
}
private function create():void
{
if (isLocked) return;
createCurve();
createVector();
}
private function init():void
{
if (isLocked) return;
midSrc = Number(_inflectionSrc) / 256.0;
midDst = Number(_inflectionDst) / 256.0;
if (_interceptMin < 0.0)
{
minSrc = - midSrc * _interceptMin;
minDst = 0.0;
}
else
{
minSrc = 0.0;
minDst = midDst * _interceptMin;
}
if (_interceptMax < 0.0)
{
maxSrc = 1.0;
maxDst = 1.0 + (1.0 - midDst) * _interceptMax;
}
else
{
maxSrc = 1.0 - (1.0 - midSrc) * _interceptMax;
maxDst = 1.0;
}
}
private function createVector():void
{
for (var i:int = 0; i < 256; i+=1)
{
colorVector[i] = limNum(256.0 * calcDstUnit((i + 0.5) / 256.0));
}
}
private function calcDstUnit(srcUnit:Number):Number
{
if (srcUnit <= minSrc) return 0.0;
else if (srcUnit < midSrc) return firstCurve(srcUnit);
else if (srcUnit < maxSrc) return secondCurve(srcUnit);
else return 1.0;
}
protected function createCurve():void
{
}
protected function firstCurve(src:Number):Number
{
return src;
}
protected function secondCurve(src:Number):Number
{
return src;
}
private function limUint(value:uint):uint
{
return value > 0xff? 0xff: value;
}
private function limNum(value:Number):uint
{
return value > 255.0? 0xff : (value < 0.0? 0x0: (value | 0));
}
public function transform(colorChannel:uint):uint
{
return colorVector[limUint(colorChannel)];
}
public function transformColor(argbColor:uint, transformAlpha:Boolean = false):uint
{
var a:uint = transformAlpha? colorVector[(argbColor >>> 24) & 0xff]: (argbColor & 0xff000000);
var r:uint = colorVector[(argbColor >>> 16) & 0xff];
var g:uint = colorVector[(argbColor >>> 8) & 0xff];
var b:uint = colorVector[argbColor & 0xff];
return (a << 24) | (r << 16) | (g << 8) | b;
}
public function interpolate(argb1:uint, argb2:uint, ratio:Number, useAplha:Boolean = false, linearRGB:Boolean = false):uint
{
return Color.interpolate(argb1, argb2, calcDstUnit(ratio), useAplha, linearRGB);
}
public function get parameter():Number { return param; }
public function set parameter(value:Number):void
{
param = value;
create();
}
public function get inflectionSrc():Number { return _inflectionSrc; }
public function set inflectionSrc(value:Number):void
{
_inflectionSrc = value;
init();
create();
}
public function get inflectionDst():Number { return _inflectionDst; }
public function set inflectionDst(value:Number):void
{
_inflectionDst = value;
init();
create();
}
public function get interceptMin():Number { return _interceptMin; }
public function set interceptMin(value:Number):void
{
_interceptMin = value;
init();
create();
}
public function get interceptMax():Number { return _interceptMax; }
public function set interceptMax(value:Number):void
{
_interceptMax = value;
init();
create();
}
public function lock():void
{
isLocked = true;
}
public function unlock():void
{
isLocked = false;
init();
create();
}
}
class ToneCurveQuadric extends ToneCurve
{
public var firstA:Number;
public var secondA:Number;
public var firstB:Number;
public var secondB:Number;
public function ToneCurveQuadric(parameter:Number = 0.0, inflectionSrc:uint = 0x80, inflectionDst:uint = 0x80, interceptMin:Number = 0.0, interceptMax:Number = 0.0)
{
super(parameter, inflectionSrc, inflectionDst, interceptMin, interceptMax);
}
override protected function createCurve():void
{
var firstDiffDst:Number;
var firstDiffSrc:Number;
var secondDiffDst:Number;
var secondDiffSrc:Number;
var firstRatio:Number;
var secondRatio:Number;
var firstParam:Number;
var secondParam:Number;
firstDiffDst = minDst - midDst - 0.001;
firstDiffSrc = minSrc - midSrc - 0.001;
firstRatio = firstDiffDst / firstDiffSrc;
secondDiffDst = maxDst - midDst + 0.001;
secondDiffSrc = maxSrc - midSrc + 0.001;
secondRatio = secondDiffDst / secondDiffSrc;
if (firstRatio < secondRatio)
{
firstParam = param;
secondParam = firstRatio / secondRatio * (1 + param) - 1;
}
else
{
firstParam = secondRatio / firstRatio * (1 + param) - 1;
secondParam = param;
}
firstA = - firstParam * firstRatio / firstDiffSrc;
firstB = firstRatio * (1 + firstParam);
secondA = - secondParam * secondRatio / secondDiffSrc;
secondB = secondRatio * (1 + secondParam);
}
override protected function firstCurve(src:Number):Number
{
src -= midSrc;
return midDst + (firstA * src + firstB) * src;
}
override protected function secondCurve(src:Number):Number
{
src -= midSrc;
return midDst + (secondA * src + secondB) * src;
}
}