2013-07-17 6 views
6

Mit etwas Mathe habe ich die folgende Java-Funktion erstellt, um eine Bitmap einzugeben, und ein zentriertes Quadrat ausschneiden, in dem ein Kreis wieder mit einem schwarzen Rand abgeschnitten wird . Der Rest des Platzes sollte transparent sein. Zusätzlich gibt es einen transparenten Abstand zu den Seiten, um die Vorschau nicht zu beschädigen, wenn das Bild über Boten gesendet wird.Beschneidungsbild senkt Qualität und Rand sieht schlecht aus

Der Code meiner Funktion ist wie folgt:

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

Diese Funktion funktioniert gut, aber es gibt einige Probleme auftreten, dass ich noch lösen nicht in der Lage war.

  • Die Qualität des Bildes ist
  • Die Grenze ist nicht wirklich rund deutlich zurückgegangen, scheint aber an den Rand des Bildes flach zu sein (bei einigen Geräten ?!)

I‘ Ich schätze jede Hilfe in Bezug auf diese Probleme. Ich muss zugeben, dass ich nicht der Beste in Mathe bin und es sollte wahrscheinlich eine bessere Formel geben, um die Grenze zu beenden.

Antwort

1

Ich denke, dass Sie PorterDuffXferMode überprüfen müssen.

Hier finden Sie einige technische Informationen zum Erstellen von Bildmodi HERE.

Es gibt ein gutes Beispiel für die Erstellung von Bitmap mit abgerundeten Kanten HERE. Sie müssen nur ein bisschen Quellcode zwicken und Sie sind bereit zu gehen ...

Ich hoffe, es wird helfen.

3

Ihr Quelltext ist schwer zu lesen, da es sich bei den Variablennamen um eine Mischung aus Deutsch und Englisch handelt. Außerdem sagen Sie nicht, welche Bildbibliothek Sie verwenden, daher wissen wir nicht genau, woher die Klassen Bitmap und Farbe kommen.

Wie auch immer, es ist sehr offensichtlich, dass Sie nur auf einer Bitmap arbeiten. Bitmap bedeutet, dass das gesamte Bild Pixel für Pixel im RAM gespeichert wird. Es gibt keine verlustbehaftete Komprimierung. Ich sehe nichts in Ihrem Quellcode, das die Qualität des Bildes beeinflussen kann.

Es ist sehr wahrscheinlich, dass die Antwort im Code ist, den Sie uns nicht zeigen. Darüber hinaus klingt das, was Sie beschreiben (eine Menge Probleme), wie eine sehr typische JPEG-Komprimierung niedriger Qualität. Ich bin sicher, irgendwo, nachdem Sie Ihre Funktion aufgerufen haben, konvertieren/speichern Sie das Bild in ein JPEG. Versuchen Sie dies an dieser Position zu BMP, TIFF oder PNG und sehen, dass der Fehler magisch verschwindet. Vielleicht können Sie auch die Qualitätsstufe des JPEG irgendwo einstellen, um das zu vermeiden.

Um es für andere leichter (vielleicht) auch eine gute Antwort zu finden, erlauben Sie mir bitte Ihren Code zu Englisch zu übersetzen:

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 für die Übersetzung hilft –

1

die Qualität Bezüglich ich nichts falsch mit Ihrem Verfahren sehen . Wenn der Code mit Java Swing ausgeführt wird, geht keine Qualität verloren. Das einzige Problem ist, dass das Bild Aliased Kanten hat.

Das Aliasing-Problem wird mit zunehmender Bildschirmauflösung tendenziell verschwinden und bei niedrigeren Auflösungen eher auffallen. Dies könnte erklären, warum Sie es nur bei einigen Geräten sehen.Das gleiche Problem gilt für Ihre Grenze, aber in diesem Fall würde es mehr bemerkbar sein, da die Farbe ist einfach schwarz.

Ihr Algorithmus definiert einen quadratischen Bereich des Originalbildes. Um das Quadrat zu finden, beginnt es von der Mitte des Bildes und erweitert sich entweder auf das width oder das height des Bildes, je nachdem, welches kleiner ist. Ich beziehe mich auf diesen Bereich als square.

Das Aliasing von Ihrem Code verursacht wird, die die Farben setzt (I Pseudo-Code verwendet):

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 
} 

einige Notizen über den Code:

  • Fall 1 hängt von dem Standardpixel Wert des Originalbildes, dh transparentes Schwarz. Es funktioniert aber besser, es explizit einzustellen
  • Fall 2 ist redundant. Behandeln Sie es auf die gleiche Weise wie bei Fall 1. Wir interessieren uns nur dafür, was innerhalb des Kreises passiert.
  • Fall 3 (wenn Sie die Grenze zeichnen) ist nicht klar, was es erwartet. Wenn Sie das Alpha des Originalbildes verwenden, besteht die Gefahr, dass Sie Ihr neues Bild verfälschen, wenn das ursprüngliche Alpha entlang der Kanten des Kreises variiert. Das ist also eindeutig falsch und kann je nach Bild möglicherweise eine weitere Ursache für Ihre Probleme sein.
  • Fall 4 ist in Ordnung.

Jetzt am Rande Ihres Kreises der folgenden Farbübergänge statt:

  • Wenn Grenze nicht verwendet wird: volle Transparenz -> Vollbildfarbe (Fall 2 und 4 in dem Pseudo-Code)
  • Wenn Grenze verwendet wird: volle Transparenz -> volle schwarze -> Vollbildfarbe (Fälle 2, 3 und 4)

um eine bessere Qualität an den Rand erreichen Sie einführen müssen Einige Zwischenzustände, die die Übergänge glatter (die neuen Übergänge sind gezeigt in kursiv) machen würde:

  • Border nicht verwendet wird: volle Transparenz ->Teiltransparenz mit Bildfarbe-> Vollbildfarbe
  • Border wird verwendet: volle Transparenz ->teilweise Transparenz der schwarzen Farbe-> volle schwarze Farbe ->teilweise Transparenz der schwarzen Farbe + Bildfarbe (dh Blending)-> Vollbildfarbe

Ich hoffe, dass

Verwandte Themen