-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOPJDecode.cs
146 lines (122 loc) · 5.57 KB
/
OPJDecode.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
using System;
using System.Runtime.InteropServices;
using OpenJPEG;
namespace testopj
{
public class OPJDecode
{
private readonly OpenJPEGFunctions.opj_msg_callback _cbInfo;
private readonly OpenJPEGFunctions.opj_msg_callback _cbWarning;
private readonly OpenJPEGFunctions.opj_msg_callback _cbError;
private readonly OpenJPEGFunctions.opj_stream_free_user_data_fn _freeUserDataFn;
private readonly OpenJPEGFunctions.opj_stream_read_fn _readFn;
private readonly OpenJPEGFunctions.opj_stream_skip_fn _skipFn;
private readonly OpenJPEGFunctions.opj_stream_seek_fn _seekFn;
private byte[] _image;
private int _offset;
public OPJDecode()
{
_cbInfo = new OpenJPEGFunctions.opj_msg_callback(MsgInfo);
_cbWarning = new OpenJPEGFunctions.opj_msg_callback(MsgWarning);
_cbError = new OpenJPEGFunctions.opj_msg_callback(MsgError);
_freeUserDataFn = new OpenJPEGFunctions.opj_stream_free_user_data_fn(FreeUserData);
_readFn = new OpenJPEGFunctions.opj_stream_read_fn(Read);
_skipFn = new OpenJPEGFunctions.opj_stream_skip_fn(Skip);
_seekFn = new OpenJPEGFunctions.opj_stream_seek_fn(Seek);
}
public BMPGray16 DecodeGray16(byte[] bin)
{
_image = bin;
_offset = 0;
var opjStream = OpenJPEGFunctions.opj_stream_default_create((int)OpenJPEGBool.True);
var opjCodec = OpenJPEGFunctions.opj_create_decompress((int)OpenJPEGCodecFormat.JP2);
var headerPtrMem = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(headerPtrMem, IntPtr.Zero);
try
{
OpenJPEGFunctions.opj_set_info_handler(opjCodec, _cbInfo, IntPtr.Zero);
OpenJPEGFunctions.opj_set_warning_handler(opjCodec, _cbWarning, IntPtr.Zero);
OpenJPEGFunctions.opj_set_error_handler(opjCodec, _cbError, IntPtr.Zero);
OpenJPEGFunctions.opj_stream_set_read_function(opjStream, _readFn);
OpenJPEGFunctions.opj_stream_set_skip_function(opjStream, _skipFn);
OpenJPEGFunctions.opj_stream_set_seek_function(opjStream, _seekFn);
OpenJPEGFunctions.opj_stream_set_user_data(opjStream, IntPtr.Zero, _freeUserDataFn);
OpenJPEGFunctions.opj_stream_set_user_data_length(opjStream, (ulong)_image.Length);
if (OpenJPEGFunctions.opj_read_header(opjStream, opjCodec, headerPtrMem) != (int)OpenJPEGBool.True)
throw new OPJException();
var headerPtr = Marshal.ReadIntPtr(headerPtrMem);
try
{
if (OpenJPEGFunctions.opj_decode(opjCodec, opjStream, headerPtr) != (int)OpenJPEGBool.True)
throw new OPJException();
var img = Marshal.PtrToStructure<OpenJPEGImage>(headerPtr);
var imgComp = Marshal.PtrToStructure<OpenJPEGImageComp>(img.comps);
var imgData16 = new ushort[imgComp.w * imgComp.h];
unsafe
{
var p = (byte*)imgComp.data;
for (var n = 0; n < imgData16.Length; ++n)
{
int v = *p;
++p;
v |= *p << 8;
p += 3;
v <<= (16 - (int)imgComp.prec);
imgData16[n] = (ushort)v;
}
}
return new BMPGray16((int)imgComp.w, (int)imgComp.h, (int)imgComp.prec, imgData16);
}
finally
{
OpenJPEGFunctions.opj_image_destroy(headerPtr);
}
}
finally
{
Marshal.FreeHGlobal(headerPtrMem);
OpenJPEGFunctions.opj_destroy_codec(opjCodec);
OpenJPEGFunctions.opj_stream_destroy(opjStream);
}
}
private void MsgInfo(string msg, IntPtr clientData)
{
Console.Write("info {0}", msg);
}
private void MsgWarning(string msg, IntPtr clientData)
{
Console.Write("warning {0}", msg);
}
private void MsgError(string msg, IntPtr clientData)
{
Console.Write("error {0}", msg);
}
private void FreeUserData(IntPtr data)
{
_image = null;
_offset = 0;
}
private int Read(IntPtr buffer, int bytes, IntPtr userData)
{
if (_offset == _image.Length)
return -1;
var l = Math.Min(bytes, _image.Length - _offset);
Marshal.Copy(_image, _offset, buffer, l);
_offset += l;
return l;
}
private long Skip(long bytes, IntPtr userData)
{
var l = Math.Min((int)bytes, _image.Length - _offset);
_offset += l;
return l;
}
private int Seek(long bytes, IntPtr userData)
{
if (bytes < 0 || bytes >= _image.Length)
return -1;
_offset = (int)bytes;
return 1;
}
}
}