/// <summary>Transforms input image into one or several destinations</summary>
        /// <param name="jpegBuf">Pointer to a buffer containing the JPEG image to decompress. This buffer is not modified</param>
        /// <param name="jpegBufSize">Size of the JPEG image (in bytes)</param>
        /// <param name="transforms">Array of transform descriptions to be applied to the source image </param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags"</param>
        /// <returns>Array of transformed jpeg images</returns>
        /// <exception cref="ArgumentNullException"><paramref name="transforms"/> is <see langword="null" />.</exception>
        /// <exception cref="ArgumentException">Transforms can not be empty</exception>
        /// <exception cref="TJException"> Throws if low level turbo jpeg function fails </exception>
        public byte[][] Transform(IntPtr jpegBuf, ulong jpegBufSize, TJTransformDescription[] transforms, TJFlags flags)
        {
            if (transforms == null)
                throw new ArgumentNullException("transforms");
            if (transforms.Length == 0)
                throw new ArgumentException("Transforms can not be empty", "transforms");

            // ReSharper disable once ExceptionNotDocumented
            var count = transforms.Length;
            var destBufs = new IntPtr[count];
            var destSizes = new ulong[count];


            int subsampl;
            int colorspace;
            int width;
            int height;
            var funcResult = TurboJpegImport.tjDecompressHeader(_transformHandle, jpegBuf, jpegBufSize,
                out width, out height, out subsampl, out colorspace);

            if (funcResult == -1)
            {
                TJUtils.GetErrorAndThrow();
            }

            Size mcuSize;
            if (!TurboJpegImport.MCUSizes.TryGetValue((TJSubsamplingOptions)subsampl, out mcuSize))
            {
                throw new TJException("Unable to read Subsampling Options from jpeg header");
            }



            var tjTransforms = new tjtransform[count];
            for (var i = 0; i < count; i++)
            {
                var x = CorrectRegionCoordinate(transforms[i].Region.X, mcuSize.Width);
                var y = CorrectRegionCoordinate(transforms[i].Region.Y, mcuSize.Height);
                var w = CorrectRegionSize(transforms[i].Region.X, x, transforms[i].Region.W, width);
                var h = CorrectRegionSize(transforms[i].Region.Y, y, transforms[i].Region.H, height);


                tjTransforms[i] = new tjtransform
                {
                    op = (int)transforms[i].Operation,
                    options = (int)transforms[i].Options,
                    r = new TJRegion
                    {
                        X = x,
                        Y = y,
                        W = w,
                        H = h
                    },
                    data = transforms[i].CallbackData,
                    customFilter = transforms[i].CustomFilter
                };
            }
            var transformsPtr =  TJUtils.StructArrayToIntPtr(tjTransforms);
            try
            {
                funcResult = TurboJpegImport.tjTransform(_transformHandle, jpegBuf, jpegBufSize, count, destBufs,
                    destSizes, transformsPtr, (int)flags);
                if (funcResult == -1)
                {
                    TJUtils.GetErrorAndThrow();
                }

                var result = new List<byte[]>();
                for (var i = 0; i < destBufs.Length; i++)
                {
                    var ptr = destBufs[i];
                    var size = destSizes[i];
                    var item = new byte[size];
                    Marshal.Copy(ptr, item, 0, (int)size);
                    result.Add(item);

                    TurboJpegImport.tjFree(ptr);
                }
                return result.ToArray();

            }
            finally
            {
                TJUtils.FreePtr(transformsPtr);
            }
        }
        /// <summary>Transforms input image into one or several destinations</summary>
        /// <param name="jpegBuf">A buffer containing the JPEG image to decompress. This buffer is not modified</param>
        /// <param name="transforms">Array of transform descriptions to be applied to the source image </param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags"</param>
        /// <returns>Array of transformed jpeg images</returns>
        /// <exception cref="ArgumentNullException"><paramref name="transforms"/> is <see langword="null" />.</exception>
        /// <exception cref="ArgumentException">Transforms can not be empty</exception>
        /// <exception cref="TJException"> Throws if low level turbo jpeg function fails </exception>
        public unsafe byte[][] Transform(byte[] jpegBuf, TJTransformDescription[] transforms, TJFlags flags)
        {
            if (transforms == null)
                throw new ArgumentNullException("transforms");
            if (transforms.Length == 0)
                throw new ArgumentException("Transforms can not be empty", "transforms");

            fixed (byte* jpegPtr = jpegBuf)
            {
                return Transform((IntPtr)jpegPtr, (ulong)jpegBuf.Length, transforms, flags);
            }
        }