簡體   English   中英

如何在Bitmap周圍創建浮雕?

[英]How to create emboss around a Bitmap?

流行游戲Words with Friends在游戲板上繪制字母拼貼作為單個實體 -

您可以在以下屏幕截圖中看到應用於所有字母圖塊的黃色線性漸變,以及邊緣上的浮雕效果:

應用截圖

我的文字游戲中,我希望有類似的效果:

浮雕的例子

所以我創建了一個游戲板大小的mBitmap ,然后將所有圖塊繪制到其中,最后將位圖繪制到我的自定義視圖中 -

建立:

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

// create yellow linear gradient
mGradStart = new Point(3 * mWidth / 4, mHeight / 3);
mGradEnd = new Point(mWidth / 4, 2 * mHeight / 3);
LinearGradient gradient = new LinearGradient(
        mGradStart.x,
        mGradStart.y,
        mGradEnd.x,
        mGradEnd.y,
        new int[]{ 0xCCFFCC00, 0xCCFFCC99, 0xCCFFCC00 },
        null,
        TileMode.CLAMP);

// create the big bitmap holding all tiles
mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);

mPaintGrad = new Paint();
mPaintGrad.setShader(gradient);

mPaintEmboss = new Paint();
mPaintEmboss.setShader(gradient);

EmbossMaskFilter filter = new EmbossMaskFilter(
    new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f);
mPaintEmboss.setMaskFilter(filter);

畫畫:

@Override
protected void onDraw(Canvas canvas) {
    mGameBoard.draw(canvas);

    // draw all tiles as rectangles into big bitmap 
    // (this code will move to onTouchEvent later)
    mBitmap.eraseColor(Color.TRANSPARENT);
    for (SmallTile tile: mTiles) {
        mCanvas.drawRect(
                tile.left, 
                tile.top, 
                tile.left + tile.width, 
                tile.top + tile.height, 
                mPaintGrad);
        tile.draw(mCanvas);
    }
    canvas.drawBitmap(mBitmap, 0, 0, mPaintEmboss); // emboss NOT displayed
    canvas.drawText("TEXT WORKS OK", 400, 400, mPaintEmboss); // ebmoss OK
    canvas.drawRect(300, 600, 800, 1200, mPaintEmboss); // emboss OK
}

EmbossMaskFilter效果與drawText()drawRect()調用一起正常,但它不適用於drawBitmap()

應用截圖

我的問題:是否可以使用PorterDuff.Mode (和extractAlpha ?)的某些組合在我的大位圖周圍繪制浮雕?

更新:

通過查看HolographicOutlineHelper.java,我已經能夠添加外部陰影:

應用截圖

使用MyView.java中的以下代碼 -

建立:

public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);

    mScale = getResources().getDisplayMetrics().density;
    mGradStart = new Point(3 * mWidth / 4, mHeight / 3);
    mGradEnd = new Point(mWidth / 4, 2 * mHeight / 3);
    LinearGradient gradient = new LinearGradient(
            mGradStart.x,
            mGradStart.y,
            mGradEnd.x,
            mGradEnd.y,
            new int[]{ 0xCCFFCC00, 0xCCFFCC99, 0xCCFFCC00 },
            null,
            TileMode.CLAMP);

    mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);

    mPaintGrad = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    mPaintGrad.setShader(gradient);

    mPaintBlur = new Paint();
    mPaintBlur.setColor(Color.BLACK);
    BlurMaskFilter blurFilter = new BlurMaskFilter(mScale * 1, Blur.OUTER);
    mPaintBlur.setMaskFilter(blurFilter);
}

畫畫:

private void prepareBitmaps() {
    mBitmap.eraseColor(Color.TRANSPARENT);
    for (SmallTile tile: mTiles) {
        mCanvas.drawRect(
                tile.left, 
                tile.top, 
                tile.left + tile.width, 
                tile.top + tile.height, 
                mPaintGrad);
        tile.draw(mCanvas);
    }

    mAlphaBitmap = mBitmap.extractAlpha(mPaintBlur, mOffset);
}

@Override
protected void onDraw(Canvas canvas) {
    mGameBoard.draw(canvas);
    canvas.drawBitmap(mAlphaBitmap, mOffset[0], mOffset[1], mPaintBlur);
    canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad);
}

但不幸的是,應用程序現在表現得很慢 - 我仍然不知道如何在位圖周圍添加浮雕效果。

我不確定我得到了你需要的東西,但是如果你只是想用一些帶有alpha通道的png字母來應用EmbossMaskFilter,你幾乎可以用這個技巧來做

EmbossMaskFilter filter = new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f);

Paint paintEmboss = new Paint();
paintEmboss.setMaskFilter(embossMaskFilter);

Bitmap helperBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas helperCanvas = new Canvas(helperBitmap);

Bitmap alpha = src.extractAlpha();
helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
alpha.recycle();

...
canvas.drawBitmap(helperBitmap, 0, 0, anyPaint);

你永遠不會想要在1 onDraw中使用所有這些代碼,因為它會在內存中創建大量對象。 src.extractAlpha(); 每次都創建新的Bitmap。 (順便說一下,我的項目git總是出現內存錯誤。添加了mAlphaBitmap.recycle();它至少可以啟動。但它仍然像地獄一樣滯后)

所以,我玩你的git存儲庫並獲得了一些結果。 這是第一次提交的演示圖像和git repo

在此輸入圖像描述

但后來我意識到,你不需要在字母周圍使用EmbossMaskFilter,你需要它們圍繞矩形。 它可以以完全相同的方式完成。 這是我如何做到這一點:

  1. 為emboss背景創建新的輔助靜態Bitmap和Canvas,就像mAlphaBitmap一樣
  2. 在每個prepareBitmaps()上繪制對輔助位圖的影響。 純色,沒有alpha。
  3. 從創建的位圖中提取alpha,如此Bitmap alpha = helperCanvas.extractAlpha();
  4. 使用浮雕濾鏡helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);在繪圖上繪制提取的alpha位圖helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
  5. 在onDraw中打印helperBitmap,在主Bitmap之前有一些alpha。

這是沒有alpha的截圖(因為這樣更容易看到形狀) 在此輸入圖像描述

這是這個版本的git演示: https//github.com/varren/AndroidEmbossMaskFilterForPng/blob/1d692d576e78bd434252a8a6c6ad2ee9f4c6dbd8/app/src/main/java/de/afarber/mytiles2/MyView.java

這是我在項目中更改的代碼的重要部分:

private static final EmbossMaskFilter filter = 
                 new EmbossMaskFilter(new float[]{1, 1, 1}, 0.5f, 0.6f, 2f);
private static Canvas helperCanvas;
private static Paint paintEmboss;

public  Canvas getHelperCanvas(int width, int height){
    if (mAlphaBitmap == null) {
        mAlphaBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        helperCanvas = new Canvas(mAlphaBitmap);
        paintEmboss = new Paint();
        paintEmboss.setColor(Color.BLACK);
    }
    return helperCanvas;
}

private void prepareBitmaps() {
    mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    helperCanvas = getHelperCanvas(mBitmap.getWidth(),mBitmap.getHeight());
    helperCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    paintEmboss.setMaskFilter(null);
    paintEmboss.setAlpha(255);

    for (SmallTile tile: mTiles) {
        if (!tile.visible) continue;
        helperCanvas.drawRect(tile.left,tile.top,tile.left + tile.width,
                tile.top + tile.height,paintEmboss);
        mCanvas.drawRect(tile.left, tile.top,tile.left + tile.width, 
                tile.top + tile.height, mPaintGrad);
        tile.draw(mCanvas);
    }

    paintEmboss.setMaskFilter(filter);
    Bitmap alpha = mAlphaBitmap.extractAlpha();
    helperCanvas.drawBitmap(alpha, 0, 0, paintEmboss);
}

protected void onDraw(Canvas canvas) {
     // ...
     paintEmboss.setAlpha(255); //todo change alpha here
    if(mAlphaBitmap!= null)canvas.drawBitmap(mAlphaBitmap, 0,0, paintEmboss);
    if(mBitmap!= null)canvas.drawBitmap(mBitmap, 0, 0, mPaintGrad);
    // ...
}

我做的最后一個三步步驟是將所有內容從onDraw移動到prepareBitmaps() ,現在性能很好,但我們在調整大小時有文本失效。 所以這是這一步的源代碼

這是一個很好的工作最終解決方案 使用過濾器移動所有塗料解決了性能問題,但我認為還有更好的選擇來實現這一點。 正如我所說的那樣,我不知道你需要什么,但這段代碼幾乎在Bitmap上創建了Emboss

PS:將細胞分裂並添加到一起時,有一種很酷的效果

PS2: new EmbossMaskFilter(new float[] { 0f, 1f, 0.5f }, 0.8f, 3f, 3f); 在具有不同屏幕分辨率的不同設備上看起來不一樣

這是使用自定義布局的建議。

你需要自己的拼字游戲板布局。 由於它是網格,這應該很容易編碼。

基本思想是擁有一組PNG陰影圖像,每種類型的相鄰細胞組合一個。 在你的布局onDraw()中,首先繪制陰影,然后在onLayout()中繪制tile。

在onDraw()中,遍歷您的tile占位符數組。 如果您有一個圖塊,則為每個邊緣檢查相鄰的單元格。 根據相鄰的內容,選擇正確的陰影圖像並繪制它。

您可以通過使陰影圖像恰好是圖塊的寬度然后專門設置角區域來減少陰影圖像的數量:一個用於270度,一個用於直線對齊,一個用於90度。

我不知道使用porter-duff是否有幫助,因為你仍然需要確定所有這些“邊緣”情況(沒有雙關語意)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM