如何对Java ByteBuffer中存储的图像数据进行水平/垂直翻转操作
实现结论
完全可以仅通过操作ByteBuffer实现图像的水平/垂直翻转,不需要引入额外的复杂方案,处理后可直接返回ByteBuffer类型的结果。
当前存储的是RGBA 4通道交织格式图像,每个像素占4字节,按行优先顺序排列,只需要通过坐标映射将原像素写入目标位置即可完成翻转,也可以选择原地交换像素实现无额外内存开销的翻转。
代码实现
水平翻转
水平翻转逻辑为同一行内的像素左右交换,y坐标保持不变:
import java.nio.ByteBuffer; public ByteBuffer flipHorizontal() { // 每个像素占4字节(RGBA顺序) int pixelByteLength = 4; // 新建和原缓冲区大小一致的缓冲区,若需保持和原缓冲区相同字节序可追加.order(imageBuffer.order()) ByteBuffer flippedBuffer = ByteBuffer.allocateDirect(imageBuffer.capacity()); for (int y = 0; y < imageHeight; y++) { for (int x = 0; x < imageWidth; x++) { // 计算原像素首字节偏移 int srcOffset = (y * imageWidth + x) * pixelByteLength; // 水平翻转后的目标x坐标 int targetX = imageWidth - 1 - x; int targetOffset = (y * imageWidth + targetX) * pixelByteLength; // 复制RGBA四个通道的字节数据 flippedBuffer.put(targetOffset, imageBuffer.get(srcOffset)); flippedBuffer.put(targetOffset + 1, imageBuffer.get(srcOffset + 1)); flippedBuffer.put(targetOffset + 2, imageBuffer.get(srcOffset + 2)); flippedBuffer.put(targetOffset + 3, imageBuffer.get(srcOffset + 3)); } } // 重置缓冲区指针到起始位置,方便后续读取 flippedBuffer.flip(); return flippedBuffer; }
垂直翻转
垂直翻转逻辑为同一列的像素上下交换,x坐标保持不变:
public ByteBuffer flipVertical() { int pixelByteLength = 4; ByteBuffer flippedBuffer = ByteBuffer.allocateDirect(imageBuffer.capacity()); for (int y = 0; y < imageHeight; y++) { // 垂直翻转后的目标y坐标 int targetY = imageHeight - 1 - y; for (int x = 0; x < imageWidth; x++) { int srcOffset = (y * imageWidth + x) * pixelByteLength; int targetOffset = (targetY * imageWidth + x) * pixelByteLength; flippedBuffer.put(targetOffset, imageBuffer.get(srcOffset)); flippedBuffer.put(targetOffset + 1, imageBuffer.get(srcOffset + 1)); flippedBuffer.put(targetOffset + 2, imageBuffer.get(srcOffset + 2)); flippedBuffer.put(targetOffset + 3, imageBuffer.get(srcOffset + 3)); } } flippedBuffer.flip(); return flippedBuffer; }
补充说明
- 以上示例采用新建缓冲区的方式实现,逻辑简单不易出错,适合绝大多数场景。如果需要原地翻转节省内存,可以遍历一半的坐标,两两交换对应位置的像素即可,避免重复交换。
- 代码中
flippedBuffer.flip()是ByteBuffer自带的读写状态切换方法,作用是将缓冲区position重置为0、limit设置为当前写入位置,是标准的缓冲区操作方法,和图像翻转功能无关。 - 如果原ByteBuffer是堆内存缓冲区,将新建缓冲区的分配方式改为
ByteBuffer.allocate()即可保持类型一致。
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

