Skip to content
This repository was archived by the owner on Dec 31, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions LibJpegWrapper/Quamotion.TurboJpegWrapper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<Company>Quamotion</Company>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/qmfrederik/AS.TurboJpegWrapper</RepositoryUrl>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<VersionPrefix>1.0.3</VersionPrefix>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<VersionPrefix>1.0.4</VersionPrefix>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
Expand Down
147 changes: 67 additions & 80 deletions LibJpegWrapper/TJCompressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class TJCompressor : IDisposable
{
private IntPtr _compressorHandle;
private bool _isDisposed;
private readonly object _lock = new object();
private readonly object _lock;

/// <summary>
/// Creates new instance of <see cref="TJCompressor"/>
Expand All @@ -25,6 +25,7 @@ public class TJCompressor : IDisposable
public TJCompressor()
{
_compressorHandle = TurboJpegImport.tjInitCompress();
_lock = new object();

if (_compressorHandle == IntPtr.Zero)
{
Expand Down Expand Up @@ -62,14 +63,13 @@ public byte[] Compress(Bitmap srcImage, TJSubsamplingOptions subSamp, int qualit
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;
// BitmapData.Stride may be negative if the bitmap is bottom up. In this case, BitmapData.Scan0 is the last scan line -> recalculate start of unmanaged memory
var stride = Math.Abs(srcData.Stride);
var srcPtr = srcData.Stride > 0 ? srcData.Scan0 : srcData.Scan0 - ((srcData.Height - 1) * stride);

try
{
return Compress(srcPtr, stride, width, height, pixelFormat, subSamp, quality, flags);

}
finally
{
Expand All @@ -79,6 +79,63 @@ public byte[] Compress(Bitmap srcImage, TJSubsamplingOptions subSamp, int qualit
}


/// <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>
/// <param name="bufSize">Size of the returned unmanaged buffer (in bytes).</param>
/// <returns></returns>
/// <exception cref="System.ObjectDisposedException">this</exception>
/// <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 TJUnmanagedMemory Compress(IntPtr srcPtr, int stride, int width, int height, PixelFormat pixelFormat, TJSubsamplingOptions subSamp, int quality, TJFlags flags, out ulong bufSize)
{
if (_isDisposed)
throw new ObjectDisposedException("this");

var tjPixelFormat = TJUtils.ConvertPixelFormat(pixelFormat);
CheckOptionsCompatibilityAndThrow(subSamp, tjPixelFormat);

var buf = IntPtr.Zero;
bufSize = 0;
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();
}

return new TJUnmanagedMemory(buf, bufSize);
}

/// <summary>
/// Compresses input image to the jpeg format with specified quality
/// </summary>
Expand Down Expand Up @@ -114,43 +171,8 @@ public byte[] Compress(Bitmap srcImage, TJSubsamplingOptions subSamp, int qualit
/// </exception>
public byte[] Compress(IntPtr srcPtr, 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
{
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();
}

var jpegBuf = new byte[bufSize];
// ReSharper disable once ExceptionNotDocumentedOptional
Marshal.Copy(buf, jpegBuf, 0, (int)bufSize);
return jpegBuf;
}
finally
{
TurboJpegImport.tjFree(buf);
}
ulong bufSize;
return Compress(srcPtr, stride, width, height, pixelFormat, subSamp, quality, flags, out bufSize);
}

/// <summary>
Expand Down Expand Up @@ -188,47 +210,13 @@ public byte[] Compress(IntPtr srcPtr, int stride, int width, int height, PixelFo
/// <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)
public 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);
}
using (var srcPtr = new TJUnmanagedMemory(srcBuf))
return Compress((IntPtr)srcPtr, stride, width, height, pixelFormat, subSamp, quality, flags);
}

/// <summary>
Expand Down Expand Up @@ -293,5 +281,4 @@ private static void CheckOptionsCompatibilityAndThrow(TJSubsamplingOptions subSa
$"Subsampling differ from {TJSubsamplingOptions.TJSAMP_GRAY} for pixel format {TJPixelFormats.TJPF_GRAY} is not supported");
}
}

}
Loading