2012-04-22 16 views
8

Estoy tratando de encontrar una forma de establecer el fondo del lienzo con un color recogido del selector de color personalizado sin quitar ningún dibujo del mismo. Intento crear una aplicación que pueda dibujar en lienzo y guardarlo como png. Pero cuando establezco un nuevo fondo para el lienzo actual, todos los dibujos desaparecen. Estoy usando algo como esto:Android cambia el color de fondo del lienzo sin perder ninguno de sus dibujos

mCanvas.drawColor(picker.getColor());

Alguna idea de cómo puedo conseguir que las cosas funcionen?

+0

Debe mostrarnos el método onDraw .. – Ronnie

+0

Hola, he adjuntado una implementación de solución a continuación. Hace más o menos lo que quiere que haga, como se describe en su pregunta. – epichorns

Respuesta

4

Cuando dibuja el color, se dibuja sobre sus dibujos. Debes dibujar el color y luego dibujar todo lo demás de nuevo.

+0

Sí, pero si guardo el mapa de bits anterior y luego lo dibujo nuevamente ... el fondo será el anterior y el nuevo color no estará en primer plano ... entonces, ¿cómo puedo solucionarlo? –

+0

Está diciendo que el orden debería ser draw_background-> draw_image cada vez que cambia el color de fondo. Es rápido, por lo que el ojo solo dirá que el fondo cambia. – DeeV

0

Mientras que su fondo es y será en otro color, que puede hacer:

for (x...) 
    for (y...) 
    if (bitmap.getPixel(x,y) == oldBackgroundColor) 
     bitmap.setPixel(x,y,newBackgroundColor) 

O bien, puede llamar su contenido en un mapa de bits fuera de la pantalla, y dibujar el fondo y luego el fuera de la pantalla a la mapa de bits real De esta forma, puede cambiar el color de fondo que se usará cuando ocurra el siguiente dibujo de dos pasos.

+0

De hecho ... Desafortunadamente, el OP probablemente quiere que el dibujo en primer plano mantenga su integridad a pesar de ser del mismo o diferente color que el fondo ... Un * filtro de reemplazo de color * es una operación destructiva, mientras que el OP probablemente quería algo similar a la superposición de capas de Photoshop ... – epichorns

+0

de acuerdo, eso es solo una solución para casos especiales, ¡ninguna solución genérica! – Bondax

7

Las respuestas ya dadas a su pregunta apuntan en la dirección correcta: es necesario separar el bloque de color de fondo y el plano de primer plano en capas separadas, luego unirlas antes de guardar todo en un archivo .png . Así es como se diseñó el flujo de trabajo de Adobe Photoshop ... Tiene sentido, si lo pensamos bien: tomemos por ejemplo un software como MsPaint: como no usa capas, tiene que depender de algoritmos de inundación para lograr (aunque de manera incompleta) algo remotamente similar a un cambio de fondo ...

Una forma de implementar tal cosa sería instanciar 2 objetos Canvas respaldados por 2 mapas de bits diferentes. El primer par Canvas-Bitmap se usará para su dibujo en primer plano, y el segundo par Canvas-Bitmap se usará para el dibujo de capas fusionadas (es decir, dibujo en primer plano + bloque de color de fondo). Entonces, el 2.º Bitmap es lo que se guardará en un archivo .png cuando lo necesite para guardarlo. De esta forma, nuestro primer par Canvas-Bitmap almacena su información de primer plano, que no se destruye si es necesario realizar un cambio de color de fondo. Cada vez que se realiza una operación, las capas se pueden fusionar en el segundo par Canvas-Bitmap para que siempre haya un mapa de bits con el contenido correcto que esté listo para guardarse a su antojo.

Aquí hay una vista personalizada que hice para aclarar esta metodología. Implementa una vista simple utilizada para pintar una línea azul en la pantalla táctil con un dedo, con un color de fondo que cambia dependiendo de la posición XY de dicho dedo para demostrar un cambio de color de fondo sin una complejidad de código innecesaria inherente a una implementación completa con una rueda de color/menús/ entre otras cosas:

package com.epichorns.basicpaint; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Point; 
import android.graphics.Paint.Style; 
import android.view.View; 

public class PaintView extends View{ 

    Bitmap mMergedLayersBitmap=null; //Note: this bitmap here contains the whole of the drawing (background+foreground) to be saved. 
    Canvas mMergedLayersCanvas=null; 

    Bitmap mBitmap = null; //bitmap onto which we draw our stuff 
    Canvas mCanvas = null; //Main canvas. Will be linked to a .bmp file 
    int mBackgroundColor = 0xFF000000; //default background color 
    Paint mDefaultPaint = new Paint(); 

    Paint mDrawPaint = new Paint(); //used for painting example foreground stuff... We draw line segments. 
    Point mDrawCoor = new Point(); //used to store last location on our PaintView that was finger-touched 

    //Constructor: we instantiate 2 Canvas-Bitmap pairs 
    public PaintView(Context context, int width, int height) { 
     super(context); 
     mMergedLayersBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
     mMergedLayersCanvas = new Canvas(mMergedLayersBitmap); 

     mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
     mCanvas = new Canvas(mBitmap); 
    } 

    //Change background color 
    public void changeColor(int newColor){ 
     mBackgroundColor = newColor; 
     invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards 
    } 

    //Called by user of PaintView in order to start a painting "stroke" (finger touching touch-screen): stores the 
    //location of the finger when it first touched the screen 
    public void startDraw(int x, int y, int radius, int color){ 
     mDrawPaint.setColor(color); 
     mDrawPaint.setStyle(Style.STROKE); 
     mDrawPaint.setStrokeWidth(radius); 
     mDrawCoor.x = x; 
     mDrawCoor.y = y;   
    } 

    //Called by user of PaintView when finger touching touch-screen is moving (must be called after a startDraw, 
    //as the latter initializes a couple of necessary things) 
    public void continueDraw(int x, int y){ 
     mCanvas.drawLine(mDrawCoor.x, mDrawCoor.y, x, y, mDrawPaint); 
     mDrawCoor.x = x; 
     mDrawCoor.y = y; 
     invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards 
    } 

    //Merge the foreground Canvas-Bitmap with a solid background color, then stores this in the 2nd Canvas-Bitmap pair. 
    private void mergeLayers(){ 
     mMergedLayersCanvas.drawColor(mBackgroundColor); 
     mMergedLayersCanvas.drawBitmap(mBitmap, 0, 0, mDefaultPaint); 
    } 

    @Override 
    public void onDraw(Canvas canvas){ 
     mergeLayers(); 
     canvas.drawBitmap(mMergedLayersBitmap, 0, 0, mDefaultPaint); 
    } 

} 

para probar este punto de vista, aquí es una actividad de prueba que utiliza la clase PaintView. Ambos de estos archivos son autosuficientes en un proyecto de Android, por lo que se puede probar en el dispositivo real sin complicaciones:

package com.epichorns.basicpaint; 

import android.app.Activity; 
import android.graphics.Color; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Display; 
import android.view.MotionEvent; 
import android.view.View; 
import android.widget.LinearLayout; 


import com.epichorns.basicpaint.PaintView; 
public class BasicPaintActivity extends Activity { 
    PaintView mPaintView=null; 
    LinearLayout mL = null; 
    boolean mIsDrawing=false; 
    int mBackgroundColor = 0xFF000000; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Display display = getWindowManager().getDefaultDisplay();  
     final float dispWidth = (float)display.getWidth(); 
     final float dispHeight = (float)display.getHeight(); 

     mPaintView = new PaintView(this, display.getWidth(), display.getHeight());  
     mPaintView.changeColor(mBackgroundColor); 
     mPaintView.setOnTouchListener(new View.OnTouchListener(){ 

      public boolean onTouch(View v, MotionEvent event) { 

      if(event.getAction()==MotionEvent.ACTION_DOWN){ 
        mPaintView.startDraw((int)event.getX(), (int)event.getY(), 6, 0x806060FF);    
        mIsDrawing=true; 
        return true; 
       } 
       else if(event.getAction()==MotionEvent.ACTION_UP){ 
        mIsDrawing=false; 
        return true; 
       } 
       else if(event.getAction()==MotionEvent.ACTION_MOVE){ 
        if(mIsDrawing){ 

         //To demonstrate background change, change background color depending on X-Y position 
         int r = (int)(255f*event.getX()/dispWidth); 
         int g = (int)(255f*event.getY()/dispHeight); 
         mBackgroundColor = Color.argb(0xFF, r,g, 0x00); 
         Log.d("DEBUG1", "Color channels: (r, g) = ("+String.valueOf(r)+", "+String.valueOf(g)+")"); 
         mPaintView.changeColor(mBackgroundColor); 

         //now, draw stuff where finger was dragging... 
         mPaintView.continueDraw((int)event.getX(), (int)event.getY()); 
         return true; 
        } 
        else{ 
         return false; 
        } 

       } 

       return false; 
      } 

     }); 

     setContentView(mPaintView); 
    } 




} 
+0

Lo que necesita es poder cambiar el fondo de las imágenes que ya están guardadas en la memoria. Como, para recuperar la imagen y separar las capas (primer plano del fondo) y luego cambiar el color de la capa de fondo y fusionar las capas como antes ... – Ronnie

+0

Hmmm. Esto no obtuve de su pregunta. Si está en lo cierto, no hay una solución limpia que no guarde en otro formato, como .psd ... Como cualquier solución basada en inundación o solución de reemplazo de color, está limitada para fallar ya que ningún software puede saber sobre el canal alfa de dibujos en primer plano semitransparentes, entre otras cosas. – epichorns

+0

... A menos que tenga permiso para guardar capas separadas en diferentes imágenes, como guardar solo la capa transparente (modo de color 8888) en primer plano en .psd y, si se necesita un fondo, guardarlo en otra imagen, o serializar la información de color en algún formato de su elección ... PSD o equivalente probablemente sea mejor en este caso, aún. – epichorns

1

vistazo si desea cambiar en la lona entonces usted tiene que llamar a invalidar aplicar estos cambia su pantalla. Y si llama invalida entonces su método onDraw() llamará.

Si desea cambiar simplemente el color de fondo del lienzo del selector de color, guarde el valor de color en la variable y llame la invalidación justo después de guardar la variable. Ahora llamará a su onDraw().Ahora cambiar el fondo del lienzo llamando setBackgroundColor(color variable) en onDraw() y sacar todo lo que quiere

1

uso canvas.drawARGB (a, r, g, b) y va a trabajar para definida

+0

La respuesta más simple y correcta. Utilice '' 'canvas.drawARGB (200, 0, 0, 0);' '' para hacer que la vista sea más oscura. – oxied

0

@ Android-Droid

Estas dos líneas de código funcionaron como encanto para mí. Cuando el usuario hace clic nunca en cualquier color (por ejemplo: rojo) establecen que el color de mPaint como

 mPaint.setColor(Color.RED); 

y cuando cada vez que desee cambiar el color de la lona

dv.setBackgroundColor(mPaint.getColor()); 

donde dv es el objeto de la clase que extiende la vista (Vista personalizada). Pruébalo y avísame si enfrentas algún problema.

0

Quizás es una vieja pregunta, pero quiero contribuir con esta solución, en caso de que está tomando el mapa de bits de una fuente, y luego hacer un estirable con una lona, ​​tal vez esto puede caber u:

@Override 
public Bitmap transform(final Bitmap source) { 
    //Background for transparent images 
    Bitmap backg = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 
    backg.eraseColor(Color.WHITE); // Any color you want... 
    Paint back = new Paint(); 
    BitmapShader backshader = new BitmapShader(backg, 
    BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); 
    back.setShader(backshader); 
    back.setAntiAlias(true); 

    // Image for the draw 
    final Paint paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, 
      Shader.TileMode.CLAMP)); 
    Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig()); 
    Canvas canvas = new Canvas(output); 

    // IMPORTANT THING 
    canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() 
      - margin, source.getHeight() - margin), radius, radius, back); // Draw the background first... 
    canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() 
      - margin, source.getHeight() - margin), radius, radius, paint); // And then Draw the image, so it draws on top of the background 

    if (source != output) { 
     source.recycle(); 
    } 

    // This is for if i want to put a border in the drawable, its optional 
    Paint paint1 = new Paint();  
    paint1.setColor(Color.parseColor("#CC6C7B8B")); 
    paint1.setStyle(Style.STROKE); 
    paint1.setAntiAlias(true); 
    paint1.setStrokeWidth(2); 
    canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() 
      - margin, source.getHeight() - margin), radius, radius, paint1); 

    // and then, return the final drawable... 
    return output; 
} 

Espero que ayude ...

Cuestiones relacionadas