2013-07-17 73 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)

为了在边缘处获得更好的质量,您需要引入一些中间状态,这将使过渡更平滑(新的过渡被示出在斜体):

  • 边界不使用:完全透明->与图像色彩->完整图像颜色
  • 边框部分透明使用:全透明->黑色部分透明度->全黑色->黑色部分透明度+图像颜色(即混合)->全部图像色彩

我希望帮助