///<summary>
/// Convert pixels from one format to another. No dithering or filtering is being done. Converting
/// from RGB to luminance takes the R channel.
///</summary>
///<param name="src">PixelBox containing the source pixels, pitches and format</param>
///<param name="dst">PixelBox containing the destination pixels, pitches and format</param>
///<remarks>
/// The source and destination boxes must have the same
/// dimensions. In case the source and destination format match, a plain copy is done.
///</remarks>
public static void BulkPixelConversion(PixelBox src, PixelBox dst)
{
Debug.Assert(src.Width == dst.Width && src.Height == dst.Height && src.Depth == dst.Depth);
// Check for compressed formats, we don't support decompression, compression or recoding
if (PixelBox.Compressed(src.Format) || PixelBox.Compressed(dst.Format))
{
if (src.Format == dst.Format)
{
CopyBytes(dst.Data, dst.Offset, src.Data, src.Offset, src.ConsecutiveSize);
return;
}
else
{
throw new Exception("This method can not be used to compress or decompress images, in PixelBox.BulkPixelConversion");
}
}
// The easy case
if (src.Format == dst.Format)
{
// Everything consecutive?
if (src.Consecutive && dst.Consecutive)
{
CopyBytes(dst.Data, dst.Offset, src.Data, src.Offset, src.ConsecutiveSize);
return;
}
unsafe {
byte *srcBytes = (byte *)src.Data.ToPointer();
byte *dstBytes = (byte *)dst.Data.ToPointer();
byte *srcptr = srcBytes + src.Offset;
byte *dstptr = dstBytes + dst.Offset;
int srcPixelSize = PixelUtil.GetNumElemBytes(src.Format);
int dstPixelSize = PixelUtil.GetNumElemBytes(dst.Format);
// Calculate pitches+skips in bytes
int srcRowPitchBytes = src.RowPitch * srcPixelSize;
//int srcRowSkipBytes = src.RowSkip * srcPixelSize;
int srcSliceSkipBytes = src.SliceSkip * srcPixelSize;
int dstRowPitchBytes = dst.RowPitch * dstPixelSize;
//int dstRowSkipBytes = dst.RowSkip * dstPixelSize;
int dstSliceSkipBytes = dst.SliceSkip * dstPixelSize;
// Otherwise, copy per row
int rowSize = src.Width * srcPixelSize;
for (int z = src.Front; z < src.Back; z++)
{
for (int y = src.Top; y < src.Bottom; y++)
{
byte *s = srcptr;
byte *d = dstptr;
for (int i = 0; i < rowSize; i++)
{
*d++ = *s++;
}
srcptr += srcRowPitchBytes;
dstptr += dstRowPitchBytes;
}
srcptr += srcSliceSkipBytes;
dstptr += dstSliceSkipBytes;
}
}
return;
}
if (PixelConversionLoops.DoOptimizedConversion(src, dst))
{
// If so, good
return;
}
unsafe {
byte *srcBytes = (byte *)src.Data.ToPointer();
byte *dstBytes = (byte *)dst.Data.ToPointer();
byte *srcptr = srcBytes + src.Offset;
byte *dstptr = dstBytes + dst.Offset;
int srcPixelSize = PixelUtil.GetNumElemBytes(src.Format);
int dstPixelSize = PixelUtil.GetNumElemBytes(dst.Format);
// Calculate pitches+skips in bytes
int srcRowSkipBytes = src.RowSkip * srcPixelSize;
int srcSliceSkipBytes = src.SliceSkip * srcPixelSize;
int dstRowSkipBytes = dst.RowSkip * dstPixelSize;
int dstSliceSkipBytes = dst.SliceSkip * dstPixelSize;
// The brute force fallback
float r, g, b, a;
for (int z = src.Front; z < src.Back; z++)
{
for (int y = src.Top; y < src.Bottom; y++)
{
for (int x = src.Left; x < src.Right; x++)
{
UnpackColor(out r, out g, out b, out a, src.Format, srcptr);
PackColor(r, g, b, a, dst.Format, dstptr);
srcptr += srcPixelSize;
dstptr += dstPixelSize;
}
srcptr += srcRowSkipBytes;
dstptr += dstRowSkipBytes;
}
srcptr += srcSliceSkipBytes;
dstptr += dstSliceSkipBytes;
}
}
}