2013-07-17 7 views
6

Usando un po 'di matematica, ho creato la seguente funzione java, per inserire una bitmap, e ritagliare un quadrato centrato in cui un cerchio è ritagliato con un bordo nero attorno ad esso . Il resto del quadrato dovrebbe essere trasparente. In aggiunta, c'è una distanza trasparente ai lati per non danneggiare l'anteprima quando si invia l'immagine tramite Messengers.L'immagine ritagliata abbassa la qualità e il bordo appare sfortunato

Il codice della mia funzione è la seguente:

public static Bitmap edit_image(Bitmap src,boolean makeborder) { 
     int width = src.getWidth(); 
     int height = src.getHeight(); 
     int A, R, G, B; 
     int pixel; 

     int middlex = width/2; 
     int middley = height/2; 

     int seitenlaenge,startx,starty; 
     if(width>height) 
     { 
      seitenlaenge=height; 
      starty=0; 

      startx = middlex - (seitenlaenge/2); 
     } 
     else 
     { 
      seitenlaenge=width; 
      startx=0; 

      starty = middley - (seitenlaenge/2); 
     } 

     int kreisradius = seitenlaenge/2; 
     int mittx = startx + kreisradius; 
     int mitty = starty + kreisradius; 
     int border=2; 
     int seitenabstand=55; 

     Bitmap bmOut = Bitmap.createBitmap(seitenlaenge+seitenabstand, seitenlaenge+seitenabstand, Bitmap.Config.ARGB_8888); 
     bmOut.setHasAlpha(true); 

     for(int x = 0; x < width; ++x) { 
      for(int y = 0; y < height; ++y) { 
       int distzumitte = (int) (Math.pow(mittx-x,2) + Math.pow(mitty-y,2)); // (Xm-Xp)^2 + (Ym-Yp)^2 = dist^2 
       distzumitte = (int) Math.sqrt(distzumitte); 

       pixel = src.getPixel(x, y); 

       A = Color.alpha(pixel); 
       R = (int)Color.red(pixel); 
       G = (int)Color.green(pixel); 
       B = (int)Color.blue(pixel); 
       int color = Color.argb(A, R, G, B); 

       int afterx=x-startx+(seitenabstand/2); 
       int aftery=y-starty+(seitenabstand/2); 

       if(x < startx || y < starty || afterx>=seitenlaenge+seitenabstand || aftery>=seitenlaenge+seitenabstand) //seitenrand 
       { 
        continue; 
       } 
       else if(distzumitte > kreisradius) 
       { 
        color=0x00FFFFFF; 
       } 
       else if(distzumitte > kreisradius-border && makeborder) //border 
       { 
        color = Color.argb(A, 0, 0, 0); 
       } 
       bmOut.setPixel(afterx, aftery, color); 
      } 
     } 

     return bmOut; 
    } 

Questa funzione funziona bene, ma ci sono alcuni problemi che si verificano che non ero in grado di risolvere ancora.

  • La qualità dell'immagine è diminuito significativamente
  • Il confine non è realmente in tondo, ma sembra essere piatta ai bordi dell'immagine (su alcuni dispositivi ?!)

I' d apprezzo qualsiasi aiuto in merito a tali problemi. Devo ammettere che non sono il migliore in matematica e che probabilmente dovrebbe esserci una formula migliore per battere il confine.

risposta

1

Penso che sia necessario controllare PorterDuffXferMode.

Troverete alcune informazioni tecniche sul modo di composizione delle immagini HERE.

C'è un buon esempio di creazione di bitmap con bordi arrotondati HERE. Hai solo bisogno di modificare un po 'il codice sorgente e sei pronto per andare ...

Spero che possa essere d'aiuto.

3

il codice sorgente è difficile da leggere, poiché è un misto di tedesco e inglese nei nomi delle variabili. Inoltre non si dice quale libreria di immagini si usa, quindi non sappiamo esattamente da dove provengano le classi Bitmap e Colore.

In ogni caso, è molto ovvio che si operi solo su una bitmap. Bitmap significa che l'intera immagine è memorizzata nella RAM pixel per pixel. Non c'è compressione lossy. Non vedo nulla nel tuo codice sorgente, che possa influenzare la qualità dell'immagine.

È molto probabile che la risposta sia nel codice che non ci viene mostrato. Inoltre, ciò che descrivi (botrh dei problemi) suona come una tipica compressione JPEG di bassa qualità. Sono sicuro che, da qualche parte, dopo aver chiamato la funzione, converti/salvi l'immagine in un JPEG. Prova a farlo in quella posizione su BMP, TIFF o PNG e verifica che l'errore scompaia magicamente. Forse puoi anche impostare il livello di qualità del JPEG da qualche parte per evitarlo.

Per rendere più facile per gli altri (forse) anche a trovare una buona risposta, mi permetta di tradurre il codice per inglese:

public static Bitmap edit_image(Bitmap src,boolean makeborder) { 
     int width = src.getWidth(); 
     int height = src.getHeight(); 
     int A, R, G, B; 
     int pixel; 

     int middlex = width/2; 
     int middley = height/2; 

     int sideLength,startx,starty; 
     if(width>height) 
     { 
      sideLength=height; 
      starty=0; 

      startx = middlex - (sideLength/2); 
     } 
     else 
     { 
      sideLength=width; 
      startx=0; 

      starty = middley - (sideLength/2); 
     } 

     int circleRadius = sideLength/2; 
     int middleX = startx + circleRadius; 
     int middleY = starty + circleRadius; 
     int border=2; 
     int sideDistance=55; 

     Bitmap bmOut = Bitmap.createBitmap(sideLength+sideDistance, sideLength+sideDistance, Bitmap.Config.ARGB_8888); 
     bmOut.setHasAlpha(true); 

     for(int x = 0; x < width; ++x) { 
      for(int y = 0; y < height; ++y) { 
       int distanceToMiddle = (int) (Math.pow(middleX-x,2) + Math.pow(middleY-y,2)); // (Xm-Xp)^2 + (Ym-Yp)^2 = dist^2 
       distanceToMiddle = (int) Math.sqrt(distanceToMiddle); 

       pixel = src.getPixel(x, y); 

       A = Color.alpha(pixel); 
       R = (int)Color.red(pixel); 
       G = (int)Color.green(pixel); 
       B = (int)Color.blue(pixel); 
       int color = Color.argb(A, R, G, B); 

       int afterx=x-startx+(sideDistance/2); 
       int aftery=y-starty+(sideDistance/2); 

       if(x < startx || y < starty || afterx>=sideLength+sideDistance || aftery>=sideLength+sideDistance) //margin 
       { 
        continue; 
       } 
       else if(distanceToMiddle > circleRadius) 
       { 
        color=0x00FFFFFF; 
       } 
       else if(distanceToMiddle > circleRadius-border && makeborder) //border 
       { 
        color = Color.argb(A, 0, 0, 0); 
       } 
       bmOut.setPixel(afterx, aftery, color); 
      } 
     } 

     return bmOut; 
    } 
+1

+1 per la traduzione –

1

Per quanto riguarda la qualità non riesco a vedere niente di sbagliato con il metodo . Eseguendo il codice con Java Swing, nessuna qualità viene persa. L'unico problema è che l'immagine ha bordi con alias.

Il problema di alias tenderà a scomparire con l'aumentare della risoluzione dello schermo e sarebbe più evidente per risoluzioni più basse. Questo potrebbe spiegare perché lo vedi solo in alcuni dispositivi.Lo stesso problema si applica al tuo confine, ma in tal caso sarebbe più evidente dal momento che il colore è nero singolo.

l'algoritmo definisce un'area quadrata dell'immagine originale. Per trovare il quadrato, esso inizia dal centro dell'immagine e si espande allo width o allo height dell'immagine, qualunque sia il più piccolo. Mi riferisco a questa area come square.

L'aliasing è causato dal codice che imposta i colori (sto usando pseudo-codice):

if (outOfSquare()) { 
    continue; // case 1: this works but you depend upon the new image' s default pixel value i.e. transparent black 
} else if (insideSquare() && ! insideCircle()) { 
    color = 0x00FFFFFF; // case 2: transparent white. <- Redundant 
} else if (insideBorder()) { 
    color = Color.argb(A, 0, 0, 0); // case 3: Black color using the transparency of the original image. 
} else { // inside the inner circle 
    // case 4: leave image color 
} 

Alcune note sul codice:

  • Caso 1 dipende il pixel di default valore dell'immagine originale cioè nero trasparente. Funziona ma meglio impostarlo in modo esplicito
  • Il caso 2 è ridondante. Gestirlo nello stesso modo in cui gestisci il caso 1. Ci interessa solo ciò che accade all'interno del cerchio.
  • Caso 3 (quando si disegna il confine) non è chiaro quello che si aspetta. Usare l'alfa dell'immagine originale ha il potenziale di rovinare la tua nuova immagine se succede che l'alfa originale varia lungo i bordi del cerchio. Quindi questo è chiaramente sbagliato e, a seconda dell'immagine, può essere potenzialmente un'altra causa dei tuoi problemi.
  • Il caso 4 è ok.

Ora alla periferia del cerchio i seguenti transizioni di colore si svolgono:

  • Se non viene utilizzato confine: piena trasparenza -> a colori immagine (caso 2 e 4 nel pseudocodice)
  • Se confine viene utilizzato: piena trasparenza -> Tutto nero -> colore immagine full (casi 2, 3 e 4)

per ottenere una migliore qualità ai bordi che è necessario introdurre alcuni stati intermedi che renderebbero le transizioni liscia (le nuove transizioni sono mostrati in corsivo):

  • Border non viene utilizzato: totale trasparenza ->parziale trasparenza in un'immagine a colori-> pieno colore immagine
  • Border è usato: piena trasparenza ->parziale trasparenza del colore nero-> full color nero ->parziale trasparenza del colore nero + cromatica delle immagini (vale a dire blending)-> immagine a colori completa

Mi auguro che aiuta

Problemi correlati