2012-08-07 43 views
15

Tôi muốn vẽ đồ họa lên Canvas sao cho màu sắc là phụ gia. Ví dụ, tôi muốn sản xuất này:
Proper additive colorsLàm thế nào để vẽ bằng alpha?

Nhưng thay vào đó, tôi có được điều này:
My results

Lưu ý rằng nửa trắng, nền nửa đen là cố ý, chỉ để xem làm thế nào alpha tương tác với cả hai hình nền. Tôi sẽ rất vui khi được làm việc này với một trong hai nền tảng. Đây là mã của tôi:

public class VennColorsActivity extends Activity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 
      } 

      @Override 
      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       int alpha = 60, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       Paint paint = new Paint(); 
       paint.setColor(Color.WHITE); 
       canvas.drawRect(new Rect(0, 0, (int) w, (int) (h/2)), paint); 
       PorterDuff.Mode mode = android.graphics.PorterDuff.Mode.ADD; 
       paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
       paint.setColorFilter(new PorterDuffColorFilter(ar, mode)); 
       paint.setColor(ar); 
       canvas.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColorFilter(new PorterDuffColorFilter(ag, mode)); 
       paint.setColor(ag); 
       canvas.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColorFilter(new PorterDuffColorFilter(ab, mode)); 
       paint.setColor(ab); 
       canvas.drawCircle(cx + tx, cy + ty, expand * r, paint); 
      } 
     } 
     this.setContentView(new VennView(this)); 
    } 
} 

Ai đó có thể vui lòng giúp tôi hiểu cách vẽ bằng màu phụ gia trong đồ họa Android?

Trả lời

26

Bạn đang đi đúng hướng. Có 3 vấn đề lớn trong mã của bạn:

  • Bạn cần phải thiết lập Xfer chế độ lọc iso màu
  • Sử dụng tạm thời bitmap để render hình ảnh của bạn
  • Alpha nên 0xFF để có được kết quả mà bạn đang tìm kiếm

Đây là những gì tôi có bằng cách sử dụng chế độ xfer. Những gì tôi đang làm - đang vẽ mọi thứ vào bitmap tạm thời và sau đó hiển thị toàn bộ bitmap cho canvas chính.

xfer mode rules

Bạn hỏi tại sao bạn cần bitmap tạm thời? Câu hỏi hay! Nếu bạn đang vẽ tất cả mọi thứ trên một khung chính, màu sắc của bạn sẽ được pha trộn với màu nền vải chính, vì vậy tất cả các màu sắc sẽ bị rối tung lên. Bitmap tạm thời trong suốt giúp giữ màu của bạn tránh xa các phần khác của giao diện người dùng

Hãy đảm bảo bạn không phân bổ bất kỳ thứ gì trong cách này theo cách này .. Ngoài ra, hãy đảm bảo bạn đã tái chế bitmap tạm thời của mình khi bạn không còn cần nó nữa.

package com.example.stack2; 

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Bitmap.Config; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuff.Mode; 
import android.graphics.PorterDuffXfermode; 
import android.os.Bundle; 
import android.view.View; 

public class YouAreWelcome extends Activity { 

    Bitmap tempBmp = Bitmap.createBitmap(1, 1, Config.ARGB_8888); 
    Canvas c = new Canvas(); 
    Paint paint = new Paint(); 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 

      } 

      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       if(tempBmp.isRecycled() || tempBmp.getWidth()!=canvas.getWidth() || tempBmp.getHeight()!=canvas.getHeight()) 
       { 
        tempBmp.recycle(); 
        tempBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888); 
        c.setBitmap(tempBmp); 
       } 

        //clear previous drawings 
       c.drawColor(Color.TRANSPARENT, Mode.CLEAR); 

       int alpha = 255, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       paint.setAntiAlias(true); 
       paint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 
       paint.setColor(ar); 
       c.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColor(ag); 
       c.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColor(ab); 
       c.drawCircle(cx + tx, cy + ty, expand * r, paint); 
       canvas.drawBitmap(tempBmp, 0, 0, null); 
      } 
     } 
     this.setContentView(new VennView(this)); 
    } 
} 
+1

Cảm ơn rất nhiều, Pavel; và nhanh quá! –

+3

BTW, bạn có biết một giải pháp thay thế cho PorterDuff.Mode.ADD tương thích với SDK phiên bản 8 không? Tài liệu nói rằng ADD đã được thêm vào trong phiên bản 8 nhưng nó nằm. Nó đã thực sự được giới thiệu trong phiên bản 11 và treo trên một số thiết bị cũ mà không nên được phép cài đặt tiện ích của tôi. –

+1

Điều này thật tuyệt!Bạn có thể áp dụng kỹ thuật này vào các ảnh bitmap chồng lên nhau không? –

2

Cảm ơn một lần nữa Pavel. Điều đó sẽ rất khó cho tôi để tự mình tìm ra. Tôi đang trả lời câu hỏi của riêng tôi để hiểu rõ hơn về chi tiết, nhưng tôi đã chấp nhận câu trả lời của bạn tốt nhất.

Bạn đúng là tôi không muốn tạo và quản lý Bitmap ngoài màn hình (và Canvas). Đó là lý do tại sao tôi đã đề cập rằng một nền màu đen hoặc trắng sẽ là tốt để thực hiện công việc này.

Tôi chưa bao giờ quan tâm đến hiệu suất trước khi tôi thấy điều gì đó hiệu quả nhưng tôi chia sẻ sự thận trọng của bạn sau thời điểm đó. Chỉnh sửa phiên bản của bạn để khắc phục điều đó và xóa những thành viên đó cung cấp cho việc triển khai bên dưới.

Cái này có mạnh không? Lưu ý hai lời gọi tới Canvas.drawColor() mà tôi nghi ngờ cũng có thể được kết hợp thành một.

package com.superliminal.android.test.venn; 

import android.app.Activity; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PorterDuff.Mode; 
import android.graphics.PorterDuffXfermode; 
import android.os.Bundle; 
import android.view.View; 

public class VennColorsActivity extends Activity { 
    private Paint paint = new Paint(); 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     class VennView extends View { 
      public VennView(Context context) { 
       super(context); 
      } 

      @Override 
      protected void onDraw(Canvas canvas) { 
       super.onDraw(canvas); 
       canvas.drawColor(Color.BLACK); 
       canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); 
       int alpha = 255, val = 255; 
       int ar = Color.argb(alpha, val, 0, 0); 
       int ag = Color.argb(alpha, 0, val, 0); 
       int ab = Color.argb(alpha, 0, 0, val); 
       float w = canvas.getWidth(); 
       float h = canvas.getHeight(); 
       float cx = w/2f; 
       float cy = h/2; 
       float r = w/5; 
       float tx = (float) (r * Math.cos(30 * Math.PI/180)); 
       float ty = (float) (r * Math.sin(30 * Math.PI/180)); 
       float expand = 1.5f; 
       paint.setAntiAlias(true); 
       paint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 
       paint.setColor(ar); 
       canvas.drawCircle(cx, cy - r, expand * r, paint); 
       paint.setColor(ag); 
       canvas.drawCircle(cx - tx, cy + ty, expand * r, paint); 
       paint.setColor(ab); 
       canvas.drawCircle(cx + tx, cy + ty, expand * r, paint); 
      } 
     } 
     setContentView(new VennView(this)); 
    } 
} 
+1

giải pháp này cũng chính xác. Tôi đề nghị sử dụng bitmap riêng biệt bởi vì thông thường bạn chỉ muốn pha trộn các màu bạn muốn và không gây rối với phần còn lại của giao diện người dùng. Chú thích duy nhất cho mã của bạn là 'canvas.drawColor (Color.BLACK);' gọi là vô dụng vì bạn xóa toàn bộ vùng bằng cách gọi 'canvas.drawColor (Color.TRANSPARENT, Mode.CLEAR);'. Vì vậy, về lý thuyết bạn có thể thả dòng này –

+0

@Melinda Green làm cách nào tôi có thể thay đổi màu sơn của canvas trên mỗi lần nhấp nút trong hoạt động của tôi để nó có thể cung cấp màu nền differnet – Erum

+0

@Erum Hannan Chỉ cần lưu trữ màu trong phương thức onClick của nút và đặt màu đó làm nền với canvas.drawColor với màu trong onDraw. –

Các vấn đề liên quan