diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/AImg.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/AImg.cs
index 64169fa..5ad99f0 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/AImg.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/AImg.cs
@@ -1,173 +1,212 @@
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using Artomatix.ImageLoader.ImgEncodingOptions;
-
-namespace Artomatix.ImageLoader
-{
- public class AImg : IDisposable
- {
- private IntPtr nativeHandle = IntPtr.Zero;
- private Stream stream;
- private bool doDisposeStream;
- private bool disposed = false;
-
- private ImgLoader.ReadCallback readCallback;
- private ImgLoader.TellCallback tellCallback;
- private ImgLoader.SeekCallback seekCallback;
-
- private Int32 _width, _height;
- private Int32 _numChannels;
- private Int32 _bytesPerChannel;
-
- public int width { get { return _width; } }
- public int height { get { return _height; } }
- public int numChannels { get { return _numChannels; } }
- public int bytesPerChannel { get { return _bytesPerChannel; } }
- public AImgFloatOrIntType floatOrInt { get; private set; }
- public AImgFileFormat detectedFileFormat { get; private set; }
- public AImgFormat decodedImgFormat { get; private set; }
- public string colourProfileName { get; private set; }
- public byte[] colourProfile { get; private set; }
-
- public AImg(AImgFileFormat fmt)
- {
- nativeHandle = NativeFuncs.inst.AImgGetAImg((Int32)fmt);
- }
-
- ///
- /// Opens an AImg from a stream.
- ///
- /// If set to true stream will be disposed whne the AImg is disposed.
- public unsafe AImg(Stream stream, bool doDisposeStream = true)
- {
- if (!stream.CanRead || !stream.CanSeek)
- throw new Exception("unusable stream");
-
- this.stream = stream;
- this.doDisposeStream = doDisposeStream;
-
- readCallback = ImgLoader.getReadCallback(stream);
- tellCallback = ImgLoader.getTellCallback(stream);
- seekCallback = ImgLoader.getSeekCallback(stream);
-
- Int32 detectedImageFormatTmp = 0;
- Int32 errCode = NativeFuncs.inst.AImgOpen(readCallback, tellCallback, seekCallback, IntPtr.Zero, out nativeHandle, out detectedImageFormatTmp);
- AImgException.checkErrorCode(nativeHandle, errCode);
-
- detectedFileFormat = (AImgFileFormat)detectedImageFormatTmp;
-
- Int32 floatOrIntTmp = 0;
- Int32 decodedImgFormatTmp = 0;
- Int32 colourProfileLen = 0;
- NativeFuncs.inst.AImgGetInfo(nativeHandle, out _width, out _height, out _numChannels, out _bytesPerChannel, out floatOrIntTmp, out decodedImgFormatTmp, out colourProfileLen);
- floatOrInt = (AImgFloatOrIntType)floatOrIntTmp;
- decodedImgFormat = (AImgFormat)decodedImgFormatTmp;
- colourProfile = new byte[colourProfileLen];
- fixed (byte* array = colourProfile)
- {
- System.Text.StringBuilder _colourProfileName = new System.Text.StringBuilder(30);
- NativeFuncs.inst.AImgGetColourProfile(nativeHandle, _colourProfileName, (IntPtr)array, out colourProfileLen);
- colourProfileName = _colourProfileName.ToString();
- }
- }
-
- ///
- /// Decodes the image into a user-specified buffer.
- ///
- /// This buffer can be of any struct type, so for example for an RGBA8 image, you might use a byte array,
- /// or a custom struct with byte fields for the r, g, b, and a components. A custom struct would need the [StructLayout(LayoutKind.Sequential), Serializable] attribute.
- public void decodeImage(T[] destBuffer, AImgFormat forceImageFormat = AImgFormat.INVALID_FORMAT) where T : struct
- {
- uint size = (uint)(Marshal.SizeOf(default(T)));
-
- if (size * destBuffer.Length < decodedImgFormat.sizeInBytes() * width * height)
- throw new ArgumentException("destBuffer is too small for this image");
-
- GCHandle pinnedArray = GCHandle.Alloc(destBuffer, GCHandleType.Pinned);
- IntPtr pointer = pinnedArray.AddrOfPinnedObject();
-
- Int32 errCode = NativeFuncs.inst.AImgDecodeImage(nativeHandle, pointer, (Int32)forceImageFormat);
- AImgException.checkErrorCode(nativeHandle, errCode);
-
- pinnedArray.Free();
- }
-
- public static AImgFormat getWhatFormatWillBeWrittenForData(AImgFileFormat fileFormat, AImgFormat format)
- {
- return (AImgFormat)NativeFuncs.inst.AImgGetWhatFormatWillBeWrittenForData((Int32)fileFormat, (Int32)format);
- }
-
- public unsafe void writeImage(T[] data, int width, int height, AImgFormat format, string profileName, byte[] colourProfile, Stream s, FormatEncodeOptions options = null) where T : struct
- {
- var writeCallback = ImgLoader.getWriteCallback(s);
- var tellCallback = ImgLoader.getTellCallback(s);
- var seekCallback = ImgLoader.getSeekCallback(s);
-
- if (profileName == string.Empty)
- profileName = "empty";
-
- GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
- IntPtr pointer = pinnedArray.AddrOfPinnedObject();
-
- fixed (byte* colourProfileArray = colourProfile)
- {
- GCHandle encodeOptionsHandle = default(GCHandle);
- IntPtr encodeOptionsPtr = IntPtr.Zero;
-
- if (options != null)
- {
- encodeOptionsHandle = GCHandle.Alloc(options, GCHandleType.Pinned);
- encodeOptionsPtr = encodeOptionsHandle.AddrOfPinnedObject();
- }
- try
- {
- int colourProfileLength = 0;
- if (colourProfile != null)
- {
- colourProfileLength = colourProfile.Length;
- }
-
- Int32 errCode = NativeFuncs.inst.AImgWriteImage(nativeHandle, pointer, width, height, (Int32)format, profileName, (IntPtr)colourProfileArray, colourProfileLength, writeCallback, tellCallback, seekCallback, IntPtr.Zero, encodeOptionsPtr);
- AImgException.checkErrorCode(nativeHandle, errCode);
- }
- finally
- {
- pinnedArray.Free();
-
- if (encodeOptionsPtr != IntPtr.Zero)
- encodeOptionsHandle.Free();
- }
- }
- GC.KeepAlive(writeCallback);
- GC.KeepAlive(tellCallback);
- GC.KeepAlive(seekCallback);
- }
-
- private void Dispose(bool disposing)
- {
- if (!disposed)
- {
- disposed = true;
-
- if (disposing)
- GC.SuppressFinalize(this);
-
- NativeFuncs.inst.AImgClose(nativeHandle);
-
- if (doDisposeStream)
- stream.Dispose();
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- ~AImg()
- {
- Dispose(false);
- }
- }
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using Artomatix.ImageLoader.ImgEncodingOptions;
+
+namespace Artomatix.ImageLoader
+{
+ public class AImg : IDisposable
+ {
+ private IntPtr nativeHandle = IntPtr.Zero;
+ private Stream stream;
+ private bool doDisposeStream;
+ private bool disposed = false;
+
+ private ImgLoader.ReadCallback readCallback;
+ private ImgLoader.TellCallback tellCallback;
+ private ImgLoader.SeekCallback seekCallback;
+
+ private Int32 _width, _height;
+ private Int32 _numChannels;
+ private Int32 _bytesPerChannel;
+
+ public int width { get { return _width; } }
+ public int height { get { return _height; } }
+ public int numChannels { get { return _numChannels; } }
+ public int bytesPerChannel { get { return _bytesPerChannel; } }
+ public AImgFloatOrIntType floatOrInt { get; private set; }
+ public AImgFileFormat detectedFileFormat { get; private set; }
+ public AImgFormat decodedImgFormat { get; private set; }
+ public string colourProfileName { get; private set; }
+ public byte[] colourProfile { get; private set; }
+
+ public AImg(AImgFileFormat fmt)
+ {
+ nativeHandle = NativeFuncs.inst.AImgGetAImg((Int32)fmt);
+ }
+
+ ///
+ /// Opens an AImg from a stream.
+ ///
+ /// If set to true stream will be disposed whne the AImg is disposed.
+ public unsafe AImg(Stream stream, bool doDisposeStream = true)
+ {
+ if (!stream.CanRead || !stream.CanSeek)
+ throw new Exception("unusable stream");
+
+ this.stream = stream;
+ this.doDisposeStream = doDisposeStream;
+
+ readCallback = ImgLoader.getReadCallback(stream);
+ tellCallback = ImgLoader.getTellCallback(stream);
+ seekCallback = ImgLoader.getSeekCallback(stream);
+
+ Int32 detectedImageFormatTmp = 0;
+ Int32 errCode = NativeFuncs.inst.AImgOpen(readCallback, tellCallback, seekCallback, IntPtr.Zero, out nativeHandle, out detectedImageFormatTmp);
+ AImgException.checkErrorCode(nativeHandle, errCode);
+
+ detectedFileFormat = (AImgFileFormat)detectedImageFormatTmp;
+
+ Int32 floatOrIntTmp = 0;
+ Int32 decodedImgFormatTmp = 0;
+ Int32 colourProfileLen = 0;
+ NativeFuncs.inst.AImgGetInfo(nativeHandle, out _width, out _height, out _numChannels, out _bytesPerChannel, out floatOrIntTmp, out decodedImgFormatTmp, out colourProfileLen);
+ floatOrInt = (AImgFloatOrIntType)floatOrIntTmp;
+ decodedImgFormat = (AImgFormat)decodedImgFormatTmp;
+ colourProfile = new byte[colourProfileLen];
+ fixed (byte* array = colourProfile)
+ {
+ System.Text.StringBuilder _colourProfileName = new System.Text.StringBuilder(30);
+ NativeFuncs.inst.AImgGetColourProfile(nativeHandle, _colourProfileName, (IntPtr)array, out colourProfileLen);
+ colourProfileName = _colourProfileName.ToString();
+ }
+ }
+
+ ///
+ /// Decodes the image into a user-specified buffer.
+ ///
+ /// This buffer can be of any struct type, so for example for an RGBA8 image, you might use a byte array,
+ /// or a custom struct with byte fields for the r, g, b, and a components. A custom struct would need the [StructLayout(LayoutKind.Sequential), Serializable] attribute.
+ public void decodeImage(T[] destBuffer, AImgFormat forceImageFormat = AImgFormat.INVALID_FORMAT) where T : struct
+ {
+ uint size = (uint)(Marshal.SizeOf(default(T)));
+
+ if (size * destBuffer.Length < decodedImgFormat.sizeInBytes() * width * height)
+ throw new ArgumentException("destBuffer is too small for this image");
+
+ GCHandle pinnedArray = GCHandle.Alloc(destBuffer, GCHandleType.Pinned);
+ IntPtr pointer = pinnedArray.AddrOfPinnedObject();
+
+ Int32 errCode = NativeFuncs.inst.AImgDecodeImage(nativeHandle, pointer, (Int32)forceImageFormat);
+ AImgException.checkErrorCode(nativeHandle, errCode);
+
+ pinnedArray.Free();
+ }
+
+ public static bool IsFormatSupported(AImgFileFormat fileFormat, AImgFormat outputFormat)
+ {
+ return NativeFuncs.inst.AImgIsFormatSupported((Int32)fileFormat, (Int32)outputFormat);
+ }
+
+ public static AImgFormat getWhatFormatWillBeWrittenForData(AImgFileFormat fileFormat, AImgFormat inputFormat, AImgFormat outputFormat)
+ {
+ return (AImgFormat)NativeFuncs.inst.AImgGetWhatFormatWillBeWrittenForData((Int32)fileFormat, (Int32)inputFormat, (Int32)outputFormat);
+ }
+
+ public static AImgFormat ChangeFormatBitDepth(AImgFormat format, AImgFormat newBitDepth)
+ {
+ return (AImgFormat)NativeFuncs.inst.AIChangeBitDepth((Int32)format, (Int32)newBitDepth);
+ }
+
+ public static AImgFormat GetBitDepth(AImgFormat format)
+ {
+ return (AImgFormat)NativeFuncs.inst.AIGetBitDepth((Int32)format);
+ }
+
+ public unsafe void writeImage(T[] data,
+ int width,
+ int height,
+ AImgFormat inputFormat,
+ string profileName, byte[] colourProfile,
+ Stream s,
+ FormatEncodeOptions options = null) where T : struct
+ {
+ writeImage(data, width, height,
+ inputFormat, inputFormat,
+ profileName, colourProfile,
+ s, options);
+ }
+
+ public unsafe void writeImage(T[] data,
+ int width,
+ int height,
+ AImgFormat inputFormat,
+ AImgFormat outputFormat,
+ string profileName, byte[] colourProfile,
+ Stream s,
+ FormatEncodeOptions options = null) where T : struct
+ {
+ var writeCallback = ImgLoader.getWriteCallback(s);
+ var tellCallback = ImgLoader.getTellCallback(s);
+ var seekCallback = ImgLoader.getSeekCallback(s);
+
+ if (profileName == string.Empty)
+ profileName = "empty";
+
+ GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
+ IntPtr pointer = pinnedArray.AddrOfPinnedObject();
+
+ fixed (byte* colourProfileArray = colourProfile)
+ {
+ GCHandle encodeOptionsHandle = default(GCHandle);
+ IntPtr encodeOptionsPtr = IntPtr.Zero;
+
+ if (options != null)
+ {
+ encodeOptionsHandle = GCHandle.Alloc(options, GCHandleType.Pinned);
+ encodeOptionsPtr = encodeOptionsHandle.AddrOfPinnedObject();
+ }
+ try
+ {
+ int colourProfileLength = 0;
+ if (colourProfile != null)
+ {
+ colourProfileLength = colourProfile.Length;
+ }
+
+ Int32 errCode = NativeFuncs.inst.AImgWriteImage(nativeHandle, pointer, width, height,
+ (Int32)inputFormat, (Int32)outputFormat,
+ profileName, (IntPtr)colourProfileArray, colourProfileLength,
+ writeCallback, tellCallback, seekCallback, IntPtr.Zero, encodeOptionsPtr);
+ AImgException.checkErrorCode(nativeHandle, errCode);
+ }
+ finally
+ {
+ pinnedArray.Free();
+
+ if (encodeOptionsPtr != IntPtr.Zero)
+ encodeOptionsHandle.Free();
+ }
+ }
+ GC.KeepAlive(writeCallback);
+ GC.KeepAlive(tellCallback);
+ GC.KeepAlive(seekCallback);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (!disposed)
+ {
+ disposed = true;
+
+ if (disposing)
+ GC.SuppressFinalize(this);
+
+ NativeFuncs.inst.AImgClose(nativeHandle);
+
+ if (doDisposeStream)
+ stream.Dispose();
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ ~AImg()
+ {
+ Dispose(false);
+ }
+ }
}
\ No newline at end of file
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Artomatix.ImageLoader.csproj b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Artomatix.ImageLoader.csproj
index 261970d..385f454 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Artomatix.ImageLoader.csproj
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Artomatix.ImageLoader.csproj
@@ -1,130 +1,104 @@
-
-
-
- Debug
- x64
- {C0BB2915-8150-4817-9351-2B7F83D96F2A}
- Library
- Artomatix.ImageLoader
- Artomatix.ImageLoader
- v4.6
- 12.0.0
- 2.0
-
-
-
-
-
- true
- bin\x64\Debug\
- DEBUG;
- true
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- 4
- false
-
-
- bin\x64\Release\
- true
- true
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- 4
-
-
- true
- bin\x86\Debug\
- DEBUG;
- true
- full
- x86
- prompt
- MinimumRecommendedRules.ruleset
- 4
- false
-
-
- bin\x86\Release\
- true
- true
- full
- x86
- prompt
- MinimumRecommendedRules.ruleset
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
- ..\..\..\..\packages\NativeBinaryManager\lib\NativeBinaryManager.dll
- True
- True
-
-
-
-
-
-
-
-
- ..\..\..\..\packages\NUnit\lib\nunit.framework.dll
- True
- True
-
-
-
-
-
-
-
-
- ..\..\..\..\packages\Stugo.Interop\lib\Stugo.Interop.dll
- True
- True
-
-
-
-
-
-
-
-
- ..\..\..\..\packages\ZipStorer\lib\net20\ZipStorer.dll
- True
- True
-
-
-
-
+
+
+
+
+ Debug
+ x64
+ {C0BB2915-8150-4817-9351-2B7F83D96F2A}
+ Library
+ Artomatix.ImageLoader
+ Artomatix.ImageLoader
+ v4.6
+ 512
+
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;
+ true
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ 4
+ false
+
+
+ bin\x64\Release\
+ true
+ true
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\..\..\packages\NativeBinaryManager\lib\NativeBinaryManager.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\..\..\packages\NUnit\lib\nunit.framework.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\..\..\packages\Stugo.Interop\lib\Stugo.Interop.dll
+ True
+ True
+
+
+
+
+
+
+
+
+ ..\..\..\..\packages\ZipStorer\lib\net452\ZipStorer.dll
+ True
+ True
+
+
+
+
\ No newline at end of file
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Enums.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Enums.cs
index 4e2218c..04edba7 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Enums.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Enums.cs
@@ -17,34 +17,48 @@ public enum AImgFileFormat
PNG_IMAGE_FORMAT = 2,
JPEG_IMAGE_FORMAT = 3,
TGA_IMAGE_FORMAT = 4,
- TIFF_IMAGE_FORMAT = 5
+ TIFF_IMAGE_FORMAT = 5,
+ HDR_IMAGE_FORMAT = 6
};
// format is [channels][bits per channel][U/F]
// U means unsigned normalised, so eg 8U maps integer vals 0-255 to float range 0-1, F means an normal float value
+
+ [Flags]
public enum AImgFormat
{
INVALID_FORMAT = -1,
- R8U = 0,
- RG8U = 1,
- RGB8U = 2,
- RGBA8U = 3,
-
- R16U = 4,
- RG16U = 5,
- RGB16U = 6,
- RGBA16U = 7,
-
- R16F = 8,
- RG16F = 9,
- RGB16F = 10,
- RGBA16F = 11,
-
- R32F = 12,
- RG32F = 13,
- RGB32F = 14,
- RGBA32F = 15
+ _8BITS = 1 << 0,
+ _16BITS = 1 << 5,
+ _32BITS = 1 << 6,
+
+ R = 1 << 1,
+ RG = 1 << 2,
+ RGB = 1 << 3,
+ RGBA = 1 << 4,
+
+ FLOAT_FORMAT = 1 << 7,
+
+ R8U = R | _8BITS,
+ RG8U = RG | _8BITS,
+ RGB8U = RGB | _8BITS,
+ RGBA8U = RGBA | _8BITS,
+
+ R16U = R | _16BITS,
+ RG16U = RG | _16BITS,
+ RGB16U = RGB | _16BITS,
+ RGBA16U = RGBA | _16BITS,
+
+ R16F = R | _16BITS | FLOAT_FORMAT,
+ RG16F = RG | _16BITS | FLOAT_FORMAT,
+ RGB16F = RGB | _16BITS | FLOAT_FORMAT,
+ RGBA16F = RGBA | _16BITS | FLOAT_FORMAT,
+
+ R32F = R | _32BITS | FLOAT_FORMAT,
+ RG32F = RG | _32BITS | FLOAT_FORMAT,
+ RGB32F = RGB | _32BITS | FLOAT_FORMAT,
+ RGBA32F = RGBA | _32BITS | FLOAT_FORMAT
};
public static class AImgFormatExtension
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Exceptions.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Exceptions.cs
index 69de3f1..509d628 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Exceptions.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Exceptions.cs
@@ -1,5 +1,6 @@
using System;
-
+using System.Runtime.Serialization;
+
namespace Artomatix.ImageLoader
{
public class AImgException : Exception
@@ -37,14 +38,23 @@ public static void checkErrorCode(IntPtr img, Int32 errorCode)
throw new AImgOpenFailedEmptyInputException(msg);
case -9:
throw new AImgInvalidEncodeArgsException(msg);
+ case -10:
+ throw new AImgWriteNotSupportedForFormat(msg);
default:
throw new AImgException("Unknown error code: " + errorCode + " " + msg);
}
}
}
- }
-
+ }
+
+ internal class AImgWriteNotSupportedForFormat : Exception
+ {
+ public AImgWriteNotSupportedForFormat(string message) : base(message)
+ {
+ }
+ }
+
public class AImgUnsupportedFiletypeException : AImgException
{
public AImgUnsupportedFiletypeException(string msg) : base(msg)
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/NativeFuncs.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/NativeFuncs.cs
index e386377..3b4e96f 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/NativeFuncs.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/NativeFuncs.cs
@@ -13,7 +13,7 @@ internal class NativeFuncs
{
private static NativeFuncs initNative()
{
- var dllPath = Path.GetFullPath("AIMG.dll");
+ var dllPath = Path.GetFullPath($"{AppDomain.CurrentDomain.BaseDirectory}/AIMG.dll");
#if DEBUG
var zipStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Artomatix.ImageLoader.embedded_files.binaries.zip");
NativeBinaryManager.NativeBinaryManager.ExtractNativeBinary(zipStream, dllPath);
@@ -69,7 +69,22 @@ private static NativeFuncs initNative()
[EntryPoint("AImgCleanUp")]
public AImgCleanUp_t AImgCleanUp;
- public delegate Int32 AImgGetWhatFormatWillBeWrittenForData_t(Int32 fileFormat, Int32 inputFormat);
+ public delegate Int32 AIChangeBitDepth_t(Int32 format, Int32 newBitDepth);
+
+ [EntryPoint("AIChangeBitDepth")]
+ public AIChangeBitDepth_t AIChangeBitDepth;
+
+ public delegate Int32 AIGetBitDepth_t(Int32 format);
+
+ [EntryPoint("AIGetBitDepth")]
+ public AIGetBitDepth_t AIGetBitDepth;
+
+ public delegate bool AImgIsFormatSupported_t(Int32 fileFormat, Int32 outputFormat);
+
+ [EntryPoint("AImgIsFormatSupported")]
+ public AImgIsFormatSupported_t AImgIsFormatSupported;
+
+ public delegate Int32 AImgGetWhatFormatWillBeWrittenForData_t(Int32 fileFormat, Int32 inputFormat, Int32 outputFormat);
[EntryPoint("AImgGetWhatFormatWillBeWrittenForData")]
public AImgGetWhatFormatWillBeWrittenForData_t AImgGetWhatFormatWillBeWrittenForData;
@@ -87,7 +102,8 @@ out Int32 detectedFileFormat
public AImgOpen_t AImgOpen;
public delegate Int32 AImgWriteImage_t(
- IntPtr img, IntPtr data, Int32 width, Int32 height, Int32 inputFormat, string profileName, IntPtr colourProfile, Int32 colourProfileLength,
+ IntPtr img, IntPtr data, Int32 width, Int32 height, Int32 inputFormat, Int32 outputFormat,
+ string profileName, IntPtr colourProfile, Int32 colourProfileLength,
[MarshalAs(UnmanagedType.FunctionPtr)] ImgLoader.WriteCallback writeCallback,
[MarshalAs(UnmanagedType.FunctionPtr)] ImgLoader.TellCallback tellCallback,
[MarshalAs(UnmanagedType.FunctionPtr)] ImgLoader.SeekCallback seekCallback,
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Properties/AssemblyInfo.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Properties/AssemblyInfo.cs
index 7d10efb..8bed5fd 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Properties/AssemblyInfo.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoader/Properties/AssemblyInfo.cs
@@ -9,7 +9,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("wheybags")]
+[assembly: AssemblyCopyright("Artomatix Limited")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/ArtomatixImageLoaderTests.csproj b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/ArtomatixImageLoaderTests.csproj
index 55f23b3..6d95b1e 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/ArtomatixImageLoaderTests.csproj
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/ArtomatixImageLoaderTests.csproj
@@ -107,7 +107,7 @@
- ..\..\..\..\packages\ZipStorer\lib\net20\ZipStorer.dll
+ ..\..\..\..\packages\ZipStorer\lib\net452\ZipStorer.dll
True
True
diff --git a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/TestAImg.cs b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/TestAImg.cs
index bd66131..0de42f4 100644
--- a/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/TestAImg.cs
+++ b/bindings/csharp/ArtomatixImageLoader/ArtomatixImageLoaderTests/TestAImg.cs
@@ -98,10 +98,34 @@ public static void TestForceImageFormat()
[Test]
public static void TestGetWhatFormatWIllBeWritten()
{
- AImgFormat res = AImg.getWhatFormatWillBeWrittenForData(AImgFileFormat.EXR_IMAGE_FORMAT, AImgFormat.RGBA32F);
+ AImgFormat res = AImg.getWhatFormatWillBeWrittenForData(AImgFileFormat.EXR_IMAGE_FORMAT, AImgFormat.RGBA32F, AImgFormat.INVALID_FORMAT);
Assert.AreEqual(AImgFormat.RGBA32F, res);
}
+ [Test]
+ public static void TestSupportedFormat()
+ {
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.TIFF_IMAGE_FORMAT, AImgFormat._8BITS));
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.TIFF_IMAGE_FORMAT, AImgFormat._16BITS));
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.TIFF_IMAGE_FORMAT, AImgFormat._32BITS));
+
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.EXR_IMAGE_FORMAT, AImgFormat._8BITS));
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.EXR_IMAGE_FORMAT, AImgFormat._16BITS));
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.EXR_IMAGE_FORMAT, AImgFormat._32BITS));
+
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.JPEG_IMAGE_FORMAT, AImgFormat._8BITS));
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.JPEG_IMAGE_FORMAT, AImgFormat._16BITS));
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.JPEG_IMAGE_FORMAT, AImgFormat._32BITS));
+
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.PNG_IMAGE_FORMAT, AImgFormat._8BITS));
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.PNG_IMAGE_FORMAT, AImgFormat._16BITS));
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.PNG_IMAGE_FORMAT, AImgFormat._32BITS));
+
+ Assert.True(AImg.IsFormatSupported(AImgFileFormat.TGA_IMAGE_FORMAT, AImgFormat._8BITS));
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.TGA_IMAGE_FORMAT, AImgFormat._16BITS));
+ Assert.False(AImg.IsFormatSupported(AImgFileFormat.TGA_IMAGE_FORMAT, AImgFormat._32BITS));
+ }
+
[Test]
public static void TestWriteExr()
{
diff --git a/paket.dependencies b/paket.dependencies
index 739e5c7..1cdb6f9 100644
--- a/paket.dependencies
+++ b/paket.dependencies
@@ -1,6 +1,7 @@
framework: net46
source https://api.nuget.org/v3/index.json
-nuget NativeCodeBuilder 0.1.3 framework: >= net45, content: once
+source ./built_packages
+nuget NativeCodeBuilder 0.3.1 framework: >= net45, content: once
nuget NUnit == 2.6.4
nuget Stugo.Interop == 0.2
diff --git a/paket.lock b/paket.lock
index e37debf..7f71abc 100644
--- a/paket.lock
+++ b/paket.lock
@@ -3,8 +3,8 @@ NUGET
remote: https://api.nuget.org/v3/index.json
NativeBinaryManager (0.1) - content: once
ZipStorer (>= 2.38)
- NativeCodeBuilder (0.1.3) - content: once
+ NativeCodeBuilder (0.3.1) - content: once, framework: >= net45
NativeBinaryManager (0.1)
NUnit (2.6.4)
Stugo.Interop (0.2)
- ZipStorer (2.38) - content: once
+ ZipStorer (3.4) - content: once
diff --git a/src_c/AIL.cpp b/src_c/AIL.cpp
index c5b4d1e..548c9cb 100644
--- a/src_c/AIL.cpp
+++ b/src_c/AIL.cpp
@@ -12,40 +12,44 @@
#include "jpeg.h"
#include "tga.h"
#include "tiff.h"
+#include "hdr.h"
#ifdef HAVE_EXR
- #include
+#include
#endif
std::map loaders;
-
int32_t AImgInitialise()
{
- #ifdef HAVE_EXR
- loaders[AImgFileFormat::EXR_IMAGE_FORMAT] = new AImg::ExrImageLoader();
- #endif
+#ifdef HAVE_EXR
+ loaders[AImgFileFormat::EXR_IMAGE_FORMAT] = new AImg::ExrImageLoader();
+#endif
+
+#ifdef HAVE_PNG
+ loaders[AImgFileFormat::PNG_IMAGE_FORMAT] = new AImg::PNGImageLoader();
+#endif
- #ifdef HAVE_PNG
- loaders[AImgFileFormat::PNG_IMAGE_FORMAT] = new AImg::PNGImageLoader();
- #endif
+#ifdef HAVE_JPEG
+ loaders[AImgFileFormat::JPEG_IMAGE_FORMAT] = new AImg::JPEGImageLoader();
+#endif
- #ifdef HAVE_JPEG
- loaders[AImgFileFormat::JPEG_IMAGE_FORMAT] = new AImg::JPEGImageLoader();
- #endif
+#ifdef HAVE_TGA
+ loaders[AImgFileFormat::TGA_IMAGE_FORMAT] = new AImg::TGAImageLoader();
+#endif
- #ifdef HAVE_TGA
- loaders[AImgFileFormat::TGA_IMAGE_FORMAT] = new AImg::TGAImageLoader();
- #endif
+#ifdef HAVE_TIFF
+ loaders[AImgFileFormat::TIFF_IMAGE_FORMAT] = new AImg::TIFFImageLoader();
+#endif
- #ifdef HAVE_TIFF
- loaders[AImgFileFormat::TIFF_IMAGE_FORMAT] = new AImg::TIFFImageLoader();
- #endif
+#ifdef HAVE_HDR
+ loaders[AImgFileFormat::HDR_IMAGE_FORMAT] = new AImg::HDRImageLoader();
+#endif
- for(auto it = loaders.begin(); it != loaders.end(); ++it)
+ for (auto it = loaders.begin(); it != loaders.end(); ++it)
{
int32_t err = it->second->initialise();
- if(err != AImgErrorCode::AIMG_SUCCESS)
+ if (err != AImgErrorCode::AIMG_SUCCESS)
return err;
}
@@ -54,7 +58,7 @@ int32_t AImgInitialise()
void AImgCleanUp()
{
- for(auto it = loaders.begin(); it != loaders.end(); ++it)
+ for (auto it = loaders.begin(); it != loaders.end(); ++it)
delete it->second;
loaders.clear();
@@ -73,7 +77,7 @@ int32_t AImgOpen(ReadCallback readCallback, TellCallback tellCallback, SeekCallb
int32_t startPos = tellCallback(callbackData);
uint8_t testByte;
- if(readCallback(callbackData, &testByte, 1) != 1)
+ if (readCallback(callbackData, &testByte, 1) != 1)
return AImgErrorCode::AIMG_OPEN_FAILED_EMPTY_INPUT;
seekCallback(callbackData, startPos);
@@ -81,9 +85,9 @@ int32_t AImgOpen(ReadCallback readCallback, TellCallback tellCallback, SeekCallb
int32_t fileFormat = UNKNOWN_IMAGE_FORMAT;
int32_t retval = AIMG_UNSUPPORTED_FILETYPE;
- for(auto it = loaders.begin(); it != loaders.end(); ++it)
+ for (auto it = loaders.begin(); it != loaders.end(); ++it)
{
- if(it->second->canLoadImage(readCallback, tellCallback, seekCallback, callbackData))
+ if (it->second->canLoadImage(readCallback, tellCallback, seekCallback, callbackData))
{
fileFormat = it->second->getAImgFileFormatValue();
@@ -95,7 +99,7 @@ int32_t AImgOpen(ReadCallback readCallback, TellCallback tellCallback, SeekCallb
}
}
- if(detectedFileFormat != NULL)
+ if (detectedFileFormat != NULL)
*detectedFileFormat = fileFormat;
return retval;
@@ -136,220 +140,221 @@ AImgHandle AImgGetAImg(int32_t fileFormat)
return loaders[fileFormat]->getAImg();
}
-int32_t AImgWriteImage(AImgHandle imgH, void* data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions)
+int32_t AImgWriteImage(AImgHandle imgH, void* data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions)
{
AImg::AImgBase* img = (AImg::AImgBase*)imgH;
int32_t err = img->verifyEncodeOptions(encodingOptions);
- if(err != AImgErrorCode::AIMG_SUCCESS)
+ if (err != AImgErrorCode::AIMG_SUCCESS)
return err;
- return img->writeImage(data, width, height, inputFormat, profileName, colourProfile, colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, encodingOptions);
+ return img->writeImage(data, width, height, inputFormat, outputFormat, profileName, colourProfile, colourProfileLen,
+ writeCallback, tellCallback, seekCallback, callbackData, encodingOptions);
}
void convertToRGBA32F(void* src, std::vector& dest, size_t i, int32_t inFormat)
{
switch (inFormat)
{
- case AImgFormat::R8U:
- {
- uint8_t* srcF = ((uint8_t*)src) + (i*1);
+ case AImgFormat::R8U:
+ {
+ uint8_t* srcF = ((uint8_t*)src) + (i * 1);
- dest[0] = ((float)srcF[0]) / 255.0f;
- dest[1] = ((float)srcF[0]) / 255.0f;
- dest[2] = ((float)srcF[0]) / 255.0f;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 255.0f;
+ dest[1] = ((float)srcF[0]) / 255.0f;
+ dest[2] = ((float)srcF[0]) / 255.0f;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RG8U:
- {
- uint8_t* srcF = ((uint8_t*)src) + (i*2);
+ case AImgFormat::RG8U:
+ {
+ uint8_t* srcF = ((uint8_t*)src) + (i * 2);
- dest[0] = ((float)srcF[0]) / 255.0f;
- dest[1] = ((float)srcF[1]) / 255.0f;
- dest[2] = 0;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 255.0f;
+ dest[1] = ((float)srcF[1]) / 255.0f;
+ dest[2] = 0;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGB8U:
- {
- uint8_t* srcF = ((uint8_t*)src) + (i*3);
+ case AImgFormat::RGB8U:
+ {
+ uint8_t* srcF = ((uint8_t*)src) + (i * 3);
- dest[0] = ((float)srcF[0]) / 255.0f;
- dest[1] = ((float)srcF[1]) / 255.0f;
- dest[2] = ((float)srcF[2]) / 255.0f;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 255.0f;
+ dest[1] = ((float)srcF[1]) / 255.0f;
+ dest[2] = ((float)srcF[2]) / 255.0f;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA8U:
- {
- uint8_t* srcF = ((uint8_t*)src) + (i*4);
+ case AImgFormat::RGBA8U:
+ {
+ uint8_t* srcF = ((uint8_t*)src) + (i * 4);
- dest[0] = ((float)srcF[0]) / 255.0f;
- dest[1] = ((float)srcF[1]) / 255.0f;
- dest[2] = ((float)srcF[2]) / 255.0f;
- dest[3] = ((float)srcF[3]) / 255.0f;
+ dest[0] = ((float)srcF[0]) / 255.0f;
+ dest[1] = ((float)srcF[1]) / 255.0f;
+ dest[2] = ((float)srcF[2]) / 255.0f;
+ dest[3] = ((float)srcF[3]) / 255.0f;
- break;
- }
+ break;
+ }
- #ifdef HAVE_EXR
- case AImgFormat::R16F:
- {
- half* srcF = ((half*)src) + (i*1);
+#ifdef HAVE_EXR
+ case AImgFormat::R16F:
+ {
+ half* srcF = ((half*)src) + (i * 1);
- dest[0] = (float)srcF[0];
- dest[1] = (float)srcF[0];
- dest[2] = (float)srcF[0];
- dest[3] = 1;
+ dest[0] = (float)srcF[0];
+ dest[1] = (float)srcF[0];
+ dest[2] = (float)srcF[0];
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RG16F:
- {
- half* srcF = ((half*)src) + (i*2);
+ case AImgFormat::RG16F:
+ {
+ half* srcF = ((half*)src) + (i * 2);
- dest[0] = (float)srcF[0];
- dest[1] = (float)srcF[1];
- dest[2] = 0;
- dest[3] = 1;
+ dest[0] = (float)srcF[0];
+ dest[1] = (float)srcF[1];
+ dest[2] = 0;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGB16F:
- {
- half* srcF = ((half*)src) + (i*3);
+ case AImgFormat::RGB16F:
+ {
+ half* srcF = ((half*)src) + (i * 3);
- dest[0] = (float)srcF[0];
- dest[1] = (float)srcF[1];
- dest[2] = (float)srcF[2];
- dest[3] = 1;
+ dest[0] = (float)srcF[0];
+ dest[1] = (float)srcF[1];
+ dest[2] = (float)srcF[2];
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA16F:
- {
- half* srcF = ((half*)src) + (i*4);
+ case AImgFormat::RGBA16F:
+ {
+ half* srcF = ((half*)src) + (i * 4);
- dest[0] = (float)srcF[0];
- dest[1] = (float)srcF[1];
- dest[2] = (float)srcF[2];
- dest[3] = (float)srcF[3];
+ dest[0] = (float)srcF[0];
+ dest[1] = (float)srcF[1];
+ dest[2] = (float)srcF[2];
+ dest[3] = (float)srcF[3];
- break;
- }
- #endif
+ break;
+ }
+#endif
- case AImgFormat::R16U:
- {
- uint16_t* srcF = ((uint16_t*)src) + (i*1);
+ case AImgFormat::R16U:
+ {
+ uint16_t* srcF = ((uint16_t*)src) + (i * 1);
- dest[0] = ((float)srcF[0]) / 65535.0f;
- dest[1] = ((float)srcF[0]) / 65535.0f;
- dest[2] = ((float)srcF[0]) / 65535.0f;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 65535.0f;
+ dest[1] = ((float)srcF[0]) / 65535.0f;
+ dest[2] = ((float)srcF[0]) / 65535.0f;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RG16U:
- {
- uint16_t* srcF = ((uint16_t*)src) + (i*2);
+ case AImgFormat::RG16U:
+ {
+ uint16_t* srcF = ((uint16_t*)src) + (i * 2);
- dest[0] = ((float)srcF[0]) / 65535.0f;
- dest[1] = ((float)srcF[1]) / 65535.0f;
- dest[2] = 0;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 65535.0f;
+ dest[1] = ((float)srcF[1]) / 65535.0f;
+ dest[2] = 0;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGB16U:
- {
- uint16_t* srcF = ((uint16_t*)src) + (i*3);
+ case AImgFormat::RGB16U:
+ {
+ uint16_t* srcF = ((uint16_t*)src) + (i * 3);
- dest[0] = ((float)srcF[0]) / 65535.0f;
- dest[1] = ((float)srcF[1]) / 65535.0f;
- dest[2] = ((float)srcF[2]) / 65535.0f;
- dest[3] = 1;
+ dest[0] = ((float)srcF[0]) / 65535.0f;
+ dest[1] = ((float)srcF[1]) / 65535.0f;
+ dest[2] = ((float)srcF[2]) / 65535.0f;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA16U:
- {
- uint16_t* srcF = ((uint16_t*)src) + (i*4);
+ case AImgFormat::RGBA16U:
+ {
+ uint16_t* srcF = ((uint16_t*)src) + (i * 4);
- dest[0] = ((float)srcF[0]) / 65535.0f;
- dest[1] = ((float)srcF[1]) / 65535.0f;
- dest[2] = ((float)srcF[2]) / 65535.0f;
- dest[3] = ((float)srcF[3]) / 65535.0f;
+ dest[0] = ((float)srcF[0]) / 65535.0f;
+ dest[1] = ((float)srcF[1]) / 65535.0f;
+ dest[2] = ((float)srcF[2]) / 65535.0f;
+ dest[3] = ((float)srcF[3]) / 65535.0f;
- break;
- }
+ break;
+ }
- case AImgFormat::R32F:
- {
- float* srcF = ((float*)src) + (i*1);
+ case AImgFormat::R32F:
+ {
+ float* srcF = ((float*)src) + (i * 1);
- dest[0] = srcF[0];
- dest[1] = srcF[0];
- dest[2] = srcF[0];
- dest[3] = 1;
+ dest[0] = srcF[0];
+ dest[1] = srcF[0];
+ dest[2] = srcF[0];
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RG32F:
- {
- float* srcF = ((float*)src) + (i*2);
+ case AImgFormat::RG32F:
+ {
+ float* srcF = ((float*)src) + (i * 2);
- dest[0] = srcF[0];
- dest[1] = srcF[1];
- dest[2] = 0;
- dest[3] = 1;
+ dest[0] = srcF[0];
+ dest[1] = srcF[1];
+ dest[2] = 0;
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGB32F:
- {
- float* srcF = ((float*)src) + (i*3);
+ case AImgFormat::RGB32F:
+ {
+ float* srcF = ((float*)src) + (i * 3);
- dest[0] = srcF[0];
- dest[1] = srcF[1];
- dest[2] = srcF[2];
- dest[3] = 1;
+ dest[0] = srcF[0];
+ dest[1] = srcF[1];
+ dest[2] = srcF[2];
+ dest[3] = 1;
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA32F:
- {
- float* srcF = ((float*)src) + (i*4);
+ case AImgFormat::RGBA32F:
+ {
+ float* srcF = ((float*)src) + (i * 4);
- dest[0] = srcF[0];
- dest[1] = srcF[1];
- dest[2] = srcF[2];
- dest[3] = srcF[3];
+ dest[0] = srcF[0];
+ dest[1] = srcF[1];
+ dest[2] = srcF[2];
+ dest[3] = srcF[3];
- break;
- }
+ break;
+ }
- default:
- {
- break;
- }
+ default:
+ {
+ break;
+ }
}
}
@@ -357,335 +362,390 @@ void convertFromRGBA32F(std::vector& src, void* dst, size_t i, int32_t ou
{
switch (outFormat)
{
- case AImgFormat::R8U:
- {
- uint8_t* dstF = ((uint8_t*)dst) + (i*1);
+ case AImgFormat::R8U:
+ {
+ uint8_t* dstF = ((uint8_t*)dst) + (i * 1);
- dstF[0] = (uint8_t)(src[0] * 255.0f);
+ dstF[0] = (uint8_t)(src[0] * 255.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RG8U:
- {
- uint8_t* dstF = ((uint8_t*)dst) + (i*2);
+ case AImgFormat::RG8U:
+ {
+ uint8_t* dstF = ((uint8_t*)dst) + (i * 2);
- dstF[0] = (uint8_t)(src[0] * 255.0f);
- dstF[1] = (uint8_t)(src[1] * 255.0f);
+ dstF[0] = (uint8_t)(src[0] * 255.0f);
+ dstF[1] = (uint8_t)(src[1] * 255.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RGB8U:
- {
- uint8_t* dstF = ((uint8_t*)dst) + (i*3);
+ case AImgFormat::RGB8U:
+ {
+ uint8_t* dstF = ((uint8_t*)dst) + (i * 3);
- dstF[0] = (uint8_t)(src[0] * 255.0f);
- dstF[1] = (uint8_t)(src[1] * 255.0f);
- dstF[2] = (uint8_t)(src[2] * 255.0f);
+ dstF[0] = (uint8_t)(src[0] * 255.0f);
+ dstF[1] = (uint8_t)(src[1] * 255.0f);
+ dstF[2] = (uint8_t)(src[2] * 255.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA8U:
- {
- uint8_t* dstF = ((uint8_t*)dst) + (i*4);
+ case AImgFormat::RGBA8U:
+ {
+ uint8_t* dstF = ((uint8_t*)dst) + (i * 4);
- dstF[0] = (uint8_t)(src[0] * 255.0f);
- dstF[1] = (uint8_t)(src[1] * 255.0f);
- dstF[2] = (uint8_t)(src[2] * 255.0f);
- dstF[3] = (uint8_t)(src[3] * 255.0f);
+ dstF[0] = (uint8_t)(src[0] * 255.0f);
+ dstF[1] = (uint8_t)(src[1] * 255.0f);
+ dstF[2] = (uint8_t)(src[2] * 255.0f);
+ dstF[3] = (uint8_t)(src[3] * 255.0f);
- break;
- }
+ break;
+ }
- #ifdef HAVE_EXR
- case AImgFormat::R16F:
- {
- half* dstF = ((half*)dst) + (i*1);
+#ifdef HAVE_EXR
+ case AImgFormat::R16F:
+ {
+ half* dstF = ((half*)dst) + (i * 1);
- dstF[0] = src[0];
+ dstF[0] = src[0];
- break;
- }
+ break;
+ }
- case AImgFormat::RG16F:
- {
- half* dstF = ((half*)dst) + (i*2);
+ case AImgFormat::RG16F:
+ {
+ half* dstF = ((half*)dst) + (i * 2);
- dstF[0] = src[0];
- dstF[1] = src[1];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
- break;
- }
+ break;
+ }
- case AImgFormat::RGB16F:
- {
- half* dstF = ((half*)dst) + (i*3);
+ case AImgFormat::RGB16F:
+ {
+ half* dstF = ((half*)dst) + (i * 3);
- dstF[0] = src[0];
- dstF[1] = src[1];
- dstF[2] = src[2];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
+ dstF[2] = src[2];
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA16F:
- {
- half* dstF = ((half*)dst) + (i*4);
+ case AImgFormat::RGBA16F:
+ {
+ half* dstF = ((half*)dst) + (i * 4);
- dstF[0] = src[0];
- dstF[1] = src[1];
- dstF[2] = src[2];
- dstF[3] = src[3];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
+ dstF[2] = src[2];
+ dstF[3] = src[3];
- break;
- }
- #endif
+ break;
+ }
+#endif
- case AImgFormat::R16U:
- {
- uint16_t* dstF = ((uint16_t*)dst) + (i*1);
+ case AImgFormat::R16U:
+ {
+ uint16_t* dstF = ((uint16_t*)dst) + (i * 1);
- dstF[0] = (uint16_t)(src[0] * 65535.0f);
+ dstF[0] = (uint16_t)(src[0] * 65535.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RG16U:
- {
- uint16_t* dstF = ((uint16_t*)dst) + (i*2);
+ case AImgFormat::RG16U:
+ {
+ uint16_t* dstF = ((uint16_t*)dst) + (i * 2);
- dstF[0] = (uint16_t)(src[0] * 65535.0f);
- dstF[1] = (uint16_t)(src[1] * 65535.0f);
+ dstF[0] = (uint16_t)(src[0] * 65535.0f);
+ dstF[1] = (uint16_t)(src[1] * 65535.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RGB16U:
- {
- uint16_t* dstF = ((uint16_t*)dst) + (i*3);
+ case AImgFormat::RGB16U:
+ {
+ uint16_t* dstF = ((uint16_t*)dst) + (i * 3);
- dstF[0] = (uint16_t)(src[0] * 65535.0f);
- dstF[1] = (uint16_t)(src[1] * 65535.0f);
- dstF[2] = (uint16_t)(src[2] * 65535.0f);
+ dstF[0] = (uint16_t)(src[0] * 65535.0f);
+ dstF[1] = (uint16_t)(src[1] * 65535.0f);
+ dstF[2] = (uint16_t)(src[2] * 65535.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA16U:
- {
- uint16_t* dstF = ((uint16_t*)dst) + (i*4);
+ case AImgFormat::RGBA16U:
+ {
+ uint16_t* dstF = ((uint16_t*)dst) + (i * 4);
- dstF[0] = (uint16_t)(src[0] * 65535.0f);
- dstF[1] = (uint16_t)(src[1] * 65535.0f);
- dstF[2] = (uint16_t)(src[2] * 65535.0f);
- dstF[3] = (uint16_t)(src[3] * 65535.0f);
+ dstF[0] = (uint16_t)(src[0] * 65535.0f);
+ dstF[1] = (uint16_t)(src[1] * 65535.0f);
+ dstF[2] = (uint16_t)(src[2] * 65535.0f);
+ dstF[3] = (uint16_t)(src[3] * 65535.0f);
- break;
- }
+ break;
+ }
- case AImgFormat::R32F:
- {
- float* dstF = ((float*)dst) + (i*1);
+ case AImgFormat::R32F:
+ {
+ float* dstF = ((float*)dst) + (i * 1);
- dstF[0] = src[0];
+ dstF[0] = src[0];
- break;
- }
+ break;
+ }
- case AImgFormat::RG32F:
- {
- float* dstF = ((float*)dst) + (i*2);
+ case AImgFormat::RG32F:
+ {
+ float* dstF = ((float*)dst) + (i * 2);
- dstF[0] = src[0];
- dstF[1] = src[1];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
- break;
- }
+ break;
+ }
- case AImgFormat::RGB32F:
- {
- float* dstF = ((float*)dst) + (i*3);
+ case AImgFormat::RGB32F:
+ {
+ float* dstF = ((float*)dst) + (i * 3);
- dstF[0] = src[0];
- dstF[1] = src[1];
- dstF[2] = src[2];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
+ dstF[2] = src[2];
- break;
- }
+ break;
+ }
- case AImgFormat::RGBA32F:
- {
- float* dstF = ((float*)dst) + (i*4);
+ case AImgFormat::RGBA32F:
+ {
+ float* dstF = ((float*)dst) + (i * 4);
- dstF[0] = src[0];
- dstF[1] = src[1];
- dstF[2] = src[2];
- dstF[3] = src[3];
+ dstF[0] = src[0];
+ dstF[1] = src[1];
+ dstF[2] = src[2];
+ dstF[3] = src[3];
- break;
- }
+ break;
+ }
- default:
+ default:
+ {
+ break;
+ }
+ }
+}
+
+int32_t AIGetBitDepth(int32_t format)
+{
+ AImgFormat bitDepths[] = {
+ AImgFormat::_8BITS,
+ AImgFormat::_16BITS,
+ AImgFormat::_32BITS };
+
+ for (const AImgFormat &flag : bitDepths)
+ {
+ if (format & flag)
{
- break;
+ return flag;
}
}
+
+ delete[](&bitDepths);
+
+ return AImgFormat::INVALID_FORMAT;
+}
+
+int32_t AIChangeBitDepth(int32_t format, int32_t newBitDepth)
+{
+ if (newBitDepth != AImgFormat::_8BITS
+ && newBitDepth != AImgFormat::_16BITS
+ && newBitDepth != AImgFormat::_32BITS)
+ {
+ return AImgFormat::INVALID_FORMAT;
+ }
+
+ int32_t oldBitDepth = AIGetBitDepth(format);
+
+ // Remove old flag and add new one
+ int32_t newFormat = format;
+ if (oldBitDepth != AImgFormat::INVALID_FORMAT)
+ {
+ newFormat = format & ~oldBitDepth;
+ }
+
+ newFormat |= newBitDepth;
+
+ // Add float flag if the new bit depth is 32
+ if (newBitDepth == AImgFormat::_32BITS)
+ {
+ newFormat |= AImgFormat::FLOAT_FORMAT;
+ }
+
+ // Remove float flag if the new bit depth is 8
+ else if (newBitDepth == AImgFormat::_8BITS)
+ {
+ newFormat &= ~AImgFormat::FLOAT_FORMAT;
+ }
+
+ return (AImgFormat)newFormat;
}
void AIGetFormatDetails(int32_t format, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt)
{
- switch(format)
+ switch (format)
{
- case AImgFormat::R8U:
- {
- *numChannels = 1;
- *bytesPerChannel = 1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::R8U:
+ {
+ *numChannels = 1;
+ *bytesPerChannel = 1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RG8U:
- {
- *numChannels = 2;
- *bytesPerChannel = 1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RG8U:
+ {
+ *numChannels = 2;
+ *bytesPerChannel = 1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RGB8U:
- {
- *numChannels = 3;
- *bytesPerChannel = 1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RGB8U:
+ {
+ *numChannels = 3;
+ *bytesPerChannel = 1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RGBA8U:
- {
- *numChannels = 4;
- *bytesPerChannel = 1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RGBA8U:
+ {
+ *numChannels = 4;
+ *bytesPerChannel = 1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::R16F:
- {
- *numChannels = 1;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::R16F:
+ {
+ *numChannels = 1;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RG16F:
- {
- *numChannels = 2;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RG16F:
+ {
+ *numChannels = 2;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RGB16F:
- {
- *numChannels = 3;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RGB16F:
+ {
+ *numChannels = 3;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RGBA16F:
- {
- *numChannels = 4;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RGBA16F:
+ {
+ *numChannels = 4;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::R16U:
- {
- *numChannels = 1;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::R16U:
+ {
+ *numChannels = 1;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RG16U:
- {
- *numChannels = 2;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RG16U:
+ {
+ *numChannels = 2;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RGB16U:
- {
- *numChannels = 3;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RGB16U:
+ {
+ *numChannels = 3;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::RGBA16U:
- {
- *numChannels = 4;
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- break;
- }
+ case AImgFormat::RGBA16U:
+ {
+ *numChannels = 4;
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ break;
+ }
- case AImgFormat::R32F:
- {
- *numChannels = 1;
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::R32F:
+ {
+ *numChannels = 1;
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RG32F:
- {
- *numChannels = 2;
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RG32F:
+ {
+ *numChannels = 2;
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RGB32F:
- {
- *numChannels = 3;
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RGB32F:
+ {
+ *numChannels = 3;
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- case AImgFormat::RGBA32F:
- {
- *numChannels = 4;
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- break;
- }
+ case AImgFormat::RGBA32F:
+ {
+ *numChannels = 4;
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ break;
+ }
- default:
- {
- *numChannels = -1;
- *bytesPerChannel = -1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_UNKNOWN;
- break;
- }
+ default:
+ {
+ *numChannels = -1;
+ *bytesPerChannel = -1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_UNKNOWN;
+ break;
+ }
}
}
int32_t AImgConvertFormat(void* src, void* dest, int32_t width, int32_t height, int32_t inFormat, int32_t outFormat)
{
- #ifndef HAVE_EXR
- if(inFormat == AImgFormat::R16F || inFormat == AImgFormat::RG16F || inFormat == AImgFormat::RGB16F || inFormat == AImgFormat::RGBA16F ||
- outFormat == AImgFormat::R16F || outFormat == AImgFormat::RG16F || outFormat == AImgFormat::RGB16F || outFormat == AImgFormat::RGBA16F)
+#ifndef HAVE_EXR
+ if (inFormat == AImgFormat::R16F || inFormat == AImgFormat::RG16F || inFormat == AImgFormat::RGB16F || inFormat == AImgFormat::RGBA16F ||
+ outFormat == AImgFormat::R16F || outFormat == AImgFormat::RG16F || outFormat == AImgFormat::RGB16F || outFormat == AImgFormat::RGBA16F)
{
AISetLastErrorDetails("Bad format requested, 16 bit float formats not available when compiled without EXR support");
return AImgErrorCode::AIMG_CONVERSION_FAILED_BAD_FORMAT;
}
- #endif
+#endif
std::vector scratch(4);
@@ -695,12 +755,12 @@ int32_t AImgConvertFormat(void* src, void* dest, int32_t width, int32_t height,
AIGetFormatDetails(outFormat, &_, &_, &floatOrInt);
bool outIsFloat = floatOrInt == AImgFloatOrIntType::FITYPE_FLOAT;
- for(int32_t i = 0; i < width*height; i++)
+ for (int32_t i = 0; i < width*height; i++)
{
convertToRGBA32F(src, scratch, i, inFormat);
// clamp to 0-1 range
- if(inIsFloat && !outIsFloat)
+ if (inIsFloat && !outIsFloat)
{
scratch[0] = std::min(1.0f, std::max(0.0f, scratch[0]));
scratch[1] = std::min(1.0f, std::max(0.0f, scratch[1]));
@@ -714,9 +774,14 @@ int32_t AImgConvertFormat(void* src, void* dest, int32_t width, int32_t height,
return AImgErrorCode::AIMG_SUCCESS;
}
-int32_t AImgGetWhatFormatWillBeWrittenForData(int32_t fileFormat, int32_t inputFormat)
+bool AImgIsFormatSupported(int32_t fileFormat, int32_t outputFormat)
{
- return loaders[fileFormat]->getWhatFormatWillBeWrittenForData(inputFormat);
+ return loaders[fileFormat]->isFormatSupported(outputFormat);
+}
+
+int32_t AImgGetWhatFormatWillBeWrittenForData(int32_t fileFormat, int32_t inputFormat, int32_t outputFormat)
+{
+ return loaders[fileFormat]->getWhatFormatWillBeWrittenForData(inputFormat, outputFormat);
}
struct SimpleMemoryCallbackData
@@ -731,11 +796,11 @@ struct SimpleMemoryCallbackData
int32_t CALLCONV simpleMemoryReadCallback(void* callbackData, uint8_t* dest, int32_t count)
{
auto data = (SimpleMemoryCallbackData*)callbackData;
-
+
int32_t toWrite = count;
int32_t end = data->currentPos + count;
-
- if(end > data->size)
+
+ if (end > data->size)
toWrite = data->size - data->currentPos;
memcpy(dest, data->buffer + data->currentPos, toWrite);
@@ -752,7 +817,7 @@ void CALLCONV simpleMemoryWriteCallback(void* callbackData, const uint8_t* src,
int32_t toWrite = count;
int32_t end = data->currentPos + count;
- if(end > data->size)
+ if (end > data->size)
toWrite = data->size - data->currentPos;
memcpy(data->buffer + data->currentPos, src, toWrite);
@@ -767,11 +832,11 @@ void CALLCONV simpleMemoryResizableWriteCallback(void* callbackData, const uint8
int32_t toWrite = count;
int32_t end = data->currentPos + count;
- if(end > data->size)
+ if (end > data->size)
{
data->vecBuffer->resize(end);
data->buffer = &data->vecBuffer->operator[](0);
- data->size = data->vecBuffer->size();
+ data->size = (int32_t)data->vecBuffer->size();
}
memcpy(data->buffer + data->currentPos, src, toWrite);
@@ -779,7 +844,6 @@ void CALLCONV simpleMemoryResizableWriteCallback(void* callbackData, const uint8
data->currentPos += toWrite;
}
-
int32_t CALLCONV simpleMemoryTellCallback(void* callbackData)
{
auto data = (SimpleMemoryCallbackData*)callbackData;
@@ -796,7 +860,7 @@ void AIGetSimpleMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallback*
{
*readCallback = &simpleMemoryReadCallback;
*writeCallback = &simpleMemoryWriteCallback;
- *tellCallback = &simpleMemoryTellCallback;
+ *tellCallback = &simpleMemoryTellCallback;
*seekCallback = &simpleMemorySeekCallback;
auto data = new SimpleMemoryCallbackData();
@@ -815,7 +879,7 @@ void AIGetResizableMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallba
*seekCallback = &simpleMemorySeekCallback;
auto data = new SimpleMemoryCallbackData();
- data->size = vec->size();
+ data->size = (int32_t)vec->size();
data->buffer = &vec->operator[](0);
data->currentPos = 0;
data->vecBuffer = vec;
@@ -832,4 +896,4 @@ void AIDestroySimpleMemoryBufferCallbacks(ReadCallback readCallback, WriteCallba
auto data = (SimpleMemoryCallbackData*)callbackData;
delete data;
-}
+}
\ No newline at end of file
diff --git a/src_c/AIL.h b/src_c/AIL.h
index a20b914..3da113b 100644
--- a/src_c/AIL.h
+++ b/src_c/AIL.h
@@ -4,109 +4,120 @@
#include
#ifdef __cplusplus
-extern "C"
+extern "C"
{
#endif
#ifdef WIN32
- #define CALLCONV __stdcall
+#define CALLCONV __stdcall
- #ifdef IS_AIL_COMPILE
- #define EXPORT_FUNC __declspec(dllexport)
- #else
- #define EXPORT_FUNC __declspec(dllimport)
- #endif
+#ifdef IS_AIL_COMPILE
+#define EXPORT_FUNC __declspec(dllexport)
#else
- #define CALLCONV
- #define EXPORT_FUNC
+#define EXPORT_FUNC __declspec(dllimport)
+#endif
+#else
+#define CALLCONV
+#define EXPORT_FUNC
#endif
-///////////////////////
-// Callback typedefs //
-///////////////////////
-typedef int32_t (CALLCONV *ReadCallback) (void* callbackData, uint8_t* dest, int32_t count);
-typedef void (CALLCONV *WriteCallback) (void* callbackData, const uint8_t* src, int32_t count);
-typedef int32_t (CALLCONV *TellCallback) (void* callbackData);
-typedef void (CALLCONV *SeekCallback) (void* callbackData, int32_t pos);
-
-
-////////////////
-// Core enums //
-////////////////
-
-// format is [channels][bits per channel][U/F]
-// U means unsigned normalised, so eg 8U maps integer vals 0-255 to float range 0-1, F means a normal float value
-enum AImgFormat
-{
- INVALID_FORMAT = -1,
-
- R8U = 0,
- RG8U = 1,
- RGB8U = 2,
- RGBA8U = 3,
-
- R16U = 4,
- RG16U = 5,
- RGB16U = 6,
- RGBA16U = 7,
-
- R16F = 8,
- RG16F = 9,
- RGB16F = 10,
- RGBA16F = 11,
-
- R32F = 12,
- RG32F = 13,
- RGB32F = 14,
- RGBA32F = 15
-};
-
-enum AImgErrorCode
-{
- AIMG_SUCCESS = 0,
- AIMG_UNSUPPORTED_FILETYPE = -1,
- AIMG_LOAD_FAILED_EXTERNAL = -2, // load failed in an external library
- AIMG_LOAD_FAILED_INTERNAL = -3, // load failed inside ArtomatixImageLoader
- AIMG_CONVERSION_FAILED_BAD_FORMAT = -4,
- AIMG_WRITE_FAILED_EXTERNAL = -5,
- AIMG_WRITE_FAILED_INTERNAL = -6,
- AIMG_LOAD_FAILED_UNSUPPORTED_TIFF = -7,
- AIMG_OPEN_FAILED_EMPTY_INPUT = -8,
- AIMG_INVALID_ENCODE_ARGS = -9
-};
-
-enum AImgFileFormat
-{
- UNKNOWN_IMAGE_FORMAT = -1,
- EXR_IMAGE_FORMAT = 1,
- PNG_IMAGE_FORMAT = 2,
- JPEG_IMAGE_FORMAT = 3,
- TGA_IMAGE_FORMAT = 4,
- TIFF_IMAGE_FORMAT = 5
-};
-
-enum AImgFloatOrIntType
-{
- FITYPE_UNKNOWN = -1,
- FITYPE_FLOAT = 0,
- FITYPE_INT = 1
-};
-
-/////////////////////////////
-// Encoding option structs //
-/////////////////////////////
-// //
-// - All option structs //
-// will have an int32 as //
-// their first member, //
-// which shall be required //
-// to be set to the //
-// AImgFileFormat code for //
-// that file format. //
-/////////////////////////////
-
-
-// These defines copied from libpng's png.h
+ ///////////////////////
+ // Callback typedefs //
+ ///////////////////////
+ typedef int32_t(CALLCONV *ReadCallback) (void* callbackData, uint8_t* dest, int32_t count);
+ typedef void (CALLCONV *WriteCallback) (void* callbackData, const uint8_t* src, int32_t count);
+ typedef int32_t(CALLCONV *TellCallback) (void* callbackData);
+ typedef void (CALLCONV *SeekCallback) (void* callbackData, int32_t pos);
+
+ ////////////////
+ // Core enums //
+ ////////////////
+
+ // format is [channels][bits per channel][U/F]
+ // U means unsigned normalised, so eg 8U maps integer vals 0-255 to float range 0-1, F means a normal float value
+ enum AImgFormat
+ {
+ INVALID_FORMAT = -1,
+
+ _8BITS = 1 << 0,
+ _16BITS = 1 << 5,
+ _32BITS = 1 << 6,
+
+ R = 1 << 1,
+ RG = 1 << 2,
+ RGB = 1 << 3,
+ RGBA = 1 << 4,
+
+ FLOAT_FORMAT = 1 << 7,
+
+ R8U = R | _8BITS,
+ RG8U = RG | _8BITS,
+ RGB8U = RGB | _8BITS,
+ RGBA8U = RGBA | _8BITS,
+
+ R16U = R | _16BITS,
+ RG16U = RG | _16BITS,
+ RGB16U = RGB | _16BITS,
+ RGBA16U = RGBA | _16BITS,
+
+ R16F = R | _16BITS | FLOAT_FORMAT,
+ RG16F = RG | _16BITS | FLOAT_FORMAT,
+ RGB16F = RGB | _16BITS | FLOAT_FORMAT,
+ RGBA16F = RGBA | _16BITS | FLOAT_FORMAT,
+
+ R32F = R | _32BITS | FLOAT_FORMAT,
+ RG32F = RG | _32BITS | FLOAT_FORMAT,
+ RGB32F = RGB | _32BITS | FLOAT_FORMAT,
+ RGBA32F = RGBA | _32BITS | FLOAT_FORMAT
+ };
+
+ enum AImgErrorCode
+ {
+ AIMG_SUCCESS = 0,
+ AIMG_UNSUPPORTED_FILETYPE = -1,
+ AIMG_LOAD_FAILED_EXTERNAL = -2, // load failed in an external library
+ AIMG_LOAD_FAILED_INTERNAL = -3, // load failed inside ArtomatixImageLoader
+ AIMG_CONVERSION_FAILED_BAD_FORMAT = -4,
+ AIMG_WRITE_FAILED_EXTERNAL = -5,
+ AIMG_WRITE_FAILED_INTERNAL = -6,
+ AIMG_LOAD_FAILED_UNSUPPORTED_TIFF = -7,
+ AIMG_OPEN_FAILED_EMPTY_INPUT = -8,
+ AIMG_INVALID_ENCODE_ARGS = -9,
+ AIMG_WRITE_NOT_SUPPORTED_FOR_FORMAT = -10
+ };
+
+ enum AImgFileFormat
+ {
+ UNKNOWN_IMAGE_FORMAT = -1,
+ EXR_IMAGE_FORMAT = 1,
+ PNG_IMAGE_FORMAT = 2,
+ JPEG_IMAGE_FORMAT = 3,
+ TGA_IMAGE_FORMAT = 4,
+ TIFF_IMAGE_FORMAT = 5,
+ HDR_IMAGE_FORMAT = 6
+ };
+
+ enum AImgFloatOrIntType
+ {
+ FITYPE_UNKNOWN = -1,
+ FITYPE_FLOAT = 0,
+ FITYPE_INT = 1
+ };
+
+ /////////////////////////////
+ // Encoding option structs //
+ /////////////////////////////
+ // //
+ // - All option structs //
+ // will have an int32 as //
+ // their first member, //
+ // which shall be required //
+ // to be set to the //
+ // AImgFileFormat code for //
+ // that file format. //
+ /////////////////////////////
+
+ // These defines copied from libpng's png.h
#define AIL_PNG_NO_FILTERS 0x00
#define AIL_PNG_FILTER_NONE 0x08
#define AIL_PNG_FILTER_SUB 0x10
@@ -115,53 +126,56 @@ enum AImgFloatOrIntType
#define AIL_PNG_FILTER_PAETH 0x80
#define AIL_PNG_ALL_FILTERS (AIL_PNG_FILTER_NONE | AIL_PNG_FILTER_SUB | AIL_PNG_FILTER_UP | AIL_PNG_FILTER_AVG | AIL_PNG_FILTER_PAETH)
-struct PngEncodingOptions
-{
- int32_t type;
- int32_t compressionLevel; // Used with png_set_compression_level()
- int32_t filter; // Used with png_set_filter(), set to some combination of AIL_PNG_ flag defines from above.
-};
+ struct PngEncodingOptions
+ {
+ int32_t type;
+ int32_t compressionLevel; // Used with png_set_compression_level()
+ int32_t filter; // Used with png_set_filter(), set to some combination of AIL_PNG_ flag defines from above.
+ };
-//////////////////////////
-// Public API functions //
-//////////////////////////
+ //////////////////////////
+ // Public API functions //
+ //////////////////////////
-typedef void* AImgHandle;
+ typedef void* AImgHandle;
-EXPORT_FUNC const char* AImgGetErrorDetails(AImgHandle img);
+ EXPORT_FUNC const char* AImgGetErrorDetails(AImgHandle img);
-// detectedFileFormat will be set to a member from AImgFileFormat if non-null, otherwise it is ignored.
-EXPORT_FUNC int32_t AImgOpen(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, AImgHandle* imgPtr, int32_t* detectedFileFormat);
-EXPORT_FUNC void AImgClose(AImgHandle img);
+ // detectedFileFormat will be set to a member from AImgFileFormat if non-null, otherwise it is ignored.
+ EXPORT_FUNC int32_t AImgOpen(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, AImgHandle* imgPtr, int32_t* detectedFileFormat);
+ EXPORT_FUNC void AImgClose(AImgHandle img);
-EXPORT_FUNC int32_t AImgGetInfo(AImgHandle img, int32_t* width, int32_t* height, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt, int32_t* decodedImgFormat, uint32_t *colourProfileLen);
-EXPORT_FUNC int32_t AImgGetColourProfile(AImgHandle img, char* profileName, uint8_t* colourProfile, uint32_t *colourProfileLen);
-EXPORT_FUNC int32_t AImgDecodeImage(AImgHandle img, void* destBuffer, int32_t forceImageFormat);
-EXPORT_FUNC int32_t AImgInitialise();
-EXPORT_FUNC void AImgCleanUp();
+ EXPORT_FUNC int32_t AImgGetInfo(AImgHandle img, int32_t* width, int32_t* height, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt, int32_t* decodedImgFormat, uint32_t *colourProfileLen);
+ EXPORT_FUNC int32_t AImgGetColourProfile(AImgHandle img, char* profileName, uint8_t* colourProfile, uint32_t *colourProfileLen);
+ EXPORT_FUNC int32_t AImgDecodeImage(AImgHandle img, void* destBuffer, int32_t forceImageFormat);
+ EXPORT_FUNC int32_t AImgInitialise();
+ EXPORT_FUNC void AImgCleanUp();
-EXPORT_FUNC void AIGetFormatDetails(int32_t format, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt);
-EXPORT_FUNC int32_t AImgConvertFormat(void* src, void* dest, int32_t width, int32_t height, int32_t inFormat, int32_t outFormat);
+ EXPORT_FUNC int32_t AIGetBitDepth(int32_t format);
+ EXPORT_FUNC int32_t AIChangeBitDepth(int32_t format, int32_t newBitDepth);
+ EXPORT_FUNC void AIGetFormatDetails(int32_t format, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt);
+ EXPORT_FUNC int32_t AImgConvertFormat(void* src, void* dest, int32_t width, int32_t height, int32_t inFormat, int32_t outFormat);
-EXPORT_FUNC int32_t AImgGetWhatFormatWillBeWrittenForData(int32_t fileFormat, int32_t inputFormat);
+ EXPORT_FUNC bool AImgIsFormatSupported(int32_t fileFormat, int32_t outputFormat);
-EXPORT_FUNC AImgHandle AImgGetAImg(int32_t fileFormat);
+ EXPORT_FUNC int32_t AImgGetWhatFormatWillBeWrittenForData(int32_t fileFormat, int32_t inputFormat, int32_t outputFormat);
-// encodingOptions should be one of the encoding option structs detailed in the section above. It shoudl be the struct that corresponds to the image format being written.
-EXPORT_FUNC int32_t AImgWriteImage(AImgHandle imgH, void* data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions);
+ EXPORT_FUNC AImgHandle AImgGetAImg(int32_t fileFormat);
-EXPORT_FUNC void AIGetSimpleMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallback* writeCallback, TellCallback* tellCallback, SeekCallback* seekCallback, void** callbackData, void* buffer, int32_t size);
-EXPORT_FUNC void AIDestroySimpleMemoryBufferCallbacks(ReadCallback readCallback, WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData);
+ // encodingOptions should be one of the encoding option structs detailed in the section above. It shoudl be the struct that corresponds to the image format being written.
+ EXPORT_FUNC int32_t AImgWriteImage(AImgHandle imgH, void* data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions);
+ EXPORT_FUNC void AIGetSimpleMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallback* writeCallback, TellCallback* tellCallback, SeekCallback* seekCallback, void** callbackData, void* buffer, int32_t size);
+ EXPORT_FUNC void AIDestroySimpleMemoryBufferCallbacks(ReadCallback readCallback, WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
- #include
- EXPORT_FUNC void AIGetResizableMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallback* writeCallback, TellCallback* tellCallback, SeekCallback* seekCallback, void** callbackData, std::vector* vec);
+#include
+EXPORT_FUNC void AIGetResizableMemoryBufferCallbacks(ReadCallback* readCallback, WriteCallback* writeCallback, TellCallback* tellCallback, SeekCallback* seekCallback, void** callbackData, std::vector* vec);
#endif
#endif //ARTOMATIX_AIL_H
diff --git a/src_c/CMakeLists.txt b/src_c/CMakeLists.txt
index 46329f2..75dce7a 100644
--- a/src_c/CMakeLists.txt
+++ b/src_c/CMakeLists.txt
@@ -2,8 +2,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
include("cmake/HunterGate.cmake")
HunterGate(
- URL "https://github.com/Artomatix/hunter/archive/OpenEXR-test-2.tar.gz"
- SHA1 "c86e9e6fde6b96fc57ac2184692baeb4d71e9fd6"
+ URL "https://github.com/Artomatix/hunter/archive/v43-OpenEXR.tar.gz"
+ SHA1 "faefc63600c5e431a59d406bbd0db743a659f1a9"
LOCAL
)
@@ -20,23 +20,21 @@ set(PNG_ENABLED ON CACHE BOOL "enable loading PNG files")
set(JPEG_ENABLED ON CACHE BOOL "enable loading JPEG files")
set(TIFF_ENABLED ON CACHE BOOL "enable loading TIFF files")
set(TGA_ENABLED ON CACHE BOOL "enable loading TGA files")
+set(HDR_ENABLED ON CACHE BOOL "enable loading HDR files")
set(BUILD_SHARE_TYPE SHARED CACHE STRING "set build type, valid values: SHARED|STATIC")
set(CMAKE_POSITION_INDEPENDENT_CODE YES)
add_library(AIL ${BUILD_SHARE_TYPE}
- exr.cpp
- exr.h
- png.h
- png.cpp
- jpeg.h
- jpeg.cpp
- tga.h
- tga.cpp
- tiff.h
- tiff.cpp
- AIL.cpp
- AIL.h
+
+ exr.cpp exr.h
+ png.h png.cpp
+ jpeg.h jpeg.cpp
+ tga.h tga.cpp
+ tiff.h tiff.cpp
+ AIL.h AIL.cpp
+ hdr.h hdr.cpp
+
AIL_internal.h
ImageLoaderBase.h
extern/stb_image.h
@@ -111,6 +109,10 @@ if(TIFF_ENABLED)
add_definitions(-DHAVE_TIFF)
endif()
+if (HDR_ENABLED)
+ add_definitions(-DHAVE_HDR)
+endif()
+
SET(CMAKE_DEBUG_POSTFIX "")
#########
diff --git a/src_c/ImageLoaderBase.h b/src_c/ImageLoaderBase.h
index 597e7d6..ec7ad11 100644
--- a/src_c/ImageLoaderBase.h
+++ b/src_c/ImageLoaderBase.h
@@ -17,8 +17,9 @@ namespace AImg
virtual int32_t getColourProfile(char* profileName, uint8_t* colourProfile, uint32_t *colourProfileLen) = 0;
virtual int32_t decodeImage(void* destBuffer, int32_t forceImageFormat) = 0;
- virtual int32_t writeImage(void* data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions) = 0;
+ virtual int32_t writeImage(void* data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat,
+ const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData, void* encodingOptions) = 0;
const char* getErrorDetails()
{
@@ -52,7 +53,9 @@ namespace AImg
virtual std::string getFileExtension() = 0;
virtual int32_t getAImgFileFormatValue() = 0;
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat) = 0;
+ virtual bool isFormatSupported(int32_t format) = 0;
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat) = 0;
};
}
diff --git a/src_c/cmake/Hunter/config.cmake b/src_c/cmake/Hunter/config.cmake
index 76f60ec..bdefdeb 100644
--- a/src_c/cmake/Hunter/config.cmake
+++ b/src_c/cmake/Hunter/config.cmake
@@ -1,4 +1,4 @@
-hunter_config(OpenEXR VERSION "1.0.1" CMAKE_ARGS CMAKE_POSITION_INDEPENDENT_CODE=YES)
+hunter_config(OpenEXR VERSION "1.0.2" CMAKE_ARGS CMAKE_POSITION_INDEPENDENT_CODE=YES)
hunter_config(ZLIB VERSION "1.2.8-p3" CMAKE_ARGS CMAKE_POSITION_INDEPENDENT_CODE=YES)
hunter_config(PNG VERSION "1.6.16-p4" CMAKE_ARGS CMAKE_POSITION_INDEPENDENT_CODE=YES)
hunter_config(Jpeg VERSION "9b-p1" CMAKE_ARGS CMAKE_POSITION_INDEPENDENT_CODE=YES)
diff --git a/src_c/cmake/HunterGate.cmake b/src_c/cmake/HunterGate.cmake
index 99882d2..887557a 100644
--- a/src_c/cmake/HunterGate.cmake
+++ b/src_c/cmake/HunterGate.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2013-2015, Ruslan Baratov
+# Copyright (c) 2013-2018, Ruslan Baratov
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
# This is a gate file to Hunter package manager.
# Include this file using `include` command and add package you need, example:
#
-# cmake_minimum_required(VERSION 3.0)
+# cmake_minimum_required(VERSION 3.2)
#
# include("cmake/HunterGate.cmake")
# HunterGate(
@@ -42,30 +42,41 @@
# * https://github.com/hunter-packages/gate/
# * https://github.com/ruslo/hunter
-cmake_minimum_required(VERSION 3.0) # Minimum for Hunter
+option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
+
+if(HUNTER_ENABLED)
+ if(CMAKE_VERSION VERSION_LESS "3.2")
+ message(
+ FATAL_ERROR
+ "At least CMake version 3.2 required for Hunter dependency management."
+ " Update CMake or set HUNTER_ENABLED to OFF."
+ )
+ endif()
+endif()
+
include(CMakeParseArguments) # cmake_parse_arguments
-option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
option(HUNTER_STATUS_PRINT "Print working status" ON)
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
+option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
function(hunter_gate_status_print)
- foreach(print_message ${ARGV})
- if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+ if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
+ foreach(print_message ${ARGV})
message(STATUS "[hunter] ${print_message}")
- endif()
- endforeach()
+ endforeach()
+ endif()
endfunction()
function(hunter_gate_status_debug)
- foreach(print_message ${ARGV})
- if(HUNTER_STATUS_DEBUG)
+ if(HUNTER_STATUS_DEBUG)
+ foreach(print_message ${ARGV})
string(TIMESTAMP timestamp)
message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
- endif()
- endforeach()
+ endforeach()
+ endif()
endfunction()
function(hunter_gate_wiki wiki_page)
@@ -188,20 +199,6 @@ function(hunter_gate_detect_root)
)
endfunction()
-macro(hunter_gate_lock dir)
- if(NOT HUNTER_SKIP_LOCK)
- if("${CMAKE_VERSION}" VERSION_LESS "3.2")
- hunter_gate_fatal_error(
- "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK"
- WIKI "error.can.not.lock"
- )
- endif()
- hunter_gate_status_debug("Locking directory: ${dir}")
- file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
- hunter_gate_status_debug("Lock done")
- endif()
-endmacro()
-
function(hunter_gate_download dir)
string(
COMPARE
@@ -241,7 +238,10 @@ function(hunter_gate_download dir)
set(build_dir "${dir}/Build")
set(cmakelists "${dir}/CMakeLists.txt")
- hunter_gate_lock("${dir}")
+ hunter_gate_status_debug("Locking directory: ${dir}")
+ file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
+ hunter_gate_status_debug("Lock done")
+
if(EXISTS "${done_location}")
# while waiting for lock other instance can do all the job
hunter_gate_status_debug("File '${done_location}' found, skip install")
@@ -258,7 +258,7 @@ function(hunter_gate_download dir)
file(
WRITE
"${cmakelists}"
- "cmake_minimum_required(VERSION 3.0)\n"
+ "cmake_minimum_required(VERSION 3.2)\n"
"project(HunterDownload LANGUAGES NONE)\n"
"include(ExternalProject)\n"
"ExternalProject_Add(\n"
@@ -269,6 +269,8 @@ function(hunter_gate_download dir)
" SHA1=${HUNTER_GATE_SHA1}\n"
" DOWNLOAD_DIR\n"
" \"${dir}\"\n"
+ " TLS_VERIFY\n"
+ " ${HUNTER_TLS_VERIFY}\n"
" SOURCE_DIR\n"
" \"${dir}/Unpacked\"\n"
" CONFIGURE_COMMAND\n"
@@ -292,21 +294,40 @@ function(hunter_gate_download dir)
# Otherwise on Visual Studio + MDD this will fail with error:
# "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
- set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
+ get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
+ set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
else()
# 'toolchain_arg' can't be empty
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
endif()
+ string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
+ if(no_make)
+ set(make_arg "")
+ else()
+ # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
+ set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
+ endif()
+
execute_process(
- COMMAND "${CMAKE_COMMAND}" "-H${dir}" "-B${build_dir}" "-G${CMAKE_GENERATOR}" "${toolchain_arg}"
+ COMMAND
+ "${CMAKE_COMMAND}"
+ "-H${dir}"
+ "-B${build_dir}"
+ "-G${CMAKE_GENERATOR}"
+ "${toolchain_arg}"
+ ${make_arg}
WORKING_DIRECTORY "${dir}"
RESULT_VARIABLE download_result
${logging_params}
)
if(NOT download_result EQUAL 0)
- hunter_gate_internal_error("Configure project failed")
+ hunter_gate_internal_error(
+ "Configure project failed."
+ "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
+ "In directory ${dir}"
+ )
endif()
hunter_gate_status_print(
@@ -351,6 +372,17 @@ macro(HunterGate)
# Empty function to avoid error "unknown function"
function(hunter_add_package)
endfunction()
+
+ set(
+ _hunter_gate_disabled_mode_dir
+ "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
+ )
+ if(EXISTS "${_hunter_gate_disabled_mode_dir}")
+ hunter_gate_status_debug(
+ "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
+ )
+ list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
+ endif()
elseif(_hunter_gate_done)
hunter_gate_status_debug("Secondary HunterGate (use old settings)")
hunter_gate_self(
@@ -361,7 +393,7 @@ macro(HunterGate)
)
include("${_hunter_self}/cmake/Hunter")
else()
- set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}")
+ set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
if(_have_project_name)
diff --git a/src_c/exr.cpp b/src_c/exr.cpp
index ebb1a44..2aa2ef1 100644
--- a/src_c/exr.cpp
+++ b/src_c/exr.cpp
@@ -18,486 +18,491 @@
namespace AImg
{
-class CallbackIStream : public Imf::IStream
-{
- public:
- CallbackIStream(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData) : IStream("")
+ class CallbackIStream : public Imf::IStream
{
- mReadCallback = readCallback;
- mTellCallback = tellCallback;
- mSeekCallback = seekCallback;
- mCallbackData = callbackData;
- }
+ public:
+ CallbackIStream(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData) : IStream("")
+ {
+ mReadCallback = readCallback;
+ mTellCallback = tellCallback;
+ mSeekCallback = seekCallback;
+ mCallbackData = callbackData;
+ }
- virtual bool read(char c[], int n)
- {
- return mReadCallback(mCallbackData, (uint8_t *)c, n) == n;
- }
+ virtual bool read(char c[], int n)
+ {
+ return mReadCallback(mCallbackData, (uint8_t *)c, n) == n;
+ }
- virtual uint64_t tellg()
- {
- return mTellCallback(mCallbackData);
- }
+ virtual uint64_t tellg()
+ {
+ return mTellCallback(mCallbackData);
+ }
- virtual void seekg(uint64_t pos)
- {
- mSeekCallback(mCallbackData, pos);
- }
+ virtual void seekg(uint64_t pos)
+ {
+ mSeekCallback(mCallbackData, (int32_t)pos);
+ }
- virtual void clear()
- {
- }
+ virtual void clear()
+ {
+ }
- ReadCallback mReadCallback;
- TellCallback mTellCallback;
- SeekCallback mSeekCallback;
- void *mCallbackData;
-};
+ ReadCallback mReadCallback;
+ TellCallback mTellCallback;
+ SeekCallback mSeekCallback;
+ void *mCallbackData;
+ };
-class CallbackOStream : public Imf::OStream
-{
- public:
- CallbackOStream(WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData) : OStream("")
+ class CallbackOStream : public Imf::OStream
{
- mWriteCallback = writeCallback;
- mTellCallback = tellCallback;
- mSeekCallback = seekCallback;
- mCallbackData = callbackData;
- }
+ public:
+ CallbackOStream(WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData) : OStream("")
+ {
+ mWriteCallback = writeCallback;
+ mTellCallback = tellCallback;
+ mSeekCallback = seekCallback;
+ mCallbackData = callbackData;
+ }
- virtual void write(const char c[], int n)
- {
- mWriteCallback(mCallbackData, (const uint8_t *)c, n);
- }
+ virtual void write(const char c[], int n)
+ {
+ mWriteCallback(mCallbackData, (const uint8_t *)c, n);
+ }
- virtual uint64_t tellp()
- {
- return mTellCallback(mCallbackData);
- }
+ virtual uint64_t tellp()
+ {
+ return mTellCallback(mCallbackData);
+ }
- virtual void seekp(uint64_t pos)
- {
- mSeekCallback(mCallbackData, pos);
- }
+ virtual void seekp(uint64_t pos)
+ {
+ mSeekCallback(mCallbackData, (int32_t)pos);
+ }
- virtual void clear()
- {
- }
+ virtual void clear()
+ {
+ }
- WriteCallback mWriteCallback;
- TellCallback mTellCallback;
- SeekCallback mSeekCallback;
- void *mCallbackData;
-};
+ WriteCallback mWriteCallback;
+ TellCallback mTellCallback;
+ SeekCallback mSeekCallback;
+ void *mCallbackData;
+ };
-int32_t ExrImageLoader::initialise()
-{
- try
+ int32_t ExrImageLoader::initialise()
{
- Imf::staticInitialize();
+ try
+ {
+ Imf::staticInitialize();
- return AImgErrorCode::AIMG_SUCCESS;
- }
- catch (const std::exception &e)
- {
- return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+ catch (const std::exception)
+ {
+ return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
+ }
}
-}
-bool ExrImageLoader::canLoadImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
-{
- int32_t startingPos = tellCallback(callbackData);
-
- std::vector header(4);
- readCallback(callbackData, &header[0], 4);
+ bool ExrImageLoader::canLoadImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
+ {
+ int32_t startingPos = tellCallback(callbackData);
- seekCallback(callbackData, startingPos);
+ std::vector header(4);
+ readCallback(callbackData, &header[0], 4);
- return header[0] == 0x76 && header[1] == 0x2f && header[2] == 0x31 && header[3] == 0x01;
-}
-
-std::string ExrImageLoader::getFileExtension()
-{
- return "EXR";
-}
+ seekCallback(callbackData, startingPos);
-int32_t ExrImageLoader::getAImgFileFormatValue()
-{
- return EXR_IMAGE_FORMAT;
-}
-
-class ExrFile : public AImgBase
-{
- public:
- CallbackIStream *data = nullptr;
- Imf::InputFile *file = nullptr;
- Imath::Box2i dw;
+ return header[0] == 0x76 && header[1] == 0x2f && header[2] == 0x31 && header[3] == 0x01;
+ }
- virtual ~ExrFile()
+ std::string ExrImageLoader::getFileExtension()
{
- if (data)
- delete data;
- if (file)
- delete file;
+ return "EXR";
}
- int32_t getDecodeFormat()
+ int32_t ExrImageLoader::getAImgFileFormatValue()
{
- bool useHalfFloat = true;
-
- // yes, I am actually pretty sure this is the only way to get a channel count...
- int32_t channelNum = 0;
- const Imf::ChannelList &channels = file->header().channels();
- for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
- {
- channelNum++;
-
- // If any channels are UINT or FLOAT, then decode the whole thing as FLOAT
- // Otherwise, if everything is HALF, then we can decode as HALF
- if(it.channel().type != Imf::PixelType::HALF)
- useHalfFloat = false;
- }
+ return EXR_IMAGE_FORMAT;
+ }
- if(channelNum <= 0)
- return AImgFormat::INVALID_FORMAT;
+ bool isFormatSupportedByExr(int32_t format)
+ {
+ int32_t flags = format & AImgFormat::_16BITS;
+ int32_t fl = format & AImgFormat::_32BITS;
+ int32_t floatF = format & AImgFormat::FLOAT_FORMAT;
- // start at the 1-channel version + offset to get the correct channel count format
- int32_t format = useHalfFloat ? AImgFormat::R16F : AImgFormat::R32F;
- format += (std::min(channelNum, 4) - 1); // min because we just truncate channels if we have >4 (exrs can have any number of channels)
+ bool isSupported = (fl || flags) && floatF;
- return format;
+ return isSupported;
}
- virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ AImgFormat getWriteFormatExr(int32_t inputFormat, int32_t outputFormat)
{
- *width = dw.max.x - dw.min.x + 1;
- *height = dw.max.y - dw.min.y + 1;
- *decodedImgFormat = getDecodeFormat();
- if(colourProfileLen != NULL)
+ if (outputFormat != inputFormat
+ && outputFormat != AImgFormat::INVALID_FORMAT
+ && isFormatSupportedByExr(outputFormat))
{
- *colourProfileLen = 0;
+ return (AImgFormat)outputFormat;
}
- *numChannels = 0;
-
- Imf::PixelType lastChannelType;
- bool allChannelsSame = true;
-
- bool isFirstChannel = true;
-
- const Imf::ChannelList &channels = file->header().channels();
- for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
+ if (!isFormatSupportedByExr(inputFormat))
{
- (*numChannels)++;
-
- if (isFirstChannel)
- {
- isFirstChannel = false;
- lastChannelType = it.channel().type;
- }
+ // set inputBufFormat to the format with the same number of channels as inputFormat, but is 32F
+ int32_t bytesPerChannelTmp, numChannelsTmp, floatOrIntTmp;
+ AIGetFormatDetails(inputFormat, &numChannelsTmp, &bytesPerChannelTmp, &floatOrIntTmp);
- if (it.channel().type != lastChannelType)
- allChannelsSame = false;
- }
+ AImgFormat res;
- if (!allChannelsSame)
- {
- *bytesPerChannel = -1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_UNKNOWN;
- }
- else
- {
- if (lastChannelType == Imf::PixelType::UINT)
- {
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- }
- if (lastChannelType == Imf::PixelType::FLOAT)
- {
- *bytesPerChannel = 4;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- }
- else if (lastChannelType == Imf::PixelType::HALF)
- {
- *bytesPerChannel = 2;
- *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
- }
+ if (bytesPerChannelTmp > 2)
+ res = AImgFormat::_32BITS;
else
- {
- mErrorDetails = "[AImg::EXRImageLoader::EXRFile::] Invalid channel type in exr file";
- return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
- }
+ res = AImgFormat::_16BITS;
+
+ return (AImgFormat)(res | AImgFormat::FLOAT_FORMAT | (1 << numChannelsTmp));
}
- return AImgErrorCode::AIMG_SUCCESS;
+ return (AImgFormat)inputFormat;
}
-
- virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+
+ class ExrFile : public AImgBase
{
- if(colourProfile != NULL)
- {
- *colourProfileLen = 0;
- }
- if(profileName != NULL)
+ public:
+ CallbackIStream *data = nullptr;
+ Imf::InputFile *file = nullptr;
+ Imath::Box2i dw;
+
+ virtual ~ExrFile()
{
- std::strcpy(profileName, "no_profile");
+ if (data)
+ delete data;
+ if (file)
+ delete file;
}
- return AImgErrorCode::AIMG_SUCCESS;
- }
-
- virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
- {
- try
+ int32_t getDecodeFormat()
{
- int32_t width = dw.max.x - dw.min.x + 1;
- int32_t height = dw.max.y - dw.min.y + 1;
+ bool useHalfFloat = true;
- int32_t decodeFormat = getDecodeFormat();
+ // yes, I am actually pretty sure this is the only way to get a channel count...
+ int32_t channelNum = 0;
+ const Imf::ChannelList &channels = file->header().channels();
+ for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
+ {
+ channelNum++;
- int32_t decodeFormatNumChannels, decodeFormatBytesPerChannel, decodeFormatFloatOrInt;
- AIGetFormatDetails(decodeFormat, &decodeFormatNumChannels, &decodeFormatBytesPerChannel, &decodeFormatFloatOrInt);
+ // If any channels are UINT or FLOAT, then decode the whole thing as FLOAT
+ // Otherwise, if everything is HALF, then we can decode as HALF
+ if (it.channel().type != Imf::PixelType::HALF)
+ useHalfFloat = false;
+ }
+
+ if (channelNum <= 0)
+ return AImgFormat::INVALID_FORMAT;
+ // start at the 1-channel version + offset to get the correct channel count format
+ int32_t format = (useHalfFloat ? AImgFormat::_16BITS : AImgFormat::_32BITS) | AImgFormat::FLOAT_FORMAT;
+ format |= (AImgFormat::R << (std::min(channelNum, 4) - 1)); // min because we just truncate channels if we have >4 (exrs can have any number of channels)
- void *destBuffer = realDestBuffer;
+ return format;
+ }
- std::vector convertTmpBuffer(0);
- if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ {
+ *width = dw.max.x - dw.min.x + 1;
+ *height = dw.max.y - dw.min.y + 1;
+ *decodedImgFormat = getDecodeFormat();
+ if (colourProfileLen != NULL)
{
- convertTmpBuffer.resize(width * height * decodeFormatBytesPerChannel * decodeFormatNumChannels);
- destBuffer = &convertTmpBuffer[0];
+ *colourProfileLen = 0;
}
- std::vector allChannelNames;
- bool isRgba = true;
+ *numChannels = 0;
+
+ Imf::PixelType lastChannelType;
+ bool allChannelsSame = true;
+
+ bool isFirstChannel = true;
const Imf::ChannelList &channels = file->header().channels();
for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
{
- std::string name = it.name();
- allChannelNames.push_back(it.name());
- if (name != "R" && name != "G" && name != "B" && name != "A")
- isRgba = false;
- }
+ (*numChannels)++;
- std::vector usedChannelNames;
+ if (isFirstChannel)
+ {
+ isFirstChannel = false;
+ lastChannelType = it.channel().type;
+ }
- // ensure RGBA byte order, when loading an rgba image
- if (isRgba)
+ if (it.channel().type != lastChannelType)
+ allChannelsSame = false;
+ }
+
+ if (!allChannelsSame)
{
- if (std::find(allChannelNames.begin(), allChannelNames.end(), "R") != allChannelNames.end())
- usedChannelNames.push_back("R");
- if (std::find(allChannelNames.begin(), allChannelNames.end(), "G") != allChannelNames.end())
- usedChannelNames.push_back("G");
- if (std::find(allChannelNames.begin(), allChannelNames.end(), "B") != allChannelNames.end())
- usedChannelNames.push_back("B");
- if (std::find(allChannelNames.begin(), allChannelNames.end(), "A") != allChannelNames.end())
- usedChannelNames.push_back("A");
+ *bytesPerChannel = -1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_UNKNOWN;
}
- // otherwise just whack em in in order
else
{
- for (uint32_t i = 0; i < allChannelNames.size(); i++)
+ if (lastChannelType == Imf::PixelType::UINT)
{
- if (usedChannelNames.size() >= 4)
- break;
-
- if (std::find(usedChannelNames.begin(), usedChannelNames.end(), allChannelNames[i]) == usedChannelNames.end())
- usedChannelNames.push_back(allChannelNames[i]);
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
}
- }
-
- Imf::FrameBuffer frameBuffer;
- for (uint32_t i = 0; i < usedChannelNames.size(); i++)
- {
- if(decodeFormatBytesPerChannel == 4)
+ if (lastChannelType == Imf::PixelType::FLOAT)
{
- frameBuffer.insert(usedChannelNames[i],
- Imf::Slice(Imf::FLOAT,
- ((char *)destBuffer) + i * sizeof(float),
- sizeof(float) * usedChannelNames.size(),
- sizeof(float) * width * usedChannelNames.size(),
- 1, 1,
- 0.0));
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
}
- else if(decodeFormatBytesPerChannel == 2)
+ else if (lastChannelType == Imf::PixelType::HALF)
{
- frameBuffer.insert(usedChannelNames[i],
- Imf::Slice(Imf::HALF,
- ((char *)destBuffer) + i * sizeof(half),
- sizeof(half) * usedChannelNames.size(),
- sizeof(half) * width * usedChannelNames.size(),
- 1, 1,
- 0.0));
+ *bytesPerChannel = 2;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
}
else
{
- mErrorDetails = "[AImg::EXRImageLoader::EXRFile::] invalid decodeFormatBytesPerChannel";
+ mErrorDetails = "[AImg::EXRImageLoader::EXRFile::] Invalid channel type in exr file";
return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
}
}
- file->setFrameBuffer(frameBuffer);
- file->readPixels(dw.min.y, dw.max.y);
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ {
+ if (colourProfile != NULL)
{
- int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, width, height, decodeFormat, forceImageFormat);
- if (err != AImgErrorCode::AIMG_SUCCESS)
- return err;
+ *colourProfileLen = 0;
+ }
+ if (profileName != NULL)
+ {
+ std::strcpy(profileName, "no_profile");
}
return AImgErrorCode::AIMG_SUCCESS;
}
- catch (const std::exception &e)
- {
- mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
- return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
- }
- }
- virtual int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
- {
- try
+ virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
{
- data = new CallbackIStream(readCallback, tellCallback, seekCallback, callbackData);
- file = new Imf::InputFile(*data);
- dw = file->header().dataWindow();
+ try
+ {
+ int32_t width = dw.max.x - dw.min.x + 1;
+ int32_t height = dw.max.y - dw.min.y + 1;
- return AImgErrorCode::AIMG_SUCCESS;
- }
- catch (const std::exception &e)
- {
- mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
- }
+ int32_t decodeFormat = getDecodeFormat();
- int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void *encodingOptions)
- {
- AIL_UNUSED_PARAM(encodingOptions);
+ int32_t decodeFormatNumChannels, decodeFormatBytesPerChannel, decodeFormatFloatOrInt;
+ AIGetFormatDetails(decodeFormat, &decodeFormatNumChannels, &decodeFormatBytesPerChannel, &decodeFormatFloatOrInt);
- try
- {
- std::vector reformattedDataTmp(0);
+ if (decodeFormatBytesPerChannel != 2 && decodeFormatBytesPerChannel != 4)
+ {
+ mErrorDetails = "[AImg::EXRImageLoader::EXRFile::] invalid decodeFormatBytesPerChannel";
+ return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
+ }
- void *inputBuf = data;
- AImgFormat inputBufFormat = (AImgFormat)inputFormat;
+ char *destBuffer = (char *)realDestBuffer;
- // need 32F or 16F data, so convert if necessary
- if (!((inputFormat >= AImgFormat::R32F && inputFormat <= AImgFormat::RGBA32F) || (inputFormat >= AImgFormat::R16F && inputFormat <= AImgFormat::RGBA16F)))
- {
- // set inputBufFormat to the format with the same number of channels as inputFormat, but is 32F
- int32_t bytesPerChannelTmp, numChannelsTmp, floatOrIntTmp;
- AIGetFormatDetails(inputFormat, &numChannelsTmp, &bytesPerChannelTmp, &floatOrIntTmp);
+ std::vector convertTmpBuffer(0);
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ {
+ convertTmpBuffer.resize(width * height * decodeFormatBytesPerChannel * decodeFormatNumChannels);
+ destBuffer = (char *)convertTmpBuffer.data();
+ }
+
+ std::vector allChannelNames;
+ bool isRgba = true;
+
+ const Imf::ChannelList &channels = file->header().channels();
+ for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
+ {
+ std::string name = it.name();
+ allChannelNames.push_back(it.name());
+ if (name != "R" && name != "G" && name != "B" && name != "A")
+ isRgba = false;
+ }
+
+ std::vector usedChannelNames;
- if(bytesPerChannelTmp > 2)
- inputBufFormat = (AImgFormat)(AImgFormat::R32F + numChannelsTmp - 1);
+ // ensure RGBA byte order, when loading an rgba image
+ if (isRgba)
+ {
+ if (std::find(allChannelNames.begin(), allChannelNames.end(), "R") != allChannelNames.end())
+ usedChannelNames.push_back("R");
+ if (std::find(allChannelNames.begin(), allChannelNames.end(), "G") != allChannelNames.end())
+ usedChannelNames.push_back("G");
+ if (std::find(allChannelNames.begin(), allChannelNames.end(), "B") != allChannelNames.end())
+ usedChannelNames.push_back("B");
+ if (std::find(allChannelNames.begin(), allChannelNames.end(), "A") != allChannelNames.end())
+ usedChannelNames.push_back("A");
+ }
+ // otherwise just whack em in in order
else
- inputBufFormat = (AImgFormat)(AImgFormat::R16F + numChannelsTmp - 1);
+ {
+ for (uint32_t i = 0; i < allChannelNames.size(); i++)
+ {
+ if (usedChannelNames.size() >= 4)
+ break;
+
+ if (std::find(usedChannelNames.begin(), usedChannelNames.end(), allChannelNames[i]) == usedChannelNames.end())
+ usedChannelNames.push_back(allChannelNames[i]);
+ }
+ }
- // resize reformattedDataTmp to fit the converted image data
- AIGetFormatDetails(inputBufFormat, &numChannelsTmp, &bytesPerChannelTmp, &floatOrIntTmp);
- reformattedDataTmp.resize(numChannelsTmp * bytesPerChannelTmp * width * height);
+ Imf::FrameBuffer frameBuffer;
+ auto displayWindow = file->header().displayWindow();
- AImgConvertFormat(data, &reformattedDataTmp[0], width, height, inputFormat, inputBufFormat);
- inputBuf = &reformattedDataTmp[0];
- }
+ auto fbMaxW = std::max(dw.max.x, displayWindow.max.x) + 1;
+
+ auto channelType = decodeFormatBytesPerChannel == 4 ? Imf::FLOAT : Imf::HALF;
+ for (uint32_t i = 0; i < usedChannelNames.size(); i++)
+ {
+ auto slice = Imf::Slice(channelType,
+ destBuffer + i * decodeFormatBytesPerChannel,
+ usedChannelNames.size() * decodeFormatBytesPerChannel,
+ fbMaxW * usedChannelNames.size() * decodeFormatBytesPerChannel,
+ 1,
+ 1,
+ 0.0);
+
+ frameBuffer.insert(usedChannelNames[i], slice);
+ }
- int32_t bytesPerChannel, numChannels, floatOrInt;
- AIGetFormatDetails(inputBufFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+ file->setFrameBuffer(frameBuffer);
+ auto dataWindow = file->header().dataWindow();
+ file->readPixels(dataWindow.min.y, dataWindow.max.y);
- const char *RGBAChannelNames[] = {"R", "G", "B", "A"};
- const char *GreyScaleChannelName = "Y";
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ {
+ int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, width, height, decodeFormat, forceImageFormat);
+ if (err != AImgErrorCode::AIMG_SUCCESS)
+ return err;
+ }
- Imf::Header header(width, height);
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+ catch (const std::exception &e)
+ {
+ mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
+ return AImgErrorCode::AIMG_LOAD_FAILED_INTERNAL;
+ }
+ }
- for (int32_t i = 0; i < numChannels; i++)
+ virtual int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
+ {
+ try
{
- const char *channelName;
- if (numChannels == 1)
- channelName = GreyScaleChannelName;
- else
- channelName = RGBAChannelNames[i];
+ data = new CallbackIStream(readCallback, tellCallback, seekCallback, callbackData);
+ file = new Imf::InputFile(*data);
+ dw = file->header().displayWindow();
+ auto header = file->header();
- header.channels().insert(channelName, Imf::Channel((bytesPerChannel == 4) ? Imf::FLOAT : Imf::HALF));
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+ catch (const std::exception &e)
+ {
+ mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
}
+ }
- Imf::FrameBuffer frameBuffer;
+ int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void *encodingOptions)
+ {
+ AIL_UNUSED_PARAM(encodingOptions);
- for (int32_t i = 0; i < numChannels; i++)
+ try
{
- const char *channelName;
- if (numChannels == 1)
- channelName = GreyScaleChannelName;
- else
- channelName = RGBAChannelNames[i];
+ std::vector reformattedDataTmp(0);
- frameBuffer.insert(
- channelName,
- Imf::Slice(
- (bytesPerChannel == 4) ? Imf::FLOAT : Imf::HALF,
- &((char *)inputBuf)[bytesPerChannel * i],
- bytesPerChannel * numChannels,
- bytesPerChannel * width * numChannels,
- 1, 1,
- 0.0));
- }
+ void *inputBuf = data;
+ AImgFormat inputBufFormat = getWriteFormatExr(inputFormat, outputFormat);
- CallbackOStream ostream(writeCallback, tellCallback, seekCallback, callbackData);
- Imf::OutputFile file(ostream, header);
- file.setFrameBuffer(frameBuffer);
- file.writePixels(height);
+ bool needConversion = inputBufFormat != inputFormat;
- return AImgErrorCode::AIMG_SUCCESS;
- }
- catch (const std::exception &e)
- {
- mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
- return AImgErrorCode::AIMG_WRITE_FAILED_EXTERNAL;
- }
- }
-};
+ // need 32F or 16F data, so convert if necessary
+ if (needConversion)
+ {
+ // resize reformattedDataTmp to fit the converted image data
+ int32_t bytesPerChannelTmp, numChannelsTmp, floatOrIntTmp;
+ AIGetFormatDetails(inputBufFormat, &numChannelsTmp, &bytesPerChannelTmp, &floatOrIntTmp);
+ reformattedDataTmp.resize(numChannelsTmp * bytesPerChannelTmp * width * height);
-AImgBase *ExrImageLoader::getAImg()
-{
- return new ExrFile();
-}
+ AImgConvertFormat(data, &reformattedDataTmp[0], width, height, inputFormat, inputBufFormat);
+ inputBuf = &reformattedDataTmp[0];
+ }
-AImgFormat ExrImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat)
-{
- int32_t bytesPerChannel, numChannels, floatOrInt;
- AIGetFormatDetails(inputFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+ int32_t bytesPerChannel, numChannels, floatOrInt;
+ AIGetFormatDetails(inputBufFormat, &numChannels, &bytesPerChannel, &floatOrInt);
- // TODO: allow writing 16-bit float exrs too
- /*if(bytesPerChannel < 2)
- {
- switch(numChannels)
+ const char *RGBAChannelNames[] = { "R", "G", "B", "A" };
+ const char *GreyScaleChannelName = "Y";
+
+ Imf::Header header(width, height);
+
+ for (int32_t i = 0; i < numChannels; i++)
+ {
+ const char *channelName;
+ if (numChannels == 1)
+ channelName = GreyScaleChannelName;
+ else
+ channelName = RGBAChannelNames[i];
+
+ header.channels().insert(channelName, Imf::Channel((bytesPerChannel == 4) ? Imf::FLOAT : Imf::HALF));
+ }
+
+ Imf::FrameBuffer frameBuffer;
+
+ for (int32_t i = 0; i < numChannels; i++)
+ {
+ const char *channelName;
+ if (numChannels == 1)
+ channelName = GreyScaleChannelName;
+ else
+ channelName = RGBAChannelNames[i];
+
+ frameBuffer.insert(
+ channelName,
+ Imf::Slice(
+ (bytesPerChannel == 4) ? Imf::FLOAT : Imf::HALF,
+ &((char *)inputBuf)[bytesPerChannel * i],
+ bytesPerChannel * numChannels,
+ bytesPerChannel * width * numChannels,
+ 1, 1,
+ 0.0));
+ }
+
+ CallbackOStream ostream(writeCallback, tellCallback, seekCallback, callbackData);
+ Imf::OutputFile file(ostream, header);
+ file.setFrameBuffer(frameBuffer);
+ file.writePixels(height);
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+ catch (const std::exception &e)
{
- case 1: return AImgFormat::R16F;
- case 2: return AImgFormat::RG16F;
- case 3: return AImgFormat::RGB16F;
- case 4: return AImgFormat::RGBA16F;
+ mErrorDetails = std::string("[AImg::EXRImageLoader::EXRFile::] ") + e.what();
+ return AImgErrorCode::AIMG_WRITE_FAILED_EXTERNAL;
}
}
- else*/
+ };
+
+ AImgBase *ExrImageLoader::getAImg()
{
- switch (numChannels)
- {
- case 1:
- return AImgFormat::R32F;
- case 2:
- return AImgFormat::RG32F;
- case 3:
- return AImgFormat::RGB32F;
- case 4:
- return AImgFormat::RGBA32F;
- }
+ return new ExrFile();
}
- return AImgFormat::INVALID_FORMAT;
-}
+ bool ExrImageLoader::isFormatSupported(int32_t format)
+ {
+ return isFormatSupportedByExr(format);
+ }
+
+ AImgFormat ExrImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat)
+ {
+ return getWriteFormatExr(inputFormat, outputFormat);
+ }
}
-#endif // HAVE_EXR
+#endif // HAVE_EXR
\ No newline at end of file
diff --git a/src_c/exr.h b/src_c/exr.h
index 06c45b5..4bffe37 100644
--- a/src_c/exr.h
+++ b/src_c/exr.h
@@ -16,7 +16,9 @@ namespace AImg
virtual std::string getFileExtension();
virtual int32_t getAImgFileFormatValue();
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat);
+ virtual bool isFormatSupported(int32_t format);
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
};
}
diff --git a/src_c/hdr.cpp b/src_c/hdr.cpp
new file mode 100644
index 0000000..656f78d
--- /dev/null
+++ b/src_c/hdr.cpp
@@ -0,0 +1,184 @@
+#include "hdr.h"
+#include "AIL_internal.h"
+
+#define STBI_ONLY_HDR
+
+#include "extern/stb_image.h"
+#include
+
+namespace AImg
+{
+ namespace STBIHDRCallbacks
+ {
+ int readCallback(void * user, char * data, int size)
+ {
+ CallbackData * callbackFunctions = (CallbackData *)user;
+ return callbackFunctions->readCallback(callbackFunctions->callbackData, (uint8_t *)data, size);
+ }
+
+ void seekCallback(void * user, int num_bytes)
+ {
+ CallbackData * callbackFunctions = (CallbackData *)user;
+ callbackFunctions->seekCallback(callbackFunctions->callbackData, num_bytes);
+ }
+
+ int eofCallback(void * user)
+ {
+ CallbackData * callbackFunctions = (CallbackData *)user;
+
+ int startPos = callbackFunctions->tellCallback(callbackFunctions->callbackData);
+ callbackFunctions->seekCallback(callbackFunctions->callbackData, startPos + 1);
+
+ int newPos = callbackFunctions->tellCallback(callbackFunctions->callbackData);
+
+ callbackFunctions->seekCallback(callbackFunctions->callbackData, startPos);
+
+ return (startPos - newPos) != 0 ? 1 : 0;
+ }
+ }
+
+ class HDRFile : public AImgBase
+ {
+ public:
+
+ virtual int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
+ {
+ data.readCallback = readCallback;
+ data.tellCallback = tellCallback;
+ data.seekCallback = seekCallback;
+ data.callbackData = callbackData;
+
+ stbi_io_callbacks callback;
+ callback.read = STBIHDRCallbacks::readCallback;
+ callback.skip = STBIHDRCallbacks::seekCallback;
+ callback.eof = STBIHDRCallbacks::eofCallback;
+
+ int startingPosition = tellCallback(callbackData);
+ stbi_hdr_to_ldr_gamma(1.0f);
+ stbi_ldr_to_hdr_gamma(1.0f);
+
+ stbi_info_from_callbacks(&callback, &data, &width, &height, &numChannels);
+ seekCallback(callbackData, startingPosition);
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
+ {
+ stbi_io_callbacks callbacks;
+
+ callbacks.read = STBIHDRCallbacks::readCallback;
+ callbacks.skip = STBIHDRCallbacks::seekCallback;
+ callbacks.eof = STBIHDRCallbacks::eofCallback;
+ float * loadedData = stbi_loadf_from_callbacks(&callbacks, &data, &width, &height, &numChannels, numChannels);
+
+ if (!loadedData)
+ {
+ mErrorDetails = "[AImg::HDRImageLoader::HDRFile::decodeImage] stbi_loadf_from_callbacks failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
+
+ int32_t decodeFormat = AImgFormat::RGB32F;
+ int32_t numChannels, bytesPerChannel, floatOrInt;
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
+ void* destBuffer = realDestBuffer;
+
+ std::vector convertTmpBuffer(0);
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ {
+ convertTmpBuffer.resize(width * height * bytesPerChannel * numChannels);
+ destBuffer = convertTmpBuffer.data();
+ }
+
+ memcpy(destBuffer, loadedData, width * height * bytesPerChannel * numChannels);
+ stbi_image_free(loadedData);
+
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ {
+ int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, width, height, decodeFormat, forceImageFormat);
+ if (err != AImgErrorCode::AIMG_SUCCESS)
+ return err;
+ }
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ virtual int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
+ {
+ return AImgErrorCode::AIMG_WRITE_NOT_SUPPORTED_FOR_FORMAT;
+ }
+
+ virtual int32_t getImageInfo(int32_t* width, int32_t* height, int32_t* numChannels, int32_t* bytesPerChannel, int32_t* floatOrInt, int32_t* decodedImgFormat, uint32_t *colourProfileLen)
+ {
+ *width = this->width;
+ *height = this->height;
+ *numChannels = this->numChannels;
+ *bytesPerChannel = 4;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_FLOAT;
+ *decodedImgFormat = AImgFormat::RGB32F;
+
+ if (colourProfileLen != NULL)
+ {
+ *colourProfileLen = 0;
+ }
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ {
+ if (colourProfile != NULL)
+ {
+ *colourProfileLen = 0;
+ }
+ if (profileName != NULL)
+ {
+ std::strcpy(profileName, "no_profile");
+ }
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ private:
+ CallbackData data;
+ int32_t numChannels, width, height;
+ };
+
+ AImgBase * HDRImageLoader::getAImg()
+ {
+ return new HDRFile();
+ }
+
+ bool HDRImageLoader::canLoadImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData)
+ {
+ int startingPosition = tellCallback(callbackData);
+
+ std::vector magic = { 0x23, 0x3f, 0x52, 0x41, 0x44, 0x49, 0x41, 0x4e, 0x43, 0x45, 0x0a };
+
+ std::vector readBackData;
+ readBackData.resize(magic.size());
+
+ readCallback(callbackData, readBackData.data(), (int32_t)magic.size());
+
+ seekCallback(callbackData, startingPosition);
+
+ return memcmp(magic.data(), readBackData.data(), magic.size()) == 0;
+ }
+
+ std::string HDRImageLoader::getFileExtension()
+ {
+ return "HDR";
+ }
+
+ int32_t HDRImageLoader::getAImgFileFormatValue()
+ {
+ return HDR_IMAGE_FORMAT;
+ }
+
+ int32_t HDRImageLoader::initialise() { return AImgErrorCode::AIMG_SUCCESS; }
+
+ bool HDRImageLoader::isFormatSupported(int32_t format) { return format == AImgFormat::RGB32F; }
+
+ AImgFormat HDRImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat) { return AImgFormat::RGB32F; }
+}
\ No newline at end of file
diff --git a/src_c/hdr.h b/src_c/hdr.h
new file mode 100644
index 0000000..493d84c
--- /dev/null
+++ b/src_c/hdr.h
@@ -0,0 +1,26 @@
+#ifndef ARTOMATIX_HDR_H
+#define ARTOMATIX_HDR_H
+
+#include "ImageLoaderBase.h"
+
+#include
+namespace AImg
+{
+ class HDRImageLoader : public ImageLoaderBase
+ {
+ public:
+
+ virtual AImgBase * getAImg();
+ virtual int32_t initialise();
+
+ virtual bool canLoadImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void* callbackData);
+ virtual std::string getFileExtension();
+ virtual int32_t getAImgFileFormatValue();
+
+ virtual bool isFormatSupported(int32_t format);
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/src_c/jpeg.cpp b/src_c/jpeg.cpp
index ca93ffa..81e5f30 100644
--- a/src_c/jpeg.cpp
+++ b/src_c/jpeg.cpp
@@ -15,7 +15,6 @@ namespace AImg
jpeg_source_mgr pub;
void *data;
CallbackData callbackFunctionData;
-
} ArtomatixJPEGSourceMGR;
typedef struct
@@ -27,8 +26,8 @@ namespace AImg
typedef struct
{
- jpeg_error_mgr pub;
- jmp_buf buf;
+ jpeg_error_mgr pub;
+ jmp_buf buf;
} ArtomatixErrorStruct;
namespace JPEGConsts
@@ -36,7 +35,6 @@ namespace AImg
// Buffer size used in libjpeg
const size_t BUFFER_SIZE = 4096;
const int Quality = 99;
-
}
namespace JPEGCallbackFunctions
@@ -50,21 +48,20 @@ namespace AImg
boolean emptyOutputBuffer(j_compress_ptr cinfo)
{
- ArtomatixJPEGDestinationMGR * dst = (ArtomatixJPEGDestinationMGR *) cinfo->dest;
+ ArtomatixJPEGDestinationMGR * dst = (ArtomatixJPEGDestinationMGR *)cinfo->dest;
dst->callbackFunctionData.writeCallback(dst->callbackFunctionData.callbackData, (uint8_t *)dst->buffer, JPEGConsts::BUFFER_SIZE);
- dst->pub.next_output_byte = (JOCTET *) dst->buffer;
+ dst->pub.next_output_byte = (JOCTET *)dst->buffer;
dst->pub.free_in_buffer = JPEGConsts::BUFFER_SIZE;
return TRUE;
}
void termDestination(j_compress_ptr cinfo)
{
-
- ArtomatixJPEGDestinationMGR * dst = (ArtomatixJPEGDestinationMGR *) cinfo->dest;
+ ArtomatixJPEGDestinationMGR * dst = (ArtomatixJPEGDestinationMGR *)cinfo->dest;
size_t datacount = JPEGConsts::BUFFER_SIZE - dst->pub.free_in_buffer;
if (datacount > 0)
- dst->callbackFunctionData.writeCallback(dst->callbackFunctionData.callbackData, (uint8_t *)dst->buffer, datacount);
+ dst->callbackFunctionData.writeCallback(dst->callbackFunctionData.callbackData, (uint8_t *)dst->buffer, (int32_t)datacount);
}
}
@@ -82,19 +79,18 @@ namespace AImg
{
while (num_bytes > (long)src->pub.bytes_in_buffer)
{
-
- num_bytes -= src->pub.bytes_in_buffer;
+ num_bytes -= (long)(src->pub.bytes_in_buffer);
(*src->pub.fill_input_buffer)(cinfo);
}
- src->pub.next_input_byte += (size_t) num_bytes;
- src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ src->pub.next_input_byte += (size_t)num_bytes;
+ src->pub.bytes_in_buffer -= (size_t)num_bytes;
}
}
boolean fillInputBuffer(j_decompress_ptr cinfo)
{
- ArtomatixJPEGSourceMGR * src = (ArtomatixJPEGSourceMGR *)cinfo->src;
+ ArtomatixJPEGSourceMGR * src = (ArtomatixJPEGSourceMGR *)cinfo->src;
size_t bytesRead = src->callbackFunctionData.readCallback(src->callbackFunctionData.callbackData, (uint8_t *)src->data, JPEGConsts::BUFFER_SIZE);
if (bytesRead <= 0)
@@ -114,13 +110,13 @@ namespace AImg
void lessAnnoyingEmitMessage(j_common_ptr cinfo, int msg_level)
{
- if (msg_level == 0)
+ if (msg_level == 0)
(*cinfo->err->output_message) (cinfo);
}
void handleFatalError(j_common_ptr cinfo)
{
- ArtomatixErrorStruct * err = (ArtomatixErrorStruct *) cinfo->err;
+ ArtomatixErrorStruct * err = (ArtomatixErrorStruct *)cinfo->err;
longjmp(err->buf, 1);
}
}
@@ -130,11 +126,11 @@ namespace AImg
if (cinfo->src == NULL)
{
cinfo->src = (jpeg_source_mgr *)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(ArtomatixJPEGSourceMGR));
- ((ArtomatixJPEGSourceMGR * )cinfo->src)->data = (void *)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, JPEGConsts::BUFFER_SIZE);
+ ((ArtomatixJPEGSourceMGR *)cinfo->src)->data = (void *)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, JPEGConsts::BUFFER_SIZE);
((ArtomatixJPEGSourceMGR *)cinfo->src)->callbackFunctionData = callbackData;
}
- ArtomatixJPEGSourceMGR * src = (ArtomatixJPEGSourceMGR *)cinfo->src;
+ ArtomatixJPEGSourceMGR * src = (ArtomatixJPEGSourceMGR *)cinfo->src;
src->pub.init_source = JPEGCallbackFunctions::ReadFunctions::initSource;
src->pub.fill_input_buffer = JPEGCallbackFunctions::ReadFunctions::fillInputBuffer;
src->pub.skip_input_data = JPEGCallbackFunctions::ReadFunctions::skipInputData;
@@ -144,7 +140,6 @@ namespace AImg
src->pub.bytes_in_buffer = 0;
}
-
void setArtomatixDestinationMGR(j_compress_ptr cinfo, CallbackData callbackData)
{
if (cinfo->dest == NULL)
@@ -158,9 +153,8 @@ namespace AImg
src->pub.init_destination = JPEGCallbackFunctions::WriteFunctions::initDestination;
src->pub.empty_output_buffer = JPEGCallbackFunctions::WriteFunctions::emptyOutputBuffer;
src->pub.term_destination = JPEGCallbackFunctions::WriteFunctions::termDestination;
- src->pub.next_output_byte = (JOCTET *) src->buffer;
+ src->pub.next_output_byte = (JOCTET *)src->buffer;
src->pub.free_in_buffer = JPEGConsts::BUFFER_SIZE;
-
}
int32_t JPEGImageLoader::initialise()
@@ -171,10 +165,10 @@ namespace AImg
bool JPEGImageLoader::canLoadImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
{
AIL_UNUSED_PARAM(tellCallback);
- uint8_t magic[] = {0xFF, 0xD8, 0xFF};
+ uint8_t magic[] = { 0xFF, 0xD8, 0xFF };
int startingPosition = tellCallback(callbackData);
- std::vector header(4);
+ std::vector header(4);
readCallback(callbackData, &header[0], 4);
seekCallback(callbackData, startingPosition);
@@ -194,223 +188,232 @@ namespace AImg
class JPEGFile : public AImgBase
{
- public:
- jpeg_decompress_struct jpeg_read_struct;
- ArtomatixErrorStruct err_mgr;
+ public:
+ jpeg_decompress_struct jpeg_read_struct;
+ ArtomatixErrorStruct err_mgr;
+ JPEGFile()
+ {
+ jpeg_create_decompress(&jpeg_read_struct);
+ }
- JPEGFile()
- {
- jpeg_create_decompress(&jpeg_read_struct);
- }
+ virtual ~JPEGFile()
+ {
+ jpeg_destroy_decompress(&jpeg_read_struct);
+ }
- virtual ~JPEGFile()
+ int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
+ {
+ CallbackData data;
+ data.callbackData = callbackData;
+ data.readCallback = readCallback;
+ data.tellCallback = tellCallback;
+ data.seekCallback = seekCallback;
+
+ setArtomatixSourceMGR(&jpeg_read_struct, data);
+ jpeg_read_struct.err = jpeg_std_error(&err_mgr.pub);
+
+ ArtomatixErrorStruct jerr;
+ jpeg_read_struct.err = jpeg_std_error(&jerr.pub);
+ //jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
+ jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
+
+ ArtomatixErrorStruct * err_ptr = (ArtomatixErrorStruct *)jpeg_read_struct.err;
+ if (setjmp(err_ptr->buf))
{
- jpeg_destroy_decompress(&jpeg_read_struct);
- }
+ mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::openImage] jpeg_read_header failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
- int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
- {
- CallbackData data;
- data.callbackData = callbackData;
- data.readCallback = readCallback;
- data.tellCallback = tellCallback;
- data.seekCallback = seekCallback;
-
- setArtomatixSourceMGR(&jpeg_read_struct, data);
- jpeg_read_struct.err = jpeg_std_error(&err_mgr.pub);
-
- ArtomatixErrorStruct jerr;
- jpeg_read_struct.err = jpeg_std_error(&jerr.pub);
- //jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
- jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
-
- ArtomatixErrorStruct * err_ptr = (ArtomatixErrorStruct *) jpeg_read_struct.err;
- if (setjmp(err_ptr->buf))
- {
- mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::openImage] jpeg_read_header failed!";
-
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
+ jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
+ jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
+ jpeg_read_header(&jpeg_read_struct, TRUE);
- jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
- jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
- jpeg_read_header(&jpeg_read_struct, TRUE);
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- return AImgErrorCode::AIMG_SUCCESS;
+ virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ {
+ *width = jpeg_read_struct.image_width;
+ *height = jpeg_read_struct.image_height;
+ *bytesPerChannel = 1;
+ *numChannels = jpeg_read_struct.num_components;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ *decodedImgFormat = AImgFormat::_8BITS | AImgFormat::R << (jpeg_read_struct.num_components - 1);
+ if (colourProfileLen != NULL)
+ {
+ *colourProfileLen = 0;
}
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ {
+ if (colourProfile != NULL)
{
- *width = jpeg_read_struct.image_width;
- *height = jpeg_read_struct.image_height;
- *bytesPerChannel = 1;
- *numChannels = jpeg_read_struct.num_components;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- *decodedImgFormat = ((int)AImgFormat::R8U) + jpeg_read_struct.num_components - 1;
- if(colourProfileLen != NULL)
- {
- *colourProfileLen = 0;
- }
- return AImgErrorCode::AIMG_SUCCESS;
+ *colourProfileLen = 0;
}
-
- virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ if (profileName != NULL)
{
- if(colourProfile != NULL)
- {
- *colourProfileLen = 0;
- }
- if(profileName != NULL)
- {
- std::strcpy(profileName, "no_profile");
- }
-
- return AImgErrorCode::AIMG_SUCCESS;
+ std::strcpy(profileName, "no_profile");
}
- virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
- {
- void* destBuffer = realDestBuffer;
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- std::vector convertTmpBuffer(0);
- if(forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != AImgFormat::RGB8U)
- {
- int32_t numChannels, bytesPerChannel, floatOrInt;
- AIGetFormatDetails(AImgFormat::RGB8U, &numChannels, &bytesPerChannel, &floatOrInt);
+ virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
+ {
+ void* destBuffer = realDestBuffer;
- convertTmpBuffer.resize(jpeg_read_struct.image_width * jpeg_read_struct.image_height * bytesPerChannel * numChannels);
- destBuffer = &convertTmpBuffer[0];
- }
+ std::vector convertTmpBuffer(0);
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != AImgFormat::RGB8U)
+ {
+ int32_t numChannels, bytesPerChannel, floatOrInt;
+ AIGetFormatDetails(AImgFormat::RGB8U, &numChannels, &bytesPerChannel, &floatOrInt);
- ArtomatixErrorStruct jerr;
- jpeg_read_struct.err = jpeg_std_error(&jerr.pub);
- jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
- jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
+ convertTmpBuffer.resize(jpeg_read_struct.image_width * jpeg_read_struct.image_height * bytesPerChannel * numChannels);
+ destBuffer = &convertTmpBuffer[0];
+ }
- ArtomatixErrorStruct * err_ptr = (ArtomatixErrorStruct *) jpeg_read_struct.err;
+ ArtomatixErrorStruct jerr;
+ jpeg_read_struct.err = jpeg_std_error(&jerr.pub);
+ jpeg_read_struct.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
+ jpeg_read_struct.err->error_exit = JPEGCallbackFunctions::handleFatalError;
- if (setjmp(err_ptr->buf))
- {
- mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::decodeImage] jpeg_start_decompress failed!";
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
+ ArtomatixErrorStruct * err_ptr = (ArtomatixErrorStruct *)jpeg_read_struct.err;
- jpeg_start_decompress(&jpeg_read_struct);
+ if (setjmp(err_ptr->buf))
+ {
+ mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::decodeImage] jpeg_start_decompress failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
- int row_stride = jpeg_read_struct.output_components * jpeg_read_struct.output_width;
+ jpeg_start_decompress(&jpeg_read_struct);
- JSAMPROW buffer[1];
+ int row_stride = jpeg_read_struct.output_components * jpeg_read_struct.output_width;
- buffer[0] = (JSAMPROW) destBuffer;
+ JSAMPROW buffer[1];
- if (setjmp(err_ptr->buf))
- {
- mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::decodeImage] jpeg_read_scanlines failed!";
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
+ buffer[0] = (JSAMPROW)destBuffer;
- while (jpeg_read_struct.output_scanline < jpeg_read_struct.output_height)
- {
- jpeg_read_scanlines(&jpeg_read_struct, buffer, 1);
- buffer[0] = (uint8_t * )buffer[0] + row_stride;
- }
+ if (setjmp(err_ptr->buf))
+ {
+ mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::decodeImage] jpeg_read_scanlines failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
- jpeg_finish_decompress(&jpeg_read_struct);
+ while (jpeg_read_struct.output_scanline < jpeg_read_struct.output_height)
+ {
+ jpeg_read_scanlines(&jpeg_read_struct, buffer, 1);
+ buffer[0] = (uint8_t *)buffer[0] + row_stride;
+ }
- if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != AImgFormat::RGB8U)
- {
- int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, jpeg_read_struct.image_width, jpeg_read_struct.image_height, AImgFormat::RGB8U, forceImageFormat);
- if(err != AImgErrorCode::AIMG_SUCCESS)
- return err;
- }
+ jpeg_finish_decompress(&jpeg_read_struct);
- return AImgErrorCode::AIMG_SUCCESS;
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != AImgFormat::RGB8U)
+ {
+ int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, jpeg_read_struct.image_width, jpeg_read_struct.image_height, AImgFormat::RGB8U, forceImageFormat);
+ if (err != AImgErrorCode::AIMG_SUCCESS)
+ return err;
}
- int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
- {
- AIL_UNUSED_PARAM(encodingOptions);
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- std::vector convertBuffer(0);
- if (inputFormat != AImgFormat::RGB8U)
- {
- convertBuffer.resize(width * height * 3);
+ int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
+ {
+ AIL_UNUSED_PARAM(encodingOptions);
+ AIL_UNUSED_PARAM(outputFormat);
- int32_t convertError = AImgConvertFormat(data, &convertBuffer[0], width, height, inputFormat, AImgFormat::RGB8U);
+ std::vector convertBuffer(0);
+ if (inputFormat != AImgFormat::RGB8U)
+ {
+ convertBuffer.resize(width * height * 3);
- if (convertError != AImgErrorCode::AIMG_SUCCESS)
- return convertError;
- data = &convertBuffer[0];
- }
+ int32_t convertError = AImgConvertFormat(data, &convertBuffer[0], width, height, inputFormat, AImgFormat::RGB8U);
- CallbackData dataStruct;
- dataStruct.writeCallback = writeCallback;
- dataStruct.tellCallback = tellCallback;
- dataStruct.seekCallback = seekCallback;
- dataStruct.callbackData = callbackData;
+ if (convertError != AImgErrorCode::AIMG_SUCCESS)
+ return convertError;
+ data = &convertBuffer[0];
+ }
- ArtomatixErrorStruct jerr;
- jpeg_compress_struct cinfo;
- cinfo.err = jpeg_std_error(&jerr.pub);
- cinfo.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
- cinfo.err->error_exit = JPEGCallbackFunctions::handleFatalError;
- jpeg_create_compress(&cinfo);
+ CallbackData dataStruct;
+ dataStruct.writeCallback = writeCallback;
+ dataStruct.tellCallback = tellCallback;
+ dataStruct.seekCallback = seekCallback;
+ dataStruct.callbackData = callbackData;
- setArtomatixDestinationMGR(&cinfo, dataStruct);
+ ArtomatixErrorStruct jerr;
+ jpeg_compress_struct cinfo;
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ cinfo.err->emit_message = JPEGCallbackFunctions::lessAnnoyingEmitMessage;
+ cinfo.err->error_exit = JPEGCallbackFunctions::handleFatalError;
+ jpeg_create_compress(&cinfo);
- cinfo.image_width = width;
- cinfo.image_height = height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
+ setArtomatixDestinationMGR(&cinfo, dataStruct);
- jpeg_set_defaults(&cinfo);
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
- jpeg_set_quality(&cinfo, JPEGConsts::Quality, TRUE);
+ jpeg_set_defaults(&cinfo);
- if (setjmp(jerr.buf))
- {
- mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::writeImage] jpeg_start_compress failed!";
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
- jpeg_start_compress(&cinfo, TRUE);
+ jpeg_set_quality(&cinfo, JPEGConsts::Quality, TRUE);
- int row_stride = width * cinfo.input_components;
+ if (setjmp(jerr.buf))
+ {
+ mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::writeImage] jpeg_start_compress failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
+ jpeg_start_compress(&cinfo, TRUE);
- JSAMPROW row_pointer[1];
+ int row_stride = width * cinfo.input_components;
+ JSAMPROW row_pointer[1];
- if (setjmp(jerr.buf))
- {
- mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::writeImage] jpeg_write_scanlines failed!";
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
+ if (setjmp(jerr.buf))
+ {
+ mErrorDetails = "[AImg::JPEGImageLoader::JPEGFile::writeImage] jpeg_write_scanlines failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
+ }
- while(cinfo.next_scanline < cinfo.image_height)
- {
- row_pointer[0] = (uint8_t *)data + row_stride * cinfo.next_scanline;
- jpeg_write_scanlines(&cinfo, row_pointer, 1);
- }
+ while (cinfo.next_scanline < cinfo.image_height)
+ {
+ row_pointer[0] = (uint8_t *)data + row_stride * cinfo.next_scanline;
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
- return AImgErrorCode::AIMG_SUCCESS;
- }
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
};
- AImgFormat JPEGImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat)
+ AImgFormat JPEGImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat)
{
AIL_UNUSED_PARAM(inputFormat);
+ AIL_UNUSED_PARAM(outputFormat);
return AImgFormat::RGB8U;
}
+ bool JPEGImageLoader::isFormatSupported(int32_t format)
+ {
+ bool floatFormat = format & AImgFormat::FLOAT_FORMAT;
+ bool bitDepth8 = format & AImgFormat::_8BITS;
+ bool rgb = format & AImgFormat::RGB;
+
+ bool isSupported = !floatFormat && bitDepth8 && rgb;
+ return isSupported;
+ }
+
AImgBase* JPEGImageLoader::getAImg()
{
return new JPEGFile();
}
}
-#endif // HAVE_JPEG
+#endif // HAVE_JPEG
\ No newline at end of file
diff --git a/src_c/jpeg.h b/src_c/jpeg.h
index b57e11b..207e94f 100644
--- a/src_c/jpeg.h
+++ b/src_c/jpeg.h
@@ -16,7 +16,9 @@ namespace AImg
virtual std::string getFileExtension();
virtual int32_t getAImgFileFormatValue();
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat);
+ virtual bool isFormatSupported(int32_t format);
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
};
}
diff --git a/src_c/png.cpp b/src_c/png.cpp
index af24c40..a18d4b3 100644
--- a/src_c/png.cpp
+++ b/src_c/png.cpp
@@ -11,7 +11,6 @@
namespace AImg
{
-
int32_t PNGImageLoader::initialise()
{
return AImgErrorCode::AIMG_SUCCESS;
@@ -25,7 +24,7 @@ namespace AImg
seekCallback(callbackData, startingPosition);
- uint8_t png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
return ((int32_t)(memcmp(&header[0], &png_signature[0], 8))) == 0;
}
@@ -34,14 +33,14 @@ namespace AImg
{
CallbackData callbackData = *((CallbackData *)png_get_io_ptr(png_ptr));
- callbackData.readCallback(callbackData.callbackData, data, length);
+ callbackData.readCallback(callbackData.callbackData, data, (int32_t)length);
}
void png_custom_write_data(png_struct* png_ptr, png_byte* data, png_size_t length)
{
CallbackData callbackData = *((CallbackData *)png_get_io_ptr(png_ptr));
- callbackData.writeCallback(callbackData.callbackData, data, length);
+ callbackData.writeCallback(callbackData.callbackData, data, (int32_t)length);
}
std::string PNGImageLoader::getFileExtension()
@@ -59,25 +58,50 @@ namespace AImg
AIL_UNUSED_PARAM(png_ptr);
}
+ bool isFormatSupportedByPng(int32_t format)
+ {
+ bool isNotFloatFormat = !(format & AImgFormat::FLOAT_FORMAT);
+ bool is8Or16Bit = (format & AImgFormat::_8BITS || format & AImgFormat::_16BITS);
+ bool isNotRG8U = format != AImgFormat::RG8U;
+ bool isNotRG16U = format != AImgFormat::RG16U;
+ bool isSupported = isNotFloatFormat
+ && is8Or16Bit
+ && isNotRG8U
+ && isNotRG16U;
+
+ return isSupported;
+ }
- AImgFormat getWhatFormatWillBeWrittenForDataPNG(int32_t inputFormat)
+ AImgFormat getWhatFormatWillBeWrittenForDataPNG(int32_t inputFormat, int32_t outputFormat)
{
+ if (isFormatSupportedByPng(outputFormat))
+ {
+ return (AImgFormat)outputFormat;
+ }
+
int32_t numChannels, bytesPerChannel, floatOrInt;
AIGetFormatDetails(inputFormat, &numChannels, &bytesPerChannel, &floatOrInt);
- if(floatOrInt == AImgFloatOrIntType::FITYPE_FLOAT)
- return (AImgFormat) (AImgFormat::R16U + numChannels - 1); // convert to 16U version with same channelNum
+ if (floatOrInt == AImgFloatOrIntType::FITYPE_FLOAT)
+ {
+ AImgFormat outFormat = (AImgFormat)(AImgFormat::_16BITS | (AImgFormat::R << (numChannels - 1))); // convert to 16U version with same channelNum
- if (inputFormat == AImgFormat::RG8U)
- return AImgFormat::RGB16U;
+ if (outFormat == AImgFormat::RG16U)
+ return AImgFormat::RGB16U;
+
+ return outFormat;
+ }
if (inputFormat == AImgFormat::RG8U)
+ return AImgFormat::RGB8U;
+
+ if (inputFormat == AImgFormat::RG16U)
return AImgFormat::RGB16U;
- if(inputFormat >= AImgFormat::R8U && inputFormat <= AImgFormat::RGBA8U)
+ if(inputFormat & AImgFormat::_8BITS)
return (AImgFormat)inputFormat;
- if(inputFormat >= AImgFormat::R16U && inputFormat <= AImgFormat::RGBA16U)
+ if(inputFormat & AImgFormat::_16BITS)
return (AImgFormat)inputFormat;
return AImgFormat::INVALID_FORMAT;
@@ -150,24 +174,38 @@ namespace AImg
png_set_expand(png_read_ptr);
bit_depth = 8;
}
- if (png_get_valid(png_read_ptr, png_info_ptr, PNG_INFO_tRNS))
+
+ bool hasTransparency = png_get_valid(png_read_ptr, png_info_ptr, PNG_INFO_tRNS);
+ bool isGrayWithAlpha = colour_type == PNG_COLOR_TYPE_GRAY_ALPHA;
+
+ bool numChannelsChanged = false;
+
+ if (hasTransparency)
{
png_set_expand(png_read_ptr);
- if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- {
- // expand grayscale images with transparency to 4-channel RGBA because if we don't then we end up
- // with gray in R and alpha in G, and converting that up to RGBA will not yield the correct results
- png_set_gray_to_rgb(png_read_ptr);
- numChannels = 3;
- }
-
numChannels++;
}
- if(!(png_get_iCCP(png_read_ptr, png_info_ptr, &profileName, &compressionMethod, &compressedProfile, &compressedProfileLen) & PNG_INFO_iCCP))
+
+ if ((hasTransparency && colour_type == PNG_COLOR_TYPE_GRAY) || isGrayWithAlpha)
{
- compressedProfile = NULL;
- profileName = NULL;
+ // expand grayscale images with transparency to 4-channel RGBA because if we don't then we end up
+ // with gray in R and alpha in G, and converting that up to RGBA will not yield the correct results
+ png_set_gray_to_rgb(png_read_ptr);
+
+ numChannels = 4;
+ numChannelsChanged = true;
+ }
+
+ if (!numChannelsChanged)
+ {
+ // Don't load color profile if the number of color channels changes. It would be invalid
+
+ if (!(png_get_iCCP(png_read_ptr, png_info_ptr, &profileName, &compressionMethod, &compressedProfile, &compressedProfileLen) & PNG_INFO_iCCP))
+ {
+ compressedProfile = NULL;
+ profileName = NULL;
+ }
}
return AImgErrorCode::AIMG_SUCCESS;
@@ -295,7 +333,9 @@ namespace AImg
return AImgErrorCode::AIMG_SUCCESS;
}
- int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen, WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
+ int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat,
+ const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
{
AIL_UNUSED_PARAM(tellCallback);
AIL_UNUSED_PARAM(seekCallback);
@@ -319,7 +359,7 @@ namespace AImg
png_set_write_fn(png_write_ptr, (void *)callbackDataStruct, png_custom_write_data, flush_data_noop_func);
- int32_t writeFormat = getWhatFormatWillBeWrittenForDataPNG(inputFormat);
+ int32_t writeFormat = getWhatFormatWillBeWrittenForDataPNG(inputFormat, outputFormat);
std::vector convertBuffer(0);
@@ -334,6 +374,17 @@ namespace AImg
if (convertError != AImgErrorCode::AIMG_SUCCESS)
return convertError;
data = &convertBuffer[0];
+
+ int outChannels = numChannels;
+ AIGetFormatDetails(inputFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
+ if (numChannels != outChannels
+ && (numChannels != 4 || outChannels != 3)
+ && (numChannels != 3 || outChannels != 4))
+ {
+ // Don't save color profile if the number of color channels changed
+ colourProfile = NULL;
+ }
}
png_byte colour_type;
@@ -357,7 +408,6 @@ namespace AImg
colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
bit_depth = 8;
break;
-
case R16U:
colour_type = PNG_COLOR_TYPE_GRAY;
bit_depth = 16;
@@ -385,10 +435,15 @@ namespace AImg
int32_t numChannels, bytesPerChannel, floatOrInt;
AIGetFormatDetails(writeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
- void ** ptrs = (void **)malloc(sizeof(size_t) * height);
+ size_t step = width * numChannels * bytesPerChannel;
- for (int32_t y=0; y < height; y++)
- ptrs[y] = (void *)((size_t)data + y*width * numChannels * bytesPerChannel);
+ png_bytepp ptrs = (png_bytepp)malloc(sizeof(png_bytep) * height);
+
+ ptrs[0] = (png_bytep)data;
+ for (int32_t y = 1; y < height; y++)
+ {
+ ptrs[y] = ptrs[y - 1] + step;
+ }
png_set_IHDR(png_write_ptr, png_info_ptr, width, height, bit_depth, colour_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
@@ -455,9 +510,14 @@ namespace AImg
};
- AImgFormat PNGImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat)
+ AImgFormat PNGImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat)
+ {
+ return getWhatFormatWillBeWrittenForDataPNG(inputFormat, outputFormat);
+ }
+
+ bool PNGImageLoader::isFormatSupported(int32_t format)
{
- return getWhatFormatWillBeWrittenForDataPNG(inputFormat);
+ return isFormatSupportedByPng(format);
}
AImgBase* PNGImageLoader::getAImg()
diff --git a/src_c/png.h b/src_c/png.h
index da4ee6f..fb1c853 100644
--- a/src_c/png.h
+++ b/src_c/png.h
@@ -16,7 +16,9 @@ namespace AImg
virtual std::string getFileExtension();
virtual int32_t getAImgFileFormatValue();
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat);
+ virtual bool isFormatSupported(int32_t format);
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
};
}
diff --git a/src_c/tests/CMakeLists.txt b/src_c/tests/CMakeLists.txt
index 03f0f97..a66b0d8 100644
--- a/src_c/tests/CMakeLists.txt
+++ b/src_c/tests/CMakeLists.txt
@@ -17,14 +17,10 @@ if(AIMG_TESTS_ENABLED)
set(GTEST_MAINLIB "optimized;${GTEST_LOCATION}/Release/${LIBPREFIX}gtest_main${LIBSUFFIX};debug;${GTEST_LOCATION}/Debug/${LIBPREFIX}gtest_main${LIBSUFFIX}")
set(GTEST_CMAKE_ARGS "-Dgtest_force_shared_crt=ON")
endif()
+
+ hunter_add_package(GTest)
+ find_package(GTest CONFIG REQUIRED)
- include(ExternalProject)
- ExternalProject_Add(gtest
- URL https://github.com/google/googletest/archive/release-1.7.0.zip
- PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
- CMAKE_ARGS "${GTEST_CMAKE_ARGS}"
- INSTALL_COMMAND ""
- )
find_package(Threads)
@@ -34,9 +30,9 @@ if(AIMG_TESTS_ENABLED)
add_executable("test_${test_name}" "${test_name}.cpp" "testCommon.cpp" "testCommon.h")
add_dependencies("test_${test_name}" gtest)
- target_include_directories("test_${test_name}" PRIVATE ${GTEST_INCLUDES})
+ target_include_directories("test_${test_name}" PRIVATE GTest::main)
target_compile_definitions("test_${test_name}" PRIVATE TEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
- target_link_libraries("test_${test_name}" ${GTEST_LIBRARY} ${GTEST_MAINLIB} ${link_libs} ${CMAKE_THREAD_LIBS_INIT})
+ target_link_libraries("test_${test_name}" GTest::main ${link_libs} ${CMAKE_THREAD_LIBS_INIT})
set_target_properties("test_${test_name}" PROPERTIES COMPILE_FLAGS "${AIL_COMPILE_FLAGS}")
@@ -67,6 +63,10 @@ if(AIMG_TESTS_ENABLED)
ail_add_test(tiff "AIL" Yes)
endif()
+ if(HDR_ENABLED)
+ ail_add_test(hdr "AIL" Yes)
+ endif()
+
add_custom_target(aitest ${all_tests})
set_target_properties(aitest PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()
diff --git a/src_c/tests/exr.cpp b/src_c/tests/exr.cpp
index c4d555b..c592d66 100644
--- a/src_c/tests/exr.cpp
+++ b/src_c/tests/exr.cpp
@@ -7,6 +7,64 @@
#include
+void WriteImageTest(AImgFormat decodeFormat, AImgFormat writeFormat, AImgFormat expectedWritten = AImgFormat::INVALID_FORMAT)
+{
+ if (expectedWritten < 0)
+ {
+ expectedWritten = writeFormat;
+ }
+
+ auto data = readFile(getImagesDir() + "/exr/grad_32.exr");
+
+ ReadCallback readCallback = NULL;
+ WriteCallback writeCallback = NULL;
+ TellCallback tellCallback = NULL;
+ SeekCallback seekCallback = NULL;
+ void* callbackData = NULL;
+
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
+
+ AImgHandle img = NULL;
+ AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+
+ int32_t width = 64;
+ int32_t height = 32;
+
+ int32_t numChannels, bytesPerChannel, floatOrInt;
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
+ int32_t fileSize = width*height*numChannels*bytesPerChannel;
+
+ std::vector imgData(fileSize, 0);
+
+ AImgDecodeImage(img, &imgData[0], decodeFormat);
+ AImgClose(img);
+ AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+
+ std::vector fileData(fileSize);
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], (int32_t)fileData.size());
+
+ AImgHandle wImg = AImgGetAImg(AImgFileFormat::EXR_IMAGE_FORMAT);
+ AImgWriteImage(wImg, &imgData[0], width, height, decodeFormat, writeFormat, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgClose(wImg);
+
+ seekCallback(callbackData, 0);
+
+ AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+
+ int32_t _, writtenFormat;
+ AImgGetInfo(img, &_, &_, &_, &_, &_, &writtenFormat, NULL);
+ ASSERT_EQ(writtenFormat, expectedWritten);
+
+ std::vector imgData2(fileSize, 0);
+ AImgDecodeImage(img, &imgData2[0], decodeFormat);
+ AImgClose(img);
+ AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+
+ for (uint32_t i = 0; i < imgData2.size(); i++)
+ ASSERT_LE(abs(imgData[i] - imgData2[i]), 1);
+}
+
TEST(Exr, TestDetectExr)
{
ASSERT_TRUE(detectImage("/exr/grad_32.exr", EXR_IMAGE_FORMAT));
@@ -33,7 +91,7 @@ TEST(Exr, TestMemoryCallbacksRead)
{
std::vector data(10);
for(size_t i = 0; i < data.size(); i++)
- data[i] = i;
+ data[i] = (uint8_t)i;
ReadCallback readCallback = NULL;
WriteCallback writeCallback = NULL;
@@ -41,7 +99,7 @@ TEST(Exr, TestMemoryCallbacksRead)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
std::vector readBuf(data.size());
std::fill(readBuf.begin(), readBuf.end(), 100);
@@ -87,7 +145,7 @@ TEST(Exr, TestReadExr)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -123,7 +181,7 @@ TEST(Exr, TestWriteExr)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -138,10 +196,10 @@ TEST(Exr, TestWriteExr)
AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
std::vector fileData(4096); // fixed size buffer for a file write, not the best but it'll do for this test
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], (int32_t)fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::EXR_IMAGE_FORMAT);
- AImgWriteImage(wImg, &imgData[0], width, height, AImgFormat::RGB32F, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgWriteImage(wImg, &imgData[0], width, height, AImgFormat::RGB32F, AImgFormat::INVALID_FORMAT, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
AImgClose(wImg);
seekCallback(callbackData, 0);
@@ -209,7 +267,7 @@ TEST(Exr, TestOpenBadImage)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
int32_t err = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -237,51 +295,32 @@ TEST(Exr, TestOpenEmptyStream)
TEST(Exr, TestWriteExr16)
{
- auto data = readFile(getImagesDir() + "/exr/grad_32.exr");
-
- ReadCallback readCallback = NULL;
- WriteCallback writeCallback = NULL;
- TellCallback tellCallback = NULL;
- SeekCallback seekCallback = NULL;
- void* callbackData = NULL;
-
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
-
- AImgHandle img = NULL;
- AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
-
- int32_t width = 64;
- int32_t height = 32;
-
- std::vector imgData(width*height*3, 0.0f);
-
- AImgDecodeImage(img, &imgData[0], AImgFormat::RGB16F);
- AImgClose(img);
- AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
-
- std::vector fileData(8192); // fixed size buffer for a file write, not the best but it'll do for this test
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
-
- AImgHandle wImg = AImgGetAImg(AImgFileFormat::EXR_IMAGE_FORMAT);
- AImgWriteImage(wImg, &imgData[0], width, height, AImgFormat::RGB16F, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
- AImgClose(wImg);
-
- seekCallback(callbackData, 0);
-
-
- AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+ WriteImageTest(AImgFormat::RGB16F, AImgFormat::RGB16F);
+}
- int32_t _, writtenFormat;
- AImgGetInfo(img, &_, &_, &_, &_, &_, &writtenFormat, NULL);
- ASSERT_EQ(writtenFormat, AImgFormat::RGB16F);
+TEST(Exr, TestWriteConvert32To16bits)
+{
+ WriteImageTest(AImgFormat::RGB32F, AImgFormat::RGB16F);
+}
+TEST(Exr, TestWriteConvert16To32bits)
+{
+ WriteImageTest(AImgFormat::RGB16F, AImgFormat::RGB32F);
+}
- std::vector imgData2(width*height*3, 0.0f);
- AImgDecodeImage(img, &imgData2[0], AImgFormat::INVALID_FORMAT);
- AImgClose(img);
- AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+TEST(Exr, TestWrite8bits)
+{
+ WriteImageTest(AImgFormat::RGB8U, AImgFormat::INVALID_FORMAT, AImgFormat::RGB16F);
+}
+TEST(Exr, TestWrite16bitsU)
+{
+ WriteImageTest(AImgFormat::R16U, AImgFormat::R16U, AImgFormat::R16F);
+}
- for(uint32_t i = 0; i < imgData2.size(); i++)
- ASSERT_EQ(imgData[i], imgData2[i]);
+TEST(Exr, TestSupportedFormat)
+{
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::EXR_IMAGE_FORMAT, AImgFormat::_8BITS));
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::EXR_IMAGE_FORMAT, AImgFormat::_16BITS | AImgFormat::FLOAT_FORMAT));
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::EXR_IMAGE_FORMAT, AImgFormat::_32BITS | AImgFormat::FLOAT_FORMAT));
}
#endif
diff --git a/src_c/tests/hdr.cpp b/src_c/tests/hdr.cpp
new file mode 100644
index 0000000..1bae989
--- /dev/null
+++ b/src_c/tests/hdr.cpp
@@ -0,0 +1,98 @@
+#include "testCommon.h"
+#include
+#include "../AIL.h"
+#define STBI_ONLY_HDR
+#define STB_IMAGE_IMPLEMENTATION
+#include "../extern/stb_image.h"
+
+std::vector decodeHDRFile(const std::string & path)
+{
+ int width, height, comp;
+ FILE * file = fopen(path.c_str(), "rb");
+
+ stbi_hdr_to_ldr_gamma(1.0f);
+ stbi_ldr_to_hdr_gamma(1.0f);
+
+ uint8_t * loadedData = stbi_load_from_file(file, &width, &height, &comp, 0);
+ std::vector data(width * height * comp);
+
+ memcpy(&data[0], loadedData, width*height*comp);
+ stbi_image_free(loadedData);
+ fclose(file);
+
+ return data;
+}
+
+TEST(HDR, TestDetectHDR)
+{
+ ASSERT_TRUE(detectImage("/hdr/test-env.hdr", HDR_IMAGE_FORMAT));
+}
+
+TEST(HDR, TestDetectBadHDR)
+{
+ ASSERT_FALSE(detectImage("/jpeg/test.jpeg", HDR_IMAGE_FORMAT));
+}
+
+TEST(HDR, TestReadHDRFile)
+{
+ auto data = readFile(getImagesDir() + "/hdr/test-env.hdr");
+
+ ReadCallback readCallback = NULL;
+ WriteCallback writeCallback = NULL;
+ TellCallback tellCallback = NULL;
+ SeekCallback seekCallback = NULL;
+ void* callbackData = NULL;
+
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
+
+ AImgHandle img = NULL;
+ AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+
+ int32_t width;
+ int32_t height;
+ int32_t numChannels;
+ int32_t bytesPerChannel;
+ int32_t floatOrInt;
+ int32_t imgFmt;
+
+ AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &imgFmt, NULL);
+
+ std::vector imgData(width*height*numChannels*bytesPerChannel, 78);
+
+ int32_t error = AImgDecodeImage(img, &imgData[0], AImgFormat::INVALID_FORMAT);
+
+ if (error != AImgErrorCode::AIMG_SUCCESS)
+ {
+ std::cout << AImgGetErrorDetails(img) << std::endl;
+ }
+
+ auto knownData = decodeHDRFile(getImagesDir() + "/hdr/test-env.hdr");
+
+ auto ptr = knownData.data();
+ for (int32_t y = 0; y < height; y++)
+ {
+ for (int32_t x = 0; x < width; x++)
+ {
+ if (knownData[x + width*y] != imgData[(x + width*y)])
+ {
+ break;
+ }
+ ASSERT_EQ(knownData[x + width*y], imgData[(x + width*y)]);
+ }
+ }
+
+ AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+ AImgClose(img);
+}
+
+int main(int argc, char * argv[])
+{
+ AImgInitialise();
+
+ ::testing::InitGoogleTest(&argc, argv);
+ int retval = RUN_ALL_TESTS();
+
+ AImgCleanUp();
+
+ return retval;
+}
\ No newline at end of file
diff --git a/src_c/tests/jpeg.cpp b/src_c/tests/jpeg.cpp
index 47f8118..5e171e1 100644
--- a/src_c/tests/jpeg.cpp
+++ b/src_c/tests/jpeg.cpp
@@ -25,9 +25,9 @@ std::vector decodeJPEGFile(const std::string & path)
std::vector Vbuffer(row_stride*cinfo.output_height);
- uint8_t * rowBuffer = &Vbuffer[0];
+ uint8_t * rowBuffer = &Vbuffer[0];
JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
- buffer[0] = (JSAMPROW) malloc(row_stride * sizeof(JSAMPLE));
+ buffer[0] = (JSAMPROW)malloc(row_stride * sizeof(JSAMPLE));
while (cinfo.output_scanline < cinfo.output_height)
{
jpeg_read_scanlines(&cinfo, buffer, 1);
@@ -64,7 +64,6 @@ bool testReadJpegFile(const std::string& path)
return false;
}
-
int32_t width;
int32_t height;
int32_t numChannels;
@@ -86,11 +85,11 @@ bool testReadJpegFile(const std::string& path)
auto knownData = decodeJPEGFile(getImagesDir() + path);
- for(int32_t y = 0; y < height; y++)
+ for (int32_t y = 0; y < height; y++)
{
- for(int32_t x = 0; x < width; x++)
+ for (int32_t x = 0; x < width; x++)
{
- if(knownData[x + width*y] != imgData[(x + width*y)])
+ if (knownData[x + width*y] != imgData[(x + width*y)])
return false;
}
}
@@ -101,45 +100,7 @@ bool testReadJpegFile(const std::string& path)
return true;
}
-
-TEST(JPEG, TestDetectJPEG)
-{
- ASSERT_TRUE(detectImage("/jpeg/test.jpeg", JPEG_IMAGE_FORMAT));
-}
-
-TEST(JPEG, TestReadJPEGAttrs)
-{
- ASSERT_TRUE(validateImageHeaders("/jpeg/test.jpeg", 640, 400, 3, 1, AImgFloatOrIntType::FITYPE_INT, AImgFormat::RGB8U));
-}
-
-TEST(JPEG, TestReadJPEGAttrsGreyscale)
-{
- ASSERT_TRUE(validateImageHeaders("/jpeg/greyscale.jpeg", 2048, 2048, 1, 1, AImgFloatOrIntType::FITYPE_INT, AImgFormat::R8U));
-}
-
-
-TEST(JPEG, TestCompareForceImageFormat1)
-{
- ASSERT_TRUE(compareForceImageFormat("/jpeg/test.jpeg"));
-}
-
-TEST(JPEG, TestReadJPEGFile1)
-{
- ASSERT_TRUE(testReadJpegFile("/jpeg/test.jpeg"));
-}
-
-TEST(JPEG, TestReadJPEGFile2)
-{
- ASSERT_TRUE(testReadJpegFile("/jpeg/karl.jpeg"));
-}
-
-TEST(JPEG, TestReadJPEGFile3)
-{
- ASSERT_TRUE(testReadJpegFile("/jpeg/karl_comment.jpeg"));
-}
-
-
-TEST(JPEG, TestWriteJPEG)
+void TestWriteJpeg(AImgFormat decodeFormat, AImgFormat writeFormat, AImgFormat expectedWritten = AImgFormat::INVALID_FORMAT)
{
auto data = readFile(getImagesDir() + "/jpeg/test.jpeg");
@@ -163,19 +124,34 @@ TEST(JPEG, TestWriteJPEG)
AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &fmt, NULL);
+ if (decodeFormat < 0)
+ {
+ decodeFormat = (AImgFormat)fmt;
+ }
+ if (writeFormat < 0)
+ {
+ writeFormat = decodeFormat;
+ }
+ if (expectedWritten < 0)
+ {
+ expectedWritten = writeFormat;
+ }
+
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
std::vector imgData(width*height*numChannels * bytesPerChannel, 78);
- AImgDecodeImage(img, &imgData[0], AImgFormat::INVALID_FORMAT);
+ AImgDecodeImage(img, &imgData[0], decodeFormat);
AImgClose(img);
AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
- std::vector fileData(width * height * numChannels * bytesPerChannel * 5);
+ std::vector fileData(width * height * numChannels * bytesPerChannel * 5);
AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::JPEG_IMAGE_FORMAT);
- AImgWriteImage(wImg, &imgData[0], width, height, fmt, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgWriteImage(wImg, &imgData[0], width, height, decodeFormat, writeFormat, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
AImgClose(wImg);
seekCallback(callbackData, 0);
@@ -183,11 +159,16 @@ TEST(JPEG, TestWriteJPEG)
AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
std::vector imgData2(width*height*numChannels*bytesPerChannel, 0);
- AImgDecodeImage(img, &imgData2[0], AImgFormat::INVALID_FORMAT);
+ AImgDecodeImage(img, &imgData2[0], decodeFormat);
+
+ int32_t _, writtenFormat;
+ AImgGetInfo(img, &_, &_, &_, &_, &_, &writtenFormat, NULL);
+ ASSERT_EQ(writtenFormat, expectedWritten);
+
AImgClose(img);
AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
- for(uint32_t i = 0; i < imgData2.size(); i++)
+ for (uint32_t i = 0; i < imgData2.size(); i++)
{
uint8_t diff = abs(imgData[i] - imgData2[i]);
@@ -196,6 +177,60 @@ TEST(JPEG, TestWriteJPEG)
}
}
+TEST(JPEG, TestDetectJPEG)
+{
+ ASSERT_TRUE(detectImage("/jpeg/test.jpeg", JPEG_IMAGE_FORMAT));
+}
+
+TEST(JPEG, TestReadJPEGAttrs)
+{
+ ASSERT_TRUE(validateImageHeaders("/jpeg/test.jpeg", 640, 400, 3, 1, AImgFloatOrIntType::FITYPE_INT, AImgFormat::RGB8U));
+}
+
+TEST(JPEG, TestReadJPEGAttrsGreyscale)
+{
+ ASSERT_TRUE(validateImageHeaders("/jpeg/greyscale.jpeg", 2048, 2048, 1, 1, AImgFloatOrIntType::FITYPE_INT, AImgFormat::R8U));
+}
+
+TEST(JPEG, TestCompareForceImageFormat1)
+{
+ ASSERT_TRUE(compareForceImageFormat("/jpeg/test.jpeg"));
+}
+
+TEST(JPEG, TestReadJPEGFile1)
+{
+ ASSERT_TRUE(testReadJpegFile("/jpeg/test.jpeg"));
+}
+
+TEST(JPEG, TestReadJPEGFile2)
+{
+ ASSERT_TRUE(testReadJpegFile("/jpeg/karl.jpeg"));
+}
+
+TEST(JPEG, TestReadJPEGFile3)
+{
+ ASSERT_TRUE(testReadJpegFile("/jpeg/karl_comment.jpeg"));
+}
+
+TEST(JPEG, TestWriteJPEG)
+{
+ TestWriteJpeg(AImgFormat::INVALID_FORMAT, AImgFormat::INVALID_FORMAT);
+}
+
+TEST(JPEG, TestWriteConvert)
+{
+ TestWriteJpeg(AImgFormat::RGB16U, AImgFormat::INVALID_FORMAT, AImgFormat::RGB8U);
+
+ TestWriteJpeg(AImgFormat::RGB16U, AImgFormat::RGB8U);
+}
+
+TEST(JPEG, TestSupportedFormat)
+{
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::JPEG_IMAGE_FORMAT, AImgFormat::_8BITS | AImgFormat::RGB));
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::JPEG_IMAGE_FORMAT, AImgFormat::_16BITS));
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::JPEG_IMAGE_FORMAT, AImgFormat::_32BITS));
+}
+
int main(int argc, char **argv)
{
AImgInitialise();
@@ -208,4 +243,4 @@ int main(int argc, char **argv)
return retval;
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src_c/tests/png.cpp b/src_c/tests/png.cpp
index 75939ef..32e3632 100644
--- a/src_c/tests/png.cpp
+++ b/src_c/tests/png.cpp
@@ -126,7 +126,8 @@ bool validateReadPNGFile(const std::string& path)
return isEq;
}
-bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t& err, std::vector& fileData)
+bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t& err, std::vector& fileData,
+ AImgFormat decodeFormat = AImgFormat::INVALID_FORMAT, AImgFormat writeFormat = AImgFormat::INVALID_FORMAT, AImgFormat expectedWrittenFormat = AImgFormat::INVALID_FORMAT)
{
err = AImgErrorCode::AIMG_SUCCESS;
@@ -158,6 +159,22 @@ bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t&
uint32_t colourProfileLen;
err = AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &fmt, &colourProfileLen);
+
+ if (decodeFormat < 0)
+ {
+ decodeFormat = (AImgFormat)fmt;
+ }
+ if (writeFormat < 0)
+ {
+ writeFormat = decodeFormat;
+ }
+ if (expectedWrittenFormat < 0)
+ {
+ expectedWrittenFormat = writeFormat;
+ }
+
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
char profileName[30];
std::vector colourProfile(colourProfileLen);
AImgGetColourProfile(img, profileName, colourProfile.data(), &colourProfileLen);
@@ -165,7 +182,7 @@ bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t&
{
imgData.resize(width*height*numChannels * bytesPerChannel, 78);
- err = AImgDecodeImage(img, &imgData[0], AImgFormat::INVALID_FORMAT);
+ err = AImgDecodeImage(img, &imgData[0], decodeFormat);
if(err == AImgErrorCode::AIMG_SUCCESS)
{
AImgClose(img);
@@ -177,7 +194,8 @@ bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t&
AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
wImg = AImgGetAImg(AImgFileFormat::PNG_IMAGE_FORMAT);
- err = AImgWriteImage(wImg, &imgData[0], width, height, fmt, profileName, colourProfile.data(), colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, encodeOptions);
+ err = AImgWriteImage(wImg, &imgData[0], width, height, decodeFormat, writeFormat, profileName, colourProfile.data(), colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, encodeOptions);
+
if(err == AImgErrorCode::AIMG_SUCCESS)
{
fileData.resize(tellCallback(callbackData));
@@ -196,9 +214,14 @@ bool validateWritePNGFile(const std::string& path, void* encodeOptions, int32_t&
{
imgData2.resize(width*height*numChannels*bytesPerChannel, 0);
- err = AImgDecodeImage(img, &imgData2[0], AImgFormat::INVALID_FORMAT);
+ err = AImgDecodeImage(img, &imgData2[0], decodeFormat);
if(err == AImgErrorCode::AIMG_SUCCESS)
{
+ int32_t _, writtenFormat;
+ AImgGetInfo(img, &_, &_, &_, &_, &_, &writtenFormat, NULL);
+ if (writtenFormat != expectedWrittenFormat)
+ return false;
+
AImgClose(img);
img = NULL;
AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
@@ -546,7 +569,7 @@ TEST(Png, TestWriteFrom32Bit)
AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::PNG_IMAGE_FORMAT);
- AImgWriteImage(wImg, &fData[0], width, height, AImgFormat::RGBA32F, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgWriteImage(wImg, &fData[0], width, height, AImgFormat::RGBA32F, AImgFormat::INVALID_FORMAT, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
AImgClose(wImg);
seekCallback(callbackData, 0);
@@ -598,7 +621,7 @@ TEST(Png, TestWriteFrom16BitFloat)
AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::PNG_IMAGE_FORMAT);
- AImgWriteImage(wImg, &fData[0], width, height, AImgFormat::RGBA16F, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgWriteImage(wImg, &fData[0], width, height, AImgFormat::RGBA16F, AImgFormat::INVALID_FORMAT, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
AImgClose(wImg);
seekCallback(callbackData, 0);
@@ -620,6 +643,31 @@ TEST(Png, TestWriteFrom16BitFloat)
AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
}
+TEST(PNG, TestWriteConvert16)
+{
+ int32_t err;
+ std::vector fileData;
+ ASSERT_TRUE(validateWritePNGFile("/png/8-bit.png", NULL, err, fileData,
+ AImgFormat::INVALID_FORMAT, AImgFormat::RGB16U));
+ ASSERT_EQ(err, AImgErrorCode::AIMG_SUCCESS);
+}
+
+TEST(PNG, TestWriteConvert8)
+{
+ int32_t err;
+ std::vector fileData;
+ ASSERT_TRUE(validateWritePNGFile("/png/16-bit.png", NULL, err, fileData,
+ AImgFormat::RGB32F, AImgFormat::RGBA16U));
+ ASSERT_EQ(err, AImgErrorCode::AIMG_SUCCESS);
+}
+
+TEST(PNG, TestSupportedFormat)
+{
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::PNG_IMAGE_FORMAT, AImgFormat::_8BITS));
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::PNG_IMAGE_FORMAT, AImgFormat::_16BITS));
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::PNG_IMAGE_FORMAT, AImgFormat::_32BITS));
+}
+
#endif // HAVE_PNG
int main(int argc, char **argv)
diff --git a/src_c/tests/testCommon.cpp b/src_c/tests/testCommon.cpp
index 608b87d..2684bc8 100644
--- a/src_c/tests/testCommon.cpp
+++ b/src_c/tests/testCommon.cpp
@@ -12,7 +12,7 @@ bool detectImage(const std::string& path, int32_t format)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
int32_t fileFormat = UNKNOWN_IMAGE_FORMAT;
@@ -39,7 +39,7 @@ bool validateImageHeaders(const std::string & path, int32_t expectedWidth, int32
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -72,7 +72,7 @@ bool compareForceImageFormat(const std::string& path)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
int32_t err = AIMG_SUCCESS;
@@ -145,7 +145,8 @@ bool compareForceImageFormat(const std::string& path)
return true;
}
-void writeToFile(const std::string& path, int32_t width, int32_t height, void* data, int32_t inputFormat, int32_t fileFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen)
+void writeToFile(const std::string& path, int32_t width, int32_t height, void* data, int32_t inputFormat, int32_t outputFormat, int32_t fileFormat,
+ const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen)
{
ReadCallback readCallback = NULL;
WriteCallback writeCallback = NULL;
@@ -153,13 +154,14 @@ void writeToFile(const std::string& path, int32_t width, int32_t height, void* d
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- std::vector fData;
+ std::vector fData(1);
AIGetResizableMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fData);
AImgHandle wImg = AImgGetAImg(fileFormat);
- AImgWriteImage(wImg, data, width, height, inputFormat, profileName, colourProfile, colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ AImgWriteImage(wImg, data, width, height, inputFormat, outputFormat, profileName, colourProfile, colourProfileLen,
+ writeCallback, tellCallback, seekCallback, callbackData, NULL);
FILE* f = fopen(path.c_str(), "wb");
fwrite(&fData[0], 1, fData.size(), f);
@@ -180,7 +182,7 @@ bool compareIccProfiles(const std::string & image1, const std::string & image2)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data1[0], data1.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data1[0], (int32_t)data1.size());
AImgHandle img1 = NULL;
int32_t detectedFormat1;
@@ -220,7 +222,7 @@ bool compareIccProfiles(const std::string & image1, const std::string & image2)
///////////////////// Read image 2
auto data2 = readFile(getImagesDir() + image2);
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data2[0], data2.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data2[0], (int32_t)data2.size());
AImgHandle img2 = NULL;
int32_t detectedFormat2;
@@ -278,7 +280,7 @@ bool compareIccProfiles(const std::string & image1, const std::string & image2)
return true;
}
-void readWriteIcc(const std::string & path, const std::string & outPath, char *profileName, uint8_t **colourProfile, uint32_t *colourProfileLen)
+void readWriteIcc(const std::string & path, const std::string & outPath, char *profileName, uint8_t **colourProfile, uint32_t *colourProfileLenPtr)
{
// Read
auto data = readFile(getImagesDir() + path);
@@ -289,7 +291,7 @@ void readWriteIcc(const std::string & path, const std::string & outPath, char *p
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], (int32_t)data.size());
AImgHandle img = NULL;
int32_t detectedFormat;
@@ -302,9 +304,9 @@ void readWriteIcc(const std::string & path, const std::string & outPath, char *p
int32_t floatOrInt = 0;
int32_t decodedImgFormat = 0;
- AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &decodedImgFormat, colourProfileLen);
- std::vector colourProfile_(*colourProfileLen);
- AImgGetColourProfile(img, profileName, colourProfile_.data(), colourProfileLen);
+ AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &decodedImgFormat, colourProfileLenPtr);
+ std::vector colourProfile_(*colourProfileLenPtr);
+ AImgGetColourProfile(img, profileName, colourProfile_.data(), colourProfileLenPtr);
*colourProfile = colourProfile_.data();
std::vector imgData;
@@ -320,10 +322,25 @@ void readWriteIcc(const std::string & path, const std::string & outPath, char *p
std::vector fileData;
fileData.resize(width * height * numChannels * bytesPerChannel * 5);
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], (int32_t)fileData.size());
AImgHandle wImg = AImgGetAImg(detectedFormat);
- AImgWriteImage(wImg, &imgData[0], width, height, decodedImgFormat, profileName, *colourProfile, *colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+
+ uint8_t * colourProfilePtr = NULL;
+ uint32_t colourProfileLen = 0;
+
+ if (colourProfile != NULL)
+ {
+ colourProfilePtr = *colourProfile;
+ }
+
+ if (colourProfileLenPtr != NULL)
+ {
+ colourProfileLen = *colourProfileLenPtr;
+ }
+
+ AImgWriteImage(wImg, &imgData[0], width, height, decodedImgFormat, decodedImgFormat,
+ profileName, colourProfilePtr, colourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, NULL);
FILE* f = fopen((getImagesDir() + outPath).c_str(), "wb");
fwrite(&fileData[0], 1, fileData.size(), f);
diff --git a/src_c/tests/testCommon.h b/src_c/tests/testCommon.h
index aae25b3..55debce 100644
--- a/src_c/tests/testCommon.h
+++ b/src_c/tests/testCommon.h
@@ -10,10 +10,10 @@ inline std::string getImagesDir()
{
std::string thisFile = __FILE__;
- char dirSep = '/';
- #ifdef WIN32
- dirSep = '\\';
- #endif
+ char dirSep = '/';
+#ifdef WIN32
+ dirSep = '\\';
+#endif
size_t pos = thisFile.find_last_of(dirSep);
size_t filenameLength = thisFile.length() - pos;
@@ -33,7 +33,7 @@ std::vector readFile(const std::string& path)
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
- std::vector retval(size/sizeof(T));
+ std::vector retval(size / sizeof(T));
fread(&retval[0], 1, size, f);
fclose(f);
@@ -45,7 +45,8 @@ bool detectImage(const std::string& path, int32_t format);
bool validateImageHeaders(const std::string & path, int32_t expectedWidth, int32_t expectedHeight, int32_t expectedNumChannels, int32_t expectedBytesPerChannel, int32_t expectedFloatOrInt, int32_t expectedFormat);
bool compareForceImageFormat(const std::string& path);
-void writeToFile(const std::string& path, int32_t width, int32_t height, void* data, int32_t inputFormat, int32_t fileFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen);
+void writeToFile(const std::string& path, int32_t width, int32_t height, void* data, int32_t inputFormat, int32_t outputFormat, int32_t fileFormat,
+ const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen);
void readWriteIcc(const std::string & path, const std::string & outPath, char *profileName, uint8_t **colourProfile, uint32_t *colourProfileLen);
bool compareIccProfiles(const std::string & image1, const std::string & image2);
diff --git a/src_c/tests/tga.cpp b/src_c/tests/tga.cpp
index bbfdc7c..1d5af22 100644
--- a/src_c/tests/tga.cpp
+++ b/src_c/tests/tga.cpp
@@ -30,6 +30,78 @@ std::vector decodeTGAFile(const std::string & path)
return data;
}
+void TestWriteTga(AImgFormat decodeFormat = AImgFormat::INVALID_FORMAT, AImgFormat writeFormat = AImgFormat::INVALID_FORMAT, AImgFormat expectedOutputFormat = AImgFormat::INVALID_FORMAT)
+{
+ auto data = readFile(getImagesDir() + "/tga/test.tga");
+
+ ReadCallback readCallback = NULL;
+ WriteCallback writeCallback = NULL;
+ TellCallback tellCallback = NULL;
+ SeekCallback seekCallback = NULL;
+ void* callbackData = NULL;
+
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
+
+ AImgHandle img = NULL;
+ AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+
+ int32_t width;
+ int32_t height;
+ int32_t numChannels;
+ int32_t bytesPerChannel;
+ int32_t floatOrInt;
+ int32_t fmt;
+
+ AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &fmt, NULL);
+
+ if (decodeFormat < 0)
+ {
+ decodeFormat = (AImgFormat)fmt;
+ }
+ if (writeFormat < 0)
+ {
+ writeFormat = decodeFormat;
+ }
+ if (expectedOutputFormat < 0)
+ {
+ expectedOutputFormat = writeFormat;
+ }
+
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
+ std::vector imgData(width*height*numChannels * bytesPerChannel, 78);
+
+ AImgDecodeImage(img, &imgData[0], decodeFormat);
+
+ AImgClose(img);
+ AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+
+ std::vector fileData(width * height * numChannels * bytesPerChannel * 5);
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
+
+ AImgHandle wImg = AImgGetAImg(AImgFileFormat::TGA_IMAGE_FORMAT);
+ auto err = AImgWriteImage(wImg, &imgData[0], width, height, decodeFormat, writeFormat, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ ASSERT_EQ(err, AImgErrorCode::AIMG_SUCCESS);
+ AImgClose(wImg);
+
+ seekCallback(callbackData, 0);
+
+ AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
+
+ std::vector imgData2(width*height*numChannels*bytesPerChannel, 0);
+ AImgDecodeImage(img, &imgData2[0], decodeFormat);
+
+ int32_t _, writtenFormat;
+ AImgGetInfo(img, &_, &_, &_, &_, &_, &writtenFormat, NULL);
+ ASSERT_EQ(writtenFormat, expectedOutputFormat);
+
+ AImgClose(img);
+ AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
+
+ for (uint32_t i = 0; i < imgData2.size(); i++)
+ ASSERT_EQ(imgData[i], imgData2[i]);
+}
+
TEST(TGA, TestDetectTGA)
{
ASSERT_TRUE(detectImage("/tga/test.tga", TGA_IMAGE_FORMAT));
@@ -166,54 +238,7 @@ TEST(TGA, TestReadTGAFile)
TEST(TGA, TestWriteTGAFile)
{
- auto data = readFile(getImagesDir() + "/tga/test.tga");
-
- ReadCallback readCallback = NULL;
- WriteCallback writeCallback = NULL;
- TellCallback tellCallback = NULL;
- SeekCallback seekCallback = NULL;
- void* callbackData = NULL;
-
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &data[0], data.size());
-
- AImgHandle img = NULL;
- AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
-
- int32_t width;
- int32_t height;
- int32_t numChannels;
- int32_t bytesPerChannel;
- int32_t floatOrInt;
- int32_t fmt;
-
- AImgGetInfo(img, &width, &height, &numChannels, &bytesPerChannel, &floatOrInt, &fmt, NULL);
-
- std::vector imgData(width*height*numChannels * bytesPerChannel, 78);
-
- AImgDecodeImage(img, &imgData[0], AImgFormat::INVALID_FORMAT);
-
- AImgClose(img);
- AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
-
- std::vector fileData(width * height * numChannels * bytesPerChannel * 5);
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
-
- AImgHandle wImg = AImgGetAImg(AImgFileFormat::TGA_IMAGE_FORMAT);
- auto err = AImgWriteImage(wImg, &imgData[0], width, height, fmt, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
- ASSERT_EQ(err, AImgErrorCode::AIMG_SUCCESS);
- AImgClose(wImg);
-
- seekCallback(callbackData, 0);
-
- AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
-
- std::vector imgData2(width*height*numChannels*bytesPerChannel, 0);
- AImgDecodeImage(img, &imgData2[0], AImgFormat::INVALID_FORMAT);
- AImgClose(img);
- AIDestroySimpleMemoryBufferCallbacks(readCallback, writeCallback, tellCallback, seekCallback, callbackData);
-
- for(uint32_t i = 0; i < imgData2.size(); i++)
- ASSERT_EQ(imgData[i], imgData2[i]);
+ TestWriteTga();
}
TEST(TGA, TestForceImageFormat)
@@ -260,6 +285,19 @@ TEST(TGA, TestForceImageFormat)
}
+TEST(TGA, TestWriteConvert)
+{
+ TestWriteTga(AImgFormat::RGB16U, AImgFormat::INVALID_FORMAT, AImgFormat::RGB8U);
+
+ TestWriteTga(AImgFormat::RGB16U, AImgFormat::RGB8U);
+}
+
+TEST(TGA, TestSupportedFormat)
+{
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::TGA_IMAGE_FORMAT, AImgFormat::_8BITS));
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::TGA_IMAGE_FORMAT, AImgFormat::_16BITS));
+ ASSERT_FALSE(AImgIsFormatSupported(AImgFileFormat::TGA_IMAGE_FORMAT, AImgFormat::_32BITS));
+}
int main(int argc, char **argv)
{
diff --git a/src_c/tests/tiff.cpp b/src_c/tests/tiff.cpp
index 3b4a51b..272b477 100644
--- a/src_c/tests/tiff.cpp
+++ b/src_c/tests/tiff.cpp
@@ -21,7 +21,7 @@ bool compareTiffToPng(const std::string& name, bool convertSrgb = false)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], pngData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], (int32_t)pngData.size());
AImgHandle img = NULL;
int32_t error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -52,7 +52,7 @@ bool compareTiffToPng(const std::string& name, bool convertSrgb = false)
auto tiffData = readFile(getImagesDir() + "/tiff/" + name);
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], tiffData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], (int32_t)tiffData.size());
error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
if (error)
@@ -96,10 +96,10 @@ bool compareTiffToPng(const std::string& name, bool convertSrgb = false)
if (convertSrgb)
{
float f;
- f = pngR / 255.0f; pngR = std::pow(f, 2.2f) * 255.0f;
- f = pngG / 255.0f; pngG = std::pow(f, 2.2f) * 255.0f;
- f = pngB / 255.0f; pngB = std::pow(f, 2.2f) * 255.0f;
- f = pngA / 255.0f; pngA = std::pow(f, 2.2f) * 255.0f;
+ f = pngR / 255.0f; pngR = (uint8_t)(std::pow(f, 2.2f) * 255.0f);
+ f = pngG / 255.0f; pngG = (uint8_t)(std::pow(f, 2.2f) * 255.0f);
+ f = pngB / 255.0f; pngB = (uint8_t)(std::pow(f, 2.2f) * 255.0f);
+ f = pngA / 255.0f; pngA = (uint8_t)(std::pow(f, 2.2f) * 255.0f);
}
uint8_t tiffR = tiffImgData[(x + y*pngWidth) * 4 + 0];
@@ -121,8 +121,13 @@ bool compareTiffToPng(const std::string& name, bool convertSrgb = false)
return true;
}
-bool testTiffWrite(int32_t testFormat)
+bool testTiffWrite(int32_t testFormat, int32_t outputFormat = -1)
{
+ if (outputFormat < 0)
+ {
+ outputFormat = testFormat;
+ }
+
auto pngData = readFile(getImagesDir() + "/tiff/8_bit_png.png");
ReadCallback readCallback = NULL;
@@ -131,7 +136,7 @@ bool testTiffWrite(int32_t testFormat)
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], pngData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], (int32_t)pngData.size());
AImgHandle img = NULL;
int32_t error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &img, NULL);
@@ -162,12 +167,15 @@ bool testTiffWrite(int32_t testFormat)
///////////
- std::vector fileData(pngWidth*pngHeight*bytesPerChannel*numChannels * 10, 79); // 10x the raw data size, should be well enough space
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
+ int32_t numChannels_out, bytesPerChannel_out, floatOrInt_out;
+ AIGetFormatDetails(outputFormat, &numChannels_out, &bytesPerChannel_out, &floatOrInt_out);
+
+ std::vector fileData(pngWidth*pngHeight*bytesPerChannel_out*numChannels_out * 10, 79); // 10x the raw data size, should be well enough space
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], (int32_t)fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::TIFF_IMAGE_FORMAT);
- error = AImgWriteImage(wImg, &pngImgData[0], pngWidth, pngHeight, testFormat, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ error = AImgWriteImage(wImg, &pngImgData[0], pngWidth, pngHeight, testFormat, outputFormat, NULL, NULL, 0, writeCallback, tellCallback, seekCallback, callbackData, NULL);
if (error)
return false;
@@ -183,7 +191,7 @@ bool testTiffWrite(int32_t testFormat)
if (error)
return false;
- if (tiffImgFmt != testFormat)
+ if (tiffImgFmt != outputFormat)
return false;
if (tiffWidth != pngWidth || tiffHeight != pngHeight)
@@ -191,7 +199,7 @@ bool testTiffWrite(int32_t testFormat)
std::vector tiffImgData(pngWidth*pngHeight*numChannels*bytesPerChannel, 78);
- error = AImgDecodeImage(img, &tiffImgData[0], AImgFormat::INVALID_FORMAT);
+ error = AImgDecodeImage(img, &tiffImgData[0], testFormat);
if (error)
return false;
@@ -215,7 +223,7 @@ bool testColourProfileFromPngToTiff()
SeekCallback seekCallback = NULL;
void* callbackData = NULL;
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], pngData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &pngData[0], (int32_t)pngData.size());
AImgHandle pngImg = NULL;
int32_t error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &pngImg, NULL);
@@ -250,7 +258,7 @@ bool testColourProfileFromPngToTiff()
////////////////////////////////////////////////////// Read tiff (only data)
auto tiffData = readFile(getImagesDir() + "/tiff/ICC.tif");
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], tiffData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], (int32_t)tiffData.size());
AImgHandle tiffImg1 = NULL;
error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &tiffImg1, NULL);
@@ -283,11 +291,11 @@ bool testColourProfileFromPngToTiff()
////////////////////////////////////////////////////// Write tiff (data plus png colour profile)
std::vector fileData(pngWidth*pngHeight*pngBytesPerChannel*pngNumChannels * 10, 79); // 10x the raw data size, should be well enough space
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], fileData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &fileData[0], (int32_t)fileData.size());
AImgHandle wImg = AImgGetAImg(AImgFileFormat::TIFF_IMAGE_FORMAT);
- error = AImgWriteImage(wImg, &tiffImgData[0], pngWidth, pngHeight, AImgFormat::RGBA8U, "", pngColourProfile.data(), pngColourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, NULL);
+ error = AImgWriteImage(wImg, &tiffImgData[0], pngWidth, pngHeight, AImgFormat::RGBA8U, AImgFormat::INVALID_FORMAT, "", pngColourProfile.data(), pngColourProfileLen, writeCallback, tellCallback, seekCallback, callbackData, NULL);
if (error)
return false;
@@ -304,7 +312,7 @@ bool testColourProfileFromPngToTiff()
////////////////////////////////////////////////////// Read written tiff (data and colour profile)
tiffData = readFile(getImagesDir() + "/tiff/ICC_png.tif");
- AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], tiffData.size());
+ AIGetSimpleMemoryBufferCallbacks(&readCallback, &writeCallback, &tellCallback, &seekCallback, &callbackData, &tiffData[0], (int32_t)tiffData.size());
AImgHandle tiffImg2 = NULL;
error = AImgOpen(readCallback, tellCallback, seekCallback, callbackData, &tiffImg2, NULL);
@@ -418,17 +426,37 @@ TEST(TIFF, TestWrite8U)
TEST(TIFF, TestWrite16U)
{
- testTiffWrite(AImgFormat::RGBA16U);
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGBA16U));
}
TEST(TIFF, TestWrite16F)
{
- testTiffWrite(AImgFormat::RGBA16F);
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGBA16F));
}
TEST(TIFF, TestWrite32F)
{
- testTiffWrite(AImgFormat::RGBA32F);
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGBA32F));
+}
+
+
+///
+/// Read the png image in its current format,
+/// save tiff image in the test format
+///
+TEST(TIFF, TestWrite8Bits)
+{
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGB8U, AImgFormat::RGB8U));
+}
+
+TEST(TIFF, TestWrite16Bits)
+{
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGB8U, AImgFormat::RGB16U));
+}
+
+TEST(TIFF, TestWrite32bits)
+{
+ ASSERT_TRUE(testTiffWrite(AImgFormat::RGB8U, AImgFormat::RGB32F));
}
TEST(TIFF, TestColourProfileFromPngToTiff)
@@ -452,6 +480,13 @@ TEST(TIFF, TestCompareWithPngICCProfile)
ASSERT_TRUE(compareIccProfiles("/png/ICC.png", "/tiff/ICC.tif"));
}
+TEST(TIFF, TestSupportedFormat)
+{
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::TIFF_IMAGE_FORMAT, AImgFormat::_8BITS));
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::TIFF_IMAGE_FORMAT, AImgFormat::_16BITS));
+ ASSERT_TRUE(AImgIsFormatSupported(AImgFileFormat::TIFF_IMAGE_FORMAT, AImgFormat::_32BITS));
+}
+
#endif // HAVE_TIFF
int main(int argc, char **argv)
diff --git a/src_c/tga.cpp b/src_c/tga.cpp
index 7c83097..ef4a8cc 100644
--- a/src_c/tga.cpp
+++ b/src_c/tga.cpp
@@ -7,6 +7,7 @@
#include
#include
#define STBI_ONLY_TGA
+#define STBI_ONLY_HDR
#define STB_IMAGE_IMPLEMENTATION
#include "extern/stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
@@ -14,19 +15,18 @@
namespace AImg
{
-
namespace STBICallbacks
{
int readCallback(void * user, char * data, int size)
{
- CallbackData * callbackFunctions = (CallbackData *)user;
+ CallbackData * callbackFunctions = (CallbackData *)user;
return callbackFunctions->readCallback(callbackFunctions->callbackData, (uint8_t *)data, size);
}
void seekCallback(void * user, int num_bytes)
{
CallbackData * callbackFunctions = (CallbackData *)user;
- callbackFunctions->seekCallback(callbackFunctions->callbackData, num_bytes);
+ callbackFunctions->seekCallback(callbackFunctions->callbackData, num_bytes);
}
void writeFunc(void * user, void * data, int size)
@@ -36,19 +36,27 @@ namespace AImg
}
}
- AImgFormat getWhatFormatWillBeWrittenForDataTGA(int32_t inputFormat)
+ AImgFormat getWhatFormatWillBeWrittenForDataTGA(int32_t inputFormat, int32_t outputFormat)
{
+ AIL_UNUSED_PARAM(outputFormat);
+
int32_t numChannels, bytesPerChannel, floatOrInt;
AIGetFormatDetails(inputFormat, &numChannels, &bytesPerChannel, &floatOrInt);
- if(floatOrInt == AImgFloatOrIntType::FITYPE_FLOAT)
- return (AImgFormat) (AImgFormat::R8U + bytesPerChannel - 1); // convert to 8U version with same channelNum
+ switch (numChannels)
+ {
+ case 1:
+ return AImgFormat::R8U;
+
+ case 2:
+ return AImgFormat::RG8U;
- if(inputFormat >= AImgFormat::R8U && inputFormat <= AImgFormat::RGBA8U)
- return (AImgFormat)inputFormat;
+ case 3:
+ return AImgFormat::RGB8U;
- if(inputFormat >= AImgFormat::R16U && inputFormat <= AImgFormat::RGBA16U)
- return (AImgFormat) (AImgFormat::R8U + bytesPerChannel - 1); // convert to 8U version with same channelNum
+ default:
+ break;
+ }
return AImgFormat::INVALID_FORMAT;
}
@@ -70,7 +78,7 @@ namespace AImg
bool hasCorrectColourMapType = (header[1] == 0 || header[1] == 1);
bool hasCorrectImageType = (header[2] == 0 || header[2] == 1 || header[2] == 2 || header[2] == 3 || header[2] == 9 || header[2] == 10 || header[2] == 11);
- uint16_t paletteLength = *(uint16_t *) (header + 5);
+ uint16_t paletteLength = *(uint16_t *)(header + 5);
uint16_t width = *(uint16_t *)(header + 12);
uint16_t height = *(uint16_t *)(header + 14);
@@ -96,159 +104,165 @@ namespace AImg
return TGA_IMAGE_FORMAT;
}
+ bool isFormatSupportedByTga(int32_t format)
+ {
+ return format & AImgFormat::_8BITS;
+ }
+
class TGAFile : public AImgBase
{
- public:
- CallbackData data;
- int32_t numChannels, width, height;
+ public:
+ CallbackData data;
+ int32_t numChannels, width, height;
- int32_t getDecodeFormat()
+ int32_t getDecodeFormat()
+ {
+ switch (numChannels)
{
- switch (numChannels)
- {
- case 1:
- return AImgFormat::R8U;
- case 2:
- return AImgFormat::RG8U;
- case 3:
- return AImgFormat::RGB8U;
- case 4:
- return AImgFormat::RGBA8U;
- default:
- return AImgFormat::INVALID_FORMAT;
- }
+ case 1:
+ return AImgFormat::R8U;
+ case 2:
+ return AImgFormat::RG8U;
+ case 3:
+ return AImgFormat::RGB8U;
+ case 4:
+ return AImgFormat::RGBA8U;
+ default:
+ return AImgFormat::INVALID_FORMAT;
}
+ }
- virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ virtual int32_t getImageInfo(int32_t *width, int32_t *height, int32_t *numChannels, int32_t *bytesPerChannel, int32_t *floatOrInt, int32_t *decodedImgFormat, uint32_t *colourProfileLen)
+ {
+ *width = this->width;
+ *height = this->height;
+ *numChannels = this->numChannels;
+ if (colourProfileLen != NULL)
{
- *width = this->width;
- *height = this->height;
- *numChannels = this->numChannels;
- if(colourProfileLen != NULL)
- {
- *colourProfileLen = 0;
- }
-
- *bytesPerChannel = 1;
- *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
- *decodedImgFormat = getDecodeFormat();
+ *colourProfileLen = 0;
+ }
- return AImgErrorCode::AIMG_SUCCESS;
+ *bytesPerChannel = 1;
+ *floatOrInt = AImgFloatOrIntType::FITYPE_INT;
+ *decodedImgFormat = getDecodeFormat();
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ {
+ if (colourProfile != NULL)
+ {
+ *colourProfileLen = 0;
}
-
- virtual int32_t getColourProfile(char *profileName, uint8_t *colourProfile, uint32_t *colourProfileLen)
+ if (profileName != NULL)
{
- if(colourProfile != NULL)
- {
- *colourProfileLen = 0;
- }
- if(profileName != NULL)
- {
- std::strcpy(profileName, "no_profile");
- }
+ std::strcpy(profileName, "no_profile");
+ }
- return AImgErrorCode::AIMG_SUCCESS;
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+
+ virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
+ {
+ stbi_io_callbacks callbacks;
+ callbacks.read = STBICallbacks::readCallback;
+ callbacks.skip = STBICallbacks::seekCallback;
+
+ uint8_t* loadedData = stbi_load_from_callbacks(&callbacks, &data, &width, &height, &numChannels, numChannels);
+
+ if (!loadedData)
+ {
+ mErrorDetails = "[AImg::TGAImageLoader::TGAFile::decodeImage] stbi_load_from_callbacks failed!";
+ return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
}
- virtual int32_t decodeImage(void *realDestBuffer, int32_t forceImageFormat)
+ int32_t decodeFormat = getDecodeFormat();
+ int32_t numChannels, bytesPerChannel, floatOrInt;
+ AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+
+ void* destBuffer = realDestBuffer;
+
+ std::vector convertTmpBuffer(0);
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
{
- stbi_io_callbacks callbacks;
- callbacks.read = STBICallbacks::readCallback;
- callbacks.skip = STBICallbacks::seekCallback;
+ convertTmpBuffer.resize(width * height * bytesPerChannel * numChannels);
+ destBuffer = &convertTmpBuffer[0];
+ }
- uint8_t* loadedData = stbi_load_from_callbacks(&callbacks, &data, &width, &height, &numChannels, numChannels);
+ memcpy(destBuffer, loadedData, width * height * bytesPerChannel * numChannels);
+ stbi_image_free(loadedData);
- if(!loadedData)
- {
- mErrorDetails = "[AImg::TGAImageLoader::TGAFile::decodeImage] stbi_load_from_callbacks failed!";
- return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
- }
+ if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
+ {
+ int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, width, height, decodeFormat, forceImageFormat);
+ if (err != AImgErrorCode::AIMG_SUCCESS)
+ return err;
+ }
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
- int32_t decodeFormat = getDecodeFormat();
- int32_t numChannels, bytesPerChannel, floatOrInt;
- AIGetFormatDetails(decodeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+ virtual int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
+ {
+ data.readCallback = readCallback;
+ data.tellCallback = tellCallback;
+ data.seekCallback = seekCallback;
+ data.callbackData = callbackData;
+ stbi_io_callbacks callbacks;
+ callbacks.read = STBICallbacks::readCallback;
+ callbacks.skip = STBICallbacks::seekCallback;
+
+ int startingPosition = tellCallback(callbackData);
+ stbi_info_from_callbacks(&callbacks, &data, &width, &height, &numChannels);
+ seekCallback(callbackData, startingPosition);
+
+ return AImgErrorCode::AIMG_SUCCESS;
+ }
+ virtual int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
+ {
+ AIL_UNUSED_PARAM(profileName);
+ AIL_UNUSED_PARAM(colourProfile);
+ AIL_UNUSED_PARAM(colourProfileLen);
+ AIL_UNUSED_PARAM(encodingOptions);
- void* destBuffer = realDestBuffer;
+ int32_t writeFormat = getWhatFormatWillBeWrittenForDataTGA(inputFormat, outputFormat);
- std::vector convertTmpBuffer(0);
- if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
- {
- convertTmpBuffer.resize(width * height * bytesPerChannel * numChannels);
- destBuffer = &convertTmpBuffer[0];
- }
+ std::vector convertBuffer(0);
- memcpy(destBuffer, loadedData, width * height * bytesPerChannel * numChannels);
- stbi_image_free(loadedData);
+ int32_t numChannels, bytesPerChannel, floatOrInt;
+ AIGetFormatDetails(writeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+ if (writeFormat != inputFormat)
+ {
+ convertBuffer.resize(width * height * numChannels * bytesPerChannel);
- if (forceImageFormat != AImgFormat::INVALID_FORMAT && forceImageFormat != decodeFormat)
- {
- int32_t err = AImgConvertFormat(destBuffer, realDestBuffer, width, height, decodeFormat, forceImageFormat);
- if(err != AImgErrorCode::AIMG_SUCCESS)
- return err;
- }
+ int32_t convertError = AImgConvertFormat(data, &convertBuffer[0], width, height, inputFormat, writeFormat);
- return AImgErrorCode::AIMG_SUCCESS;
+ if (convertError != AImgErrorCode::AIMG_SUCCESS)
+ return convertError;
+ data = &convertBuffer[0];
}
- virtual int32_t openImage(ReadCallback readCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData)
- {
- data.readCallback = readCallback;
- data.tellCallback = tellCallback;
- data.seekCallback = seekCallback;
- data.callbackData = callbackData;
- stbi_io_callbacks callbacks;
- callbacks.read = STBICallbacks::readCallback;
- callbacks.skip = STBICallbacks::seekCallback;
-
- int startingPosition = tellCallback(callbackData);
- stbi_info_from_callbacks(&callbacks, &data, &width, &height, &numChannels);
- seekCallback(callbackData, startingPosition);
+ CallbackData callbackFunctions;
+ callbackFunctions.tellCallback = tellCallback;
+ callbackFunctions.writeCallback = writeCallback;
+ callbackFunctions.seekCallback = seekCallback;
+ callbackFunctions.callbackData = callbackData;
+ int err = stbi_write_tga_to_func(&STBICallbacks::writeFunc, &callbackFunctions, width, height, numChannels, data);
+ if (err != 0)
+ {
return AImgErrorCode::AIMG_SUCCESS;
}
-
- virtual int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
- WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void* encodingOptions)
+ else
{
- AIL_UNUSED_PARAM(encodingOptions);
-
- int32_t writeFormat = getWhatFormatWillBeWrittenForDataTGA(inputFormat);
-
- std::vector convertBuffer(0);
-
- int32_t numChannels, bytesPerChannel, floatOrInt;
- AIGetFormatDetails(writeFormat, &numChannels, &bytesPerChannel, &floatOrInt);
-
- if (writeFormat != inputFormat)
- {
- convertBuffer.resize(width * height * numChannels * bytesPerChannel);
-
- int32_t convertError = AImgConvertFormat(data, &convertBuffer[0], width, height, inputFormat, writeFormat);
-
- if (convertError != AImgErrorCode::AIMG_SUCCESS)
- return convertError;
- data = &convertBuffer[0];
- }
-
- CallbackData callbackFunctions;
- callbackFunctions.tellCallback = tellCallback;
- callbackFunctions.writeCallback = writeCallback;
- callbackFunctions.seekCallback = seekCallback;
- callbackFunctions.callbackData = callbackData;
-
- int err = stbi_write_tga_to_func(&STBICallbacks::writeFunc, &callbackFunctions, width, height, numChannels, data);
- if (err != 0)
- {
- return AImgErrorCode::AIMG_SUCCESS;
- }
- else
- {
- mErrorDetails = "[AImg::TGAImageLoader::TGAFile::writeImage] stbi_write_tga_to_func failed!";
- return AImgErrorCode::AIMG_WRITE_FAILED_EXTERNAL;
- }
+ mErrorDetails = "[AImg::TGAImageLoader::TGAFile::writeImage] stbi_write_tga_to_func failed!";
+ return AImgErrorCode::AIMG_WRITE_FAILED_EXTERNAL;
}
+ }
};
AImgBase * TGAImageLoader::getAImg()
@@ -256,10 +270,14 @@ namespace AImg
return new TGAFile();
}
- AImgFormat TGAImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat)
+ AImgFormat TGAImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat)
{
- return getWhatFormatWillBeWrittenForDataTGA(inputFormat);
+ return getWhatFormatWillBeWrittenForDataTGA(inputFormat, outputFormat);
}
+ bool TGAImageLoader::isFormatSupported(int32_t format)
+ {
+ return isFormatSupportedByTga(format);
+ }
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src_c/tga.h b/src_c/tga.h
index 64d32c7..a2efe2d 100644
--- a/src_c/tga.h
+++ b/src_c/tga.h
@@ -7,7 +7,7 @@ namespace AImg
{
class TGAImageLoader : public ImageLoaderBase
{
- public:
+ public:
virtual AImgBase * getAImg();
virtual int32_t initialise();
@@ -15,8 +15,9 @@ namespace AImg
virtual std::string getFileExtension();
virtual int32_t getAImgFileFormatValue();
+ virtual bool isFormatSupported(int32_t format);
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat);
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
};
}
diff --git a/src_c/tiff.cpp b/src_c/tiff.cpp
index c10af88..ad48d07 100644
--- a/src_c/tiff.cpp
+++ b/src_c/tiff.cpp
@@ -15,13 +15,21 @@
namespace AImg
{
- AImgFormat getWriteFormatTiff(int32_t inputFormat)
+ AImgFormat getWriteFormatTiff(int32_t inputFormat, int32_t outputFormat)
{
// Tiff can write all currently supported formats. Here we are just future-proofing in case we add some more formats later that tiff can't do
- if (inputFormat > AImgFormat::INVALID_FORMAT && inputFormat <= AImgFormat::RGBA32F)
+ if (inputFormat <= AImgFormat::INVALID_FORMAT || inputFormat > AImgFormat::RGBA32F)
+ return AImgFormat::INVALID_FORMAT;
+
+ if(inputFormat == outputFormat || outputFormat == AImgFormat::INVALID_FORMAT)
return (AImgFormat)inputFormat;
- return AImgFormat::INVALID_FORMAT;
+ int32_t outDepth = AIGetBitDepth(outputFormat);
+
+ if(outDepth == AImgFormat::INVALID_FORMAT)
+ return (AImgFormat)inputFormat;
+
+ return (AImgFormat)AIChangeBitDepth(inputFormat, outDepth);
}
struct tiffCallbackData
@@ -40,7 +48,7 @@ namespace AImg
{
tiffCallbackData *callbacks = (tiffCallbackData *)st;
- return callbacks->mReadCallback(callbacks->callbackData, (uint8_t *)buffer, size);
+ return callbacks->mReadCallback(callbacks->callbackData, (uint8_t *)buffer, (int32_t)size);
}
tsize_t tiff_Write(thandle_t st, tdata_t buffer, tsize_t size)
@@ -48,7 +56,7 @@ namespace AImg
tiffCallbackData *callbacks = (tiffCallbackData *)st;
int32_t start = callbacks->mTellCallback(callbacks->callbackData);
- callbacks->mWriteCallback(callbacks->callbackData, (uint8_t *)buffer, size);
+ callbacks->mWriteCallback(callbacks->callbackData, (uint8_t *)buffer, (int32_t)size);
int32_t end = callbacks->mTellCallback(callbacks->callbackData);
if (end > callbacks->furthestPositionWritten)
@@ -104,7 +112,7 @@ namespace AImg
}
}
- callbacks->mSeekCallback(callbacks->callbackData, finalPos);
+ callbacks->mSeekCallback(callbacks->callbackData, (int32_t)finalPos);
return callbacks->mTellCallback(callbacks->callbackData);
}
@@ -128,26 +136,26 @@ namespace AImg
{
int mantissaBits = 16;
int exponentBits = 7;
- int maxExponent = pow(2, exponentBits) - 1;
+ int maxExponent = (int)(1 << exponentBits) - 1;
int v = *((int *)src);
int sign = v >> 23;
- int exponent = (v >> mantissaBits) & (int)(pow(2, exponentBits) - 1);
- int mantissa = v & (int)(pow(2, mantissaBits) - 1);
+ int exponent = (v >> mantissaBits) & ((int)(1 << exponentBits) - 1);
+ int mantissa = v & ((int)(1 << mantissaBits) - 1);
if (exponent == 0)
{
if (mantissa != 0)
{
- while ((mantissa & (int)pow(2, mantissaBits)) == 0)
+ while ((mantissa & (int)(1 << mantissaBits)) == 0)
{
mantissa <<= 1;
exponent--;
}
exponent++;
- mantissa &= (int)(pow(2, mantissaBits) - 1);
- exponent += 127 - (pow(2, exponentBits - 1) - 1);
+ mantissa &= ((int)(1 << mantissaBits) - 1);
+ exponent += 127 - (int)((1 << (exponentBits - 1)) - 1);
}
}
@@ -157,7 +165,7 @@ namespace AImg
}
else
{
- exponent += 127 - (pow(2, exponentBits - 1) - 1);
+ exponent += 127 - (int)((1 << (exponentBits - 1)) - 1);
}
mantissa <<= (23 - mantissaBits);
@@ -197,21 +205,21 @@ namespace AImg
{
// handle 24-bit float (lolwtf)
if (bitsPerChannel == 24 && sampleFormat == SAMPLEFORMAT_IEEEFP)
- return ((int32_t)AImgFormat::R32F) - 1 + channels;
+ return AImgFormat::_32BITS | AImgFormat::FLOAT_FORMAT | (AImgFormat::R << (channels - 1));
if (sampleFormat == SAMPLEFORMAT_IEEEFP)
{
if (bitsPerChannel == 16)
- return ((int32_t)AImgFormat::R16F) - 1 + channels;
+ return AImgFormat::_16BITS | AImgFormat::FLOAT_FORMAT | (AImgFormat::R << (channels - 1));
else if (bitsPerChannel == 32)
- return ((int32_t)AImgFormat::R32F) - 1 + channels;
+ return AImgFormat::_32BITS | AImgFormat::FLOAT_FORMAT | (AImgFormat::R << (channels - 1));
}
else if (sampleFormat == SAMPLEFORMAT_UINT || sampleFormat == SAMPLEFORMAT_INT)
{
if (bitsPerChannel == 8)
- return ((int32_t)AImgFormat::R8U) - 1 + channels;
+ return AImgFormat::_8BITS | (AImgFormat::R << (channels - 1));
else if (bitsPerChannel == 16)
- return ((int32_t)AImgFormat::R16U) - 1 + channels;
+ return AImgFormat::_16BITS | (AImgFormat::R << (channels - 1));
}
}
@@ -279,7 +287,7 @@ namespace AImg
destBuffer = &convertTmpBuffer[0];
}
- uint32 stripsize = TIFFStripSize(tiff);
+ uint32 stripsize = (uint32)TIFFStripSize(tiff);
int32_t bytesPerChannel = bitsPerChannel / 8;
std::vector stripBuffer(stripsize);
@@ -451,7 +459,7 @@ namespace AImg
return AImgErrorCode::AIMG_LOAD_FAILED_EXTERNAL;
}
- bool hasSamplesPerPixel = TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &channels);
+ bool hasSamplesPerPixel = TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &channels) != 0;
AImgErrorCode retval = AImgErrorCode::AIMG_SUCCESS;
@@ -547,7 +555,7 @@ namespace AImg
return retval;
}
- int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
+ int32_t writeImage(void *data, int32_t width, int32_t height, int32_t inputFormat, int32_t outputFormat, const char *profileName, uint8_t *colourProfile, uint32_t colourProfileLen,
WriteCallback writeCallback, TellCallback tellCallback, SeekCallback seekCallback, void *callbackData, void *encodingOptions)
{
// Suppress unused warning
@@ -565,7 +573,7 @@ namespace AImg
int32_t retval = AIMG_SUCCESS;
- int32_t wFormat = getWriteFormatTiff(inputFormat);
+ int32_t wFormat = getWriteFormatTiff(inputFormat, outputFormat);
if (wFormat == AImgFormat::INVALID_FORMAT)
{
mErrorDetails = "[AImg::TIFFImageLoader::TiffFile::writeImage] Cannot write this format to tiff."; // developers: see comment in getWriteFormatTiff
@@ -576,6 +584,19 @@ namespace AImg
int32_t numChannels, bytesPerChannel, floatOrInt;
AIGetFormatDetails(wFormat, &numChannels, &bytesPerChannel, &floatOrInt);
+ // Convert
+ std::vector convertBuffer(0);
+ if (wFormat != inputFormat)
+ {
+ convertBuffer.resize(width * height * numChannels * bytesPerChannel);
+
+ int32_t convertError = AImgConvertFormat(data, &convertBuffer[0], width, height, inputFormat, wFormat);
+
+ if (convertError != AImgErrorCode::AIMG_SUCCESS)
+ return convertError;
+ data = &convertBuffer[0];
+ }
+
TIFFSetField(wTiff, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(wTiff, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(wTiff, TIFFTAG_SAMPLESPERPIXEL, numChannels);
@@ -615,7 +636,7 @@ namespace AImg
TIFFClose(wTiff);
- // Leave the pointer at the end of the file, libtiff does NOT do this by default.
+ // Leave the pointer at the end of the file, because libtiff doesn't... because it's a fantastic piece of software
wCallbacks.mSeekCallback(wCallbacks.callbackData, wCallbacks.furthestPositionWritten);
return retval;
@@ -661,10 +682,17 @@ namespace AImg
return AImgFileFormat::TIFF_IMAGE_FORMAT;
}
- AImgFormat TIFFImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat)
+ AImgFormat TIFFImageLoader::getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat)
{
- return getWriteFormatTiff(inputFormat);
+ return getWriteFormatTiff(inputFormat, outputFormat);
+ }
+
+ bool TIFFImageLoader::isFormatSupported(int32_t format)
+ {
+ AIL_UNUSED_PARAM(format);
+
+ return true;
}
}
-#endif // HAVE_TIFF
+#endif // HAVE_TIFF
\ No newline at end of file
diff --git a/src_c/tiff.h b/src_c/tiff.h
index 76f6831..dc2d95c 100644
--- a/src_c/tiff.h
+++ b/src_c/tiff.h
@@ -16,7 +16,9 @@ namespace AImg
virtual std::string getFileExtension();
virtual int32_t getAImgFileFormatValue();
- virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat);
+ virtual bool isFormatSupported(int32_t format);
+
+ virtual AImgFormat getWhatFormatWillBeWrittenForData(int32_t inputFormat, int32_t outputFormat);
};
}
diff --git a/test_images/hdr/test-env.hdr b/test_images/hdr/test-env.hdr
new file mode 100644
index 0000000..98015a7
Binary files /dev/null and b/test_images/hdr/test-env.hdr differ