-
Notifications
You must be signed in to change notification settings - Fork 0
/
FileIO.cs
233 lines (203 loc) · 5.96 KB
/
FileIO.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
////////////////////////////////////////////////////////////////////////
//
// This file is part of pdn-jpeg-2000, a FileType plugin for Paint.NET
// that loads and saves JPEG 2000 images.
//
// Copyright (c) 2012-2018 Nicholas Hayes
//
// This file is licensed under the MIT License.
// See LICENSE.txt for complete licensing and attribution information.
//
////////////////////////////////////////////////////////////////////////
using Jpeg2000Filetype.Properties;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
namespace Jpeg2000Filetype
{
internal static class FileIO
{
internal enum CodecError : int
{
Ok = 1,
InitFailed = 0,
OutOfMemory = -1,
UnknownFormat = -2,
DecodeFailure = -3,
TooManyComponents = -4,
ProfileCreation = -5,
ProfileConversion = -6,
ImageBufferWrite = -7,
EncodeFailure = -8
}
[StructLayout(LayoutKind.Sequential)]
internal struct ImageData
{
public int width;
public int height;
public int channels;
[MarshalAs(UnmanagedType.U1)]
public bool hasAlpha;
public IntPtr data;
public double dpcmX;
public double dpcmY;
}
[StructLayout(LayoutKind.Sequential)]
internal struct EncodeParams
{
public int quality;
public double dpcmX;
public double dpcmY;
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int ReadDelegate(IntPtr buffer, int count);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int WriteDelegate(IntPtr buffer, int count);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int SeekDelegate(int offset, int origin);
[StructLayout(LayoutKind.Sequential)]
private sealed class IOCallbacks
{
[MarshalAs(UnmanagedType.FunctionPtr)]
public ReadDelegate Read;
[MarshalAs(UnmanagedType.FunctionPtr)]
public WriteDelegate Write;
[MarshalAs(UnmanagedType.FunctionPtr)]
public SeekDelegate Seek;
}
[SuppressUnmanagedCodeSecurity]
private static class IO_x86
{
[DllImport("Jpeg2000IO_x86.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern CodecError DecodeFile(IOCallbacks callbacks, out ImageData output);
[DllImport("Jpeg2000IO_x86.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern CodecError EncodeFile(
IntPtr inData,
int width,
int height,
int stride,
int channelCount,
EncodeParams parameters,
IOCallbacks callbacks);
[DllImport("Jpeg2000IO_x86.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern void FreeImageData(ref ImageData data);
}
[SuppressUnmanagedCodeSecurity]
private static class IO_x64
{
[DllImport("Jpeg2000IO_x64.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern CodecError DecodeFile(IOCallbacks callbacks, out ImageData output);
[DllImport("Jpeg2000IO_x64.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern CodecError EncodeFile(
IntPtr inData,
int width,
int height,
int stride,
int channelCount,
EncodeParams parameters,
IOCallbacks callbacks);
[DllImport("Jpeg2000IO_x64.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern void FreeImageData(ref ImageData data);
}
public static unsafe CodecError DecodeFile(Stream input, out ImageData output)
{
StreamIOCallbacks streamCallbacks = new StreamIOCallbacks(input);
IOCallbacks callbacks = new IOCallbacks()
{
Read = new ReadDelegate(streamCallbacks.Read),
Write = new WriteDelegate(streamCallbacks.Write),
Seek = new SeekDelegate(streamCallbacks.Seek)
};
CodecError result;
if (IntPtr.Size == 8)
{
result = IO_x64.DecodeFile(callbacks, out output);
}
else
{
result = IO_x86.DecodeFile(callbacks, out output);
}
GC.KeepAlive(callbacks);
GC.KeepAlive(streamCallbacks);
return result;
}
public static void FreeImageData(ref ImageData data)
{
if (IntPtr.Size == 8)
{
IO_x64.FreeImageData(ref data);
}
else
{
IO_x86.FreeImageData(ref data);
}
}
public static void EncodeFile(IntPtr inData, int width, int height, int stride, int channelCount, EncodeParams parameters, Stream output)
{
StreamIOCallbacks streamCallbacks = new StreamIOCallbacks(output);
IOCallbacks callbacks = new IOCallbacks()
{
Read = new ReadDelegate(streamCallbacks.Read),
Write = new WriteDelegate(streamCallbacks.Write),
Seek = new SeekDelegate(streamCallbacks.Seek)
};
CodecError result;
if (IntPtr.Size == 8)
{
result = IO_x64.EncodeFile(inData, width, height, stride, channelCount, parameters, callbacks);
}
else
{
result = IO_x86.EncodeFile(inData, width, height, stride, channelCount, parameters, callbacks);
}
GC.KeepAlive(callbacks);
GC.KeepAlive(streamCallbacks);
if (result != CodecError.Ok)
{
string message = string.Empty;
switch (result)
{
case CodecError.InitFailed:
message = Resources.InitFailed;
break;
case CodecError.OutOfMemory:
throw new OutOfMemoryException();
case CodecError.EncodeFailure:
message = Resources.EncodeFailure;
break;
case CodecError.ImageBufferWrite:
message = Resources.ImageBufferWrite;
break;
}
throw new FormatException(message);
}
}
private sealed class StreamIOCallbacks
{
private readonly Stream stream;
public StreamIOCallbacks(Stream stream)
{
this.stream = stream;
}
public int Read(IntPtr buffer, int count)
{
byte[] bytes = new byte[count];
int bytesRead = stream.Read(bytes, 0, count);
Marshal.Copy(bytes, 0, buffer, count);
return bytesRead;
}
public int Write(IntPtr buffer, int count)
{
byte[] bytes = new byte[count];
Marshal.Copy(buffer, bytes, 0, count);
stream.Write(bytes, 0, count);
return count;
}
public int Seek(int offset, int origin)
{
return (int)stream.Seek(offset, (SeekOrigin)origin);
}
}
}
}