/// <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="outBuf">The buffer into which to store the decompressed JPEG image.</param> /// <param name="destPixelFormat">Pixel format of the destination image (see <see cref="TJPixelFormat"/> "Pixel formats".)</param> /// <param name="flags">The bitwise OR of one or more of the <see cref="TJFlags"/> "flags".</param> /// <param name="width">Width of image in pixels.</param> /// <param name="height">Height of image in pixels.</param> /// <param name="stride">Bytes per line in the destination image.</param> public unsafe void Decompress(Span <byte> jpegBuf, Span <byte> outBuf, TJPixelFormat destPixelFormat, TJFlags flags, out int width, out int height, out int stride) { Verify.NotDisposed(this); fixed(byte *jpegBufPtr = jpegBuf) fixed(byte *outBufPtr = outBuf) { int subsampl; int colorspace; var funcResult = TurboJpegImport.TjDecompressHeader( this.decompressorHandle, jpegBufPtr, (nuint)jpegBuf.Length, out width, out height, out subsampl, out colorspace); TJUtils.ThrowOnError(funcResult); var targetFormat = destPixelFormat; stride = TurboJpegImport.TJPAD(width * TurboJpegImport.PixelSizes[targetFormat]); var bufSize = stride * height; if (outBuf.Length < bufSize) { throw new ArgumentOutOfRangeException(nameof(outBuf)); } funcResult = TurboJpegImport.TjDecompress( this.decompressorHandle, jpegBufPtr, (nuint)jpegBuf.Length, outBufPtr, width, stride, height, (int)targetFormat, (int)flags); TJUtils.ThrowOnError(funcResult); } }
/// <summary> /// Retrieve information about a JPEG image without decompressing it. /// </summary> /// <param name="jpegBuf"> /// Pointer to a buffer containing a JPEG image. This buffer is not modified. /// </param> /// <param name="destPixelFormat"> /// The pixel format of the uncompressed image. /// </param> /// <param name="width"> /// Pointer to an integer variable that will receive the width (in pixels) of the JPEG image. /// </param> /// <param name="height"> /// Pointer to an integer variable that will receive the height (in pixels) of the JPEG image. /// </param> /// <param name="stride"> /// Pointer to an integer variable that will receive the stride (in bytes) of the JPEG image. /// </param> /// <param name="bufSize"> /// The size of a buffer that can receive the uncompressed JPEG image. /// </param> public void GetImageInfo(Span <byte> jpegBuf, TJPixelFormat destPixelFormat, out int width, out int height, out int stride, out int bufSize) { Verify.NotDisposed(this); int subsampl; int colorspace; fixed(byte *jpegBufPtr = jpegBuf) { var funcResult = TurboJpegImport.TjDecompressHeader( this.decompressorHandle, jpegBufPtr, (nuint)jpegBuf.Length, out width, out height, out subsampl, out colorspace); stride = TurboJpegImport.TJPAD(width * TurboJpegImport.PixelSizes[destPixelFormat]); bufSize = stride * height; } }
/// <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="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(Span <byte> jpegBuf, TJTransformDescription[] transforms, TJFlags flags) { Verify.NotDisposed(this); if (transforms == null) { throw new ArgumentNullException(nameof(transforms)); } if (transforms.Length == 0) { throw new ArgumentException("Transforms can not be empty", nameof(transforms)); } fixed(byte *jpegBufPtr = jpegBuf) { var count = transforms.Length; var destBufs = new IntPtr[count]; var destSizes = new uint[count]; int subsampl; int colorspace; int width; int height; var funcResult = TurboJpegImport.TjDecompressHeader( this.transformHandle, jpegBufPtr, (nuint)jpegBuf.Length, out width, out height, out subsampl, out colorspace); TJUtils.ThrowOnError(funcResult); Size mcuSize; if (!TurboJpegImport.MCUSizes.TryGetValue((TJSubsamplingOption)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( this.transformHandle, jpegBufPtr, (nuint)jpegBuf.Length, count, destBufs, destSizes, transformsPtr, (int)flags); TJUtils.ThrowOnError(funcResult); 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); } } }