public void CompressBitmap( [Values (TJSubsamplingOptions.TJSAMP_GRAY, TJSubsamplingOptions.TJSAMP_411, TJSubsamplingOptions.TJSAMP_420, TJSubsamplingOptions.TJSAMP_440, TJSubsamplingOptions.TJSAMP_422, TJSubsamplingOptions.TJSAMP_444)] TJSubsamplingOptions options, [Values(1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)] int quality) { var imageidx = 0; foreach (var bitmap in TestUtils.GetTestImages("*.bmp")) { try { Trace.WriteLine($"Options: {options}; Quality: {quality}"); Assert.DoesNotThrow(() => { var result = _compressor.Compress(bitmap, options, quality, TJFlags.NONE); Assert.NotNull(result); var file = Path.Combine(OutDirectory, $"{imageidx}_{quality}_{options}.jpg"); File.WriteAllBytes(file, result); }); } finally { bitmap.Dispose(); } imageidx++; } }
public void CompressIntPtr( [Values (TJSubsamplingOptions.TJSAMP_GRAY, TJSubsamplingOptions.TJSAMP_411, TJSubsamplingOptions.TJSAMP_420, TJSubsamplingOptions.TJSAMP_440, TJSubsamplingOptions.TJSAMP_422, TJSubsamplingOptions.TJSAMP_444)] TJSubsamplingOptions options, [Values(1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)] int quality) { foreach (var bitmap in TestUtils.GetTestImages("*.bmp")) { BitmapData data = null; try { data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); Trace.WriteLine($"Options: {options}; Quality: {quality}"); Assert.DoesNotThrow(() => { var result = _compressor.Compress(data.Scan0, data.Stride, data.Width, data.Height, TestUtils.ConvertPixelFormat(data.PixelFormat), options, quality, TJFlags.NONE); Assert.NotNull(result); }); } finally { if (data != null) { bitmap.UnlockBits(data); } bitmap.Dispose(); } } }
/// <summary> /// Compresses input image to the jpeg format with specified quality /// </summary> /// <param name="srcImage"> Source image to be converted </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> /// <remarks>Only <see cref="PixelFormat.Format24bppRgb"/>, <see cref="PixelFormat.Format32bppArgb"/>, <see cref="PixelFormat.Format8bppIndexed"/> pixel formats are supported</remarks> /// <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(Bitmap srcImage, TJSubsamplingOptions subSamp, int quality, TJFlags flags) { if (_isDisposed) { throw new ObjectDisposedException("this"); } var pixelFormat = srcImage.PixelFormat; var width = srcImage.Width; var height = srcImage.Height; // ReSharper disable once ExceptionNotDocumented var srcData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat); var stride = srcData.Stride; var srcPtr = srcData.Scan0; try { return(Compress(srcPtr, stride, width, height, pixelFormat, subSamp, quality, flags)); } finally { // ReSharper disable once ExceptionNotDocumented srcImage.UnlockBits(srcData); } }
/// <summary> /// Compresses input image to the jpeg format with specified quality /// </summary> /// <param name="srcImage"> Source image to be converted </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> /// <remarks>Only <see cref="PixelFormat.Format24bppRgb"/>, <see cref="PixelFormat.Format32bppArgb"/>, <see cref="PixelFormat.Format8bppIndexed"/> pixel formats are supported</remarks> /// <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(Bitmap srcImage, TJSubsamplingOptions subSamp, int quality, TJFlags flags) { if (_isDisposed) throw new ObjectDisposedException("this"); var pixelFormat = srcImage.PixelFormat; var width = srcImage.Width; var height = srcImage.Height; // ReSharper disable once ExceptionNotDocumented var srcData = srcImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat); var stride = srcData.Stride; var srcPtr = srcData.Scan0; try { return Compress(srcPtr, stride, width, height, pixelFormat, subSamp, quality, flags); } finally { // ReSharper disable once ExceptionNotDocumented srcImage.UnlockBits(srcData); } }
private static void CheckOptionsCompatibilityAndThrow(TJSubsamplingOptions subSamp, TJPixelFormats srcFormat) { if (srcFormat == TJPixelFormats.TJPF_GRAY && subSamp != TJSubsamplingOptions.TJSAMP_GRAY) { throw new NotSupportedException( $"Subsampling differ from {TJSubsamplingOptions.TJSAMP_GRAY} for pixel format {TJPixelFormats.TJPF_GRAY} is not supported"); } }
/// <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); } }
public async void CompressAsync( [Values (TJSubsamplingOptions.TJSAMP_GRAY, TJSubsamplingOptions.TJSAMP_411, TJSubsamplingOptions.TJSAMP_420, TJSubsamplingOptions.TJSAMP_440, TJSubsamplingOptions.TJSAMP_422, TJSubsamplingOptions.TJSAMP_444)] TJSubsamplingOptions options, [Values(1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)] int quality) { foreach (var bitmap in TestUtils.GetTestImages("*.bmp")) { var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); try { var stride = data.Stride; var width = data.Width; var height = data.Height; var pixelFormat = TestUtils.ConvertPixelFormat(data.PixelFormat); var buf = new byte[stride * height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); Trace.WriteLine($"Options: {options}; Quality: {quality}"); CancellationTokenSource cancellation = new CancellationTokenSource(); await _compressor.CompressAsync(data.Scan0, stride, width, height, pixelFormat, options, quality, TJFlags.NONE, async (ptr, size, state, token) => { await Task.Delay(10, token); Assert.IsTrue(ptr != IntPtr.Zero, "ptr != IntPtr.Zero"); Assert.IsTrue(size > 0, "size > 0"); Assert.IsNull(state, "state != null"); }, null, cancellation.Token); } finally { bitmap.UnlockBits(data); bitmap.Dispose(); } } }
public void CompressByteArray( [Values (TJSubsamplingOptions.TJSAMP_GRAY, TJSubsamplingOptions.TJSAMP_411, TJSubsamplingOptions.TJSAMP_420, TJSubsamplingOptions.TJSAMP_440, TJSubsamplingOptions.TJSAMP_422, TJSubsamplingOptions.TJSAMP_444)] TJSubsamplingOptions options, [Values(1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)] int quality) { foreach (var bitmap in TestUtils.GetTestImages("*.bmp")) { try { var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); var stride = data.Stride; var width = data.Width; var height = data.Height; var pixelFormat = TestUtils.ConvertPixelFormat(data.PixelFormat); var buf = new byte[stride * height]; Marshal.Copy(data.Scan0, buf, 0, buf.Length); bitmap.UnlockBits(data); Trace.WriteLine($"Options: {options}; Quality: {quality}"); Assert.DoesNotThrow(() => { var result = _compressor.Compress(buf, stride, width, height, pixelFormat, options, quality, TJFlags.NONE); Assert.NotNull(result); }); } finally { bitmap.Dispose(); } } }
public JpegFrame(JpegCompressor compressor, int width, int height, TJSubsamplingOptions subSampling) { _compressor = compressor; checked { Width = width; Height = height; SubSampling = subSampling; MaxBufferSize = (int)JpegLibrary.tjBufSize(width, height, (int)subSampling); } var bufferHandle = JpegLibrary.tjAlloc(MaxBufferSize); if (bufferHandle == IntPtr.Zero) { throw new OutOfMemoryException( $"Failed to allocate TurboJPEG buffer of size {width}x{height}, subSampling {subSampling}"); } SetResourceHandle(bufferHandle); }
/// <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); } }
public JpegFrame CreateFrameBuffer(int maxWidth, int maxHeight, TJSubsamplingOptions subSampling) { return(new JpegFrame(this, maxWidth, maxHeight, subSampling)); }
private static void CheckOptionsCompatibilityAndThrow(TJSubsamplingOptions subSamp, TJPixelFormats srcFormat) { if (srcFormat == TJPixelFormats.TJPF_GRAY && subSamp != TJSubsamplingOptions.TJSAMP_GRAY) throw new NotSupportedException( $"Subsampling differ from {TJSubsamplingOptions.TJSAMP_GRAY} for pixel format {TJPixelFormats.TJPF_GRAY} is not supported"); }
/// <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); } }
/// <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); } }