Example #1
0
        /// <summary>
        /// Decompress a JPEG image.
        /// </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="destPixelFormat">Pixel format of the destination image (see <see cref="SKColorType"/> "Pixel formats".)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags".</param>
        /// <returns>Decompressed image of specified format.</returns>
        /// <exception cref="TJException">Throws if underlying decompress function failed.</exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore.</exception>
        /// <exception cref="NotSupportedException">Convertion to the requested pixel format can not be performed.</exception>
        public static SKBitmap Decompress(this TJDecompressor @this, IntPtr jpegBuf, ulong jpegBufSize, SKColorType destPixelFormat, TJFlags flags)
        {
            _ = @this ?? throw new ArgumentNullException(nameof(@this));

            var targetFormat = TJSkiaUtils.ConvertPixelFormat(destPixelFormat);

            @this.GetImageInfo(jpegBuf, jpegBufSize, targetFormat, out var width, out var height, out var stride, out var outBufSize);

            var info = new SKImageInfo(width, height, destPixelFormat);

            if (info.RowBytes != stride)
            {
                throw new NotSupportedException($"Skia expected the RowBytes/stride to be {info.RowBytes} for the given parameters but MozJPEG returns {stride}. Those values need to be equal.");
            }
            if (info.BytesSize != outBufSize)
            {
                throw new NotSupportedException($"Skia expected the BytesSize/number of bytes required to store the bitmap data to be {info.BytesSize} for the given parameters but MozJPEG returns {outBufSize}. Those values need to be equal.");
            }

            var dst    = new SKBitmap(info);
            var dstPtr = dst.GetPixels();

            @this.Decompress(jpegBuf, jpegBufSize, dstPtr, outBufSize, targetFormat, flags, out _, out _, out _);
            return(dst);
        }
Example #2
0
        /// <summary>
        /// Decompress a JPEG image to an RGB, grayscale, or CMYK image.
        /// </summary>
        /// <param name="jpegBuf">A buffer containing the JPEG image to decompress. This buffer is not modified.</param>
        /// <param name="destPixelFormat">Pixel format of the destination image (see <see cref="PixelFormat"/> "Pixel formats".)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags".</param>
        /// <returns>Decompressed image of specified format.</returns>
        /// <exception cref="TJException">Throws if underlying decompress function failed.</exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore.</exception>
        /// <exception cref="NotSupportedException">Convertion to the requested pixel format can not be performed.</exception>
        public static unsafe Bitmap Decompress(this TJDecompressor @this, byte[] jpegBuf, PixelFormat destPixelFormat, TJFlags flags)
        {
            var jpegBufSize = (ulong)jpegBuf.Length;

            fixed(byte *jpegPtr = jpegBuf)
            {
                return(@this.Decompress((IntPtr)jpegPtr, jpegBufSize, destPixelFormat, flags));
            }
        }
Example #3
0
        public static byte[] Recompress(
            ReadOnlySpan <byte> jpegBytes,
            int quality = 70,
            TJSubsamplingOption subsampling = TJSubsamplingOption.Chrominance420,
            TJFlags flags = TJFlags.None)
        {
            var pixelFormat = TJPixelFormat.BGRA;

            using var decr = new TJDecompressor();
            var raw = decr.Decompress(jpegBytes, pixelFormat, flags, out var width, out var height, out var stride);

            decr.Dispose();

            using var compr = new TJCompressor();
            var compressed = compr.Compress(raw, stride, width, height, pixelFormat, subsampling, quality, flags);

            return(compressed);
        }
Example #4
0
        /// <summary>
        /// Decompress a JPEG image.
        /// </summary>
        /// <param name="jpegBuf">A buffer containing the JPEG image to decompress. This buffer is not modified.</param>
        /// <param name="destPixelFormat">Pixel format of the destination image (see <see cref="SKColorType"/> "Pixel formats".)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags".</param>
        /// <returns>Decompressed image of specified format.</returns>
        /// <exception cref="TJException">Throws if underlying decompress function failed.</exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore.</exception>
        /// <exception cref="NotSupportedException">Convertion to the requested pixel format can not be performed.</exception>
        public static SKBitmap Decompress(this TJDecompressor @this, ReadOnlySpan <byte> jpegBuf, SKColorType destPixelFormat, TJFlags flags)
        {
            _ = @this ?? throw new ArgumentNullException(nameof(@this));

            // see https://stackoverflow.com/questions/537573/how-to-get-intptr-from-byte-in-c-sharp
            var pinnedArray = GCHandle.Alloc(jpegBuf.GetPinnableReference(), GCHandleType.Pinned);

            try
            {
                IntPtr pointer     = pinnedArray.AddrOfPinnedObject();
                var    jpegBufSize = (ulong)jpegBuf.Length;
                return(@this.Decompress(pointer, jpegBufSize, destPixelFormat, flags));
            }
            finally
            {
                pinnedArray.Free();
            }
        }
Example #5
0
        /// <summary>
        /// Decompress a JPEG image to an RGB, grayscale, or CMYK image.
        /// </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="destPixelFormat">Pixel format of the destination image (see <see cref="PixelFormat"/> "Pixel formats".)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags".</param>
        /// <returns>Decompressed image of specified format.</returns>
        /// <exception cref="TJException">Throws if underlying decompress function failed.</exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore.</exception>
        /// <exception cref="NotSupportedException">Convertion to the requested pixel format can not be performed.</exception>
        public static unsafe Bitmap Decompress(this TJDecompressor @this, IntPtr jpegBuf, ulong jpegBufSize, PixelFormat destPixelFormat, TJFlags flags)
        {
            var    targetFormat = TJGdiPlusUtils.ConvertPixelFormat(destPixelFormat);
            int    width;
            int    height;
            int    stride;
            var    buffer = @this.Decompress(jpegBuf, jpegBufSize, targetFormat, flags, out width, out height, out stride);
            Bitmap result;

            fixed(byte *bufferPtr = buffer)
            {
                result = new Bitmap(width, height, stride, destPixelFormat, (IntPtr)bufferPtr);
                if (destPixelFormat == PixelFormat.Format8bppIndexed)
                {
                    result.Palette = TJGdiPlusUtils.FixPaletteToGrayscale(result.Palette);
                }
            }

            return(result);
        }