2013-07-17 108 views
6

使用一些數學,我創建了下面的Java函數,輸入一個位圖,並讓它裁剪出一個居中的正方形,其中一個圓圈被再次裁剪出來,周圍有一個黑色邊框。 廣場的其餘部分應該是透明的。 另外,當通過信使發送圖像時,透明的距離不會損害預覽。裁剪圖像降低質量和邊框看起來不好

我的函數的代碼如下:

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

此功能工作正常,但也有一些問題存在的,我是不能夠解決呢。

  • 圖像的質量下降顯著
  • 邊框是不是真正圓形的,但似乎是平坦的圖像的邊緣(在某些設備?)

I」 d感謝有關這些問題的任何幫助。我不得不承認,我不是數學上的最好成績,也許應該有一個更好的公式來限制邊界。

回答

1

我認爲你需要檢查PorterDuffXferMode。

你會發現一些關於合成圖像模式HERE的技術信息。

有一些很好的例子,使邊緣圓潤的位圖HERE。你只需要調整一點源代碼,你就可以去...

希望它會有所幫助。

3

你的源代碼很難閱讀,因爲它是德語和英語的混合變量名稱。另外你不會說你使用了哪個圖像庫,所以我們不完全知道類位圖和顏色來自哪裏。

無論如何,這是非常明顯的,你只在一個位圖上操作。位圖意味着整個圖像以像素爲單位存儲在RAM中。沒有有損壓縮。我沒有看到源代碼中的任何內容,這可能會影響圖像的質量。

很可能,答案出現在代碼中,您不會向我們顯示。另外,你所描述的(問題的僵局)聽起來像是一種非常典型的低質量JPEG壓縮。我確信,在你打電話給你的某個地方,你將圖像轉換/保存爲JPEG格式。 試着在那個位置對BMP,TIFF或PNG這樣做,並看到錯誤消失神奇。也許你也可以在某處設置JPEG的質量等級來避免這種情況。

爲了方便其他人(可能)也找到了很好的答案,請允許我對你的代碼翻譯成英文:

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的翻譯 –

1

關於質量也看不出什麼毛病的方法。使用Java Swing運行代碼不會丟失質量。唯一的問題是圖像有別名邊緣

隨着屏幕分辨率的提高,混疊問題將趨於消失,而對於較低的分辨率,混疊問題將更加明顯。這也許可以解釋爲什麼你只能在某些設備上看到它。同樣的問題適用於您的邊框,但在這種情況下,由於顏色是單黑色,因此會更明顯。

您的算法定義了原始圖像的正方形區域。要找到從圖像中心開始的方塊,並展開圖像中的較小者的widthheight。我指的是square這個區域。

的混疊是由你的代碼,設置顏色引起的(我使用僞代碼):

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 
} 

的一些注意事項有關代碼:

  • 案例1依賴於默認像素原始圖像的值,即透明黑色。它的工作原理,但更好地明確設置
  • 情況2是多餘的。以與處理案例1相同的方式處理它。我們只對圈內發生的事感興趣。案例3(繪製邊框時)並不清楚它的期望。如果發生原始阿爾法沿着圓的邊緣變化,使用原始圖像的阿爾法有可能搞亂你的新圖像。所以這顯然是錯誤的,並且根據圖像,可能會成爲你問題的另一個原因。
  • 案例4沒問題。

現在,在您的社交圈外圍以下顏色過渡發生:如果不使用

  • 邊框:全透明->完整的圖像顏色(情況2和4的僞代碼)
  • 如果邊界使用:全透明->全黑->全圖像顏色(情況2,3和4)

爲了在邊緣處獲得更好的質量,您需要引入一些中間狀態,這將使過渡更平滑(新的過渡被示出在斜體):

  • 邊界不使用:完全透明->與圖像色彩->完整圖像顏色
  • 邊框部分透明使用:全透明->黑色部分透明度->全黑色->黑色部分透明度+圖像顏色(即混合)->全部圖像色彩

我希望幫助