// blend1.cpp : DLL アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include #ifdef _MANAGED #pragma managed(push, off) #endif extern "C" { typedef unsigned char n_byte; int __stdcall get_blend_func_count(); char* __stdcall get_blend_func_key(int no); char* __stdcall get_blend_func_name(int no); void __stdcall blend(unsigned char* dst,const unsigned char* col,const unsigned char* alpha,int col_step ,int alpha_step,int num_channel,int num_pixel,int no); //追加する合成方法の数を返す。 int __stdcall get_blend_func_count() { return 3; } //psdファイルに保存するときのkeyを返す。 /* 'norm' = normal 'dark' = darken 'lite' = lighten 'hue ' = hue 'sat ' = saturation 'colr' = color 'lum ' = luminosity 'mul ' = multiply 'scrn' = screen 'diss' = dissolve 'over' = overlay 'hLit' = hard light 'sLit' = soft light 'diff' = difference 'smud' = exlusion 'div ' = color dodge 'idiv' = color burn */ char* __stdcall get_blend_func_key(int no) { if (no == 0) {//ビビットライト return "vLit"; } if (no == 1) {//リニアライト return "lLit"; } if (no == 2) {//ピンライト return "pLit"; } return 0; } //合成方法の名前を返す。 char* __stdcall get_blend_func_name(int no) { if (no == 0) { return "ビビットライト"; } if (no == 1) { return "リニアライト"; } if (no == 2) { return "ピンライト"; } return ""; } //合成を行う関数。 //num_channel チャンネル数。グレーモードの場合は1、カラーモードの場合は3 void __stdcall blend(unsigned char* dst,const unsigned char* col,const unsigned char* alpha,int col_step,int alpha_step ,int num_channel,int num_pixel,int no) { if (no == 0) {//ビビットライト // 計算サイト http://stackoverflow.com/questions/5919663/how-does-photoshop-blend-two-images-together // 255 - ((255 - bg) *256 ) / (fg*2) //  (A << 8 ) / (255 - (2 * (B - 128))) if (num_channel == 1) {// ビビットライト グレスケ const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = 0; if(*col<128 && 0<*col) { d = 255 - ((255 - *dst) *256) / (*col*2);} else if(*col<=0) { d = 0;} else { d = (*dst *256 ) / (255 - (2 * (*col - 128))) ;} d = d < 0 ? 0 : ( d < 255 ? d : 255); *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } else if (num_channel == 3) { // ビビットライト カラー const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = 0; if(*col<128 && 0<*col) { d = 255 - ((255 - *dst) *256) / (*col*2);} else if(*col<=0) { d = 0;} else { d = (*dst *256 ) / (255 - (2 * (*col - 128))) ;} double d1 = 0; if(*(col+1)<128 && 0<*(col+1)) { d1 = 255 - ((255 - *(dst+1)) *256) / (*(col+1)*2);} else if(*(col+1)<=0) { d1 = 0;} else { d1 = (*(dst+1) *256 ) / (255 - (2 * (*(col+1) - 128))) ;} double d2 = 0; if(*(col+2)<128 && 0<*(col+2)) { d2 = 255 - ((255 - *(dst+2)) *256) / (*(col+2)*2);} else if(*(col+2)<=0) { d2 = 0;} else { d2 = (*(dst+2) *256 ) / (255 - (2 * (*(col+2) - 128))) ;} d = d < 0 ? 0 : ( d < 255 ? d : 255); d1 = d1 < 0 ? 0 : ( d1 < 255 ? d1 : 255); d2 = d2 < 0 ? 0 : ( d2 < 255 ? d2 : 255); // レイヤーの色×不透明度 + 下のレイヤーの色×(100%-不透明度) *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; *(dst + 1) = d1 * *alpha/255.00 + *(dst+1) * (1.00-*alpha/255.00)+0.5; *(dst + 2) = d2 * *alpha/255.00 + *(dst+2) * (1.00-*alpha/255.00)+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } } //---------------------------- if (no == 1) {//リニアライト // 計算サイト http://www.bea.hi-ho.ne.jp/gaku-iwa/color/conjn.html if (num_channel == 1) { // リニアライト グレスケ const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = *col *2 + *dst -256; d = d < 0 ? 0 : ( d < 255 ? d : 255); *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } else if (num_channel == 3) { // リニアライト カラー const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = *col *2 + *dst -256; double d1 = *(col + 1) *2 + *(dst + 1) -256; double d2 = *(col + 2) *2 + *(dst + 2) -256; d = d < 0 ? 0 : ( d < 255 ? d : 255); d1 = d1 < 0 ? 0 : ( d1 < 255 ? d1 : 255); d2 = d2 < 0 ? 0 : ( d2 < 255 ? d2 : 255); // レイヤーの色×不透明度 + 下のレイヤーの色×(100%-不透明度) *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; *(dst + 1) = d1 * *alpha/255.00 + *(dst+1) * (1.00-*alpha/255.00)+0.5; *(dst + 2) = d2 * *alpha/255.00 + *(dst+2) * (1.00-*alpha/255.00)+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } } //---------------------------- if (no == 2) {//ピンライト // 計算サイト http://dunnbypaul.net/blends/ // f (Blend > 1/2) R = max(Base,2*(Blend-1/2)) // if (Blend <= 1/2) R = min(Base,2*Blend) if (num_channel == 1) { // ピンライト グレスケ const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = 0; if(*col<128) { d = (int)min(*dst, *col *2) ;} else { d = (int)max(*dst,(*col-128)*2) ;} *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } else if (num_channel == 3) { // ピンライト カラー const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { double d = 0; if(*col<128) { d = (int)min(*dst, *col *2) ;} else { d = (int)max(*dst,(*col-128)*2) ;} double d1 = 0; if(*(col+1)<128) { d1 = (int)min(*(dst+1), *(col+1) *2) ;} else { d1 = (int)max(*(dst+1),(*(col+1)-128)*2) ;} double d2 = 0; if(*(col+2)<128) { d2 = (int)min(*(dst+2), *(col+2) *2) ;} else { d2 = (int)max(*(dst+2),(*(col+2)-128)*2) ;} // レイヤーの色×不透明度 + 下のレイヤーの色×(100%-不透明度) *dst = (d * *alpha/255.00) + (*dst * (1.00-*alpha/255.00))+0.5; *(dst + 1) = d1 * *alpha/255.00 + *(dst+1) * (1.00-*alpha/255.00)+0.5; *(dst + 2) = d2 * *alpha/255.00 + *(dst+2) * (1.00-*alpha/255.00)+0.5; alpha += alpha_step; col += col_step; dst += col_step; } } } } //下のレイヤーと結合で使用される void __stdcall merge(n_byte* dst,const n_byte* col,const n_byte* base_col,const n_byte* alpha,const n_byte* base_alpha ,int col_step,int alpha_step,int base_alpha_step,int num_channel,int num_pixel,int no) { if (no == 0) {//ビビットライト if (num_channel == 1) {//グレースケールモード const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = 0; if(*col<128 && 0<*col) { d = (int)( 255 - ((255 - *base_col) *256) / (*col*2) );} else if(*col<=0) { d = 0;} else { d = (int)( (*base_col *256 ) / (255 - (2 * (*col - 128))) );} d = d < 0 ? 0 : ( d < 255 ? d : 255); // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *base_alpha; } dst += 2; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += alpha_step; } } else if (num_channel == 3) { const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = 0; if(*col<128 && 0<*col) { d = (int)( 255 - ((255 - *base_col) *256) / (*col*2) );} else if(*col<=0) { d = 0;} else { d = (int)( (*base_col *256 ) / (255 - (2 * (*col - 128))) );} double d1 = 0; if(*(col+1)<128 && 0<*(col+1)) { d1 = (int)( 255 - ((255 - *(base_col+1)) *256) / (*(col+1)*2) );} else if(*(col+1)<=0) { d1 = 0;} else { d1 = (int)( (*(base_col+1) *256 ) / (255 - (2 * (*(col+1) - 128))) );} double d2 = 0; if(*(col+2)<128 && 0<*(col+2)) { d2 = (int)( 255 - ((255 - *(base_col+2)) *256) / (*(col+2)*2) );} else if(*(col+2)<=0) { d2 = 0;} else { d2 = (int)( (*(base_col+2) *256 ) / (255 - (2 * (*(col+2) - 128))) );} d = d < 0 ? 0 : ( d < 255 ? d : 255); d1 = d1 < 0 ? 0 : ( d1 < 255 ? d1 : 255); d2 = d2 < 0 ? 0 : ( d2 < 255 ? d2 : 255); // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = (a1/255.0 *(a0/255.0) * d1 + (a1/255.0) *(1-a0/255.0) * *(col+1) + (1-a1/255.0)*(a0/255.0) * *(base_col+1) ) / ca +0.5; *(dst + 2) = (a1/255.0 *(a0/255.0) * d2 + (a1/255.0) *(1-a0/255.0) * *(col+2) + (1-a1/255.0)*(a0/255.0) * *(base_col+2) ) / ca +0.5; *(dst + 3) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *(base_col + 1); *(dst + 2) = *(base_col + 2); *(dst + 3) = *base_alpha; } dst += 4; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += base_alpha_step; } } } //---------------------------- if (no == 1) {//リニアライト if (num_channel == 1) { const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = *col *2 + *base_col -256; d = d < 0 ? 0 : ( d < 255 ? d : 255); // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *base_alpha; } dst += 2; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += alpha_step; } } else if (num_channel == 3) { const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = *col *2 + *base_col -256; double d1 = *(col + 1) *2 + *(base_col + 1) -256; double d2 = *(col + 2) *2 + *(base_col + 2) -256; d = d < 0 ? 0 : ( d < 255 ? d : 255); d1 = d1 < 0 ? 0 : ( d1 < 255 ? d1 : 255); d2 = d2 < 0 ? 0 : ( d2 < 255 ? d2 : 255); // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = (a1/255.0 *(a0/255.0) * d1 + (a1/255.0) *(1-a0/255.0) * *(col+1) + (1-a1/255.0)*(a0/255.0) * *(base_col+1) ) / ca +0.5; *(dst + 2) = (a1/255.0 *(a0/255.0) * d2 + (a1/255.0) *(1-a0/255.0) * *(col+2) + (1-a1/255.0)*(a0/255.0) * *(base_col+2) ) / ca +0.5; *(dst + 3) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *(base_col + 1); *(dst + 2) = *(base_col + 2); *(dst + 3) = *base_alpha; } dst += 4; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += base_alpha_step; } } } //---------------------------- if (no == 2) {//ピンライト if (num_channel == 1) { const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = 0; if(*col<128) { d = (int)min(*base_col, *col *2) ;} else { d = (int)max(*base_col,(*col-128)*2) ;} // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *base_alpha; } dst += 2; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += alpha_step; } } else if (num_channel == 3) { const unsigned char* col_end = col + num_pixel * col_step; while (col < col_end) { unsigned int a0 = *base_alpha; unsigned int a1 = *alpha; if (a1 != 0) { double d = 0; if(*col<128) { d = (int)min(*base_col, *col *2) ;} else { d = (int)max(*base_col,(*col-128)*2) ;} double d1 = 0; if(*(col+1)<128) { d1 = (int)min(*(base_col+1), *(col+1) *2) ;} else { d1 = (int)max(*(base_col+1),(*(col+1)-128)*2) ;} double d2 = 0; if(*(col+2)<128) { d2 = (int)min(*(base_col+2), *(col+2) *2) ;} else { d2 = (int)max(*(base_col+2),(*(col+2)-128)*2) ;} // 不透明度を入れた計算 // Ca = 1-(1-Fa)*(1-Ba) //=( Fa *Ba * func(Bc,Fc) + Fa *(1-Ba) * Fc + (1-Fa)*Ba * Bc ) / Ca //http://www.greenwood.co.jp/~k-aki/article/pixel_composite.html double ca = 1 - (1- a1/255.0) * (1-a0/255.0) ; *dst = (a1/255.0 *(a0/255.0) * d + (a1/255.0) *(1-a0/255.0) * *col + (1-a1/255.0)*(a0/255.0) * *base_col ) / ca +0.5; *(dst + 1) = (a1/255.0 *(a0/255.0) * d1 + (a1/255.0) *(1-a0/255.0) * *(col+1) + (1-a1/255.0)*(a0/255.0) * *(base_col+1) ) / ca +0.5; *(dst + 2) = (a1/255.0 *(a0/255.0) * d2 + (a1/255.0) *(1-a0/255.0) * *(col+2) + (1-a1/255.0)*(a0/255.0) * *(base_col+2) ) / ca +0.5; *(dst + 3) = n_byte(((a0 + a1) * 255 - a0 * a1) / 255); } else { *dst = *base_col; *(dst + 1) = *(base_col + 1); *(dst + 2) = *(base_col + 2); *(dst + 3) = *base_alpha; } dst += 4; col += col_step; base_col += col_step; alpha += alpha_step; base_alpha += base_alpha_step; } } } } } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } #ifdef _MANAGED #pragma managed(pop) #endif