Exemple #1
0
        /// <summary>
        /// Resizes planar image
        /// </summary>
        /// <param name="newSize"></param>
        /// <returns></returns>
        public PlanarImage Resize(Size newSize)
        {
            PlanarImage result = new PlanarImage(newSize.Width, newSize.Height, this.PixelType);

            ConverterResizer.Apply(this, result);
            return(result);
        }
Exemple #2
0
        /// <summary>
        /// Performs both conversion and resize in a single operation
        /// </summary>
        /// <param name="newPixelType"></param>
        /// <param name="newSize"></param>
        /// <returns></returns>
        public PlanarImage ConvertAndResize(PixelAlignmentType newPixelType, Size newSize)
        {
            PlanarImage result = new PlanarImage(newSize.Width, newSize.Height, newPixelType);

            ConverterResizer.Apply(this, result);
            return(result);
        }
        public static PlanarImage FromBitmap(Bitmap source, PixelAlignmentType format, ColorSpace colorspace = ColorSpace.DEFAULT)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_rgbMapper[source.PixelFormat],
                                                    source.Width, source.Height, m_pixelTypeMapper[format],
                                                    SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            int *pCoef = SwScale.sws_getCoefficients(colorspace);
            int *inv_table;
            int *table;
            int  srcRange, dstRange, brightness, contrast, saturation;

            int result = SwScale.sws_getColorspaceDetails(context, out inv_table, out srcRange, out table, out dstRange, out brightness, out contrast, out saturation);

            if (result != -1)
            {
                result = SwScale.sws_setColorspaceDetails(context, pCoef, srcRange, table, dstRange, brightness, contrast, saturation);
            }

            PlanarImage yuv  = new PlanarImage(source.Width, source.Height, format);
            BitmapData  data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat);

            unsafe
            {
                pInput[0] = (byte *)data.Scan0.ToPointer();
                result    = SwScale.sws_scale(context, pInput, new int[] { data.Stride, 0, 0, 0 }, 0, source.Height, yuv.PixelDataPointer, yuv.Pitches);
                if (result != yuv.Height)
                {
                    throw new InvalidOperationException();
                }
            }

            source.UnlockBits(data);
            SwScale.sws_freeContext(context);
            return(yuv);
        }
Exemple #4
0
        /// <summary>
        /// Converts planar image to another pixel alignment type
        /// </summary>
        /// <param name="newPixelType"></param>
        /// <returns></returns>
        public PlanarImage Convert(PixelAlignmentType newPixelType)
        {
            PlanarImage result = new PlanarImage(this.Width, this.Height, newPixelType);

            ConverterResizer.Apply(this, result);
            return(result);
        }
Exemple #5
0
        /// <summary>
        /// Loads PlanarImage properties from provided stream
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static PlanarImage Load(Stream stream)
        {
            BinaryFormatter bf  = new BinaryFormatter();
            PlanarImage     yuv = (PlanarImage)bf.Deserialize(stream);

            return(yuv);
        }
Exemple #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static PlanarImage Load(string fileName)
        {
            FileStream  fs    = File.OpenRead(fileName);
            PlanarImage image = Load(fs);

            fs.Close();
            return(image);
        }
        public PlanarImage DoTheWork(PlanarImage source)
        {
            PlanarImage target = new PlanarImage(m_targetSize.Width, m_targetSize.Height, m_targetType);
            int result = SwScale.sws_scale(m_context, source.PixelDataPointer, source.Pitches, 0, source.Height, target.PixelDataPointer, target.Pitches);
            if (result != target.Height)
            {
                throw new InvalidOperationException();
            }

            return target;
        }
        public PlanarImage DoTheWork(PlanarImage source)
        {
            PlanarImage target = new PlanarImage(m_targetSize.Width, m_targetSize.Height, m_targetType);
            int         result = SwScale.sws_scale(m_context, source.PixelDataPointer, source.Pitches, 0, source.Height, target.PixelDataPointer, target.Pitches);

            if (result != target.Height)
            {
                throw new InvalidOperationException();
            }

            return(target);
        }
        public static void Apply(PlanarImage source, PlanarImage target)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_pixelTypeMapper[source.PixelType],
                                            target.Width, target.Height, m_pixelTypeMapper[target.PixelType],
                                            SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            int result = SwScale.sws_scale(context, source.PixelDataPointer, source.Pitches, 0, source.Height, target.PixelDataPointer, target.Pitches);
            if (result != target.Height)
            {
                throw new InvalidOperationException();
            }

            SwScale.sws_freeContext(context);
        }
        public static void Apply(PlanarImage source, PlanarImage target)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_pixelTypeMapper[source.PixelType],
                                                    target.Width, target.Height, m_pixelTypeMapper[target.PixelType],
                                                    SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            int result = SwScale.sws_scale(context, source.PixelDataPointer, source.Pitches, 0, source.Height, target.PixelDataPointer, target.Pitches);

            if (result != target.Height)
            {
                throw new InvalidOperationException();
            }

            SwScale.sws_freeContext(context);
        }
        public static Bitmap ToBitmap(PlanarImage source, PixelFormat format, ColorSpace colorspace = ColorSpace.DEFAULT)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_pixelTypeMapper[source.PixelType],
                                                    source.Width, source.Height, m_rgbMapper[format],
                                                    SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);


            int *pCoef = SwScale.sws_getCoefficients(colorspace);
            int *inv_table;
            int *table;
            int  srcRange, dstRange, brightness, contrast, saturation;

            int result = SwScale.sws_getColorspaceDetails(context, out inv_table, out srcRange, out table, out dstRange, out brightness, out contrast, out saturation);

            if (result != -1)
            {
                result = SwScale.sws_setColorspaceDetails(context, pCoef, srcRange, pCoef, dstRange, brightness, contrast, saturation);
            }

            Bitmap     bmp  = new Bitmap(source.Width, source.Height, format);
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, format);

            unsafe
            {
                pInput[0] = (byte *)data.Scan0.ToPointer();

                result = SwScale.sws_scale(context, source.PixelDataPointer, source.Pitches, 0, source.Height, pInput, new int[] { data.Stride, 0, 0, 0 });
                if (result != source.Height)
                {
                    throw new InvalidOperationException();
                }
            }

            bmp.UnlockBits(data);
            if (bmp.Palette != null && bmp.Palette.Entries != null && bmp.Palette.Entries.Length > 0)
            {
                ColorPalette cp = bmp.Palette;
                for (int i = 0; i < cp.Entries.Length; i++)
                {
                    cp.Entries[i] = Color.FromArgb(i, i, i);
                }
                bmp.Palette = cp;
            }

            SwScale.sws_freeContext(context);
            return(bmp);
        }
        public static PlanarImage FromBitmap(Bitmap source, PixelAlignmentType format, ColorSpace colorspace = ColorSpace.DEFAULT)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_rgbMapper[source.PixelFormat],
                                             source.Width, source.Height, m_pixelTypeMapper[format],
                                             SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

            int* pCoef = SwScale.sws_getCoefficients(colorspace);
            int* inv_table;
            int* table;
            int srcRange, dstRange, brightness, contrast, saturation;

            int result = SwScale.sws_getColorspaceDetails(context, out inv_table, out srcRange, out table, out dstRange, out brightness, out contrast, out saturation);
            if (result != -1)
            {
                result = SwScale.sws_setColorspaceDetails(context, pCoef, srcRange, table, dstRange, brightness, contrast, saturation);
            }

            PlanarImage yuv = new PlanarImage(source.Width, source.Height, format);
            BitmapData data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat);

            unsafe
            {
                pInput[0] = (byte*)data.Scan0.ToPointer();
                result = SwScale.sws_scale(context, pInput, new int[] { data.Stride, 0, 0, 0 }, 0, source.Height, yuv.PixelDataPointer, yuv.Pitches);
                if (result != yuv.Height)
                {
                    throw new InvalidOperationException();
                }
            }

            source.UnlockBits(data);
            SwScale.sws_freeContext(context);
            return yuv;
        }
 /// <summary>
 /// Performs both conversion and resize in a single operation
 /// </summary>
 /// <param name="newPixelType"></param>
 /// <param name="newSize"></param>
 /// <returns></returns>
 public PlanarImage ConvertAndResize(PixelAlignmentType newPixelType, Size newSize)
 {
     PlanarImage result = new PlanarImage(newSize.Width, newSize.Height, newPixelType);
     ConverterResizer.Apply(this, result);
     return result;
 }
 /// <summary>
 /// Resizes planar image
 /// </summary>
 /// <param name="newSize"></param>
 /// <returns></returns>
 public PlanarImage Resize(Size newSize)
 {
     PlanarImage result = new PlanarImage(newSize.Width, newSize.Height, this.PixelType);
     ConverterResizer.Apply(this, result);
     return result;
 }
 /// <summary>
 /// Converts planar image to another pixel alignment type
 /// </summary>
 /// <param name="newPixelType"></param>
 /// <returns></returns>
 public PlanarImage Convert(PixelAlignmentType newPixelType)
 {
     PlanarImage result = new PlanarImage(this.Width, this.Height, newPixelType);
     ConverterResizer.Apply(this, result);
     return result;
 }
        public static PlanarImage Crop(PlanarImage source, Rectangle cropArea)
        {
            PlanarImage result = new PlanarImage(cropArea.Width, cropArea.Height, source.PixelType);
            switch (source.PixelType)
            {
                case PixelAlignmentType.I420:
                case PixelAlignmentType.YV12:
                    IntPtr dest = result.Planes[0];
                    IntPtr src = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    dest = result.Planes[1];
                    src = source.Planes[1] + cropArea.Y / 2 * source.Width / 2 + cropArea.X / 2;
                    for (int i = 0; i < cropArea.Height / 2; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width / 2);
                        dest += cropArea.Width / 2;
                        src += source.Width / 2;
                    }

                    dest = result.Planes[2];
                    src = source.Planes[2] + cropArea.Y / 2 * source.Width / 2 + cropArea.X / 2;
                    for (int i = 0; i < cropArea.Height / 2; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width / 2);
                        dest += cropArea.Width / 2;
                        src += source.Width / 2;
                    }

                    break;
                case PixelAlignmentType.NV12:
                case PixelAlignmentType.NV21:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    dest = result.Planes[1];
                    src = source.Planes[1] + cropArea.Y * source.Width / 2 + cropArea.X;
                    for (int i = 0; i < cropArea.Height / 2; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    break;

                case PixelAlignmentType.YUY2:
                case PixelAlignmentType.UYVY:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X * 2;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, source.Pitches[0]);
                        dest += result.Pitches[0];
                        src += source.Pitches[0];
                    }
                    break;

                case PixelAlignmentType.YUV:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    dest = result.Planes[1];
                    src = source.Planes[1] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    dest = result.Planes[2];
                    src = source.Planes[2] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }
                    break;

                case PixelAlignmentType.Y800:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }
                    break;

                case PixelAlignmentType.Y411:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, result.Pitches[0]);
                        dest += result.Pitches[0];
                        src += source.Pitches[0];
                    }

                    dest = result.Planes[1];
                    src = source.Planes[1] + cropArea.Y * source.Pitches[1] + cropArea.X / 4;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, result.Pitches[1]);
                        dest += result.Pitches[1];
                        src += source.Pitches[1];
                    }

                    dest = result.Planes[2];
                    src = source.Planes[2] + cropArea.Y * source.Pitches[2] + cropArea.X / 4;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, result.Pitches[2]);
                        dest += result.Pitches[2];
                        src += source.Pitches[2];
                    }
                    break;

                case PixelAlignmentType.Y410:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width);
                        dest += cropArea.Width;
                        src += source.Width;
                    }

                    dest = result.Planes[1];
                    src = source.Planes[1] + cropArea.Y / 4 * source.Width / 4 + cropArea.X / 4;
                    for (int i = 0; i < cropArea.Height / 4; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width / 4);
                        dest += cropArea.Width / 4;
                        src += source.Width / 4;
                    }

                    dest = result.Planes[2];
                    src = source.Planes[2] + cropArea.Y / 4 * source.Width / 4 + cropArea.X / 4;
                    for (int i = 0; i < cropArea.Height / 4; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width / 4);
                        dest += cropArea.Width / 4;
                        src += source.Width / 4;
                    }
                    break;

                case PixelAlignmentType.Y16:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width * 2);
                        dest += cropArea.Width * 2;
                        src += source.Width * 2;
                    }
                    break;

                case PixelAlignmentType.RGB24:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width * 3);
                        dest += cropArea.Width * 3;
                        src += source.Width * 3;
                    }
                    break;

                case PixelAlignmentType.BGRA:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width * 4);
                        dest += cropArea.Width * 4;
                        src += source.Width * 4;
                    }
                    break;

                case PixelAlignmentType.ABGR:
                    dest = result.Planes[0];
                    src = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                    for (int i = 0; i < cropArea.Height; i++)
                    {
                        RtlMoveMemory(dest, src, cropArea.Width * 4);
                        dest += cropArea.Width * 4;
                        src += source.Width * 4;
                    }
                    break;

                default:
                    throw new InvalidOperationException("Unknown pixel alignment type " + source.PixelType);
            }

            return result;
        }
        public void Render(IntPtr yBuffer, IntPtr uBuffer, IntPtr vBuffer)
        {
            PlanarImage source = null;

            switch (this.pixelType)
            {
                case PixelAlignmentType.YV12:
                case PixelAlignmentType.I420:
                    source = new PlanarImage(this.width, this.height, this.pixelType, new IntPtr[] { yBuffer, uBuffer, vBuffer });
                    break;

                case PixelAlignmentType.NV12:
                    source = new PlanarImage(this.width, this.height, this.pixelType, new IntPtr[] { yBuffer, uBuffer });
                    break;

                // 打包格式
                case PixelAlignmentType.YUY2:
                case PixelAlignmentType.UYVY:
                case PixelAlignmentType.BGRA:
                case PixelAlignmentType.ABGR:
                case PixelAlignmentType.RGB24:
                    source = new PlanarImage(this.width, this.height, this.pixelType, yBuffer, this.frameSize); 
                    break;

                default:
                    return;
            }

            PlanarImage image = this.converter.DoTheWork(source);
            this.DisplayImage(image);
        }
        public void Render(IntPtr buffer)
        {
            PlanarImage source = new PlanarImage(this.width, this.height, this.pixelType, buffer, this.frameSize);
            PlanarImage image = this.converter.DoTheWork(source);

            this.DisplayImage(image);
        }
Exemple #19
0
        public static PlanarImage Crop(PlanarImage source, Rectangle cropArea)
        {
            PlanarImage result = new PlanarImage(cropArea.Width, cropArea.Height, source.PixelType);

            switch (source.PixelType)
            {
            case PixelAlignmentType.I420:
            case PixelAlignmentType.YV12:
                IntPtr dest = result.Planes[0];
                IntPtr src  = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                dest = result.Planes[1];
                src  = source.Planes[1] + cropArea.Y / 2 * source.Width / 2 + cropArea.X / 2;
                for (int i = 0; i < cropArea.Height / 2; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width / 2);
                    dest += cropArea.Width / 2;
                    src  += source.Width / 2;
                }

                dest = result.Planes[2];
                src  = source.Planes[2] + cropArea.Y / 2 * source.Width / 2 + cropArea.X / 2;
                for (int i = 0; i < cropArea.Height / 2; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width / 2);
                    dest += cropArea.Width / 2;
                    src  += source.Width / 2;
                }

                break;

            case PixelAlignmentType.NV12:
            case PixelAlignmentType.NV21:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                dest = result.Planes[1];
                src  = source.Planes[1] + cropArea.Y * source.Width / 2 + cropArea.X;
                for (int i = 0; i < cropArea.Height / 2; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                break;

            case PixelAlignmentType.YUY2:
            case PixelAlignmentType.UYVY:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X * 2;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, source.Pitches[0]);
                    dest += result.Pitches[0];
                    src  += source.Pitches[0];
                }
                break;

            case PixelAlignmentType.YUV:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                dest = result.Planes[1];
                src  = source.Planes[1] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                dest = result.Planes[2];
                src  = source.Planes[2] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }
                break;

            case PixelAlignmentType.Y800:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }
                break;

            case PixelAlignmentType.Y411:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, result.Pitches[0]);
                    dest += result.Pitches[0];
                    src  += source.Pitches[0];
                }

                dest = result.Planes[1];
                src  = source.Planes[1] + cropArea.Y * source.Pitches[1] + cropArea.X / 4;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, result.Pitches[1]);
                    dest += result.Pitches[1];
                    src  += source.Pitches[1];
                }

                dest = result.Planes[2];
                src  = source.Planes[2] + cropArea.Y * source.Pitches[2] + cropArea.X / 4;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, result.Pitches[2]);
                    dest += result.Pitches[2];
                    src  += source.Pitches[2];
                }
                break;

            case PixelAlignmentType.Y410:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Width + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width);
                    dest += cropArea.Width;
                    src  += source.Width;
                }

                dest = result.Planes[1];
                src  = source.Planes[1] + cropArea.Y / 4 * source.Width / 4 + cropArea.X / 4;
                for (int i = 0; i < cropArea.Height / 4; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width / 4);
                    dest += cropArea.Width / 4;
                    src  += source.Width / 4;
                }

                dest = result.Planes[2];
                src  = source.Planes[2] + cropArea.Y / 4 * source.Width / 4 + cropArea.X / 4;
                for (int i = 0; i < cropArea.Height / 4; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width / 4);
                    dest += cropArea.Width / 4;
                    src  += source.Width / 4;
                }
                break;

            case PixelAlignmentType.Y16:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width * 2);
                    dest += cropArea.Width * 2;
                    src  += source.Width * 2;
                }
                break;

            case PixelAlignmentType.RGB24:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width * 3);
                    dest += cropArea.Width * 3;
                    src  += source.Width * 3;
                }
                break;

            case PixelAlignmentType.BGRA:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width * 4);
                    dest += cropArea.Width * 4;
                    src  += source.Width * 4;
                }
                break;

            case PixelAlignmentType.ABGR:
                dest = result.Planes[0];
                src  = source.Planes[0] + cropArea.Y * source.Pitches[0] + cropArea.X;
                for (int i = 0; i < cropArea.Height; i++)
                {
                    RtlMoveMemory(dest, src, cropArea.Width * 4);
                    dest += cropArea.Width * 4;
                    src  += source.Width * 4;
                }
                break;

            default:
                throw new InvalidOperationException("Unknown pixel alignment type " + source.PixelType);
            }

            return(result);
        }
        public static Bitmap ToBitmap(PlanarImage source, PixelFormat format, ColorSpace colorspace = ColorSpace.DEFAULT)
        {
            IntPtr context = SwScale.sws_getContext(source.Width, source.Height, m_pixelTypeMapper[source.PixelType],
                                             source.Width, source.Height, m_rgbMapper[format],
                                             SwScale.ConvertionFlags.SWS_BICUBIC, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);


            int* pCoef = SwScale.sws_getCoefficients(colorspace);
            int* inv_table;
            int* table;
            int srcRange, dstRange, brightness, contrast, saturation;

            int result = SwScale.sws_getColorspaceDetails(context, out inv_table, out srcRange, out table, out dstRange, out brightness, out contrast, out saturation);
            if (result != -1)
            {
                result = SwScale.sws_setColorspaceDetails(context, pCoef, srcRange, pCoef, dstRange, brightness, contrast, saturation);
            }

            Bitmap bmp = new Bitmap(source.Width, source.Height, format);
            BitmapData data = bmp.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, format);

            unsafe
            {
                pInput[0] = (byte*)data.Scan0.ToPointer();

                result = SwScale.sws_scale(context, source.PixelDataPointer, source.Pitches, 0, source.Height, pInput, new int[] { data.Stride, 0, 0, 0 });
                if (result != source.Height)
                {
                    throw new InvalidOperationException();
                }
            }

            bmp.UnlockBits(data);
            if (bmp.Palette != null && bmp.Palette.Entries != null && bmp.Palette.Entries.Length > 0)
            {
                ColorPalette cp = bmp.Palette;
                for (int i = 0; i < cp.Entries.Length; i++)
                {
                    cp.Entries[i] = Color.FromArgb(i, i, i);
                }
                bmp.Palette = cp;
            }

            SwScale.sws_freeContext(context);
            return bmp;
        }
        private void DisplayImage(PlanarImage image)
        {
            if (!this.imageSource.Dispatcher.CheckAccess())
            {
                this.imageSource.Dispatcher.Invoke((Action)(() => this.DisplayImage(image)));
                return;
            }

            this.imageSource.Lock();
            Interop.Memcpy(this.imageSource.BackBuffer, image.Planes[0], image.PlaneSizes[0]);
            this.imageSource.AddDirtyRect(this.imageSourceRect);
            this.imageSource.Unlock();
        }