Rotate an YUV byte array on Android
The following method can rotate a YUV420 byte array by 90 degree.
private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte [] yuv = new byte[imageWidth*imageHeight*3/2]; // Rotate the Y luma int i = 0; for(int x = 0;x < imageWidth;x++) { for(int y = imageHeight-1;y >= 0;y--) { yuv[i] = data[y*imageWidth+x]; i++; } } // Rotate the U and V color components i = imageWidth*imageHeight*3/2-1; for(int x = imageWidth-1;x > 0;x=x-2) { for(int y = 0;y < imageHeight/2;y++) { yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x]; i--; yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)]; i--; } } return yuv;}
(Note that this might only work if the width and height is a factor of 4)
Here are the options to turn a different corner (90, 180, 270):
public static byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; // Rotate the Y luma int i = 0; for (int x = 0; x < imageWidth; x++) { for (int y = imageHeight - 1; y >= 0; y--) { yuv[i] = data[y * imageWidth + x]; i++; } } // Rotate the U and V color components i = imageWidth * imageHeight * 3 / 2 - 1; for (int x = imageWidth - 1; x > 0; x = x - 2) { for (int y = 0; y < imageHeight / 2; y++) { yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x]; i--; yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)]; i--; } } return yuv;}private static byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; int i = 0; int count = 0; for (i = imageWidth * imageHeight - 1; i >= 0; i--) { yuv[count] = data[i]; count++; } i = imageWidth * imageHeight * 3 / 2 - 1; for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth * imageHeight; i -= 2) { yuv[count++] = data[i - 1]; yuv[count++] = data[i]; } return yuv;}public static byte[] rotateYUV420Degree270(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; int nWidth = 0, nHeight = 0; int wh = 0; int uvHeight = 0; if (imageWidth != nWidth || imageHeight != nHeight) { nWidth = imageWidth; nHeight = imageHeight; wh = imageWidth * imageHeight; uvHeight = imageHeight >> 1;// uvHeight = height / 2 } // ??Y int k = 0; for (int i = 0; i < imageWidth; i++) { int nPos = 0; for (int j = 0; j < imageHeight; j++) { yuv[k] = data[nPos + i]; k++; nPos += imageWidth; } } for (int i = 0; i < imageWidth; i += 2) { int nPos = wh; for (int j = 0; j < uvHeight; j++) { yuv[k] = data[nPos + i]; yuv[k + 1] = data[nPos + i + 1]; k += 2; nPos += imageWidth; } } return rotateYUV420Degree180(yuv, imageWidth, imageHeight);}
Here's how I did it
This block of code is setup elsewhere
Camera.Size size Rect rectangle = new Rect(); rectangle.bottom = size.height; rectangle.top = 0; rectangle.left = 0; rectangle.right = size.width;
This is the method that does the work
private Bitmap rotateBitmap(YuvImage yuvImage, int orientation, Rect rectangle) { ByteArrayOutputStream os = new ByteArrayOutputStream(); yuvImage.compressToJpeg(rectangle, 100, os); Matrix matrix = new Matrix(); matrix.postRotate(orientation); byte[] bytes = os.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); return Bitmap.createBitmap(bitmap, 0 , 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); }
compress the YUVImage into a JPEG so that bitmap can handle it. Rotate the bitmap and then export it. To get it back to a JPEG which is how I wanted it I used this line
image.compress(Bitmap.CompressFormat.JPEG, 50, outputStream);