裁剪图像的透明边缘
Posted
技术标签:
【中文标题】裁剪图像的透明边缘【英文标题】:Crop transparent edges of an image 【发布时间】:2017-11-07 18:13:18 【问题描述】:我正在尝试制作一个仅从右侧和左侧裁剪BufferedImage
的透明边缘的函数。
所以,我在网上的某个地方找到了这种方法,但是我真的不明白pixels[]
数组填充了什么?我假设它是每个像素的 alpha、红色、绿色、蓝色值(根据 (j*width+i)*4
中的 4
判断,它每第四个元素选取一次),但是对于 @987654326,这个数组的长度是 299208
@image(我知道它不是 2 的幂,忽略它)。
那么,我该如何做到这一点,我很好奇这个像素阵列中实际存储了什么?
public static BufferedImage trimHorizontally(BufferedImage img)
final byte[] pixels = ((DataBufferByte)img.getRaster().getDataBuffer()).getData();
int width = img.getWidth(), height = img.getHeight();
int x0, x1;
int j, i;
leftLoop:
for(i = 0; i < width; i++)
for(j = 0; j < height; j++)
if(pixels[(j*width+i)*4] != 0)
break leftLoop;
x0 = i;
rightLoop:
for(i = width-1; i >= 0; i--)
for(j = 0; j < height; j++)
if(pixels[(j*width+i)*4] != 0)
break rightLoop;
x1 = i+1;
return img.getSubimage(x0, 0, x1-x0, height);
我在上面的代码中基本上做的是从左侧和右侧扫描图像,检查 alpha 值并标记我需要裁剪的距离,但它会引发异常,因为循环完成时没有检测任何不透明的像素(我裁剪的图像肯定不透明)。
我查了一下,发现大于0
的alpha值实际上在pixels[]
数组的35000
的索引之上,通过(j*width+i)*4
的计算我只能达到18000
。 ...
【问题讨论】:
pixels[]
数组确实存储了您的想法。不知道为什么长度这么长。
您的图像是否已经使用getSubimage(...)
方法裁剪?请注意,此方法不会创建副本,因此图像将与原始图像共享支持数组(包括大小)。您可以从Raster
获得正确的偏移量/尺寸。此外,将DataBuffer
无条件转换为DataBufferInt
或DataBufferByte
显然是不安全的,除非您完全控制输入图像。
是的,图像在使用此方法之前已使用 getSubimage() 进行裁剪...
【参考方案1】:
快速修复
您可以使用以下方法制作像素:
final int[] pixels = ((DataBufferInt)img.getAlphaRaster().getDataBuffer()).getData();
并删除两个(j*width+i)*4
中的*4
。这只会使您的 pixels[]
仅包含 alpha 值,而不包含 RGB。
但是有一个更安全(没有不安全的DataBuffer
强制转换)、更易读的解决方案:
首选版本
我所做的更改是停止使用可怕的byte
数组,而只需使用getRGB()
方法。 alpha值可以通过使用the RGB+alpha constructor创建Color
,然后使用getAlpha()
方法获得。
现在下面的代码对我有用:
public static BufferedImage trimHorizontally(BufferedImage img)
int width = img.getWidth(), height = img.getHeight();
int x0, x1;
int j, i;
int alpha;
leftLoop:
for(i = 0; i < width; i++)
for(j = 0; j < height; j++)
if(new Color(img.getRGB(i, j), true).getAlpha() != 0)
break leftLoop;
x0 = i;
rightLoop:
for(i = width-1; i >= 0; i--)
for(j = 0; j < height; j++)
if(new Color(img.getRGB(i, j), true).getAlpha() != 0)
break rightLoop;
x1 = i+1;
return img.getSubimage(x0, 0, x1-x0, height);
注意事项:
img
必须是TYPE_INT_ARGB
类型,或者是在getRGB()
数据的最后一个字节中保留其alpha 值的其他类型(如果您不知道这意味着什么,只需尝试上面的代码如果它不起作用covert to ARGB。)
还要确保使用image format that supports transparency(不是 JPG)。
【讨论】:
是的,确实如此。但是,我在某处听说使用 getRGB 与使用像素 [] 数组的方式相比效率低下。以上是关于裁剪图像的透明边缘的主要内容,如果未能解决你的问题,请参考以下文章