Skip to content

Instantly share code, notes, and snippets.

@slodge
Created June 13, 2012 21:50
Show Gist options
  • Save slodge/2926704 to your computer and use it in GitHub Desktop.
Save slodge/2926704 to your computer and use it in GitHub Desktop.
PlanarYUVLuminanceSource - for use with Mono4Android in-app scanning
public class PlanarYUVLuminanceSource : LuminanceSource
{
private readonly sbyte[] yuvData;
private readonly int dataWidth;
private readonly int dataHeight;
private readonly int left;
private readonly int top;
public PlanarYUVLuminanceSource(sbyte[] yuvData,
int dataWidth,
int dataHeight,
int left,
int top,
int width,
int height,
bool reverseHorizontal)
: base(width, height)
{
if (left + width > dataWidth || top + height > dataHeight)
{
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
this.yuvData = yuvData;
this.dataWidth = dataWidth;
this.dataHeight = dataHeight;
this.left = left;
this.top = top;
if (reverseHorizontal)
{
this.reverseHorizontal(width, height);
}
}
public override sbyte[] getRow(int y, sbyte[] row)
{
if (y < 0 || y >= Height)
{
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = Width;
if (row == null || row.Length < width)
{
row = new sbyte[width];
}
int offset = (y + top) * dataWidth + left;
Array.Copy(yuvData, offset, row, 0, width);
return row;
}
public override sbyte[] Matrix
{
get
{
int width = Width;
int height = Height;
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if (width == dataWidth && height == dataHeight)
{
return yuvData;
}
int area = width*height;
sbyte[] matrix = new sbyte[area];
int inputOffset = top*dataWidth + left;
// If the width matches the full width of the underlying data, perform a single copy.
if (width == dataWidth)
{
Array.Copy(yuvData, inputOffset, matrix, 0, area);
return matrix;
}
// Otherwise copy one cropped row at a time.
sbyte[] yuv = yuvData;
for (int y = 0; y < height; y++)
{
int outputOffset = y*width;
Array.Copy(yuv, inputOffset, matrix, outputOffset, width);
inputOffset += dataWidth;
}
return matrix;
}
}
public override bool CropSupported
{
get
{
return true;
}
}
public override LuminanceSource crop(int left, int top, int width, int height)
{
return new PlanarYUVLuminanceSource(yuvData,
dataWidth,
dataHeight,
this.left + left,
this.top + top,
width,
height,
false);
}
public Bitmap renderCroppedGreyscaleBitmap()
{
int width = Width;
int height = Height;
int[] pixels = new int[width * height];
sbyte[] yuv = yuvData;
int inputOffset = top * dataWidth + left;
for (int y = 0; y < height; y++)
{
int outputOffset = y * width;
for (int x = 0; x < width; x++)
{
int grey = yuv[inputOffset + x] & 0xff;
pixels[outputOffset + x] = (int)(0xFF000000 | (grey * 0x00010101));
}
inputOffset += dataWidth;
}
Bitmap bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
bitmap.SetPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
private void reverseHorizontal(int width, int height)
{
sbyte[] yuvData = this.yuvData;
for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth)
{
int middle = rowStart + width / 2;
for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--)
{
sbyte temp = yuvData[x1];
yuvData[x1] = yuvData[x2];
yuvData[x2] = temp;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment