使用一些数学,我创建了以下java函数,以输入位图,并使其裁剪出一个居中的正方形,其中再次裁剪出一个圆圈,周围有一个黑色边框。正方形的其余部分应该是透明的。此外,通过Messengers发送图像时,侧面有一个透明的距离,以免损坏预览。
我的函数的代码如下:
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;
}
此功能工作正常,但是出现了一些我无法解决的问题。
- 图像质量明显下降
- 边框不是很圆,但在图像的边缘看起来很平坦(在某些设备上?!
我将不胜感激有关该问题的任何帮助。我不得不承认,我在数学方面不是最好的,可能应该有一个更好的公式来划分边界。
您的源代码很难阅读,因为它在变量名称中混合了德语和英语。此外,您没有说您使用哪个图像库,因此我们并不确切知道位图和颜色类的来源。
无论如何,很明显,您仅在位图上操作。位图意味着整个图像逐个像素存储在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;
}
我认为你需要检查PorterDuffXferMode。
您将在这里找到有关合成图像模式的一些技术信息。
这里有一些制作圆角边缘位图的很好的例子。你只需要调整一点源代码,你就可以开始了......
希望它会有所帮助。
关于质量,我看不出你的方法有什么问题。使用Java Swing运行代码不会丢失质量。唯一的问题是图像具有锯齿边缘。
随着屏幕分辨率的增加,混叠问题往往会消失,对于较低的分辨率会更加明显。这可以解释为什么您只在某些设备中看到它。同样的问题适用于您的边框,但在这种情况下,它会更明显,因为颜色是单一黑色。
您的算法定义了原始图像的正方形区域。要找到正方形,它从图像的中心开始,然后扩展到图像的width
或height
,以较小的为准。我把这个区域称为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(绘制边框时(不清楚它的期望。如果原始 alpha 沿圆的边缘变化,使用原始图像的 alpha 可能会弄乱您的新图像。因此,这显然是错误的,并且根据图像,可能是导致问题的另一个原因。
- 案例 4 没问题。
现在,在圆圈的外围,将发生以下颜色过渡:
- 如果未使用边框:完全透明
->
完整图像颜色(伪代码中的大小写 2 和 4( - 如果使用边框:全透明
->
全黑->
全图像颜色(情况 2、3 和 4(
为了在边缘获得更好的质量,您需要引入一些中间状态,使过渡更平滑(新的过渡以斜体显示(:
- 不使用边框:完全透明
->
部分透明,图像颜色->
完整图像颜色 - 使用边框:黑色的完全透明
->
部分透明度->
全黑色->
黑色+图像颜色(即混合(的部分透明度->
全图像颜色
我希望这有所帮助