/// <summary>
        /// Compresses input image to the jpeg format with specified quality
        /// </summary>
        /// <param name="srcPtr">
        /// Pointer to an image buffer containing RGB, grayscale, or CMYK pixels to be compressed.
        /// This buffer is not modified.
        /// </param>
        /// <param name="stride">
        /// Bytes per line in the source image.
        /// Normally, this should be <c>width * BytesPerPixel</c> if the image is unpadded,
        /// or <c>TJPAD(width * BytesPerPixel</c> if each line of the image
        /// is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps.
        /// You can also be clever and use this parameter to skip lines, etc.
        /// Setting this parameter to 0 is the equivalent of setting it to
        /// <c>width * BytesPerPixel</c>.
        /// </param>
        /// <param name="width">Width (in pixels) of the source image</param>
        /// <param name="height">Height (in pixels) of the source image</param>
        /// <param name="pixelFormat">Pixel format of the source image (see <see cref="PixelFormat"/> "Pixel formats")</param>
        /// <param name="subSamp">
        /// The level of chrominance subsampling to be used when
        /// generating the JPEG image (see <see cref="TJSubsamplingOptions"/> "Chrominance subsampling options".)
        /// </param>
        /// <param name="quality">The image quality of the generated JPEG image (1 = worst, 100 = best)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags"</param>
        /// <exception cref="TJException"> Throws if compress function failed </exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore</exception>
        /// <exception cref="NotSupportedException">
        /// Some parameters' values are incompatible:
        /// <list type="bullet">
        /// <item><description>Subsampling not equals to <see cref="TJSubsamplingOptions.TJSAMP_GRAY"/> and pixel format <see cref="TJPixelFormats.TJPF_GRAY"/></description></item>
        /// </list>
        /// </exception>
        public byte[] Compress(IntPtr srcPtr, int stride, int width, int height, PixelFormat pixelFormat = PixelFormat.Format32bppArgb, TJSubsamplingOptions subSamp = TJSubsamplingOptions.TJSAMP_420, int quality = 50, TJFlags flags = TJFlags.FASTDCT)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException("this");
            }

            var tjPixelFormat = TJUtils.ConvertPixelFormat(pixelFormat);

            CheckOptionsCompatibilityAndThrow(subSamp, tjPixelFormat);
            TJDoCompDel compresscall = TurboJpegImport.tjCompress2;

            if (isXPlatform)
            {
                compresscall = TurboJpegImport_xplat.tjCompressX;
            }

            var   buf     = IntPtr.Zero;
            ulong bufSize = 0;

            try
            {
                var result = compresscall(
                    _compressorHandle,
                    srcPtr,
                    width,
                    stride,
                    height,
                    (int)tjPixelFormat,
                    ref buf,
                    ref bufSize,
                    (int)subSamp,
                    quality,
                    (int)flags);

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

                var jpegBuf = new byte[bufSize];
                // ReSharper disable once ExceptionNotDocumentedOptional
                Marshal.Copy(buf, jpegBuf, 0, (int)bufSize);
                return(jpegBuf);
            }
            finally
            {
                TurboJpegImport.tjFree(buf);
            }
        }
        /// <summary>
        /// Compresses input image to the jpeg format with specified quality
        /// </summary>
        /// <param name="srcBuf">
        /// Image buffer containing RGB, grayscale, or CMYK pixels to be compressed.
        /// This buffer is not modified.
        /// </param>
        /// <param name="stride">
        /// Bytes per line in the source image.
        /// Normally, this should be <c>width * BytesPerPixel</c> if the image is unpadded,
        /// or <c>TJPAD(width * BytesPerPixel</c> if each line of the image
        /// is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps.
        /// You can also be clever and use this parameter to skip lines, etc.
        /// Setting this parameter to 0 is the equivalent of setting it to
        /// <c>width * BytesPerPixel</c>.
        /// </param>
        /// <param name="width">Width (in pixels) of the source image</param>
        /// <param name="height">Height (in pixels) of the source image</param>
        /// <param name="pixelFormat">Pixel format of the source image (see <see cref="PixelFormat"/> "Pixel formats")</param>
        /// <param name="subSamp">
        /// The level of chrominance subsampling to be used when
        /// generating the JPEG image (see <see cref="TJSubsamplingOptions"/> "Chrominance subsampling options".)
        /// </param>
        /// <param name="quality">The image quality of the generated JPEG image (1 = worst, 100 = best)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags"</param>
        /// <exception cref="TJException">
        /// Throws if compress function failed
        /// </exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore</exception>
        /// <exception cref="NotSupportedException">
        /// Some parameters' values are incompatible:
        /// <list type="bullet">
        /// <item><description>Subsampling not equals to <see cref="TJSubsamplingOptions.TJSAMP_GRAY"/> and pixel format <see cref="TJPixelFormats.TJPF_GRAY"/></description></item>
        /// </list>
        /// </exception>
        public unsafe byte[] Compress(byte[] srcBuf, int stride, int width, int height, PixelFormat pixelFormat, TJSubsamplingOptions subSamp, int quality, TJFlags flags)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException("this");
            }

            var tjPixelFormat = TJUtils.ConvertPixelFormat(pixelFormat);

            CheckOptionsCompatibilityAndThrow(subSamp, tjPixelFormat);

            var   buf     = IntPtr.Zero;
            ulong bufSize = 0;

            try
            {
                fixed(byte *srcBufPtr = srcBuf)
                {
                    var result = TurboJpegImport.tjCompress2(
                        _compressorHandle,
                        (IntPtr)srcBufPtr,
                        width,
                        stride,
                        height,
                        (int)tjPixelFormat,
                        ref buf,
                        ref bufSize,
                        (int)subSamp,
                        quality,
                        (int)flags);

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

                var jpegBuf = new byte[bufSize];

                // ReSharper disable once ExceptionNotDocumentedOptional
                Marshal.Copy(buf, jpegBuf, 0, (int)bufSize);
                return(jpegBuf);
            }
            finally
            {
                TurboJpegImport.tjFree(buf);
            }
        }
Exemple #3
0
        /// <summary>
        /// Compresses input image to the jpeg format with specified quality
        /// </summary>
        /// <param name="srcPtr">
        /// Pointer to an image buffer containing RGB, grayscale, or CMYK pixels to be compressed.
        /// This buffer is not modified.
        /// </param>
        /// <param name="stride">
        /// Bytes per line in the source image.
        /// Normally, this should be <c>width * BytesPerPixel</c> if the image is unpadded,
        /// or <c>TJPAD(width * BytesPerPixel</c> if each line of the image
        /// is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps.
        /// You can also be clever and use this parameter to skip lines, etc.
        /// Setting this parameter to 0 is the equivalent of setting it to
        /// <c>width * BytesPerPixel</c>.
        /// </param>
        /// <param name="width">Width (in pixels) of the source image</param>
        /// <param name="height">Height (in pixels) of the source image</param>
        /// <param name="tjPixelFormat">Pixel format of the source image (see <see cref="TJPixelFormats"/> "Pixel formats")</param>
        /// <param name="subSamp">
        /// The level of chrominance subsampling to be used when
        /// generating the JPEG image (see <see cref="TJSubsamplingOptions"/> "Chrominance subsampling options".)
        /// </param>
        /// <param name="quality">The image quality of the generated JPEG image (1 = worst, 100 = best)</param>
        /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags"</param>
        /// <param name="onAsyncCompressionCompleted">Method to process compressed data</param>
        /// <param name="state">User-defined state passed to <paramref name="onAsyncCompressionCompleted"/> method</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <exception cref="TJException">Throws if compress function failed.</exception>
        /// <exception cref="ObjectDisposedException">Object is disposed and can not be used anymore</exception>
        /// <exception cref="NotSupportedException">
        /// Some parameters' values are incompatible:
        /// <list type="bullet">
        /// <item><description>Subsampling not equals to <see cref="TJSubsamplingOptions.TJSAMP_GRAY"/> and pixel format <see cref="TJPixelFormats.TJPF_GRAY"/></description></item>
        /// </list>
        /// </exception>
        /// <returns>
        /// </returns>
        public async Task CompressAsync(IntPtr srcPtr, int stride, int width, int height,
                                        TJPixelFormats tjPixelFormat, TJSubsamplingOptions subSamp, int quality, TJFlags flags,
                                        TJAsyncCompressionComplete onAsyncCompressionCompleted, object state, CancellationToken cancellationToken)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException("this");
            }
            if (onAsyncCompressionCompleted == null)
            {
                throw new ArgumentNullException(nameof(onAsyncCompressionCompleted));
            }

            CheckOptionsCompatibilityAndThrow(subSamp, tjPixelFormat);

            var   buf     = IntPtr.Zero;
            ulong bufSize = 0;

            try
            {
                var result = TurboJpegImport.tjCompress2(
                    _compressorHandle,
                    srcPtr,
                    width,
                    stride,
                    height,
                    (int)tjPixelFormat,
                    ref buf,
                    ref bufSize,
                    (int)subSamp,
                    quality,
                    (int)flags);

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

                await onAsyncCompressionCompleted(buf, (int)bufSize, state, cancellationToken);
            }
            finally
            {
                TurboJpegImport.tjFree(buf);
            }
        }
Exemple #4
0
        /// <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);
            }
        }