///<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; } } }