2012-04-22 10 views
8

Sto cercando un modo per impostare lo sfondo della tela con un colore prelevato dal selettore colori personalizzato senza rimuovere alcun disegno su di esso. Sto cercando di creare un'applicazione che possa disegnare su tela e salvarla come png. Ma quando ho impostato un nuovo sfondo per la tela corrente, tutti i disegni sono spariti. Sto usando qualcosa di simile:Android cambia colore di sfondo della tela senza perdere alcun disegno.

mCanvas.drawColor(picker.getColor());

Tutte le idee come posso far funzionare le cose?

+0

Devi mostrarci il metodo onDraw .. – Ronnie

+0

Ciao, ho aggiunto una implementazione di soluzione qui sotto. Fa praticamente quello che vuoi che faccia come descritto nella tua domanda. – epichorns

risposta

4

Quando si disegna il colore, viene disegnato sui disegni. Devi disegnare il colore e poi disegnare di nuovo ogni cosa.

+0

sì, ma se salgo la vecchia bitmap e poi la disegna di nuovo ... è lo sfondo sarà quello vecchio e il nuovo colore non sarà in primo piano ... quindi come posso risolvere il problema? –

+0

Sta dicendo che l'ordine dovrebbe essere draw_background-> draw_image ogni volta che cambia il colore dello sfondo. È veloce in modo che l'occhio indichi solo lo sfondo. – DeeV

0

Finché il fondo è e sarà in un altro colore, si può fare:

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

In alternativa, è possibile disegnare i tuoi contenuti su una bitmap fuori schermo, e disegnare lo sfondo e poi il fuori campo al bitmap effettiva. In questo modo puoi cambiare il backgroundcolor che verrà usato quando verrà eseguito il prossimo disegno in due fasi.

+0

Infatti ... Sfortunatamente, l'OP probabilmente vuole che il disegno in primo piano mantenga la sua integrità nonostante abbia lo stesso colore o lo stesso colore dello sfondo ... Un * filtro di sostituzione del colore * è un'operazione distruttiva, mentre l'OP probabilmente voleva qualcosa simile alla stratificazione di Photoshop ... – epichorns

+0

d'accordo, questa è solo una soluzione per casi speciali, nessuna soluzione generica! – Bondax

7

Le risposte già fornite alla domanda sono tutte rivolte nella giusta direzione: è necessario separare il blocco di colore di sfondo e il disegno in primo piano in livelli separati, quindi unirli prima di salvarlo interamente in un file .png . Ecco come è progettato anche il flusso di lavoro Adobe Photoshop ... Ha senso, se ci pensiamo: prendiamo ad esempio un software come MsPaint: perché non usa i livelli, deve fare affidamento su cose come gli algoritmi di floodfill realizzare (anche se in modo incompleto) qualcosa di simile a un cambio di sottofondo ...

Un modo per implementare una cosa del genere sarebbe istanziare 2 oggetti Canvas supportati da 2 bitmap differenti. La prima coppia Canvas-Bitmap verrebbe utilizzata per il disegno in primo piano e la seconda coppia Canvas-Bitmap verrebbe utilizzata per il disegno a strati uniti (ad esempio disegno in primo piano + blocco colore di sfondo). Quindi la seconda bitmap è quella che verrà salvata in un file .png quando ne hai bisogno per essere salvata. In questo modo, la nostra prima coppia Canvas-Bitmap memorizza le informazioni in primo piano, che non vengono distrutte se è necessario apportare una modifica del colore di sfondo. Ogni volta che viene eseguita un'operazione, i livelli possono essere uniti nella seconda coppia Canvas-Bitmap in modo che ci sia sempre una bitmap con il contenuto corretto che è pronto per essere salvato secondo i vostri desideri.

Ecco una vista personalizzata che ho apportato per eliminare questa metodologia. Implementa una semplice vista usata per dipingere una linea blu sul touch-screen usando un dito, con un colore di sfondo che cambia a seconda della posizione XY di detto dito in modo da dimostrare un cambiamento di colore di sfondo senza complessità di codice inutile inerente ad un'implementazione completa con una ruota colore/menu/tra l'altro:

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); 
    } 

} 

per testare questo punto di vista, ecco un test di attività che utilizza la classe PaintView. Entrambi i file sono autosufficienti in un progetto Android, in modo da poterlo testare sul vostro dispositivo reale senza problemi:

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

Ciò di cui ha bisogno è poter cambiare lo sfondo delle immagini che sono già state salvate in memoria. Mi piace, per recuperare l'immagine e separare i livelli (in primo piano dallo sfondo) e quindi cambiare il colore del livello di sfondo e unire nuovamente i livelli come prima. – Ronnie

+0

Hmmm. Questo non ho ottenuto dalla sua domanda. Se sei corretto, allora non c'è soluzione pulita a corto di risparmio in un altro formato, come .psd ... Come qualsiasi soluzione basata su una discarica, o soluzione di sostituzione del colore, è destinata a fallire in quanto nessun software può sapere sul canale alfa di disegni in primo piano semitrasparenti, tra le altre cose. – epichorns

+0

... A meno che non sia autorizzato a salvare livelli separati in immagini diverse, ad esempio salvare solo il livello trasparente in primo piano (modalità colore 8888) in un .psd e, se è necessario uno sfondo, salvarlo in un'altra immagine o serializzare le informazioni sul colore in un formato a sua scelta ... PSD o equivalente probabilmente sarebbe meglio in questo caso, ancora. – epichorns

1

un'occhiata se volete cambiare qualcosa in tela, allora dovete chiamare invalidare applicare questi cambia lo schermo. Se invochi una chiamata invalida, verrà chiamato il tuo metodo onDraw().

Se si desidera modificare solo il colore di sfondo dell'area di disegno dal selettore di colori, quindi salvare il valore del colore nella variabile e chiamare invalidate subito dopo aver salvato la variabile. Ora lo onDraw() chiamerà.Ora cambiare sfondo del canvas chiamando setBackgroundColor(color variable) in onDraw() e disegnare tutto il resto che si desidera

1

uso canvas.drawARGB (a, r, g, b) e si lavorerà per definitiva

+0

La risposta più semplice e corretta. Usa '' 'canvas.drawARGB (200, 0, 0, 0);' '' per rendere la vista più scura. – oxied

0

@ Android-Droid

Queste due righe di codice hanno funzionato come un fascino per me. Quando l'utente fa clic sempre su ogni colore (es: Rosso) impostato quel colore a mPaint come

 mPaint.setColor(Color.RED); 

e quando mai si desidera cambiare il colore tela

dv.setBackgroundColor(mPaint.getColor()); 

dove dv è l'oggetto della classe che estende la vista (vista personalizzata). Provalo e fammi sapere se hai problemi.

0

Forse è una vecchia questione, ma voglio contribuire con questa soluzione, Nel caso in cui si stanno prendendo il bitmap da una fonte, e poi fare un disegnabile con tela, forse questo può andare bene 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; 
} 

Spero che sia d'aiuto ...

Problemi correlati