/// <summary>
        /// Losslessly transform the JPEG image associated with this transformer instance into one or more JPEG images
        /// stored in the given destination buffers. Lossless transforms work by moving the raw coefficients from one
        /// JPEG image structure to another without altering the values of the coefficients. While this is typically
        /// faster than decompressing the image, transforming it, and re-compressing it, lossless transforms are not
        /// free. Each lossless transform requires reading and performing Huffman decoding on all of the coefficients
        /// in the source image, regardless of the size of the destination image, thus this method provides a means of
        /// generating multiple transformed images from the same source or of applying multiple transformations
        /// simultaneously, in order to eliminate the need to read the source coefficients multiple times.
        /// </summary>
        /// <param name="destBuffers">
        /// An array of image buffers. <paramref name="destBuffers" />[i] will receive a JPEG image that has been
        /// transformed using the parameters in <paramref name="transforms" />[i].  Use
        /// <see cref="NativeMethods.bufSize" /> to determine the maximum size for each buffer based on the
        /// transformed or cropped width and height and the chroma subsampling used in the source image.
        /// </param>
        /// <param name="transforms">An array of <seealso cref="TurboJpegTransform" /> instances, each of which
        /// specifies the transform parameters and/or cropping region for the corresponding transformed output image.
        /// </param>
        /// <param name="options">The flags to use for the transforms.</param>
        public void Transform(byte[][] destBuffers, TurboJpegTransform[] transforms, TurboJpegFlags options)
        {
            Contract.Requires(destBuffers != null);
            Contract.Requires(transforms != null);
            Contract.Requires(transforms.Length == destBuffers.Length);
            Contract.Requires(Enum.IsDefined(typeof(TransformOptions), options));
            Contract.Ensures(Contract.ForAll(destBuffers, _ => _ != null));

            Contract.Assume(this.JpegBuffer != null, "JPEG buffer not initialized");

            var count = destBuffers.Length;
            var destBufferPtrs = new IntPtr[count];
            this.transformedSizes = new int[count];

            if (NativeMethods.transform(this.Handle,
                                        this.JpegBuffer,
                                        this.JpegSize,
                                        count,
                                        ref destBufferPtrs,
                                        ref this.transformedSizes,
                                        transforms,
                                        options) != 0)
            {
                throw new Exception(TurboJpegInterop.GetLastError());
            }

            // we now have the result in buffers on the unmanaged heap
            for (var i = 0; i < count; ++i)
            {
                destBuffers[i] = new byte[this.transformedSizes[i]];
                Marshal.Copy(destBufferPtrs[i], destBuffers[i], 0, this.transformedSizes[i]);
            }
        }
        /// <summary>
        /// Losslessly transform the JPEG image associated with this transformer instance and return an array of
        /// <seealso cref="TurboJpegDecompressor" /> instances, each of which has a transformed JPEG image associated
        /// with it.
        /// </summary>
        /// <param name="transforms">An array of <see cref="TurboJpegTransform" /> instances, each of which specifies
        /// the transform parameters and/or cropping region for the corresponding transformed output image.</param>
        /// <param name="flags">The flags to use when transforming.</param>
        /// <param name="preallocateBuffers">If set to <c>true</c>, preallocate buffers.</param>
        /// <returns>
        /// An array of <seealso cref="TurboJpegDecompressor" /> instances, each of which has a transformed
        /// JPEG image associated with it.
        /// </returns>
        public TurboJpegDecompressor[] Transform(TurboJpegTransform[] transforms, TurboJpegFlags flags, bool preallocateBuffers)
        {
            Contract.Requires(transforms != null);
            Contract.Requires(Enum.IsDefined(typeof(TransformOptions), flags));
            Contract.Ensures(Contract.Result<TurboJpegDecompressor[]>() != null);
            Contract.Ensures(Contract.Result<TurboJpegDecompressor[]>().Length == transforms.Length);
            Contract.Ensures(Contract.ForAll(Contract.Result<TurboJpegDecompressor[]>(), _ => _ != null));

            var count = transforms.Length;
            var destinationBuffers = new byte[count][];
            Contract.Assume(this.Width > 0, "JPEG buffer not initialized");
            Contract.Assume(this.Height > 0, "JPEG buffer not initialized");

            var decompressors = new TurboJpegDecompressor[count];

            if (preallocateBuffers)
            {
                for (var i = 0; i < count; i++)
                {
                    var width = this.Width;
                    var height = this.Height;
                    if ((transforms[i].Options & TransformOptions.Crop) != 0)
                    {
                        if (transforms[i].Width != 0)
                        {
                            width = transforms[i].Width;
                        }

                        if (transforms[i].Height != 0)
                        {
                            height = transforms[i].Height;
                        }
                    }

                    destinationBuffers[i] = new byte[NativeMethods.bufSize(width, height, this.Subsampling)];
                }

                this.Transform(destinationBuffers, transforms, flags);
                for (var i = 0; i < count; i++)
                {
                    decompressors[i] = new TurboJpegDecompressor(destinationBuffers[i]);
                }
            }
            else
            {
                var destBufferPtrs = new IntPtr[count];
                this.transformedSizes = new int[count];

                if (NativeMethods.transform(this.Handle,
                                            this.JpegBuffer,
                                            this.JpegSize,
                                            count,
                                            ref destBufferPtrs,
                                            ref this.transformedSizes,
                                            transforms,
                                            flags) != 0)
                {
                    throw new Exception(TurboJpegInterop.GetLastError());
                }

                // we now have the result in buffers on the unmanaged heap
                for (var i = 0; i < count; ++i)
                {
                    decompressors[i] = new TurboJpegDecompressor();
                    decompressors[i].SetJpegImage(destBufferPtrs[i]);
                }
            }

            return decompressors;
        }
 internal static extern int transform(IntPtr handle,
                                      byte[] sourceBuffer,
                                      int sourceSize,
                                      int count,
                                      ref IntPtr[] destinationBuffers,
                                      ref int[] sizes,
                                      TurboJpegTransform[] transforms,
                                      [MarshalAs(UnmanagedType.I4)] TurboJpegFlags flags);