/// <summary> /// Creates a <see cref="Bitmap"/> from the image. /// </summary> /// <param name="makeCopy">Indicates whether to make a copy of the image data or not.</param> /// <returns>A corresponding <see cref="Bitmap"/> image.</returns> /// <remarks>If the <paramref name="makeCopy"/> parameter is set to <see langword="true"/>, then the method /// creates a copy of the image, so the <see cref="Bitmap"/> stays valid even when the /// image gets disposed. However, setting this parameter to <see langword="false"/> creates a <see cref="Bitmap"/> image which is just a wrapper around the image data. In this case, if the image is disposed, the /// will no longer be valid and accessing it will generate an exception.</remarks> public Bitmap ToBitmap(bool makeCopy = true) { Bitmap bitmap = null; try { if (!makeCopy) { bitmap = new Bitmap(this.width, this.height, this.stride, PixelFormatHelper.ToSystemPixelFormat(this.pixelFormat), this.image.Data); if (this.pixelFormat == PixelFormat.Gray_8bpp) { Operators.SetGrayscalePalette(bitmap); } } else { // create new image of required format bitmap = new Bitmap(this.width, this.height, PixelFormatHelper.ToSystemPixelFormat(this.pixelFormat)); if (this.pixelFormat == PixelFormat.Gray_8bpp) { // set palette to grayscale Operators.SetGrayscalePalette(bitmap); } // lock destination bitmap data BitmapData bitmapData = bitmap.LockBits( new Rectangle(0, 0, this.width, this.height), ImageLockMode.ReadWrite, PixelFormatHelper.ToSystemPixelFormat(this.pixelFormat)); int bitmapStride = bitmapData.Stride; int lineSize = Math.Min(this.stride, bitmapStride); unsafe { byte *dst = (byte *)bitmapData.Scan0.ToPointer(); byte *src = (byte *)this.image.Data.ToPointer(); if (this.stride != bitmapStride) { // copy image for (int y = 0; y < this.height; y++) { Buffer.MemoryCopy(src, dst, lineSize, lineSize); dst += bitmapStride; src += this.stride; } } else { var size = this.stride * this.height; Buffer.MemoryCopy(src, dst, size, size); } } // unlock destination images bitmap.UnlockBits(bitmapData); } return(bitmap); } catch (Exception) { if (bitmap != null) { bitmap.Dispose(); } throw new Exception("The image has some invalid properties, which caused a failure while converting it to managed image."); } }
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; } }); } }
/// <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[2], srcCopy[1], srcCopy[0]); srcCopy += 3; } }); } } else if ((this.pixelFormat == PixelFormat.Gray_16bpp) && (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++) { // copy msb only *dstCopy++ = *(srcCopy + 1); srcCopy += 2; } }); } } else if ((this.pixelFormat == PixelFormat.Gray_8bpp) && (pixelFormat == PixelFormat.Gray_16bpp)) { 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++) { // dest = (src << 8) | src *dstCopy++ = *srcCopy; *dstCopy++ = *srcCopy++; } }); } } else if ((this.pixelFormat == PixelFormat.Gray_8bpp) && (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++) { // dest = (src << 24) | (src << 16) | (src << 8) | 0xff *dstCopy++ = *srcCopy; *dstCopy++ = *srcCopy; *dstCopy++ = *srcCopy++; *dstCopy++ = 0xff; // alpha } }); } } else { this.CopyImageSlow(this.image.Data, this.pixelFormat, destination, stride, pixelFormat); } }