/// <summary>
        /// Decompress the JPEG source image associated with this decompressor instance and output a YUV planar image to the given
        /// destination buffer. This method performs JPEG decompression but leaves out the colour conversion step, so a planar YUV
        /// image is generated instead of an RGB image.  The padding of the planes in this image is the same as in the images
        /// generated by <seealso cref="TurboJpegCompressor#EncodeYuv(byte[], int)" />.
        /// <para>
        /// NOTE: Technically, the JPEG format uses the YCbCr colourspace, but per the convention of the digital video
        /// community, the TurboJPEG API uses "YUV" to refer to an image format consisting of Y, Cb, and Cr image planes.
        /// </para>
        /// </summary>
        /// <param name="flags">The <see cref="TurboJpegFlags" /> controlling decompression.</param>
        public TurboJpegBuffer DecompressToYuv(TurboJpegFlags flags)
        {
            Contract.Requires(Enum.IsDefined(typeof(TurboJpegFlags), flags));
            Contract.Ensures(Contract.Result <TurboJpegBuffer>()
                             .BufferSize > 0,
                             "output buffer must have non-zero size");

            Contract.Assume(this.jpegBuffer != null, "No JPEG image is associated with this instance");

            var bufferSize = NativeMethods.bufSizeYUV(this.jpegWidth, 4, this.jpegHeight, this.jpegSubsampling);

            using (var buffer = new TurboJpegSafeHandle(NativeMethods.alloc(bufferSize)))
            {
                var ptr = buffer.DangerousGetHandle();
                if (NativeMethods.decompressToYUV(this.Handle,
                                                  this.jpegBuffer,
                                                  this.jpegBuffer.Length,
                                                  ref ptr,
                                                  this.jpegWidth,
                                                  4,
                                                  this.jpegHeight,
                                                  flags) != 0)
                {
                    throw new Exception(TurboJpegInterop.GetLastError());
                }

                // we now have the result in a buffer on the unmanaged heap.
                return(new TurboJpegBuffer(ptr, bufferSize));
            }
        }
        /// <summary>
        /// Decompress the JPEG source image associated with this decompressor instance and output a decompressed image to
        /// the given destination buffer.
        /// </summary>
        /// <param name="desiredWidth">The desired width (in pixels) of the decompressed image.  If the desired image
        /// dimensions are different than the dimensions of the JPEG image being decompressed, then TurboJPEG will use
        /// scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired
        /// dimensions. Setting this to 0 is the same as setting it to the width of the JPEG image; in other words the
        /// width will not be considered when determining the scaled image size).
        /// </param>
        /// <param name="pitch">The number of bytes per line of the destination image.  Normally, this should be set to
        /// <code>scaledWidth * <see cref="TurboJpegUtilities.GetPixelSize" />(pixelFormat)</code> if the decompressed
        /// image is unpadded, but you can use this to, for instance, pad each line of the decompressed image to a
        /// 4-byte boundary or to decompress the JPEG image into a region of a larger image. NOTE: <code>scaledWidth</code>
        /// can be determined by calling
        /// <code>scalingFactor.<seealso cref="TurboJpegScalingFactor#getScaled getScaled" />(jpegWidth)</code> or by
        /// calling <seealso cref="GetScaledWidth" />. Setting this parameter to 0 is the equivalent of setting it to
        /// <code>scaledWidth * <see cref="TurboJpegUtilities.GetPixelSize" />(pixelFormat)</code>.</param>
        /// <param name="desiredHeight">
        /// The desired Height (in pixels) of the decompressed image (or image region.)  If the desired
        /// image dimensions are different than the dimensions of the JPEG image being decompressed, then TurboJPEG will use
        /// scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired dimensions.
        /// Setting this to 0 is the same as setting it to the Height of the JPEG image (in other words, the Height will not be
        /// considered when determining the scaled image size.)
        /// </param>
        /// <param name="pixelFormat">
        /// pixel format of the decompressed/decoded image (one of
        /// <seealso cref="TurboJpegUtilities#Rgb TurboJpegUtilities.PF_*" />)
        /// </param>
        /// <param name="flags">
        /// the bitwise OR of one or more of
        /// <seealso cref="TurboJpegUtilities#BottomUp TurboJpegUtilities.FLAG_*" />
        /// </param>
        public TurboJpegBuffer Decompress(int desiredWidth,
                                          int pitch,
                                          int desiredHeight,
                                          PixelFormat pixelFormat,
                                          TurboJpegFlags flags)
        {
            Contract.Requires(desiredWidth >= 0, "desiredWidth must be non-negative");
            Contract.Requires(desiredHeight >= 0, "desiredHeight must be non-negative");
            Contract.Requires(pitch >= 0, "pitch must be non-negative");
            Contract.Requires(Enum.IsDefined(typeof(TurboJpegFlags), flags));
            Contract.Ensures(Contract.Result <TurboJpegBuffer>()
                             .BufferSize > 0,
                             "output buffer must have non-zero size");

            Contract.Assume(this.jpegBuffer != null, "No JPEG image is associated with this instance");

            var pixelSize    = TurboJpegUtilities.GetPixelSize(pixelFormat);
            var scaledWidth  = this.GetScaledWidth(desiredWidth, desiredHeight);
            var scaledHeight = this.GetScaledHeight(desiredWidth, desiredHeight);

            if (pitch == 0)
            {
                pitch = scaledWidth * pixelSize;
            }

            var bufferSize = pitch * scaledHeight;

            // having allocated memory with the libjpeg-turbo allocator, we must ensure that we release it with the
            // matching deallocator lest Bad Things happen. Unlike compress, where the initial buffer size is a best
            // guess, we know the dimensions of the uncompressed image and the number of bits per pixel and so sizing
            // it appropriately is trivial and the buffer will never be reallocated
            using (var buffer = new TurboJpegSafeHandle(NativeMethods.alloc(bufferSize)))
            {
                var ptr = buffer.DangerousGetHandle();
                if (NativeMethods.decompress(this.Handle,
                                             this.jpegBuffer,
                                             this.jpegBuffer.Length,
                                             ptr,
                                             desiredWidth,
                                             pitch,
                                             desiredHeight,
                                             pixelFormat,
                                             flags) != 0)
                {
                    throw new Exception(TurboJpegInterop.GetLastError());
                }

                // we now have the result in a buffer on the unmanaged heap.
                return(new TurboJpegBuffer(ptr, bufferSize));
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TurboJpegBase"/> class.
        /// </summary>
        /// <param name="turboJpegHandle">The TurboJPEG handle.</param>
        protected TurboJpegBase(IntPtr turboJpegHandle)
        {
            Contract.Requires(turboJpegHandle != null);

            this.turboJpegObject = new TurboJpegSafeHandle(turboJpegHandle);
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TurboJpegBase"/> class.
        /// </summary>
        /// <param name="turboJpegHandle">The TurboJPEG handle.</param>
        protected TurboJpegBase(IntPtr turboJpegHandle)
        {
            Contract.Requires(turboJpegHandle != null);

            this.turboJpegObject = new TurboJpegSafeHandle(turboJpegHandle);
        }
        /// <summary>
        /// Decompress the JPEG source image associated with this decompressor instance and output a YUV planar image to the given
        /// destination buffer. This method performs JPEG decompression but leaves out the colour conversion step, so a planar YUV
        /// image is generated instead of an RGB image.  The padding of the planes in this image is the same as in the images
        /// generated by <seealso cref="TurboJpegCompressor#EncodeYuv(byte[], int)" />.
        /// <para>
        /// NOTE: Technically, the JPEG format uses the YCbCr colourspace, but per the convention of the digital video
        /// community, the TurboJPEG API uses "YUV" to refer to an image format consisting of Y, Cb, and Cr image planes.
        /// </para>
        /// </summary>
        /// <param name="flags">The <see cref="TurboJpegFlags" /> controlling decompression.</param>
        public TurboJpegBuffer DecompressToYuv(TurboJpegFlags flags)
        {
            Contract.Requires(Enum.IsDefined(typeof(TurboJpegFlags), flags));
            Contract.Ensures(Contract.Result<TurboJpegBuffer>()
                                 .BufferSize > 0,
                             "output buffer must have non-zero size");

            Contract.Assume(this.jpegBuffer != null, "No JPEG image is associated with this instance");

            var bufferSize = NativeMethods.bufSizeYUV(this.jpegWidth, 4, this.jpegHeight, this.jpegSubsampling);
            using(var buffer = new TurboJpegSafeHandle(NativeMethods.alloc(bufferSize)))
            {
                var ptr = buffer.DangerousGetHandle();
                if (NativeMethods.decompressToYUV(this.Handle,
                                                     this.jpegBuffer,
                                                     this.jpegBuffer.Length,
                                                     ref ptr,
                                                     this.jpegWidth,
                                                     4,
                                                     this.jpegHeight,
                                                     flags) != 0)
                {
                    throw new Exception(TurboJpegInterop.GetLastError());
                }

                // we now have the result in a buffer on the unmanaged heap. 
                return new TurboJpegBuffer(ptr, bufferSize);
            }
        }
        /// <summary>
        /// Decompress the JPEG source image associated with this decompressor instance and output a decompressed image to
        /// the given destination buffer.
        /// </summary>
        /// <param name="desiredWidth">The desired width (in pixels) of the decompressed image.  If the desired image
        /// dimensions are different than the dimensions of the JPEG image being decompressed, then TurboJPEG will use
        /// scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired
        /// dimensions. Setting this to 0 is the same as setting it to the width of the JPEG image; in other words the
        /// width will not be considered when determining the scaled image size).
        /// </param>
        /// <param name="pitch">The number of bytes per line of the destination image.  Normally, this should be set to
        /// <code>scaledWidth * <see cref="TurboJpegUtilities.GetPixelSize" />(pixelFormat)</code> if the decompressed
        /// image is unpadded, but you can use this to, for instance, pad each line of the decompressed image to a
        /// 4-byte boundary or to decompress the JPEG image into a region of a larger image. NOTE: <code>scaledWidth</code>
        /// can be determined by calling
        /// <code>scalingFactor.<seealso cref="TurboJpegScalingFactor#getScaled getScaled" />(jpegWidth)</code> or by
        /// calling <seealso cref="GetScaledWidth" />. Setting this parameter to 0 is the equivalent of setting it to
        /// <code>scaledWidth * <see cref="TurboJpegUtilities.GetPixelSize" />(pixelFormat)</code>.</param>
        /// <param name="desiredHeight">
        /// The desired Height (in pixels) of the decompressed image (or image region.)  If the desired
        /// image dimensions are different than the dimensions of the JPEG image being decompressed, then TurboJPEG will use
        /// scaling in the JPEG decompressor to generate the largest possible image that will fit within the desired dimensions.
        /// Setting this to 0 is the same as setting it to the Height of the JPEG image (in other words, the Height will not be
        /// considered when determining the scaled image size.)
        /// </param>
        /// <param name="pixelFormat">
        /// pixel format of the decompressed/decoded image (one of
        /// <seealso cref="TurboJpegUtilities#Rgb TurboJpegUtilities.PF_*" />)
        /// </param>
        /// <param name="flags">
        /// the bitwise OR of one or more of
        /// <seealso cref="TurboJpegUtilities#BottomUp TurboJpegUtilities.FLAG_*" />
        /// </param>
        public TurboJpegBuffer Decompress(int desiredWidth,
                                          int pitch,
                                          int desiredHeight,
                                          PixelFormat pixelFormat,
                                          TurboJpegFlags flags)
        {
            Contract.Requires(desiredWidth >= 0, "desiredWidth must be non-negative");
            Contract.Requires(desiredHeight >= 0, "desiredHeight must be non-negative");
            Contract.Requires(pitch >= 0, "pitch must be non-negative");
            Contract.Requires(Enum.IsDefined(typeof(TurboJpegFlags), flags));
            Contract.Ensures(Contract.Result<TurboJpegBuffer>()
                                 .BufferSize > 0,
                             "output buffer must have non-zero size");

            Contract.Assume(this.jpegBuffer != null, "No JPEG image is associated with this instance");

            var pixelSize = TurboJpegUtilities.GetPixelSize(pixelFormat);
            var scaledWidth = this.GetScaledWidth(desiredWidth, desiredHeight);
            var scaledHeight = this.GetScaledHeight(desiredWidth, desiredHeight);
            if (pitch == 0)
            {
                pitch = scaledWidth * pixelSize;
            }

            var bufferSize = pitch * scaledHeight;

            // having allocated memory with the libjpeg-turbo allocator, we must ensure that we release it with the 
            // matching deallocator lest Bad Things happen. Unlike compress, where the initial buffer size is a best 
            // guess, we know the dimensions of the uncompressed image and the number of bits per pixel and so sizing 
            // it appropriately is trivial and the buffer will never be reallocated
            using(var buffer = new TurboJpegSafeHandle(NativeMethods.alloc(bufferSize)))
            {
                var ptr = buffer.DangerousGetHandle();
                if (NativeMethods.decompress(this.Handle,
                                                this.jpegBuffer,
                                                this.jpegBuffer.Length,
                                                ptr,
                                                desiredWidth,
                                                pitch,
                                                desiredHeight,
                                                pixelFormat,
                                                flags) != 0)
                {
                    throw new Exception(TurboJpegInterop.GetLastError());
                }

                // we now have the result in a buffer on the unmanaged heap. 
                return new TurboJpegBuffer(ptr, bufferSize);
            }
        }