1

マージしたい 2 つの LinearGradients があります。

  • rgb(0, 0, 0)からrgb(0, 255, 0)(黒から緑) に向かう 1 つの水平方向
  • rgb(0, 0, 0)からrgb(0, 0, 255)(黒から青) に向かう 1 つの垂直方向

私のコードは次のようになります。

Shader horizo​​ntal = new LinearGradient(0, 0, width, 0, new float[]{Color.rgb(0, 0, 0), Color.rgb(0, 255, 0)}, null, Shader.TileMode.CLAMP) ;
Shader vertical = new LinearGradient(0, 0, 0, height, new float[]{Color.rgb(0, 0, 0), Color.rgb(0, 0, 255)}, null, Shader.TileMode.CLAMP) ;
ComposeShader シェーダー = new ComposeShader(水平、垂直、モード);
paint.setShader(シェーダ);

赤の値は変化する可能性がありますが、他の 2 つの値は一定です。結果のグラデーションをカラーピッカーで使用したい。次のように表示する必要があります: (ここでも確認できます。カラー ピッカーの右側のペインにある R の文字をクリックする必要があります)。

勾配

私はいくつかの PorterDuff モードを試しました。SCREENほぼ完璧ですが、軽すぎる場合もあります。ADD128 より小さい赤の値を 0 であるかのように表示MULTIPLYします。正方形を 1 つの単色で塗りつぶすだけです。また、グラデーションの色をアルファ 128 に設定してみました。これによりADD、暗すぎXORたり、薄すぎたりしSCREENます。

このグラデーションを正しく作成するにはどうすればよいですか? どの PorterDuff モードを使用すればよいですか?


グラデーションが正しく描画されているかどうかをテストするために、選択した色と同じ色でカーソルを描画します。(選択した色は座標で計算されます) value 以外のすべてのピボット値について、カーソルが見えにくい/見えません。

hsv

白いグラデーションが透明になるのが早すぎるようです。それを作成するために、2 つの線形勾配を作成し、それらをPorterDuff モードComposeShaderとマージしました。SRC_OVER次に、値 (明るさ) の値に対応する透明度を持つ黒い四角形を描画します。必要に応じてコードを投稿できます。

4

1 に答える 1

3

編集:

私はいくつかの仮定をするつもりです。参照したリンクに基づいて、右側の垂直スライダーのようなスライダー コントロールを使用してリアルタイムで「ピボット」カラーを変更できる同様のことをしたいと思うでしょう。また、ピボットの色として赤/緑/青を切り替えたいと仮定します。

パフォーマンスを向上させる方法は次のとおりです。

  • 色の配列を一度割り当てて、intその配列を再利用します。
  • ビットマップを一度割り当てて、ビットマップを再利用します。
  • 常にビットマップを 256 x 256 にし、ビットマップを描画するときに適切なサイズにスケーリングします。このようにして、すべての計算がカウントされます。重複ピクセルはありません。

これらすべてを念頭に置いて、ルーチンを書き直します。

    private void changeColor(int w, int h, int[] pixels, char pivotColor, int pivotColorValue, boolean initial) {

        if (pivotColorValue < 0 || pivotColorValue > 255) {
            throw new IllegalArgumentException("color value must be between 0 and 255, was " + pivotColorValue);
        }

        if (initial) {

            // set all the bits of the color

            int alpha = 0xFF000000;

            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
                    int r = 0, b = 0, g = 0;
                    switch (pivotColor) {
                        case 'R':
                        case 'r':
                            r = pivotColorValue << 16;
                            g = (256 * x / w) << 8;
                            b = 256 * y / h;
                            break;
                        case 'G':
                        case 'g':
                            r = (256 * x / w) << 16;
                            g = pivotColorValue << 8;
                            b = 256 * y / h;
                            break;
                        case 'B':
                        case 'b':
                            r = (256 * x / w) << 16;
                            g = (256 * y / h) << 8;
                            b = pivotColorValue;
                            break;
                    }
                    int index = y * w + x;
                    pixels[index] = alpha | r | g | b;
                }
            }
        } else {

            // only set the bits of the color that is changing

            int colorBits = 0;
            switch (pivotColor) {
                case 'R':
                case 'r':
                    colorBits = pivotColorValue << 16;
                    break;
                case 'G':
                case 'g':
                    colorBits = pivotColorValue << 8;
                    break;
                case 'B':
                case 'b':
                    colorBits = pivotColorValue;
                    break;
            }

            for (int i = 0; i < pixels.length; i++) {
                switch (pivotColor) {
                    case 'R':
                    case 'r':
                        pixels[i] = (pixels[i] & 0xFF00FFFF) | colorBits;
                        break;
                    case 'G':
                    case 'g':
                        pixels[i] = (pixels[i] & 0xFFFF00FF) | colorBits;
                        break;
                    case 'B':
                    case 'b':
                        pixels[i] = (pixels[i] & 0xFFFFFF00) | colorBits;
                        break;
                }
            }
        }

これが私がそれをテストした方法です:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private ImageView mImageView;

    private Bitmap mBitmap;

    private int[] mPixels;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("Demo");

        mPixels = new int[256 * 256];
        mBitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888);
        mImageView = (ImageView) findViewById(R.id.imageview);

        long start = SystemClock.elapsedRealtime();

        changeColor(256, 256, mPixels, 'r', 0, true);
        mBitmap.setPixels(mPixels, 0, 256, 0, 0, 256, 256);
        mImageView.setImageBitmap(mBitmap);

        long elapsed = SystemClock.elapsedRealtime() - start;
        Log.d(TAG, "initial elapsed time: " + elapsed + " ms");

        SeekBar seekBar = (SeekBar) findViewById(R.id.seekbar);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

                long start = SystemClock.elapsedRealtime();

                changeColor(256, 256, mPixels, 'r', progress, false);
                mBitmap.setPixels(mPixels, 0, 256, 0, 0, 256, 256);
                mImageView.setImageBitmap(mBitmap);

                long elapsed = SystemClock.elapsedRealtime() - start;
                Log.d(TAG, "elapsed time: " + elapsed + " ms");
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) { }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) { }
        });

    }

    // changeColor method goes here
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="fitCenter"/>

    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="24dp"
        android:max="255"/>

</LinearLayout>

それを試して、それが十分に機能するかどうかを確認してください。合理的だと思いました。


基盤となる Skia ライブラリには、これを行う Porter-Duff モードがあると思いますが、.NET では利用できませんandroid.graphics.PorterDuff.Mode

わかりました、私たちはただ自分たちでそれをしなければならないと思います:

    private Bitmap makeColorPicker(int w, int h, int r) {

        if (r < 0 || r > 255) {
            throw new IllegalArgumentException("red value must be between 0 and 255, was " + r);
        }

        // need to manage memory, OutOfMemoryError could happen here
        int[] pixels = new int[w * h];

        int baseColor = 0xFF000000 | (r << 16);  // alpha and red value

        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                int g = (256 * x / w) << 8;
                int b = 256 * y / h;
                int index = y * w + x;
                pixels[index] = baseColor | g | b;
            }
        }

        return Bitmap.createBitmap(pixels, w, h, Bitmap.Config.ARGB_8888);
    }

HSVについて:

HSV 色空間に切り替えると、いくつかの異なるオプションが開かれます。当初考えていたように 2 つの画像を合成することは理にかなっています。画像の千の言葉のバージョンを提供するだけです。PhotoShop を開かないようにしてください。

  • 色相にピボット:

    開発時にレンダリングできる双方向グラデーション画像を描いています。このグラデーションでは、右上隅のアルファがゼロになり、下端が完全に黒になり、左上隅が完全に白になります。色相角度を移動するときは、この画像の下に無地の長方形を描くだけです。色は、完全な彩度と明るさで目的の色相になるため、この色だけが右上隅に表示されます。

  • 彩度にピボット:

    ここでは 2 つのグラデーション イメージを描いています。どちらも開発時にレンダリングできます。最初は完全な彩度で、上部の水平の虹が下部の黒に溶け込んでいます。2 つ目は彩度ゼロで、上が白、下が黒です。下に虹のグラデーションを描き、上に白/黒のグラデーションを描きます。上の画像のアルファをゼロからフルに変更すると、フル サチュレーションからゼロ サチュレーションへの変化が示されます。

  • 明るさ(値)にピボット

    このために、私は黒い四角形のベースを別の画像で描いています。これは、下部で垂直にトゥイーンするのではなく、水平の虹のグラデーションでもあります(完全な明るさ)。次に、虹の画像をフル アルファからゼロ アルファに変更して明るさを調整し、下にある黒い四角形を明らかにします。

これらのアルファ合成が実際の色空間を表していることを確認するには、いくつかの計算を行う必要がありますが、かなり近いと思います.

于 2016-12-14T15:56:09.480 に答える