Android でビットマップ ブレンディングを使用する必要がある状況にあります。iOS版のアプリと同じようにします。
iOS の連中は PorterDuff モードを使用していましたが、これは現在 Android のPorterDuff クラスには標準で存在しません。
まさにソフトライトモードが必要ですが、それを忘れてください-Androidに欠けているいくつかのモードの全体像に対処することにしました。
調査中に見つけたリンクは次のとおりです。
それらのすべてに目的の式が含まれているため、メソッドを記述して、必要なすべてのブレンド モードを実装するのは非常に簡単に思えます。
しかし、そこからトラブルが始まります。
上記のリンクの式は色成分のみを扱い、アルファは当然のことであるかのように脇に置きます。しかし、そうではありません。
これまでのところ、私はこのSO questionのコードを手に入れました。ソフトライト式を実装するメソッドを書き直そうと考えてoverlay_byte(int sc, int dc, int sa, int da)
いますが、どうすればいいのかsa
、da
変数がわかりません。
PS: ブレンド モードの裸の Java 実装のパフォーマンスが、ネイティブ android の PorterDuff クラスのパフォーマンスとはかけ離れていることは承知していますが、それは後で対処できます...
後で追加:
昨日以来、私はいくつかのより深い調査を行い、Java でソフトライト ブレンディング モードを実装する方法を見つけました。ソースは次のとおりです (PorterDuff.Mode.LIGHTEN などのすぐに使用できるモードを使用するときに、Android 内で機能するものと同じです)。
私はsoftlight_byte
そこからメソッドを取り、彼が使用するすべてのものをJavaに翻訳しました(ここでできる限りのことをしました)。結果は機能しますが、画像が正しくありません。下の部分は問題ないように見えますが、上の部分は焼き直されます。Javaに書き直した私のコードは次のとおりです。
public Bitmap applyBlendMode(Bitmap srcBmp, Bitmap destBmp)
{
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
int srcPixels[] = new int[width * height];;
int destPixels[] = new int[width * height];
int resultPixels[] = new int[width * height];
int aS = 0, rS = 0, gS = 0, bS = 0;
int rgbS = 0;
int aD = 0, rD = 0, gD = 0, bD = 0;
int rgbD = 0;
try
{
srcBmp.getPixels(srcPixels, 0, width, 0, 0, width, height);
destBmp.getPixels(destPixels, 0, width, 0, 0, width, height);
srcBmp.recycle();
destBmp.recycle();
}
catch(IllegalArgumentException e) {
}
catch(ArrayIndexOutOfBoundsException e) {
}
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
rgbS = srcPixels[y*width + x];
aS = (rgbS >> 24) & 0xff;
rS = (rgbS >> 16) & 0xff;
gS = (rgbS >> 8) & 0xff;
bS = (rgbS ) & 0xff;
rgbD = destPixels[y*width + x];
aD = ((rgbD >> 24) & 0xff);
rD = (rgbD >> 16) & 0xff;
gD = (rgbD >> 8) & 0xff;
bD = (rgbD ) & 0xff;
rS = softlight_byte(rD, rS, aS, aD);
gS = softlight_byte(gD, gS, aS, aD);
bS = softlight_byte(bD, bS, aS, aD);
aS = aS + aD - Math.round((aS * aD)/255f);
resultPixels[y*width + x] = ((int)aS << 24) | ((int)rS << 16) | ((int)gS << 8) | (int)bS;
}
}
return Bitmap.createBitmap(resultPixels, width, height, srcBmp.getConfig());
}
int softlight_byte(int sc, int dc, int sa, int da) {
int m = (da != 0) ? dc * 256 / da : 0;
int rc;
if (2 * sc <= sa) {
rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
} else if (4 * dc <= da) {
int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
} else {
int tmp = sqrtUnitByte(m) - m;
rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
}
return clampDiv255Round(rc + sc * (255 - da) + dc * (255 - sa));
}
/** returns 255 * sqrt(n/255) */
private int sqrtUnitByte(int n) {
return skSqrtBits(n, 15 + 4);
}
/** Return the integer square root of value, with a bias of bitBias */
int skSqrtBits(int value, int bitBias) {
if (value < 0) { Log.wtf(TAG, "ASSERTION!"); } // bitBias always 15+4, no check required
int root = 0;
int remHi = 0;
int remLo = value;
do {
root <<= 1;
remHi = (remHi<<2) | (remLo>>30);
remLo <<= 2;
int testDiv = (root << 1) + 1;
if (remHi >= testDiv) {
remHi -= testDiv;
root++;
}
} while (--bitBias >= 0);
return root;
}
int clampDiv255Round(int prod) {
if (prod <= 0) {
return 0;
} else if (prod >= 255*255) {
return 255;
} else {
return skDiv255Round(prod);
}
}
/** Just the rounding step in SkDiv255Round: round(value / 255)
*/
private static int skDiv255Round(int prod) {
prod += 128;
return (prod + (prod >> 8)) >> 8;
}
誰かが間違いの可能性をチェックできますか?これは私にとって非常に重要です!
PS:applyBlendMode
上記のSOの質問とsoftlight_byte(rD, rS, aS, aD);
認識から取られました-C ++から書き直されました。