Вот одно решение, которое действительно быстрое, поскольку оно не меняет данные, а только способ отображения данных.
Хитрость в том, что порядок каналов (порядок байтов) контролируется SampleModel
. И вы можете изменить пример модели, не изменяя данные, чтобы отображать одни и те же данные по-разному.
Если у вас уже есть BufferedImage
, самый простой способ создать образец модели с замененными каналами - это создать нового дочернего элемента Raster
с использованием метода Raster.createWritableChild(...)
и указать канал (или «полосу») порядок в последнем параметре.
bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0,
new int[]{2, 1, 0}); // default order is 0, 1, 2
В приведенном ниже примере данные изображения одинаковы (если есть сомнения, попробуйте переместить часть рисования после клонирования изображения и убедитесь, что результат такой же). Меняются только каналы:
public static void main(String[] args) {
// Original
final BufferedImage bgr = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
// Paint something
Graphics2D graphics = bgr.createGraphics();
try {
graphics.setColor(Color.BLUE);
graphics.fillRect(0, 0, bgr.getWidth(), bgr.getHeight());
graphics.setColor(Color.YELLOW);
graphics.fillRect(0, 0, bgr.getWidth(), bgr.getHeight() / 3);
graphics.setColor(Color.GREEN);
graphics.fillRect(0, 0, bgr.getWidth() / 3, bgr.getHeight());
}
finally {
graphics.dispose();
}
// Clone, and swap BGR -> RGB
ColorModel colorModel = bgr.getColorModel();
WritableRaster swapped = bgr.getRaster().createWritableChild(0, 0, bgr.getWidth(), bgr.getHeight(), 0, 0,
new int[]{2, 1, 0}); // default order is 0, 1, 2
final BufferedImage rgb = new BufferedImage(colorModel, swapped, colorModel.isAlphaPremultiplied(), null);
System.err.println("bgr: " + bgr); // TYPE_3BYTE_BGR (5)
System.err.println("rgb: " + rgb); // TYPE_CUSTOM (0)
// Display it all
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(new JLabel(new ImageIcon(bgr)), BorderLayout.WEST);
frame.add(new JLabel(new ImageIcon(rgb)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
PS: я знаю из комментариев, что OP не нуждается в этом, но если вам действительно нужно поменять местами каналы данных пикселей по какой-то причине (т. Е. Нужно встроенной библиотеке или около того), скорее всего, будет чтобы получить данные, выполните цикл и поменяйте местами красный и синий (1-й и 3-й) компоненты:
byte[] data = ((DataBufferByte) bgr.getRaster().getDataBuffer()).getData();
for (int i = 0; i < data.length; i += 3) {
// Swap 1st and 3rd component
byte b = data[i];
data[i] = data[i + 2];
data[i + 2] = b;
}