Обрезать прозрачные края изображения

Я пытаюсь сделать функцию, которая будет обрезать прозрачные края 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).

Другие вопросы по тегам