Esempio n. 1
0
        /// <summary>
        /// Compresses the specified image passed in the source pixel buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <returns>An arraySegment with a reference to the byte array with the compressed data in the JPEG-LS format.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height contains an invalid value.</exception>
        /// <exception cref="InvalidDataException">The compressed output doesn't fit into the maximum defined output buffer.</exception>
        public static ArraySegment <byte> Compress(JpegLSMetadataInfo info, byte[] pixels, bool jfifHeader = false)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }
            if (info.Width <= 0 || info.Width > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Width property needs to be in the range <0, 65535>");
            }
            if (info.Height <= 0 || info.Height > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Height property needs to be in the range <0, 65535>");
            }
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }
            Contract.EndContractBlock();

            var pixelCount = pixels.Length;

            Contract.Assume(pixelCount > 0 && pixelCount <= pixels.Length);
            return(Compress(info, pixels, pixelCount, jfifHeader));
        }
Esempio n. 2
0
        /// <summary>
        /// Compresses the specified image passed in the source pixel buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="pixelCount">The number of pixel in the pixel array.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <returns>An arraySegment with a reference to the byte array with the compressed data in the JPEG-LS format.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height -or- pixelCount contains an invalid value.</exception>
        /// <exception cref="InvalidDataException">The compressed output doesn't fit into the maximum defined output buffer.</exception>
        public static ArraySegment <byte> Compress(JpegLSMetadataInfo info, byte[] pixels, int pixelCount, bool jfifHeader = false)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }
            if (pixelCount <= 0 || pixelCount > pixels.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(pixelCount), "pixelCount <= 0 || pixelCount > pixels.Length");
            }

            const int JpegLSHeaderLength = 100;

            // Assume compressed size <= uncompressed size (covers 99% of the cases).
            var buffer = new byte[pixels.Length + JpegLSHeaderLength];

            if (!TryCompress(info, pixels, pixels.Length, jfifHeader, buffer, buffer.Length, out var compressedCount))
            {
                // Increase output buffer to hold compressed data.
                buffer = new byte[(int)(pixels.Length * 1.5) + JpegLSHeaderLength];

                if (!TryCompress(info, pixels, pixels.Length, jfifHeader, buffer, buffer.Length, out compressedCount))
                {
                    throw new InvalidDataException("Compression failed: compressed output larger then 1.5 * input.");
                }
            }

            return(new ArraySegment <byte>(buffer, 0, compressedCount));
        }
Esempio n. 3
0
        private static PixelFormat GetPixelFormat(JpegLSMetadataInfo info)
        {
            switch (info.ComponentCount)
            {
            case 1:
                if (info.BitsPerComponent == 8)
                {
                    return(PixelFormats.Gray8);
                }

                break;

            case 3:
                if (info.BitsPerComponent == 8)
                {
                    return(PixelFormats.Rgb24);
                }

                break;

            default:
                throw new NotSupportedException();
            }

            throw new NotSupportedException();
        }
Esempio n. 4
0
        // Design notes:
        //  - The words compress/decompress are used as these are the terms used by the .NET BCLs (System.IO.Compression namespace)
        //    The CharLS C API uses the terms encode/decode.
        //  - The input/output buffers parameters are using the common .NET order, which is different the CharLS C API.

        /// <summary>
        /// Compresses the specified image passed in the source pixel buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <returns>An arraySegment with a reference to the byte array with the compressed data in the JPEG-LS format.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height contains an invalid value.</exception>
        /// <exception cref="InvalidDataException">The compressed output doesn't fit into the maximum defined output buffer.</exception>
        public static ArraySegment <byte> Compress(JpegLSMetadataInfo info, byte[] pixels, bool jfifHeader = false)
        {
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }

            var pixelCount = pixels.Length;

            return(Compress(info, pixels, pixelCount, jfifHeader));
        }
Esempio n. 5
0
        /// <summary>
        /// Tries the compress the array with pixels into the provided buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="pixelCount">The number of pixel in the pixel array.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <param name="destination">The destination buffer that will hold the JPEG-LS compressed (encoded) bit stream.</param>
        /// <param name="destinationLength">Length of the destination buffer that can be used (can be less then the length of the destination array).</param>
        /// <param name="compressedCount">The number of bytes that have been compressed (encoded) into the destination array.</param>
        /// <returns><c>true</c> when the compressed bit stream fits into the destination array, otherwise <c>false</c>.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height -or- pixelCount -or- destinationLength contains an invalid value.</exception>
        public static bool TryCompress(JpegLSMetadataInfo info, byte[] pixels, int pixelCount, bool jfifHeader, byte[] destination, int destinationLength, out int compressedCount)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }
            if (pixelCount <= 0 || pixelCount > pixels.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(pixelCount), "pixelCount <= 0 || pixelCount > pixels.Length");
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
            if (destinationLength <= 0 || destinationLength > destination.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationLength), "destination <= 0 || destinationCount > destination.Length");
            }

            var parameters = default(JlsParameters);

            info.CopyTo(ref parameters);
            if (jfifHeader)
            {
                parameters.Jfif.Version  = (1 << 8) + 2; // JFIF version 1.02
                parameters.Jfif.Units    = 0;            // No units, aspect ratio only specified
                parameters.Jfif.DensityX = 1;            // use standard 1:1 aspect ratio. (density should always be set to non-zero values).
                parameters.Jfif.DensityY = 1;
            }

            JpegLSError result;

            if (Environment.Is64BitProcess)
            {
                result          = SafeNativeMethods.JpegLsEncodeX64(destination, destinationLength, out var count, pixels, pixelCount, ref parameters, IntPtr.Zero);
                compressedCount = (int)count;
            }
            else
            {
                result = SafeNativeMethods.JpegLsEncodeX86(destination, destinationLength, out compressedCount, pixels, pixelCount, ref parameters, IntPtr.Zero);
            }

            if (result == JpegLSError.SourceBufferTooSmall)
            {
                return(false);
            }

            HandleResult(result);
            return(true);
        }
Esempio n. 6
0
        /// <summary>
        /// Compresses the specified image passed in the source pixel buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="pixelCount">The number of pixel in the pixel array.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <returns>An arraySegment with a reference to the byte array with the compressed data in the JPEG-LS format.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height -or- pixelCount contains an invalid value.</exception>
        /// <exception cref="InvalidDataException">The compressed output doesn't fit into the maximum defined output buffer.</exception>
        public static ArraySegment <byte> Compress(JpegLSMetadataInfo info, byte[] pixels, int pixelCount, bool jfifHeader)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }
            if (info.Width <= 0 || info.Width > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Width property needs to be in the range <0, 65535>");
            }
            if (info.Height <= 0 || info.Height > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Height property needs to be in the range <0, 65535>");
            }
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }
            if (pixelCount <= 0 || pixelCount > pixels.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(pixelCount), "pixelCount <= 0 || pixelCount > pixels.Length");
            }
            Contract.EndContractBlock();

            const int JpegLSHeaderLength = 100;

            // Assume compressed size <= uncompressed size (covers 99% of the cases).
            var buffer = new byte[pixels.Length + JpegLSHeaderLength];
            int compressedCount;

            if (!TryCompress(info, pixels, pixels.Length, jfifHeader, buffer, buffer.Length, out compressedCount))
            {
                // Increase output buffer to hold compressed data.
                buffer = new byte[(int)(pixels.Length * 1.5) + JpegLSHeaderLength];

                Contract.Assume(info.Width <= 65535);
                Contract.Assume(info.Height <= 65535);
                if (!TryCompress(info, pixels, pixels.Length, jfifHeader, buffer, buffer.Length, out compressedCount))
                {
                    throw new InvalidDataException("Compression failed: compressed output larger then 1.5 * input.");
                }
            }

            Contract.Assume(buffer.Length >= compressedCount);
            return(new ArraySegment <byte>(buffer, 0, compressedCount));
        }
Esempio n. 7
0
        /// <summary>
        /// Tries the compress the array with pixels into the provided buffer.
        /// </summary>
        /// <param name="info">The meta info that describes the format and type of the pixels.</param>
        /// <param name="pixels">An array of bytes that represents the content of a bitmap image.</param>
        /// <param name="pixelCount">The number of pixel in the pixel array.</param>
        /// <param name="jfifHeader">if set to <c>true</c> a JFIF header will be added to the encoded byte stream.</param>
        /// <param name="destination">The destination buffer that will hold the JPEG-LS compressed (encoded) bit stream.</param>
        /// <param name="destinationLength">Length of the destination buffer that can be used (can be less then the length of the destination array).</param>
        /// <param name="compressedCount">The number of bytes that have been compressed (encoded) into the destination array.</param>
        /// <returns><c>true</c> when the compressed bit stream fits into the destination array, otherwise <c>false</c>.</returns>
        /// <exception cref="ArgumentNullException">info -or- pixels is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">info.Width -or- info.Height -or- pixelCount -or- destinationLength contains an invalid value.</exception>
        public static bool TryCompress(JpegLSMetadataInfo info, byte[] pixels, int pixelCount, bool jfifHeader, byte[] destination, int destinationLength, out int compressedCount)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }
            if (info.Width <= 0 || info.Width > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Width property needs to be in the range <0, 65535>");
            }
            if (info.Height <= 0 || info.Height > 65535)
            {
                throw new ArgumentOutOfRangeException(nameof(info), "info.Height property needs to be in the range <0, 65535>");
            }
            if (pixels == null)
            {
                throw new ArgumentNullException(nameof(pixels));
            }
            if (pixelCount <= 0 || pixelCount > pixels.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(pixelCount), "pixelCount <= 0 || pixelCount > pixels.Length");
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
            if (destinationLength <= 0 || destinationLength > destination.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationLength), "destination <= 0 || destinationCount > destination.Length");
            }
            Contract.Ensures(Contract.ValueAtReturn(out compressedCount) >= 0);

            var parameters = default(JlsParameters);

            info.CopyTo(ref parameters);
            if (jfifHeader)
            {
                parameters.Jfif.Version  = (1 << 8) + 2; // JFIF version 1.02
                parameters.Jfif.Units    = 0;            // No units, aspect ratio only specified
                parameters.Jfif.DensityX = 1;            // use standard 1:1 aspect ratio. (density should always be set to non-zero values).
                parameters.Jfif.DensityY = 1;
            }

            var         errorMessage = new StringBuilder(256);
            JpegLSError result;

            if (Is64BitProcess)
            {
                long count;
                result          = SafeNativeMethods.JpegLsEncode64(destination, destinationLength, out count, pixels, pixelCount, ref parameters, errorMessage);
                compressedCount = (int)count;
            }
            else
            {
                result = SafeNativeMethods.JpegLsEncode(destination, destinationLength, out compressedCount, pixels, pixelCount, ref parameters, errorMessage);
            }

            Contract.Assume(compressedCount >= 0);

            if (result == JpegLSError.CompressedBufferTooSmall)
            {
                return(false);
            }

            HandleResult(result, errorMessage);
            return(true);
        }