Skip to content

Commit 74d2566

Browse files
committed
Add support for non-bitmap image type
1 parent a773743 commit 74d2566

File tree

8 files changed

+468
-127
lines changed

8 files changed

+468
-127
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
## [Unreleased]
2+
### Enhancement
3+
- Add support for non-bitmap image type.
4+
25
### Fixed
3-
- Fix accuracy loss when generating mipmap (#7)
6+
- Fix accuracy loss when generating mipmap (#7).
47

58
## [0.1.2] - 2022-02-17
69
### Fixed

Runtime/AsyncImageLoader/FreeImage.cs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Runtime.InteropServices;
33

44
public static partial class AsyncImageLoader {
5-
public class FreeImage {
5+
public static class FreeImage {
66
public enum Format {
77
FIF_UNKNOWN = -1,
88
FIF_BMP = 0,
@@ -46,30 +46,60 @@ public enum Format {
4646
}
4747

4848
internal enum Type {
49+
/// <summary>
50+
/// unknown type
51+
/// </summary>
4952
FIT_UNKNOWN = 0,
53+
/// <summary>
54+
/// standard image : 1-, 4-, 8-, 16-, 24-, 32-bit
55+
/// </summary>
5056
FIT_BITMAP = 1,
57+
/// <summary>
58+
/// array of unsigned short : unsigned 16-bit
59+
/// </summary>
5160
FIT_UINT16 = 2,
61+
/// <summary>
62+
/// array of short : signed 16-bit
63+
/// </summary>
5264
FIT_INT16 = 3,
65+
/// <summary>
66+
/// array of unsigned long : unsigned 32-bit
67+
/// </summary>
5368
FIT_UINT32 = 4,
69+
/// <summary>
70+
/// array of long : signed 32-bit
71+
/// </summary>
5472
FIT_INT32 = 5,
73+
/// <summary>
74+
/// array of float : 32-bit IEEE floating point
75+
/// </summary>
5576
FIT_FLOAT = 6,
77+
/// <summary>
78+
/// array of double : 64-bit IEEE floating point
79+
/// </summary>
5680
FIT_DOUBLE = 7,
81+
/// <summary>
82+
/// array of FICOMPLEX : 2 x 64-bit IEEE floating point
83+
/// </summary>
5784
FIT_COMPLEX = 8,
85+
/// <summary>
86+
/// 48-bit RGB image : 3 x 16-bit
87+
/// </summary>
5888
FIT_RGB16 = 9,
89+
/// <summary>
90+
/// 64-bit RGBA image : 4 x 16-bit
91+
/// </summary>
5992
FIT_RGBA16 = 10,
93+
/// <summary>
94+
/// 96-bit RGB float image : 3 x 32-bit IEEE floating point
95+
/// </summary>
6096
FIT_RGBF = 11,
97+
/// <summary>
98+
/// 128-bit RGBA float image : 4 x 32-bit IEEE floating point
99+
/// </summary>
61100
FIT_RGBAF = 12
62101
}
63102

64-
internal enum ColorType {
65-
FIC_MINISWHITE = 0,
66-
FIC_MINISBLACK = 1,
67-
FIC_RGB = 2,
68-
FIC_PALETTE = 3,
69-
FIC_RGBALPHA = 4,
70-
FIC_CMYK = 5
71-
}
72-
73103
[System.Flags]
74104
internal enum LoadFlags {
75105
/// <summary>
@@ -142,6 +172,9 @@ internal enum LoadFlags {
142172

143173
const string FreeImageLibrary = "FreeImage";
144174

175+
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_IsLittleEndian")]
176+
internal static extern bool IsLittleEndian();
177+
145178
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_GetFileTypeFromMemory")]
146179
internal static extern Format GetFileTypeFromMemory(IntPtr memory, int size);
147180

@@ -171,5 +204,14 @@ internal enum LoadFlags {
171204

172205
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_GetBPP")]
173206
internal static extern int GetBPP(IntPtr dib);
207+
208+
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_GetBits")]
209+
internal static extern IntPtr GetBits(IntPtr dib);
210+
211+
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_GetLine")]
212+
internal static extern int GetLine(IntPtr dib);
213+
214+
[DllImport(FreeImageLibrary, EntryPoint = "FreeImage_GetPitch")]
215+
internal static extern int GetPitch(IntPtr dib);
174216
}
175217
}

Runtime/AsyncImageLoader/MipmapJobs.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,66 @@ public void Execute(int outputIndex) {
4242
_outputChannel[outputIndex] = (byte)(total >> 2);
4343
}
4444
}
45+
46+
[BurstCompile(CompileSynchronously = true)]
47+
struct ShortChannelMipmapJob : IMipmapJob<short> {
48+
public int2 InputSize { get; set; }
49+
public int2 OutputSize { get; set; }
50+
51+
public NativeSlice<short> InputChannel { get => _inputChannel; set => _inputChannel = value; }
52+
public NativeSlice<short> OutputChannel { get => _outputChannel; set => _outputChannel = value; }
53+
54+
[ReadOnly] NativeSlice<short> _inputChannel;
55+
[WriteOnly] NativeSlice<short> _outputChannel;
56+
57+
public void Execute(int outputIndex) {
58+
var outputPosition = int2(
59+
outputIndex % OutputSize.x,
60+
outputIndex / OutputSize.x
61+
);
62+
var offset = int2(0);
63+
var total = 0;
64+
65+
for (offset.y = 0; offset.y < 2; offset.y++) {
66+
for (offset.x = 0; offset.x < 2; offset.x++) {
67+
var inputPosition = min(mad(2, outputPosition, offset), InputSize - 1);
68+
var inputIndex = mad(InputSize.x, inputPosition.y, inputPosition.x);
69+
total += _inputChannel[inputIndex];
70+
}
71+
}
72+
73+
_outputChannel[outputIndex] = (short)(total >> 2);
74+
}
75+
}
76+
77+
[BurstCompile(CompileSynchronously = true)]
78+
struct FloatChannelMipmapJob : IMipmapJob<float> {
79+
public int2 InputSize { get; set; }
80+
public int2 OutputSize { get; set; }
81+
82+
public NativeSlice<float> InputChannel { get => _inputChannel; set => _inputChannel = value; }
83+
public NativeSlice<float> OutputChannel { get => _outputChannel; set => _outputChannel = value; }
84+
85+
[ReadOnly] NativeSlice<float> _inputChannel;
86+
[WriteOnly] NativeSlice<float> _outputChannel;
87+
88+
public void Execute(int outputIndex) {
89+
var outputPosition = int2(
90+
outputIndex % OutputSize.x,
91+
outputIndex / OutputSize.x
92+
);
93+
var offset = int2(0);
94+
var total = 0f;
95+
96+
for (offset.y = 0; offset.y < 2; offset.y++) {
97+
for (offset.x = 0; offset.x < 2; offset.x++) {
98+
var inputPosition = min(mad(2, outputPosition, offset), InputSize - 1);
99+
var inputIndex = mad(InputSize.x, inputPosition.y, inputPosition.x);
100+
total += _inputChannel[inputIndex];
101+
}
102+
}
103+
104+
_outputChannel[outputIndex] = .25f * total;
105+
}
106+
}
45107
}

Runtime/AsyncImageLoader/Pixels.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,52 @@ interface IPixel<TChannel> where TChannel : struct {
44
static int ChannelByteCount() => throw new System.NotImplementedException();
55
}
66

7+
struct R16Pixel : IPixel<short> {
8+
public static int ChannelCount() => 1;
9+
public static int ChannelByteCount() => sizeof(short);
10+
11+
public short r;
12+
}
13+
14+
struct RFloatPixel : IPixel<float> {
15+
public static int ChannelCount() => 1;
16+
public static int ChannelByteCount() => sizeof(float);
17+
18+
public float r;
19+
}
20+
721
struct RGB24Pixel : IPixel<byte> {
822
public static int ChannelCount() => 3;
923
public static int ChannelByteCount() => sizeof(byte);
1024

1125
public byte r, g, b;
1226
}
1327

28+
struct RGB48Pixel : IPixel<short> {
29+
public static int ChannelCount() => 3;
30+
public static int ChannelByteCount() => sizeof(short);
31+
32+
public short r, g, b;
33+
}
34+
1435
struct RGBA32Pixel : IPixel<byte> {
1536
public static int ChannelCount() => 4;
1637
public static int ChannelByteCount() => sizeof(byte);
1738

1839
public byte r, g, b, a;
1940
}
41+
42+
struct RGBA64Pixel : IPixel<short> {
43+
public static int ChannelCount() => 4;
44+
public static int ChannelByteCount() => sizeof(short);
45+
46+
public short r, g, b, a;
47+
}
48+
49+
struct RGBAFloatPixel : IPixel<float> {
50+
public static int ChannelCount() => 4;
51+
public static int ChannelByteCount() => sizeof(float);
52+
53+
public float r, g, b, a;
54+
}
2055
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using Unity.Burst;
2+
using Unity.Collections;
3+
using Unity.Collections.LowLevel.Unsafe;
4+
using Unity.Jobs;
5+
6+
public partial class AsyncImageLoader {
7+
[BurstCompile(CompileSynchronously = true)]
8+
struct TransferImageToTextureJob : IJobParallelFor {
9+
public int bytesPerLine;
10+
public int bytesPerScanline;
11+
12+
[NativeDisableUnsafePtrRestriction]
13+
public System.IntPtr bitsPtr;
14+
15+
[WriteOnly] public NativeSlice<byte> textureData;
16+
17+
public unsafe void Execute(int rowIndex) {
18+
UnsafeUtility.MemCpy(
19+
(byte*)textureData.GetUnsafePtr() + rowIndex * bytesPerLine,
20+
(bitsPtr + rowIndex * bytesPerScanline).ToPointer(),
21+
bytesPerLine
22+
);
23+
}
24+
}
25+
26+
[BurstCompile(CompileSynchronously = true)]
27+
struct TransferBGR24ImageToRGB24TextureJob : IJobParallelFor {
28+
public int bytesPerScanline;
29+
public int width;
30+
31+
[NativeDisableUnsafePtrRestriction]
32+
public System.IntPtr bitsPtr;
33+
34+
[WriteOnly] public NativeSlice<byte> textureData;
35+
36+
public unsafe void Execute(int rowIndex) {
37+
var rowData = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<RGB24Pixel>(
38+
(RGB24Pixel*)textureData.GetUnsafePtr() + rowIndex * width, sizeof(RGB24Pixel), width
39+
);
40+
var rowBits = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<RGB24Pixel>(
41+
(bitsPtr + rowIndex * bytesPerScanline).ToPointer(), sizeof(RGB24Pixel), width
42+
);
43+
44+
rowData.SliceWithStride<byte>(0).CopyFrom(rowBits.SliceWithStride<byte>(2));
45+
rowData.SliceWithStride<byte>(1).CopyFrom(rowBits.SliceWithStride<byte>(1));
46+
rowData.SliceWithStride<byte>(2).CopyFrom(rowBits.SliceWithStride<byte>(0));
47+
}
48+
}
49+
50+
[BurstCompile(CompileSynchronously = true)]
51+
struct TransferBGRA32ImageToRGBA32TextureJob : IJobParallelFor {
52+
public int bytesPerScanline;
53+
public int width;
54+
55+
[NativeDisableUnsafePtrRestriction]
56+
public System.IntPtr bitsPtr;
57+
58+
[WriteOnly] public NativeSlice<byte> textureData;
59+
60+
public unsafe void Execute(int rowIndex) {
61+
var rowData = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<RGBA32Pixel>(
62+
(RGBA32Pixel*)textureData.GetUnsafePtr() + rowIndex * width, sizeof(RGBA32Pixel), width
63+
);
64+
var rowBits = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<RGBA32Pixel>(
65+
(bitsPtr + rowIndex * bytesPerScanline).ToPointer(), sizeof(RGBA32Pixel), width
66+
);
67+
68+
rowData.SliceWithStride<byte>(0).CopyFrom(rowBits.SliceWithStride<byte>(2));
69+
rowData.SliceWithStride<byte>(1).CopyFrom(rowBits.SliceWithStride<byte>(1));
70+
rowData.SliceWithStride<byte>(2).CopyFrom(rowBits.SliceWithStride<byte>(0));
71+
rowData.SliceWithStride<byte>(3).CopyFrom(rowBits.SliceWithStride<byte>(3));
72+
}
73+
}
74+
75+
[BurstCompile(CompileSynchronously = true)]
76+
struct TransferRGBFloatImageToRGBAFloatTextureJob : IJobParallelFor {
77+
public int bytesPerScanline;
78+
public int width;
79+
80+
[NativeDisableUnsafePtrRestriction]
81+
public System.IntPtr bitsPtr;
82+
83+
[WriteOnly] public NativeSlice<byte> textureData;
84+
85+
public unsafe void Execute(int rowIndex) {
86+
var rowData = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<RGBAFloatPixel>(
87+
(RGBAFloatPixel*)textureData.GetUnsafePtr() + rowIndex * width, sizeof(RGBAFloatPixel), width
88+
);
89+
var rowAlphaData = rowData.SliceWithStride<float>(3 * sizeof(float));
90+
91+
UnsafeUtility.MemCpyStride(
92+
rowData.GetUnsafePtr(), rowData.Stride,
93+
(bitsPtr + rowIndex * bytesPerScanline).ToPointer(), 3 * sizeof(float),
94+
3 * sizeof(float), width
95+
);
96+
97+
for (var i = 0; i < rowAlphaData.Length; i++) rowAlphaData[i] = 1f;
98+
}
99+
}
100+
}

Runtime/AsyncImageLoader/TransferImageJob.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)