/// <summary> /// Copies the image to a destination pointer. /// </summary> /// <param name="destination">The destination pointer to copy the image to.</param> /// <param name="width">The destination width.</param> /// <param name="height">The destination height.</param> /// <param name="stride">The destination stride.</param> /// <param name="pixelFormat">The destination pixel format.</param> public void CopyTo(IntPtr destination, int width, int height, int stride, PixelFormat pixelFormat) { if ((this.width != width) || (this.height != height)) { throw new InvalidOperationException("Destination image has different size."); } // Check if pixel formats are the same. If so, do a straight up copy if (this.PixelFormat == pixelFormat) { if (this.stride == stride) { this.image.CopyTo(destination, stride * height); } else { unsafe { int copyLength = (this.stride < stride) ? this.stride : stride; byte *src = (byte *)this.image.Data.ToPointer(); byte *dst = (byte *)destination.ToPointer(); // copy line by line for (int i = 0; i < this.height; i++) { Buffer.MemoryCopy(src, dst, copyLength, copyLength); dst += stride; src += this.stride; } } } } else if ((this.pixelFormat == PixelFormat.BGR_24bpp) && (pixelFormat == PixelFormat.BGRX_32bpp || pixelFormat == PixelFormat.BGRA_32bpp)) { unsafe { byte *src = (byte *)this.image.Data.ToPointer(); byte *dst = (byte *)destination.ToPointer(); Parallel.For(0, this.Height, i => { byte *srcCopy = src + (this.stride * i); byte *dstCopy = dst + (stride * i); for (int j = 0; j < this.width; j++) { *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; *dstCopy++ = 255; } }); } } else if ((this.pixelFormat == PixelFormat.BGRX_32bpp) && (pixelFormat == PixelFormat.BGR_24bpp)) { unsafe { byte *src = (byte *)this.image.Data.ToPointer(); byte *dst = (byte *)destination.ToPointer(); Parallel.For(0, this.Height, i => { byte *srcCopy = src + (this.stride * i); byte *dstCopy = dst + (stride * i); for (int j = 0; j < this.width; j++) { *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; *dstCopy++ = *srcCopy++; srcCopy++; } }); } } else if ((this.pixelFormat == PixelFormat.BGR_24bpp) && (pixelFormat == PixelFormat.Gray_8bpp)) { unsafe { byte *src = (byte *)this.image.Data.ToPointer(); byte *dst = (byte *)destination.ToPointer(); Parallel.For(0, this.Height, i => { byte *srcCopy = src + (this.stride * i); byte *dstCopy = dst + (stride * i); for (int j = 0; j < this.width; j++) { *dstCopy++ = Operators.Rgb2Gray(*srcCopy, *(srcCopy + 1), *(srcCopy + 2)); srcCopy += 3; } }); } } else { this.CopyImageSlow(this.image.Data, this.pixelFormat, destination, stride, pixelFormat); } }
private void CopyImageSlow(IntPtr sourceIntPtr, PixelFormat sourceFormat, IntPtr destinationIntPtr, int destinationStride, PixelFormat destinationFormat) { unsafe { int srcBytesPerPixel = sourceFormat.GetBytesPerPixel(); int dstBytesPerPixel = destinationFormat.GetBytesPerPixel(); Parallel.For( 0, this.Height, i => { byte *srcCol = (byte *)sourceIntPtr.ToPointer() + (i * this.stride); byte *dstCol = (byte *)destinationIntPtr.ToPointer() + (i * destinationStride); for (int j = 0; j < this.width; j++) { int red = 0; int green = 0; int blue = 0; int alpha = 255; switch (sourceFormat) { case PixelFormat.Gray_8bpp: red = green = blue = srcCol[0]; break; case PixelFormat.Gray_16bpp: red = green = blue = ((ushort *)srcCol)[0]; break; case PixelFormat.BGR_24bpp: blue = srcCol[0]; green = srcCol[1]; red = srcCol[2]; break; case PixelFormat.BGRX_32bpp: blue = srcCol[0]; green = srcCol[1]; red = srcCol[2]; break; case PixelFormat.BGRA_32bpp: blue = srcCol[0]; green = srcCol[1]; red = srcCol[2]; alpha = srcCol[3]; break; case PixelFormat.RGBA_64bpp: red = ((ushort *)srcCol)[0]; green = ((ushort *)srcCol)[1]; blue = ((ushort *)srcCol)[2]; alpha = ((ushort *)srcCol)[3]; break; case PixelFormat.Undefined: default: throw new ArgumentException(ExceptionDescriptionUnexpectedPixelFormat); } switch (destinationFormat) { case PixelFormat.Gray_8bpp: dstCol[0] = Operators.Rgb2Gray((byte)red, (byte)green, (byte)blue); break; case PixelFormat.Gray_16bpp: ((ushort *)dstCol)[0] = Operators.Rgb2Gray((ushort)red, (ushort)green, (ushort)blue); break; case PixelFormat.BGR_24bpp: case PixelFormat.BGRX_32bpp: dstCol[0] = (byte)blue; dstCol[1] = (byte)green; dstCol[2] = (byte)red; break; case PixelFormat.BGRA_32bpp: dstCol[0] = (byte)blue; dstCol[1] = (byte)green; dstCol[2] = (byte)red; dstCol[3] = (byte)alpha; break; case PixelFormat.RGBA_64bpp: ((ushort *)dstCol)[0] = (ushort)red; ((ushort *)dstCol)[1] = (ushort)green; ((ushort *)dstCol)[2] = (ushort)blue; ((ushort *)dstCol)[3] = (ushort)alpha; break; case PixelFormat.Undefined: default: throw new ArgumentException(ExceptionDescriptionUnexpectedPixelFormat); } srcCol += srcBytesPerPixel; dstCol += dstBytesPerPixel; } }); } }
private void CopyImageSlow(IntPtr sourceIntPtr, PixelFormat sourceFormat, IntPtr destinationIntPtr, int destinationStride, PixelFormat destinationFormat) { unsafe { int srcBytesPerPixel = sourceFormat.GetBytesPerPixel(); int dstBytesPerPixel = destinationFormat.GetBytesPerPixel(); Parallel.For( 0, this.Height, i => { byte *srcCol = (byte *)sourceIntPtr.ToPointer() + (i * this.stride); byte *dstCol = (byte *)destinationIntPtr.ToPointer() + (i * destinationStride); for (int j = 0; j < this.width; j++) { int red; int green; int blue; int alpha; int bits; switch (sourceFormat) { case PixelFormat.Gray_8bpp: red = green = blue = srcCol[0]; alpha = 255; bits = 8; break; case PixelFormat.Gray_16bpp: red = green = blue = ((ushort *)srcCol)[0]; alpha = 65535; bits = 16; break; case PixelFormat.BGR_24bpp: case PixelFormat.BGRX_32bpp: blue = srcCol[0]; green = srcCol[1]; red = srcCol[2]; alpha = 255; bits = 8; break; case PixelFormat.BGRA_32bpp: blue = srcCol[0]; green = srcCol[1]; red = srcCol[2]; alpha = srcCol[3]; bits = 8; break; case PixelFormat.RGB_24bpp: red = srcCol[0]; green = srcCol[1]; blue = srcCol[2]; alpha = 255; bits = 8; break; case PixelFormat.RGBA_64bpp: red = ((ushort *)srcCol)[0]; green = ((ushort *)srcCol)[1]; blue = ((ushort *)srcCol)[2]; alpha = ((ushort *)srcCol)[3]; bits = 16; break; case PixelFormat.Undefined: default: throw new ArgumentException(ExceptionDescriptionUnexpectedPixelFormat); } // Convert from 8-bits-per-channel (0-255) to 16-bits-per-channel (0-65535) and visa versa when needed. switch (destinationFormat) { case PixelFormat.Gray_8bpp: case PixelFormat.BGR_24bpp: case PixelFormat.BGRX_32bpp: case PixelFormat.BGRA_32bpp: case PixelFormat.RGB_24bpp: if (bits == 16) { red >>= 8; green >>= 8; blue >>= 8; alpha >>= 8; } break; case PixelFormat.Gray_16bpp: case PixelFormat.RGBA_64bpp: if (bits == 8) { red = (red << 8) | red; green = (green << 8) | green; blue = (blue << 8) | blue; alpha = (alpha << 8) | alpha; } break; } switch (destinationFormat) { case PixelFormat.Gray_8bpp: dstCol[0] = Operators.Rgb2Gray((byte)red, (byte)green, (byte)blue); break; case PixelFormat.Gray_16bpp: ((ushort *)dstCol)[0] = Operators.Rgb2Gray((ushort)red, (ushort)green, (ushort)blue); break; case PixelFormat.BGR_24bpp: case PixelFormat.BGRX_32bpp: dstCol[0] = (byte)blue; dstCol[1] = (byte)green; dstCol[2] = (byte)red; break; case PixelFormat.BGRA_32bpp: dstCol[0] = (byte)blue; dstCol[1] = (byte)green; dstCol[2] = (byte)red; dstCol[3] = (byte)alpha; break; case PixelFormat.RGB_24bpp: dstCol[0] = (byte)red; dstCol[1] = (byte)green; dstCol[2] = (byte)blue; break; case PixelFormat.RGBA_64bpp: ((ushort *)dstCol)[0] = (ushort)red; ((ushort *)dstCol)[1] = (ushort)green; ((ushort *)dstCol)[2] = (ushort)blue; ((ushort *)dstCol)[3] = (ushort)alpha; break; case PixelFormat.Undefined: default: throw new ArgumentException(ExceptionDescriptionUnexpectedPixelFormat); } srcCol += srcBytesPerPixel; dstCol += dstBytesPerPixel; } }); } }