| INDEX |

使い処は限られているとは思いますが、色のブレンド関係のスクリプトを書いて見ました。Proccessingでいうところの「blendColor()」です。
普段使っているblendModeの仕組みメモも兼ねて。

淡白なようですが以下のようなスクリプトなりました。

 
/**
* ColorBlend
* @author nutsu
*/
 
package {
  
  public class ColorBlend {
    
    public static const ADD:String       = "add";
    public static const SUBTRACT:String   = "subtract";
    public static const DARKEN:String     = "darken";
    public static const LIGHTEN:String     = "lighten";
    public static const DIFFERENCE:String   = "difference"
    public static const MULTIPLY:String   = "multiply";
    public static const SCREEN:String     = "screen";
    public static const OVERLAY:String     = "overlay";
    public static const HARDLIGHT:String   = "hardlight";
    public static const SOFTLIGHT:String   = "softlight";
    public static const DODGE:String    = "dodge";
    public static const BURN:String      = "burn";
    public static const EXCLUSION:String  = "exclusion";
    
    public function ColorBlend() {
      throw new Error("インスタンスはつくっても意味ないです");
    }
    
    /**
     * ブレンド
     * @param  色1
     * @param  色2
     * @param  ブレンドタイプ
     */
    public static function blend( c1:uint, c2:uint, blendkind:String ):uint
    {
      switch( blendkind )
      {
        case ADD:        return add( c1, c2 );
        case SUBTRACT:   return sub( c1, c2 );
        case DARKEN:     return dark( c1, c2 );
        case LIGHTEN:    return light( c1, c2 );
        case DIFFERENCE: return diff( c1, c2 );
        case MULTIPLY:   return multi( c1, c2 );
        case SCREEN:     return screen( c1, c2 );
        case OVERLAY:    return overlay( c1, c2 );
        case HARDLIGHT:  return hard( c1, c2 );
        case SOFTLIGHT:  return soft( c1, c2 );
        case DODGE:      return dodge( c1, c2 );
        case BURN:       return burn( c1, c2 );
        case EXCLUSION:  return excl( c1, c2 );
        default:         return c2;
      }
    }
    
    
    /**
     * 加算
     */
    public static function add( c1:uint, c2:uint ):uint
    {
      return addRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function addRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return Math.min( r1 + r2, 0xff ) << 16 | Math.min( g1 + g2, 0xff ) << 8 | Math.min( b1 + b2, 0xff );
    }
    
    /**
     * 減算
     */
    public static function sub( c1:uint, c2:uint ):uint
    {
      return subRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function subRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return Math.max( r1 - r2, 0 ) << 16 | Math.max( g1 - g2, 0 ) << 8 | Math.max( b1 - b2, 0 );
    }
    
    /**
     * 暗い方
     */
    public static function dark( c1:uint, c2:uint ):uint
    {
      return darkRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function darkRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return Math.min( r1, r2 ) << 16 | Math.min( g1, g2 ) << 8 | Math.min( b1, b2 );
    }
    
    /**
     * 明るい方
     */
    public static function light( c1:uint, c2:uint ):uint
    {
      return lightRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function lightRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return Math.max( r1, r2 ) << 16 | Math.max( g1, g2 ) << 8 | Math.max( b1, b2 );
    }
    
    /**
     * 差の絶対値
     */
    public static function diff( c1:uint, c2:uint ):uint
    {
      return diffRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function diffRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return Math.abs( r1-r2 ) << 16 | Math.abs( g1-g2 ) << 8 | Math.abs( b1-b2 );
    }
    
    /**
     * 乗算
     */
    public static function multi( c1:uint, c2:uint ):uint
    {
      return multiRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function multiRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return ( r1*r2>>>8 ) << 16 | ( g1*g2>>>8 ) << 8 | b1*b2>>>8;
    }
    
    /**
     * スクリーン
     */
    public static function screen( c1:uint, c2:uint ):uint
    {
      return multi( c1 ^ 0xffffff, c2 ^ 0xffffff ) ^ 0xffffff;
    }
    public static function screenRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return multiRGB( r1^0xff, g1^0xff, b1^0xff, r2^0xff, g2^0xff, b2^0xff )^0xffffff;
    }
    
    /**
     * オーバーレイ
     */
    public static function overlay( c1:uint, c2:uint ):uint
    {
      return overlayRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function overlayRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _overlay(r1,r2)<<16 | _overlay(g1,g2)<<8 | _overlay(b1,b2);
    }
    private static function _overlay( e1:uint, e2:uint ):uint
    {
      return ( e1 < 0x80 ) ? e1*e2>>>7 : ((e1^0xff)*(e2^0xff)>>>7)^0xff;
    }
    
    /**
     * ハードライト
     */
    public static function hard( c1:uint, c2:uint ):uint
    {
      return hardRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function hardRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _hard(r1,r2)<<16 | _hard(g1,g2)<<8 | _hard(b1,b2);
    }
    private static function _hard( e1:uint, e2:uint ):uint
    {
      return ( e2 < 0x80 ) ? e1*e2>>>7 : ((e1^0xff)*(e2^0xff)>>>7)^0xff;
    }
    
    /**
     * ソフトライト
     */
    public static function soft( c1:uint, c2:uint ):uint
    {
      return softRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function softRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _soft(r1,r2)<<16 | _soft(g1,g2)<<8 | _soft(b1,b2);
    }
    private static function _soft( e1:uint, e2:uint ):uint
    {
      return Math.floor( e1 * e2 / 0xff + e1 * ( 0xff - (e1 ^ 0xff) * (e2 ^ 0xff)/0xff - e1 * e2 / 0xff )/0xff );
    }
    
    /**
     * 覆い焼き
     */
    public static function dodge( c1:uint, c2:uint ):uint
    {
      return dodgeRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function dodgeRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _dodge(r1,r2)<<16 | _dodge(g1,g2)<<8 | _dodge(b1,b2);
    }
    private static function _dodge( e1:uint, e2:uint ):uint
    {
      var x:uint;
      if ( e2 == 0xff || ( x = Math.floor( e1*0xff/(e2^0xff)) ) > 0xff )
        return 0xff;
      else
        return x;
    }
    
    /**
     * 焼き込み
     */
    public static function burn( c1:uint, c2:uint ):uint
    {
      return burnRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function burnRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _burn(r1,r2)<<16 | _burn(g1,g2)<<8 | _burn(b1,b2);
    }
    private static function _burn( e1:uint, e2:uint ):uint
    {
      var x:uint;
      if ( e2 == 0 || (x = 0xff - Math.floor( (e1^0xff)*0xff/e2 ) ) < 0 )
        return 0;
      else
        return x;
    }
    
    /**
     * 除外
     */
    public static function excl( c1:uint, c2:uint ):uint
    {
      return exclRGB( (c1 & 0xff0000)>>>16, (c1 & 0x00ff00)>>>8, c1 & 0x0000ff, (c2 & 0xff0000)>>>16, (c2 & 0x00ff00)>>>8, c2 & 0x0000ff );
    }
    public static function exclRGB( r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint ):uint
    {
      return _excl(r1,r2)<<16 | _excl(g1,g2)<<8 | _excl(b1,b2);
    }
    private static function _excl( e1:uint, e2:uint ):uint
    {
      return e1 + e2 - ( e1*e2>>>7 );
    }
  }
}

実際にProccesingで計算した値と比べると微妙に違う(1大きいとか)場合もありますが、だいたい合っているような…。
なお、Sharaku Image Manipulation Program – ブレンドモードosakana.factory – ブレンドモード詳説、を大変参考にしました。感謝です。

コメントは受け付けていません。

| INDEX |