/// <summary> /// Losslessly transform the JPEG image associated with this transformer instance into one or more JPEG images /// stored in the given destination buffers. Lossless transforms work by moving the raw coefficients from one /// JPEG image structure to another without altering the values of the coefficients. While this is typically /// faster than decompressing the image, transforming it, and re-compressing it, lossless transforms are not /// free. Each lossless transform requires reading and performing Huffman decoding on all of the coefficients /// in the source image, regardless of the size of the destination image, thus this method provides a means of /// generating multiple transformed images from the same source or of applying multiple transformations /// simultaneously, in order to eliminate the need to read the source coefficients multiple times. /// </summary> /// <param name="destBuffers"> /// An array of image buffers. <paramref name="destBuffers" />[i] will receive a JPEG image that has been /// transformed using the parameters in <paramref name="transforms" />[i]. Use /// <see cref="NativeMethods.bufSize" /> to determine the maximum size for each buffer based on the /// transformed or cropped width and height and the chroma subsampling used in the source image. /// </param> /// <param name="transforms">An array of <seealso cref="TurboJpegTransform" /> instances, each of which /// specifies the transform parameters and/or cropping region for the corresponding transformed output image. /// </param> /// <param name="options">The flags to use for the transforms.</param> public void Transform(byte[][] destBuffers, TurboJpegTransform[] transforms, TurboJpegFlags options) { Contract.Requires(destBuffers != null); Contract.Requires(transforms != null); Contract.Requires(transforms.Length == destBuffers.Length); Contract.Requires(Enum.IsDefined(typeof(TransformOptions), options)); Contract.Ensures(Contract.ForAll(destBuffers, _ => _ != null)); Contract.Assume(this.JpegBuffer != null, "JPEG buffer not initialized"); var count = destBuffers.Length; var destBufferPtrs = new IntPtr[count]; this.transformedSizes = new int[count]; if (NativeMethods.transform(this.Handle, this.JpegBuffer, this.JpegSize, count, ref destBufferPtrs, ref this.transformedSizes, transforms, options) != 0) { throw new Exception(TurboJpegInterop.GetLastError()); } // we now have the result in buffers on the unmanaged heap for (var i = 0; i < count; ++i) { destBuffers[i] = new byte[this.transformedSizes[i]]; Marshal.Copy(destBufferPtrs[i], destBuffers[i], 0, this.transformedSizes[i]); } }
/// <summary> /// Losslessly transform the JPEG image associated with this transformer instance and return an array of /// <seealso cref="TurboJpegDecompressor" /> instances, each of which has a transformed JPEG image associated /// with it. /// </summary> /// <param name="transforms">An array of <see cref="TurboJpegTransform" /> instances, each of which specifies /// the transform parameters and/or cropping region for the corresponding transformed output image.</param> /// <param name="flags">The flags to use when transforming.</param> /// <param name="preallocateBuffers">If set to <c>true</c>, preallocate buffers.</param> /// <returns> /// An array of <seealso cref="TurboJpegDecompressor" /> instances, each of which has a transformed /// JPEG image associated with it. /// </returns> public TurboJpegDecompressor[] Transform(TurboJpegTransform[] transforms, TurboJpegFlags flags, bool preallocateBuffers) { Contract.Requires(transforms != null); Contract.Requires(Enum.IsDefined(typeof(TransformOptions), flags)); Contract.Ensures(Contract.Result<TurboJpegDecompressor[]>() != null); Contract.Ensures(Contract.Result<TurboJpegDecompressor[]>().Length == transforms.Length); Contract.Ensures(Contract.ForAll(Contract.Result<TurboJpegDecompressor[]>(), _ => _ != null)); var count = transforms.Length; var destinationBuffers = new byte[count][]; Contract.Assume(this.Width > 0, "JPEG buffer not initialized"); Contract.Assume(this.Height > 0, "JPEG buffer not initialized"); var decompressors = new TurboJpegDecompressor[count]; if (preallocateBuffers) { for (var i = 0; i < count; i++) { var width = this.Width; var height = this.Height; if ((transforms[i].Options & TransformOptions.Crop) != 0) { if (transforms[i].Width != 0) { width = transforms[i].Width; } if (transforms[i].Height != 0) { height = transforms[i].Height; } } destinationBuffers[i] = new byte[NativeMethods.bufSize(width, height, this.Subsampling)]; } this.Transform(destinationBuffers, transforms, flags); for (var i = 0; i < count; i++) { decompressors[i] = new TurboJpegDecompressor(destinationBuffers[i]); } } else { var destBufferPtrs = new IntPtr[count]; this.transformedSizes = new int[count]; if (NativeMethods.transform(this.Handle, this.JpegBuffer, this.JpegSize, count, ref destBufferPtrs, ref this.transformedSizes, transforms, flags) != 0) { throw new Exception(TurboJpegInterop.GetLastError()); } // we now have the result in buffers on the unmanaged heap for (var i = 0; i < count; ++i) { decompressors[i] = new TurboJpegDecompressor(); decompressors[i].SetJpegImage(destBufferPtrs[i]); } } return decompressors; }
internal static extern int transform(IntPtr handle, byte[] sourceBuffer, int sourceSize, int count, ref IntPtr[] destinationBuffers, ref int[] sizes, TurboJpegTransform[] transforms, [MarshalAs(UnmanagedType.I4)] TurboJpegFlags flags);