Обрезать прозрачные края изображения
Я пытаюсь сделать функцию, которая будет обрезать прозрачные края BufferedImage
только с правой и левой стороны.
Итак, я нашел этот способ сделать это где-то в Интернете, однако я не очень понимаю, что такое pixels[]
массив заполнен? Я предположил, что это были значения альфа, красный, зеленый, синий для каждого пикселя (судя по 4
в (j*width+i)*4
, он выбирает каждый четвертый элемент), но длина этого массива 299208
для 68x67
изображение (я знаю, что это не степень 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);
}
То, что я в основном делаю в приведенном выше коде, сканирует изображение слева и справа, проверяя альфа-значение и отмечая расстояние, которое нужно обрезать, но это вызывает исключение, потому что циклы заканчиваются, не обнаруживая непрозрачных пикселей (и изображения, которые я обрезаю, непрозрачны).
Я сделал проверку и обнаружил, что значения альфа больше, чем 0
на самом деле выше индекса 35000
из pixels[]
массив, и с (j*width+i)*4
Расчет я могу только достичь 18000
....
1 ответ
Быстрая починка
Вы можете просто сделать пиксели с:
final int[] pixels = ((DataBufferInt)img.getAlphaRaster().getDataBuffer()).getData();
и удалите *4
в обоих (j*width+i)*4
, Это просто делает ваш pixels[]
содержат только альфа-значения, а не RGB.
Однако есть безопаснее (нет небезопасных DataBuffer
бросает), более читаемое решение:
Предпочитаемая версия
Изменения, которые я сделал, должны были остановиться с ужасным byte
массив, и просто используйте getRGB()
метод вместо. Значение альфа можно получить, создав Color
используя конструктор RGB+ альфа, а затем 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()
данные (если вы не знаете, что это значит, попробуйте приведенный выше код, и, если он не работает, скрытно в ARGB.)
Также убедитесь, что вы используете формат изображения, который поддерживает прозрачность (не JPG).